Einführung in PyTorch

Auf dieser Seite soll der Einstieg in die Programmierung von künstlicher Intelligenz mit PyTorch vermittelt werden. Es wird nur ein grundsätzliches Verständnis von Mathematik (speziell lineare Algebra) und Programmierung (speziell Python) vorrausgesetzt, jedoch keine spezifische Erfahrung mit KI.

Für einen regen Austausch zum Thema "Künstliche Intelligenz" mit dem Schwerpunkt der Programmierung wird die folgende Gruppe empfohlen.

Künstliche Intelligenz (KI) als Hobby / Artificial Intelligence (AI) as a Hobby

Facebook Gruppe: Künstliche Intelligenz (KI) als Hobby

1. Was ist ein Tensor?

Rank? Shape? Array? Vektor? Matrix? Skalar?

In diesem Video geht es um eine kurze Einführung in Tensoren, die eine Grudlegende Datenart der "künstlichen Intelligenz" sind - insbesondere für den Input von neuronalen Netzen.

Bevor Daten in neuronalen Netzen verarbeitet werden können, müssen diese üblicherweise in Tensoren umgewandelt werden.

Die Umwandung der Daten in Tensoren ist jedoch erst in späteren Videos Thema.

1. Python Code:

import torch

Rank0 = torch.rand(1)
print(Rank0)

Rank1 = torch.rand(3)
print(Rank1)

Rank2 = torch.rand(3,3)
print(Rank2)

Rank3 = torch.rand(3,3,3)
print(Rank3)
#Alternativen zu rand (nicht im Videotutorial!)

Diagonale1 = torch.eye(5)
print(Diagonale1)

AllesNullen = torch.zeros(5,5)
print(AllesNullen)

AllesEinsen = torch.ones(5,5)
print(AllesEinsen)

2. Was kann ich mit einem Tensor machen?

reshape? flatten? sum? prod? numel? max? argmax?

In diesem Video geht es um die Veränderung der Form (shape) eines Tensors, sowie um einfache Berechnungen und Angaben innerhalb eines Tensors mit PyTorch Befehlen.

Als Inputs für Input-Neuronen bei neuronalen Netzen, werden mehrdimensionale Tensoren üblicherweise in einfache Tensoren (Zahlenreihe bzw. Array) mit flatten() umgewandelt. 

Die Berechnung von mehreren Tensoren ist in späteren Videos Thema.

2. Python Code:

import torch

Terragon = torch.tensor([
[1, 1, 1],
[2, 2, 2],
[3, 3, 3],
[4, 5, 4]
])
print(Terragon)
print(Terragon.shape)

Terragon = Terragon.reshape(6,2)
print(Terragon)
print(Terragon.shape)

Terragon = Terragon.reshape(2,6)
print(Terragon)
print(Terragon.shape)

Terragon = Terragon.flatten()
print(Terragon)
print(Terragon.shape)

Terragon = Terragon.reshape(4,3)

print(Terragon.sum())
print(Terragon.sum(dim=0))
print(Terragon.sum(dim=1))

print(Terragon.prod())
print(Terragon.prod(dim=0))
print(Terragon.prod(dim=1))

print(Terragon.max())
print(Terragon.max(dim=0))
print(Terragon.max(dim=1))

print(Terragon.argmax())
print(Terragon.argmax(dim=0))
print(Terragon.argmax(dim=1))

print(Terragon.numel())

Terragon = Terragon.double()
print(Terragon.mean())
print(Terragon.mean(dim=0))
print(Terragon.mean(dim=1))
Terragon = Terragon.narrow(Dim,Start,Length) # Löscht eine Zeile im Tensor

3. Wie kann ich mit Tensoren rechnen?

add? sub? multiply? divide? sqrt? abs? neg? equal? greater than? less than?

In diesem Teil des Tutorials werden einige grundlegende Berechnungen gezeigt, die man mit einem einzelnen Tensor oder auch mit 2 oder mehr Tensoren durchführen kann.

