Apple MacBook Pro M1 Max – Lohnt es sich für Machine Learning?


Schon wieder ein neues MacBook? War das Air nicht gerade erst neu gekauft? Ja, es hat sogar noch Garantie, und dann lohnt es sich umso mehr, das Ding zu verkaufen. Ich bin ein großer Fan des Air-Formfaktors, und mit den Pro-Modellen habe ich mich nie anfreunden können. Aber die Limitierung auf 16GB Arbeitsspeicher des MacBook Air war damals schon schwer zu akzeptieren, nur Alternativen gab es nicht. Und so habe ich an dem Abend, an dem die neuen MacBook Pros mit M1 Pro und M1 Max vorgestellt wurden, auch gleich ein Gerät bestellt, ein MacBook Pro 14“ M1 Max mit 10 Kernen, 24 GPU-Kernen, 16-Kern Neutral Engine, 64 GB Arbeitsspeicher (!!!) und einer 2 TB Platte. Mein MacBook Air hat 16 GB RAM und halt den ersten M1-Prozessor mit 8 Kernen.

Warum ein Rechner mit 64 GB Arbeitsspeicher?

Ich arbeite regelmäßig mit großen Datensätzen, 10, 20, auch mal 50GB große Dateien. Aber auch eine 2GB große Datei kann Ärger machen, je nachdem was man alles für Datentransformationen und Berechnungen anstellt. Das macht auf die Dauer keinen Spaß mit einem Rechner mit wenig Arbeitsspeicher. Zwar hilft mir eine lokale Installation von Apache Spark dabei, mehrere Kerne gleichzeitig zu nutzen, aber der fehlende Arbeitsspeicher ist immer wieder ein limitierender Faktor. Für die weniger technisch Versierten unter meinen Lesern: Daten werden von der Festplatte in den Arbeitsspeicher geladen, und hier bestimmt die Geschwindigkeit der Festplatte, wie schnell das geht, denn eine Festplatte, selbst wenn es eine SSD ist, ist langsamer als der Arbeitsspeicher.

Wenn aber der Arbeitsspeicher nicht ausreicht, ich also zum Beispiel versuche, eine 20 GB große Datei in die 16 GB Arbeitsspeicher zu laden, dann fängt das Betriebssystem an, Objekte aus dem Arbeitsspeicher auf die Festplatte zu verlagern. Also von der Festplatte in den Arbeitsspeicher und wieder zurück, nur dass das auf der Festplatte nun als langsamer Arbeitsspeicher gilt. Gleichzeitig Daten auf die Festplatte zu schreiben und zu lesen macht den Rechner auch nicht schneller. Und dazu kommt der Overhead, denn das Programm, das den Arbeitsspeicher benötigt, verlagert die Objekte nicht selbst, sondern das Betriebssystem. Das Betriebssystem benötigt natürlich auch Arbeitsspeicher. Und wenn das Betriebssystem die ganze Zeit auch noch Objekte hin- und her schiebt, dann verbraucht es auch noch CPU-Zeit. Also, zu wenig Arbeitsspeicher bedeutet, dass alles ausgebremst wird.

Zwischendurch hatte ich überlegt, mir selbst ein Cluster zu bauen. Es gibt einige gute Anleitungen im Netz, wie sowas geht mit günstigen Raspberry Pis. Cool aussehen kann das auch. Aber, ich hab wenig Zeit. Ich mache das sogar vielleicht noch mal irgendwann, allein schon weil ich es ausprobieren will. Nur mal zum Nachrechnen: 8 Raspberry Pis mit 8 GB RAM plus Zubehör, da wäre ich wahrscheinlich bei knapp 1.000€ für alles. Plus jede Menge Neues lernen. Aufgeschoben ist nicht aufgehoben.

Wie habe ich getestet?

Vorab: Ich programmiere hauptsächlich in R, einer statistischen Programmiersprache. Hier habe ich zwei Szenarien:

  • Ein R-Skript, das auf einem Kern läuft, also nicht parallelisiert wird
  • Ein R-Skript, dass parallelisiert werden und daher auf einem Cluster laufen kann.

Als Cluster nutze ich Apache Spark, das sich hervorragend lokal nutzen lässt. Für die weniger technisch Versierten: Mit Spark kann ich ein Cluster erstellen, in dem die Rechenaufgaben aufgeteilt und an die einzelnen Nodes zur Verarbeitung geschickt werden. Dadurch werden Aufgaben parallel bearbeitet. Ich kann entweder ein Cluster mit vielen Computern aufbauen, muss die Daten dann über das Netzwerk schicken, oder ich installiere das Cluster lokal und nutze die Kerne meiner CPU als Nodes. Eine lokale Installation hat den großen Vorteil, dass ich keine Netzwerklatenz habe.

Wer noch mehr über R und Spark erfahren will, hier gehts zu meinem Buch über R und Data Science!

Für den ersten Test, ein Skript ohne Parallelisierung, nutze ich einen berühmten Datensatz aus der Suchmaschinengeschichte, die AOL-Daten. 36.389.575 Zeilen, knapp 2 GB groß. Viele Generationen meiner Studierenden haben diesen Datensatz schon bearbeitet. In diesem Skript werden die Suchanfragen auseinander genommen, die Anzahl der Terme pro Suchanfrage bestimmt und Korrelationen berechnet. Natürlich könnte man das auch alles parallelisieren, aber hier nutzen wir eben nur einen Kern.

