Daten effizient ein- und auslagern

  • Themenstarter Themenstarter Bob-omb
  • Beginndatum Beginndatum
B

Bob-omb

Gast
Hallo,

ich habe ein Programm, welches Klassifikatoren für die Gesichtserkennung trainiert. Bei jedem Trainingsdurchlauf sind sehr viele Berechnungen notwendig, was bedeutet, dass ein einziger Durchgang derzeit ca. 5 Minuten benötigt. Um ein akzeptables Ergebnis zu bekommen benötige ich jedoch einige Hundert solcher Durchgänge. Einen Großteil der Ergebnisse, die bei einem Trainingsdurchlauf berechnet werden, könnte ich theoretisch im nächsten Durchlauf wieder verwenden. Das Problem ist, dass die Datenmenge dabei zu groß wird, und meine 4GB Arbeitsspeicher dafür leider bei weitem nicht ausreichen. Ich habe jetzt versucht, die Ergebnisse auf Festplatte auszulagern - allerdings in sehr kleinen Schritten, was leider dazu geführt hat, dass die Lese-Schreib-Vorgänge länger dauern, als das Neuberechnen der Ergebnisse.

Die Situation sieht derzeit so aus: Ich habe eine ArrayList mit einigen zehntausend Klassifkatoren. Bei jedem Durchlauf wird nun das Ergebnis des Klassifkators auf jedem Trainingsbild berechnet. Eine der sehr aufwendigen Rechenoperationen ändert sich nicht, das heißt ich könnte einen Teil des Ergebnisses für jeden Klassifikator, auf jedem Trainingsbild auslagern. Die ArrayList hätte dann aber einige zehntausen Elemente, die wiederum einige zehntausend Ergebnisse speichern müssten - dafür habe ich leider zu wenig RAM.

Jetzt könnte ich natürlich das ganze schrittweise machen - z.b. die Ergebnisse von 1000 Klassifikatoren laden, Berechnung durchführen, anschließend die nächsten 1000 laden, usw. Das funktioniert aber leider nicht so einfach, da ich die Berechnung derzeit parallel in mehreren Threads laufen lasse, um alle Prozessorkerne auszunutzen. Jeder Thread arbeitet dabei in einem Teilbereich der ArrayList. Das heißt, jeder Thread müsste sich selbst darum kümmern, die benötigten Daten dynamisch ein- und auszulagern. Wobei man hier natürlich eine sinnvolle Schrittweite finden muss - es dürfen ja nicht zu viele Daten auf einmal im Arbeitsspeicher sein, auf der anderen Seite muss das Lesen/Schreiben von der Platte auch schneller gehen, als wenn ich die Rechnung einfach nochmal ausführe.

Das wäre jetzt auch das nächste, was ich versuchen würde. Aber vielleicht hat jemand ja noch ein paar Ideen, wie man mit so einem Problem umgeht? Oder gibt es vielleicht sogar irgendwelche Bibliotheken oder Datenbanksysteme, mit denen man Daten möglichst effizient und schnell ein- und auslagern kann?

Danke fürs Lesen 🙂
 
Hm eingentlich sit ne datenbank beim reinen elsen/schreiben langsamer, aber wenn du sychronization aund automatische auslagerung optimierung viel verwendeter ergebnisse benutzt, könnte das einen versuch wert sein. Versuch es doch einfach mla das ganze mithilfe einer mysql umzustetzen.

Bleibt noch die frage, wie speicherst du die arraylist? weil die java serialisierung ist sehr langsam im vergelich zu einer selbergeschreibenen.
Wenn du zb nur zahlen hast könnteste sowas wie
123123%231321%1312 machen und das selber parsen.
 
Möglichkeiten gibt es schon eine ganze Menge, aber ohne Einblick in deine Berechnungen, ist es schwer jetzt direkt eine zu nennen.

Ansonsten meine Erfahrung bei großen Datenimportbrummern:

- geschicktes Klassen/Datenmodell und geschickte Navigationsmöglichkeiten darin.
- bei Schreib- und Lesevorgängen (Filesystem, DB) immer Brökchen aufeinmal bearbeiten, nicht Zeile für lesen und schreiben.
- Suchvorgänge nach Elementen in großen Listen vermeiden, lieber eine Map verwenden, falls möglich.
- wenn was zu Cachen geht, cachen.
- VM- und Speicherfreundlich sein. Nicht benötigte Listen, Objekte etc. leeren oder nullen, nicht mehr Objekte erzeugen als nötig, sondern lieber resetten etc. Garbage collection ankitzeln etc.
- Bei Gesichtsberechnungen, Daten, die immer gleich sind zu einem Bild auslagern. Serialisieren?
- Speicher hochsetzen. Java Flags, z.B. "-server" probieren.
 
Ich hab eher das Gefühl, dass die Klassifikatoren zuviel Ballast mit sich rumschleppen. Die müssen sich doch nicht die Informationen für jedes Bild einzeln merken.
 
Wenn die Objekte nicht mehr zu optimieren sind, kann man u.U. noch durch Persistierung mit klugem Caching (Files, DB) noch ein wenig Speicher sparen, u.U. aber wieder Performance verlieren. Es ist dann zu vergleichen, ob eine Neuberechnung besser ist als die Persistierung.
Oft muss man aber für eine gezielte Optimierung auch große Teile des eigentlichen Algorithmus der Verarbeitung anpassen, das ist eine größere Aufgabe und muss für jedes Problem anders gelöst werden.
Oder der Moneyansatz: ein 64-Bit Betriebsystem, viel Speicher und ein schnelles Dateisystem (z.B. SSD) ;-)
 
Danke für die Antworten. Werde jetzt nochmal große Teile des Programms umschreiben und versuchen so sparsam wie möglich zu sein. Derzeit gibt es für jeden Blödsinn ein eigenes Objekt, obwohl einfache Arrays in den meisten Fällen genügen würden. Das mit dem selbst serialialisieren werden ich auch mal ausprobieren und vergleichen.

Habe nochmal versucht die Ergebnisse auszulagern, was leider an meinen langsamen Festplatten scheitert. Das Speichern dauert einfach zu lange. Liegt aber evtl. auch an dem etwas ungünstigen Softwaredesign, da ich derzeit alles serialisiere und jedes Objekt noch eine Vielzahl an anderen Objekten mit sich herumschleppt. Werde mir mal ansehen, ob ich das alles wirklich brauche.

Der Moneyansatz wird leider nichts, bin ein armer Student 🙂
 
Werde jetzt nochmal große Teile des Programms umschreiben und versuchen so sparsam wie möglich zu sein. Derzeit gibt es für jeden Blödsinn ein eigenes Objekt, obwohl einfache Arrays in den meisten Fällen genügen würden.

Das ist der richtige Ansatz. Vermeide wenn möglich Objektstrukturen, dass spart enorm viel Speicher.

Darüber hinaus wie hast du denn bisher die Objekte auf die Platte geschrieben? Etwa durch Serialisierung der gesamten Arraylist? Wenn ja, dann liegt dort das Performanzproblem. Zusätzlich werden durch Serialisierung unnötig (in diesem Fall) viele Daten auf die Festplatte geschrieben.

Statt die Objekte zu serailisieren speichere deren Attribute in einem (eigenen) Binärformat (Stichwort: NIO, JDK 1.4.2 New I/O-related APIs & Developer Guides -- from Sun Microsystems). Das spart Speicher und sollte auch beim einlesen einen ordentlichen Performanzschub geben.
 

Neue Themen


Zurück
Oben