"File \u001b[0;32m/opt/conda/lib/python3.10/site-packages/fastai/vision/core.py:98\u001b[0m, in \u001b[0;36mload_image\u001b[0;34m(fn, mode)\u001b[0m\n\u001b[1;32m 96\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mload_image\u001b[39m(fn, mode\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mNone\u001b[39;00m):\n\u001b[1;32m 97\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mOpen and load a `PIL.Image` and convert to `mode`\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m---> 98\u001b[0m im \u001b[38;5;241m=\u001b[39m \u001b[43mImage\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mopen\u001b[49m\u001b[43m(\u001b[49m\u001b[43mfn\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 99\u001b[0m im\u001b[38;5;241m.\u001b[39mload()\n\u001b[1;32m 100\u001b[0m im \u001b[38;5;241m=\u001b[39m im\u001b[38;5;241m.\u001b[39m_new(im\u001b[38;5;241m.\u001b[39mim)\n",
"\u001b[0;31mFileNotFoundError\u001b[0m: [Errno 2] No such file or directory: '/home/jovyan/work/data/results/<meine_resultate>/2022-10-18T14:15:52.011617.png'"
"Der nächste Schritt ist es eine `learner` zu erstellen. Der Learner fasst ein `Model`, mehrere `DataLoader` und eine `loss_function` zusammen in eine Methode. Die Dataloader wurden bereits erstellt, bzw. Die Iterator-Klasse `DataLoaders`.\n",
"\n",
"Die erste Frage ist es, welche Art von `Learner` gebraucht wird. Hier wird ein `Vision Learner` genutzt. Der Vision Learner ist ein sogenannter CNN (Convolutional Neural Network) Learner. Ein CNN ist ein Netzwerk, dass für die Erkennung und Klassifizierung von Bildern genutzt wird. Anhand von übertragbaren lernen kann dieses Netzwerk für die Bildererkennung genutzt werden.\n",
"\n",
"## Model\n",
"Eine Wichtige Entscheidung, die hier getroffen werden muss, ist die Entscheidung welches `Model` vewendet werden soll. Bei einem Modell handelt es sich um ein bereits trainiertes Modell mit vielen bis zu sehr vielen Daten.\n",
"\n",
"Es gibt eine grosse Auswahl von verscheidenen Modellen. Die Auswahl ein richtiges Modell ist keine Einfache. Der Unterschied zwischen den Models ist, dass das Trainieren viel länger dauern kann, dafür aber je nachdem auch genauer ist. Jedoch ist das grösste Model auch nicht immer die beste Wahl, da ein grössere Modell auch für die Auswertung länger braucht.\n",
"\n",
"Aus diesen Gründen ist die Wahl des Modells sehr wichtig und auch keine Einfache."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "265f99f9-9f50-4038-9636-367e0b3c705b",
"metadata": {},
"outputs": [],
"source": [
"learn = vision_learner(dls, resnet34)"
]
},
{
"cell_type": "markdown",
"id": "6d6ddcc9-b57e-4607-bcfb-b08417a1e3b0",
"metadata": {
"tags": []
},
"source": [
"# Learning Rate (Lern-Rate)\n",
"\n",
"Bevor man anfängt das Model zu trainieren muss die `learning rate` gefunden werden. Dabei ist es wichtig, dass eine gute Lern-Rate gefunden wird:\n",
"\n",
"- `Tiefe Lern-Rate`: Bei einer tiefen Lern-Rate dauert es länger bis das Modell einen optimalen Zustand erreicht. Das bedeutet es werden mehr Ressourcen und mehr Zeit gebraucht, als wenn man die Lern-Rate berechnet.\n",
"- `Hohe Lern-Rate`: Bei einer hohen Lern-Rate macht das Modell oft zu grosse Schritte, was dazu führen kann, dass der optimal Zustand überschossen wird und das Modell im gegenzug and Qualität verliert."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "4bf34214-5e95-4302-8332-0fabdc9fb867",
"metadata": {},
"outputs": [],
"source": [
"learn.lr_find()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "a1658d21-21a6-405c-bdaf-c782858b3acb",
"metadata": {},
"outputs": [],
"source": [
"lr = 3.630780702224001e-05"
]
},
{
"cell_type": "markdown",
"id": "d5445c86-f708-41f0-bec9-54c0c66d1606",
"metadata": {},
"source": [
"Nun ist es endlich an der Zeit das Modell zu trainieren"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5c808fd5-e966-45ab-8656-e96dbe4361ff",
"metadata": {},
"outputs": [],
"source": [
"learn.fine_tune(25, lr)"
]
},
{
"cell_type": "markdown",
"id": "4df54aa8-b7d8-49a2-a8c1-d911d4e31a9d",
"metadata": {},
"source": [
"Beim `fine_tune` wird sowohl der `train_loss`, wie auch der `valid_loss` angezeigt:\n",
"\n",
"- `train_loss`: Der Trainings-Verlust zeigt an, wie passend das Modell zu den Trainingsdaten ist. Je kleiner dieser Wert ist desto besser.\n",
"- `valid_loss`: Der Validierungs-Verlust zeigt an, wie passend das Modell zu den neuen Daten ist. Je kleiner dieser Wert ist desto besser."
]
},
{
"cell_type": "markdown",
"id": "271cb9c9-0452-4b0a-8163-8e95fd8daa73",
"metadata": {},
"source": [
"# Fertig mit dem Training\n",
"\n",
"Wenn man fertig mit dem Trainieren ist, dann kann man sich auch das Resultat anzeigen lassen"
"Daten können ganz einfach in ein `Pickle`-File exportiert werden. So können sie später mit der `load_learner`-Funktion einfach wieder geladen werden. \n",
"\n",
"**Achtung** Damit der Learner wieder importiert und gebraucht werden kann müssen auch die Funktionen, die im DataBlock benutzt wurden am neuen Ort erstellt werden. In diesem Fall ist das die Funktion `read_data_from_json`."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "198d3f9e-1687-4d94-8d6e-dd6518054039",
"metadata": {},
"outputs": [],
"source": [
"learn.export(Path('<Pfad>/<Modellname>.pkl'))"
]
},
{
"cell_type": "markdown",
"id": "25fb2731-e22e-4292-a55f-854583ec81a2",
"metadata": {},
"source": [
"# Importieren\n",
"\n",
"Wenn der Learner importiert wurde, kann dieser wie vorhin weiter verwendet werden.\n",
"\n",
"In diesem Fall wird der Learner dann auf dem Fahrzeug importiert und genutzt, damit dieses so gut wie möglich selbst fahren kann."
Zuerst müssen die benötigten Namespaces und Funktionen aus den verschiedenen Libraries importiert werden.
Um alle Funktionen aus fastai zu importieren könnte man auch das verwenden:
```python
fromfastaiimport*
fromfastai.visionimport*
```
Diese Methode ist jedoch eher unschön, da man den Überblick nicht hat, welche Namespaces man importiert hat. Falls man so mehrere Namespaces mit dem selbden Namen importiert, dann gewinnt der letzte. Als Beispiel: fastai hat einen Namespace mit dem Namen `Model`, welchen man hier nicht explizit gebraucht wird. Pytorch hat ebenfalls einen Namespace mit dem Namen `Model`, welcher gebraucht wird. Wenn man also `*` importiert kann es zu verwirrung führen welcher `Model`-Namespace jetzt verwendet wird oder von welcher Library dieser überhaupt kommt.
Darum ist es immer besser nur explizit Namespaces und Funktionen zu importieren
In diesem Abschnitt wird definiert, in welchem Ordner die Trainingsdaten gespeichert sind. Hier wird angenommen, das in dem Ordner immer pro Bild-Datei eine JSON-Datei mit demselben Namen befindet. Anschliessend wird überprüft, ob der Ordner existiert und das Resultat wird ausgegeben.
Jetzt ist alles so vorbereitet, dass man das Training mit der AI aufsetzten kann. Um damit zu beginnen muss zuerst ein `Datablock` erstellt werden. Ein Datablock ist einfach gesagt nichts anderes als ein Packet für eine genormte Schnittstelle. Das heisst, dass es sehr einfach ist anzugeben, was für Daten sind der Input, von wo kommen diese Daten, was ist der Ziel Output etc.
Da es sich hier um das Trainieren handelt werden sowohl der Erwartete Input, wie auch der dazugehörige Output benötigt.
-`blocks`: Definiert mit welchen Daten das Model arbeiten wird. Meistens werden mind. zwei Blöcke definiert. Der erste Block spezifiziert die Input-Daten und der zweite Block die erwarteten Output-Daten sind. In diesem Beispiel werden Bilder als Input erwartet und als Output ein RegressionBlock mit zwei Ausgabewerten. Anhand dieser Regression wird versucht einem Bild Werte zuzuweisen. Der Grund wieso es zwei Outputs hat ist, dass es einmal für die Steuerung und einmal für die Geschwindigkeit ist.
-`get_items`: Von wo die Input-Daten gelesen werden. In diesem Fall wird die Methode `get_image_files` verwendet, welche Bilder aus einem Verzeichnis lädt.
-`splitter`: Für das Trainieren von Daten muss bestummen werden, welche Daten für das Training und welche für die anschliessende Validierung genutzt werden. Dies kann man zufällig machen mit einem `RandomSplitter`, aber es gibt auch Methoden, wo der Nutzer dies selber definieren kann z.B. einem `FileSplitter`
-`get_y`: Wie der Output definiert wird von den Input-Daten. Hier wird die Methode 'read_data_from_json' genutzt, beiwelcher definiert wurde, dass Anhand eines Bildes die Steuerung und das Tempo ausgelesen wird.
-`item_tfms`: Falls Bilder zu gross sind, kann diese Methode verwendet werden, um eine Transformation auf allen Bildern auszuführen, wie z.B. zuscheiden, verkleiner, hereinzoomen etc.
Mit der fertigstellung des DataBlocks ist nun definiert, wie unsere Daten Strukturiert, Kategorisiert und Bearbeitet werden müssen. Als nächstes folg die Erstellung eines `DataLoaders`.
Zuerst wird der Pfad angegeben, bei welcher der DataBlock die Bilder sucht. Die Variable `bs` steht für die Batch_Size.
Ein DataLoaders ist eine Iterator-Klasse, welche vom DataBlock aufgerufen wird um die Daten in Chunks zu laden anhand der definierten Batch-Size. Also der DataLoaders erzeugt mehrere `DataLoader` Einheiten. In einem DataLoader sind die Daten dann bereits vorbereitet und ready.
Der nächste Schritt ist es eine `learner` zu erstellen. Der Learner fasst ein `Model`, mehrere `DataLoader` und eine `loss_function` zusammen in eine Methode. Die Dataloader wurden bereits erstellt, bzw. Die Iterator-Klasse `DataLoaders`.
Die erste Frage ist es, welche Art von `Learner` gebraucht wird. Hier wird ein `Vision Learner` genutzt. Der Vision Learner ist ein sogenannter CNN (Convolutional Neural Network) Learner. Ein CNN ist ein Netzwerk, dass für die Erkennung und Klassifizierung von Bildern genutzt wird. Anhand von übertragbaren lernen kann dieses Netzwerk für die Bildererkennung genutzt werden.
## Model
Eine Wichtige Entscheidung, die hier getroffen werden muss, ist die Entscheidung welches `Model` vewendet werden soll. Bei einem Modell handelt es sich um ein bereits trainiertes Modell mit vielen bis zu sehr vielen Daten.
Es gibt eine grosse Auswahl von verscheidenen Modellen. Die Auswahl ein richtiges Modell ist keine Einfache. Der Unterschied zwischen den Models ist, dass das Trainieren viel länger dauern kann, dafür aber je nachdem auch genauer ist. Jedoch ist das grösste Model auch nicht immer die beste Wahl, da ein grössere Modell auch für die Auswertung länger braucht.
Aus diesen Gründen ist die Wahl des Modells sehr wichtig und auch keine Einfache.
Bevor man anfängt das Model zu trainieren muss die `learning rate` gefunden werden. Dabei ist es wichtig, dass eine gute Lern-Rate gefunden wird:
-`Tiefe Lern-Rate`: Bei einer tiefen Lern-Rate dauert es länger bis das Modell einen optimalen Zustand erreicht. Das bedeutet es werden mehr Ressourcen und mehr Zeit gebraucht, als wenn man die Lern-Rate berechnet.
-`Hohe Lern-Rate`: Bei einer hohen Lern-Rate macht das Modell oft zu grosse Schritte, was dazu führen kann, dass der optimal Zustand überschossen wird und das Modell im gegenzug and Qualität verliert.
Daten können ganz einfach in ein `Pickle`-File exportiert werden. So können sie später mit der `load_learner`-Funktion einfach wieder geladen werden.
**Achtung** Damit der Learner wieder importiert und gebraucht werden kann müssen auch die Funktionen, die im DataBlock benutzt wurden am neuen Ort erstellt werden. In diesem Fall ist das die Funktion `read_data_from_json`.