Für den zweiten Test nutze ich einen knapp 20GB großen Datensatz von Common Crawl (150 Millionen Zeilen und 4 Spalten) und vergleiche ihn mit Daten aus Wikipedia, knapp 2GB. Hier nutze ich dann das oben erwähnte Apache Spark. In meinem M1 Max habe ich 10 Kerne, und auch wenn ich alle nutzen könnte, sollte das Betriebssystem auch noch einen Kern haben, so dass wir hier nur 9 Kerne nutzen. Um es mit dem M1 in meinem MB Air vergleichen zu können, fahren wir auch eine Testvariante, in der das MBP Max dieselbe Anzahl von Kernen nutzt wie das Air.

Wie messe ich? Es existieren mehrere Möglichkeiten, von denen ich die simpelste wähle: Ich schaue mir an, um wie viel Uhr mein Skript startet und wann es endet und berechne die Differenz. Das ist nicht sauber, das ist nicht gut, aber wir werden später sehen, dass die Messfehler hier nicht so die große Rolle spielen.

Ergebnisse: Lohnt es sich?

Es kommt drauf an. Der erste Test ist etwas ernüchternd. Denn der größere Arbeitsspeicher scheint hier wenig zu bringen, auch wenn Mutationen des AOL-Datensatzes erstellt und in den Arbeitsbereich geladen werden. Das alte M1 schafft das Skript in 57,8 Minuten, das M1 Max benötigt 42,5 Minuten. Die Daten werden wahrscheinlich durch die schnelleren SSDs zügiger in den Arbeitsspeicher geladen, aber das sind vielleicht ein paar Sekunden Unterschied. Der Rest scheint von der CPU zu kommen. Aber dafür ist der Preis des M1 Max nicht gerechtfertigt (doppelt so viel wie das MacBook Air).

Spannender wird es, wenn ich auf beiden Seiten dieselbe Anzahl von Kernen für ein Cluster verwende und dann ein Spark nutze. Die Unterschiede sind brutal: 52 Minuten für den alten M1 mit 16GB RAM, 5,4 Minuten beim neuen M1 Max mit 64GB RAM. Tatsächlich benötigt der “alte” M1 mit seinem wenigen Arbeitsspeicher viele Minuten, um den großen Datensatz laden zu können, der neue M1 Max mit den 64 GB schafft das in unter 1 Minute. Übrigens lade ich hier keine einfache CSV-Datei, sondern habe bereits einen Ordner mit ganz vielen kleinen Partitionen, so dass die Nodes unabhängig voneinander Daten einlesen können. Es liegt also nicht daran, dass sich die Nodes gegenseitig im Weg stehen beim Einlesen der großen Datei.

Nehme ich dann noch 2 Kerne mehr, also 9, dann bin ich sogar bei unter 5 Minuten. Um es mal anders auszudrücken: Vorher habe ich eine knappe Stunde auf das Ergebnis gewartet, nun bekomme ich es in ca. 5 Minuten. Das ermöglicht mir ein ganz anderes Arbeiten. Denn in der Regel brauche ich diese Ergebnisse wirklich, und es hat einfach genervt, wenn man so lange gewartet und dann die Verbindung zum Spark-Cluster abgerissen ist und man mit leeren Händen da stand. Und ja, dann lohnt sich dieser Rechner.

Einige Dinge habe ich noch nicht hinbekommen. So kann man mit RAPDIS die GPUs nutzen, und da habe ich ausreichend Kerne. Hab ich nicht zum laufen bekommen, vielleicht benötigt man dafür eben eine NVIDIA-Grafikkarte. Auch stellt Apple selbst mit ML Compute die Möglichkeit zur Verfügung, Tensorflow auf GPUs zu nutzen. Momentan habe ich keine Anwendung dafür, aber ausprobieren will ich das auf jeden Fall noch.

Und sonst so?

Ich mag den Formfaktor des MacBook Pros nicht. Der Rechner, den ich am längsten hatte, war ein MacBook Air. Als ich dann eine kurze Affäre mit einem MacBook Pro 16“ hatte, war mir klar, dass ich sofort wechseln würde, wenn es ein neues MacBook Air mit mehr Power gibt. Ich mag die Tastatur nicht. Sie fühlt sich für mich zu groß an, vielleicht auch nur, weil meine Hände anders auf dem Rechner liegen. Das 14“ MacBook Pro ist kaum größer als das 13“er MacBook Air, aber es ist viel dicker, klobiger, schwerer. Es ist nicht so elegant wie ein Air. Das 16“er mochte ich schon kaum irgendwo mit hinnehmen, ich weiß noch nicht, wie es mit diesem Rechner ist.

Der Rechner wird wärmer als mein MacBook Air, das scheint auch eher den Prozessor runterzuschalten, wenn es heiß zu werden droht. Beim MBP kann man den Rechner gerade noch so auf dem Schoß haben, wenn ich 9 von 10 Kernen im Cluster nutze, so heiß wie mein altes i9 MacBook Pro wird es aber nicht. Bei dem Intel 16er konnte ich ohne Witz die Heizung im Raum ausschalten, so viel Hitze kam da raus, und der Lüfter ging ständig. Der Lüfter des 14“er ist leiser, auch wenn er die ganze Zeit an ist.

Der Sound der Lautsprecher ist super. Das Display ist super.

Wäre ich mit einem Linux-Rechner nicht viel günstiger dabei gewesen? Ja, auf jeden Fall. Aber ich denke auch immer mehr darüber nach, wie viel Lebenszeit ich dafür aufbringen muss, mit einer Lösung zu arbeiten, die weitere Konfiguration erfordert und meine Prozesse nicht so gut unterstützt. Siehe oben, die Idee mit dem Cluster will ich immer noch verfolgen, nur fehlt mir momentan einfach die Zeit dafür.

Übrigens, mein erstes MacBook 1996 hieß noch PowerBook und hatte 4 MB RAM. Das war damals schon gigantisch viel. Und das PowerBook 5300 mit seinem 640×480 Graustufendisplay kostete damals auch um die 4.000 DM, wenn ich mich recht erinnere.