Die hier gezeigten Berechnungen sind sogenannte Element-wise Berechnungen, die eine Berechnung Schritt für Schritt für jedes Element des Tensors durchführen. Dafür müssen beide Tensoren den selben shape haben.

Eine technisch/mathematische Besonderheit bildet das sog. Broadcasting, sodass auch eine einzelne Zahl Element-wise auf jedes Element angewendet werden kann. "Im Hintergrund" wird diese eine Zahl dafür so oft "kopiert", bis die Anzahl der Elemente des Tensors erreicht ist und Element-wise angewendet werden kann.

Zusätzlich werden Funktionen gezeigt, mit denen man prüfen kann, welche Elemente in einem Tensor im Vergleich zu einem bestimmten Wert z.B. größer oder kleiner sind.

3. Python Code: 

import torch

Tensor1 = torch.rand(4,5)
Tensor2 = torch.rand(4,5)

print(Tensor1)
print(Tensor2)

#Element-wise, Component-wise, Point-wise meint alles das selbe.
#Element-wise: Berechnungen mit 2 Tensoren des gleichen Shape:

#Addieren:
print (Tensor1 + Tensor2)

#Subtrahieren:
print (Tensor1 - Tensor2)

#Multiplizieren:
print (Tensor1 * Tensor2)

#Teilen durch:
print (Tensor1 / Tensor2)

#Broadcasting: Berechnungen mit 1 Tensor und 1 Zahl:

#Addieren:
print (Tensor1 + 100)

#Subtrahieren:
print (Tensor1 - 100)

#Multiplizieren:
print (Tensor1 * 100)

#Teilen durch:
print (Tensor1 / 100)

#Wurzel von jedem Element ziehen:
print (Tensor1.sqrt())

#Absolut-Wert (Betrag) von jedem Element:
print (Tensor1.abs())

#Negativen-Wert von jedem Element:
print (Tensor1.neg())

#Prüfen, welche Elemente im Tensor gleich einem Wert sind (eq = equal to):
print (Tensor1.eq(0.5))

#Prüfen, welche Elemente im Tensor größer oder gleich einem Wert sind (gt = greater than, ge = greater or equal to):
print (Tensor1.ge(0.5))

#Prüfen, welche Elemente im Tensor kleiner als ein Wert sind (lt = less than, le = less or equal to):
print (Tensor1.lt(0.5))

4. Wie kann ich eine .CSV Datei in einen Tensor umwandeln?

.csv? .xls? .xlsx? .txt? Tabellen? Datenbanken? MySQL? pandas? read_csv?

Oft liegen die Roh-Daten, die man zur Auswertung aufbereiten muss, in unterschiedlichen Formaten vor. Üblicherweise liegen sie in diversen Datenbanken oder auch in Excel-Dateien vor.

Ein übliches Ausgabeformat aus allen diesen Quellen ist das sogenannte CSV Format. Dieses Format lässt sich aus Datenbanken und Excel gleichermaßen erzeugen und ist eigentlich nur eine reine Text-Datei, in der die Daten jedoch strukturiert (wie in einer Datenbank) angeordnet sind.

Dieses Tutorial zeigt, wie man das universelle CSV Format in einen PyTorch Tensor umwandeln kann, sodass weitere Operationen damit möglich sind.

4. Python Code:

import torch
import pandas as pd

#CSV Datei einlesen und ausgeben mit pandas
Terragon_Sample_Data = pd.read_csv('20181024_Terragon_Sample_Data.csv')
print(Terragon_Sample_Data)
print(type(Terragon_Sample_Data))

#Values aus dem Pandas DataFrame in einen PyTorch Tensor umwandeln
Terragon = torch.tensor(Terragon_Sample_Data.values)
print(Terragon)
print(Terragon.shape)

5. Wie kann ich eine .JPG Datei in einen Tensor umwandeln?

.jpg? .png? images? imread? shape? resize? rgb2gray? matplotlib? pyplot? cmap? flatten?

Eine übliche Anwendung für neuronale Netze (und PyTorch) ist die Bildanalyse, bei der ein neuronales Netz mit einer größeren Anzahl von Bildern auf spezifische Muster trainiert wird.

Der erste Schritt zur Auswertung von Bildern ist jedoch die Umwandlung z.B. der .jpg Datei in einen Tensor, der nur aus einer strukturierten Sammlung von Zahlen besteht.

Dabei wird jedes einzelne Pixel des Bildes in seine 3 Farbkanäle aufgeteilt und zusammen mit der Position des Pixels zu einem Tensor zusammengefügt. Damit alle Tensoren immer die gleiche Größe haben (gleiche Anzahl an Inputs für das neuronale Netz), müssen alle Bilder vorher auf eine einheitliche Größe skaliert werden.

Bild 2: Wenn man alle 10.000 Grau-Werte des Flatten-Tensors mit matplotlib als Graph darstellt, sieht der "Fingerabdruck" eines Bildes aus, wie eine individuelle Wave-Tonkurve.

Die Zuweisung der "Ergebnisse" zum (überwachten) Training des neuronalen Netzes wird erst in einem anderen Tutorial behandelt.

5. Python Code:

from skimage.transform import resize
from skimage.color import rgb2gray
import matplotlib.pyplot as plt
from scipy import misc
import numpy as np
import torch

#Lädt das Bild aus der JPG Datei
picture = misc.imread('christmas.jpg')
print("NumPy: ",type(picture))
print("Shape of Array: ",picture.shape)
print("dtype of Array: ",picture.dtype)

#Zeigt picture als Array mit 3 Achsen (RGB)
#np.set_printoptions(threshold=np.nan) #Zeigt das komplette Array, optional
print("Inhalt des numpy Array mit 3 RGB Achsen: ",picture)

#Resize in Standard für NN
picture = resize(picture, (100, 100), mode='constant', anti_aliasing=True)

#Graustufen umwandeln um 1 statt 3 Kanäle zu haben
picture = rgb2gray(picture)

#Zeigt picture als Array mit 1 Achse (Grey)
print("Inhalt des numpy Array mit 1 Grau Achse: ",picture)

#Zeigt das picture zur Kontrolle als Bild
plt.imshow(picture,cmap="gray") #cmap ist nur für imshow() relevant
plt.show()

#PyTorch Tensor aus dem Array erstellen
Terragon = torch.tensor(picture)
print("PyTorch Tensor : ",Terragon)
print(Terragon.shape)

#Flatten() , um als Input für NN nutzbar zu sein
Terragon = Terragon.flatten()
print("Flatten Tensor: ",Terragon)
print(Terragon.shape)

More Image Manipulation:: http://www.scipy-lectures.org/advanced/image_processing/

 

5. Additional Code for Graph:

# Tensor in numpy() umwandeln
# um mit matplotlib ausgeben zu können
X = Terragon.numpy()

# MatPlotLib Graph erstellen
plt.plot(X)
plt.title("Terragon.de Image Tensor Grayscale Graph")
plt.xlabel("Number of Pixel (row by row)")
plt.ylabel("Value of Gray of this Pixel")
plt.show()

6. Wie erstelle ich mein erstes funktionsfähiges neuronales Netz?

Input Layer? Hidden Layer? Output Layer? Batch Size? Learning Rate? Epochs? Sequential? Linear? ReLU? Sigmoid? Loss Function? Optimizer? Forward Propagation? Backward Pass? 

In diesem Tutorial geht es um unser erstes funktionsfähiges neuronales Netzwerk, welches sich zufällige Zahlen als Trainingsdaten (x) und ebenfalls Zufällige Ergbenisdaten (y) generiert und versucht, darauf basierende Vorhersagen für die Ergebnisdaten (y predicted) zu generieren.

Based on: Medium

6. Python Code:

import os.path
import torch
import torch.nn as nn

# Diverse Vorgaben zum Neuronalen Netz
Number_Input_Neurons = 10 # Muss x Tensor Dimension entsprechen
Number_Hidden_Neurons = 5 # Je mehr, desto genauer (aber zu viel bringt nichts)
Number_Output_Neurons = 1 # Muss y Tensor Dimension entsprechen
Batch_Size = 10
Learning_Rate = 0.01 # Muss individuell angepasst werden
Number_Epochs = 100 # Je höher, desto genauer
Model_Parameter_File = "20181103_model_status.pt" # Status in diese Datei schreiben/lesen

# --------------- Hier kommen die Trainingsdaten rein

# Vorgabe der Training Input-Data x (random)
x = torch.randn(Batch_Size, Number_Input_Neurons).random_(0,10)
print("Input Tensor: ", x)

# Vorgabe der Training Output-Data y (random)
y = torch.randn(Batch_Size, Number_Output_Neurons).random_(0,2)
print("Output Tensor: ", y)



# --------------- Ab hier braucht man nichts mehr zu ändern !

# Neural Network Struktur vorgeben (input -> linear -> relu -> linear -> sigmoid)
model = nn.Sequential(
nn.Linear(Number_Input_Neurons, Number_Hidden_Neurons),
nn.ReLU(),
nn.Linear(Number_Hidden_Neurons, Number_Output_Neurons),
nn.Sigmoid()
)

# Lädt die gespeicherten Weights, wenn Datei vorhanden
if os.path.isfile(Model_Parameter_File):
model.load_state_dict(torch.load(Model_Parameter_File))

# Loss Function vorgeben (Mean Squared Error Loss)
criterion = torch.nn.MSELoss()

# Optimizer vorgeben (SGD Stochastic Gradient Descent)
optimizer = torch.optim.SGD(model.parameters(), lr = Learning_Rate)

# Das ist jetzt die eigentliche Ausführung des Prozesses
# This does the forward propagation, loss computation, backward propagation and parameter updation in that sequence
for epoch in range(Number_Epochs):
# Forward Propagation
y_predicted = model(x)

# Compute and print loss
loss = criterion(y_predicted, y)
print('epoch: ', epoch, ' loss: ', loss.item())

# Zero the gradients
optimizer.zero_grad()

# perform a backward pass (backpropagation)
loss.backward()

# Update the parameters
optimizer.step()

# --------------- Ab hier nur noch Auswertungen

# Beide Tensoren für Training und Prediction anzeigen
print("y training: ",y)
print("y predicted: ",y_predicted)

# Predicted Tensor runden, um auf 1 und 0 zu kommen
y_predicted_round = torch.round(y_predicted)
print("y predicted round: ",y_predicted_round)

# Vergleichs-Tensor aus den beiden Tensoren erstellen (1 = gleich, 0 = falsch) dann Durchschnitt ausgeben
y_predicted_equal = torch.eq(y, y_predicted_round)
y_predicted_equal = y_predicted_equal.double()
print("y predicted/training % OK: ",y_predicted_equal.mean())

# Alle Weights nach dem Training anzeigen
for param in model.parameters():
print("Alle weight Values: ",param.data)

# Speichert alle Model Parameter in eine Datei
torch.save(model.state_dict(), Model_Parameter_File)

Exkurs 1: Einfacher Graph mit MatPlotLib

Mit diesem Code wird ein einfacher Graph erstellt, der zum Beispiel eine Zahlenreihe auf der x-Achse und 2 Zahlenreihen auf der y-Achse darstellt, sodass 2 Kurven entstehen.

Python Code:

import torch
import matplotlib.pyplot as plt

#Rank 1 Tensoren erstellen
X = torch.randn(20)
Y1 = torch.randn(20)
Y2 = torch.randn(20)

#Tensoren in numpy() umwandeln
#um mit matplotlib ausgeben zu können
X = X.numpy()
Y1 = Y1.numpy()
Y2 = Y2.numpy()

#MatPlotLib Graph erstellen
plt.plot(X ,Y1)
plt.plot(X ,Y2)
plt.title("Terragon Graph")
plt.xlabel("X")
plt.ylabel("Y1 und Y2")
plt.legend(["Y1","Y2"])
plt.show()

Exkurs 2: CSV Daten importieren und als Graph ausgeben

In diesem Exkurs schauen wir uns an, wie wir mit Python und Pandas eine CSV Datei importieren können und die Daten mit MatPlotLib ausgeben können.

Python Code:

import matplotlib.pyplot as plt
import pandas as pd

#CSV Datei einlesen und ausgeben mit pandas
Terragon_Sample_Data = pd.read_csv('20181024_Terragon_Sample_Data.csv')
print(Terragon_Sample_Data)
print(type(Terragon_Sample_Data))

#Eine einzelne Spalte ausgeben
print(Terragon_Sample_Data.Terragon1)

#Einen einzelnen Wert einer Spalte ausgeben
print(Terragon_Sample_Data.Terragon1.iloc[2])

#Zahlenreihen für MatPlotLib zusammenstellen
Terragon1 = Terragon_Sample_Data.Terragon1
Terragon2 = Terragon_Sample_Data.Terragon2
Terragon3 = Terragon_Sample_Data.Terragon3

#MatPlotLib Graph erstellen
plt.plot(Terragon1 ,Terragon2, 'o')
plt.plot(Terragon1 ,Terragon3)
plt.title("Terragon Graph")
plt.xlabel("Terragon1")
plt.ylabel("Terragon2 und Terragon3")
plt.legend(["Terragon2","Terragon3"])
plt.show()

Exkurs 3: Datenreihen aus MySQL in Tensor importieren

import pymysql as my
import torch

Batch_Size = 6
Input_Neurons = 10

# -------------------------------------------------------------

# Leere Tensoren erstellen, weil er sonst undefiniert Meldet
Stacked_Input = torch.ones(Input_Neurons)
Stacked_Output = torch.ones(1)

db = my.connect(host="localhost", user="xxx", passwd="xxx", db="xxx")

for Row in range(Batch_Size):
cursorInput = db.cursor()
sqlInput = "SELECT daxkurs FROM daxminute LIMIT "+str(Row)+","+str(Input_Neurons)+""
print(cursorInput.execute(sqlInput))

Input = torch.tensor(cursorInput.fetchall())
Input = Input.flatten()
#print(Input)

Stacked_Input = torch.cat([Stacked_Input,Input],0)

cursorOutput = db.cursor()
sqlOutput = "SELECT daxkurs FROM daxminute LIMIT "+str(Row+Input_Neurons)+",1" #Output_Neurons immer = 1
print(cursorOutput.execute(sqlOutput))

Output = torch.tensor(cursorOutput.fetchall())
Output = Output.flatten()
#print(Output)

Stacked_Output = torch.cat([Stacked_Output, Output], 0)

Stacked_Input = Stacked_Input.reshape(Batch_Size+1,Input_Neurons)
print(Stacked_Input)

Stacked_Output = Stacked_Output.reshape(Batch_Size+1,1)
print(Stacked_Output)

Exkurs 4: TXT Text einlesen und Wörterbuch als NumPy-Array (String) erstellen

Python Code:

import numpy as np

with open('20181025_Text_Data_Example_general.txt', 'r') as myfile:
Terragon_Sample_Data = myfile.read()#.replace('\n', ' ') #Zeilenumbrüche entfernen

#Python List mit einzelnen Wörtern aus String erstellen
Terragon_Sample_Data = Terragon_Sample_Data.replace('?', ' ').replace('!', ' ')
Terragon_Sample_Data = Terragon_Sample_Data.split()

#NumPy Array aus List erstellen (Tensor geht nicht, weil string!)
Terragon_Sample_Data = np.array(Terragon_Sample_Data)
Terragon_Sample_Data = np.unique(Terragon_Sample_Data)
Terragon_Sample_Data = np.char.lower(Terragon_Sample_Data)
print(Terragon_Sample_Data)
print(type(Terragon_Sample_Data))
print(len(Terragon_Sample_Data))