Torch ist eine Bibliothek zum Erstellen und Trainieren von [[machine_learning|neuronalen Netzwerken]].
=====Arten von Modellen=====
====Sequential====
Das Sequential-Modell ist eine einfache Möglichkeit, sequenzielle Modelle in PyTorch zu definieren. Es erlaubt uns, eine sequentielle Kette von Schichten zu erstellen, in der die Ausgabe einer Schicht als Eingabe für die nächste Schicht verwendet wird.
import torch
import torch.nn as nn
model = nn.Sequential(
nn.Linear(784, 256),
nn.ReLU(),
nn.Linear(256, 10),
nn.Softmax(dim=1)
)
In diesem Beispiel wird ein Sequential-Modell mit zwei linearen Schichten, einer ReLU-Aktivierungsfunktion und einer Softmax-Aktivierungsfunktion erstellt. Die Eingabe des Modells hat eine Größe von 784, und die Ausgabe hat eine Größe von 10.
====Module====
Das Module-Modell ist eine flexiblere Art, Modelle in PyTorch zu definieren. Es ermöglicht uns, eigene Schichten und komplexe Modelle zu erstellen, indem wir die nn.Module-Klasse erweitern.
import torch
import torch.nn as nn
class MyModel(nn.Module):
def __init__(self):
super(MyModel, self).__init__()
self.fc1 = nn.Linear(784, 256)
self.relu = nn.ReLU()
self.fc2 = nn.Linear(256, 10)
self.softmax = nn.Softmax(dim=1)
def forward(self, x):
x = self.fc1(x)
x = self.relu(x)
x = self.fc2(x)
x = self.softmax(x)
return x
model = MyModel()
In diesem Beispiel wird ein Module-Modell erstellt, das den gleichen Aufbau wie das Sequential-Modell hat. Die Schichten werden jedoch als Attribute der Modellklasse definiert, und die Vorwärtsfunktion wird durch die Methode forward festgelegt. Dadurch haben wir mehr Flexibilität bei der Gestaltung und Steuerung des Modells.
====Functional====
Das Functional-Modell ist eine weitere Möglichkeit, Modelle in PyTorch zu definieren. Es basiert auf der Verwendung von Funktionen aus dem torch.nn.functional-Modul, anstatt Schichtenobjekte zu erstellen.
import torch
import torch.nn.functional as F
def my_model(x):
x = F.linear(x, 784, 256)
x = F.relu(x)
x = F.linear(x, 256, 10)
x = F.softmax(x, dim=1)
return x
input = torch.randn(1, 784)
output = my_model(input)
In diesem Beispiel wird das Modell als eine Funktion definiert, die die Funktionen aus dem torch.nn.functional-Modul verwendet. Das Functional-Modell ist nützlich, wenn Sie ein einfaches Modell ohne interne Zustände oder trainierbare Parameter erstellen möchten.
====Convolutional====
Convolutional Neural Networks sind besonders gut geeignet für die Verarbeitung von Bildern. Sie verwenden spezielle Schichten wie Convolutional Layers und Pooling Layers, um die räumliche Struktur der Eingabedaten zu berücksichtigen.
import torch
import torch.nn as nn
class MyCNN(nn.Module):
def __init__(self):
super(MyCNN, self).__init__()
self.conv1 = nn.Conv2d(3, 16, kernel_size=3, stride=1, padding=1)
self.relu = nn.ReLU()
self.pool = nn.MaxPool2d(kernel_size=2, stride=2)
self.fc = nn.Linear(16 * 14 * 14, 10)
def forward(self, x):
x = self.conv1(x)
x = self.relu(x)
x = self.pool(x)
x = x.view(-1, 16 * 14 * 14)
x = self.fc(x)
return x
model = MyCNN()
In diesem Beispiel wird ein CNN-Modell erstellt, das eine Convolutional Layer, eine ReLU-Aktivierungsfunktion, eine Max-Pooling-Layer und eine Fully Connected Layer enthält. Das Modell wird für die Klassifikation von Bildern verwendet.
====Recurrent====
Recurrent Neural Networks sind gut geeignet für die Verarbeitung von sequenziellen Daten wie Texten oder Zeitreihen. Sie haben die Fähigkeit, Informationen über vergangene Zustände beizubehalten.
import torch
import torch.nn as nn
class MyRNN(nn.Module):
def __init__(self):
super(MyRNN, self).__init__()
self.rnn = nn.RNN(input_size=100, hidden_size=128, num_layers=2, batch_first=True)
self.fc = nn.Linear(128, 10)
def forward(self, x):
_, h = self.rnn(x)
x = self.fc(h[-1])
return x
model = MyRNN()
In diesem Beispiel wird ein RNN-Modell erstellt, das aus einer RNN-Schicht und einer Fully Connected Layer besteht. Das Modell nimmt Eingaben mit einer Sequenzlänge von 100 und gibt eine Ausgabe der Größe 10 zurück.
====Transformer====
Transformer-Modelle haben in den letzten Jahren an Beliebtheit gewonnen und sind besonders gut für die Verarbeitung von natürlicher Sprache geeignet. Sie verwenden Aufmerksamkeitsmechanismen, um die Beziehungen zwischen den Elementen einer Sequenz zu modellieren.
import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.nn import TransformerEncoder, TransformerEncoderLayer
class MyTransformer(nn.Module):
def __init__(self):
super(MyTransformer, self).__init__()
self.embedding = nn.Embedding(10000, 256)
self.transformer_layer = TransformerEncoderLayer(256, 8)
self.transformer = TransformerEncoder(self.transformer_layer, num_layers=4)
self.fc = nn.Linear(256, 10)
def forward(self, x):
x = self.embedding(x)
x = x.permute(1, 0, 2)
x = self.transformer(x)
x = x.mean(dim=0)
x = self.fc(x)
return x
model = MyTransformer()
In diesem Beispiel wird ein Transformer-Modell erstellt, das eine Embedding-Schicht, einen TransformerEncoder und eine Fully Connected Layer enthält. Das Modell nimmt Sequenzeingaben, z.B. Token-IDs, und gibt eine Ausgabe der Größe 10 zurück.
=====Pattern Recognition Example=====
# Pattern Recognition
import torch
import torch.nn as nn
import torch.optim as optim
# Daten vorbereiten (Beispiel)
sequences = [
[1,0,1,1,0],
[0,1,1,0,0],
[0,1,0,0,0],
[1,0,1,0,1],
[1,0,0,0,1],
[0,1,0,1,0],
[1,1,0,1,1],
[0,0,1,0,0]
]
labels = [1,1,0,1,0,0,0,1] # Beispieldaten fur die Musterklassifizierung
# Hyperparameter
input_size = 1
hidden_size = 5*5
output_size = 2
num_layers = 3
num_epochs = 100
learning_rate = 0.1
# Daten in Tensoren umwandeln
input_sequences = torch.tensor(sequences, dtype=torch.float32).unsqueeze(-1)
target_labels = torch.tensor(labels, dtype=torch.long)
# Modell definieren
class RNN(nn.Module):
def __init__(self, input_size, hidden_size, output_size, num_layers):
super(RNN, self).__init__()
self.hidden_size = hidden_size
self.rnn = nn.LSTM(input_size, hidden_size, num_layers, batch_first=True)
self.fc = nn.Linear(hidden_size, output_size)
def forward(self, x):
h0 = torch.zeros(num_layers, x.size(0), self.hidden_size).to(x.device)
c0 = torch.zeros(num_layers, x.size(0), self.hidden_size).to(x.device)
out, _ = self.rnn(x, (h0, c0))
out = self.fc(out[:, -1, :])
return out
model = RNN(input_size, hidden_size, output_size, num_layers)
# Verlustfunktion und Optimierungsalgorithmus definieren
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=learning_rate)
# Modell trainieren
for epoch in range(num_epochs):
optimizer.zero_grad()
outputs = model(input_sequences)
loss = criterion(outputs, target_labels)
loss.backward()
optimizer.step()
print(f'Epoch: {epoch+1}/{num_epochs}, Loss: {loss.item()}')
# Modell evaluieren
with torch.no_grad():
test_input = torch.tensor([[1,0,0,1,1]], dtype=torch.float32).unsqueeze(-1)
predicted = model(test_input)
_, predicted_labels = torch.max(predicted.data, 1)
print(f'Predicted Label: {predicted_labels.item()} {predicted.data}')
'''
torch.save(model.state_dict(), "test.pt")
model.load_state_dict(torch.load("test.pt"))
'''
=====Bigram Model=====
=====Erweitertes Bigram Model=====
import torch
import torch.nn as nn
from torch.nn import functional as F
# hyperparameters
batch_size = 16 # how many independent sequences will we process in parallel?
block_size = 32 # what is the maximum context length for predictions?
max_iters = 15000
eval_interval = 1000
learning_rate = 1e-3
device = 'cuda' if torch.cuda.is_available() else 'cpu'
eval_iters = 200
n_embd = 64
n_head = 4
n_layer = 4
dropout = 0.0
# ------------
torch.manual_seed(1337)
!wget https://raw.githubusercontent.com/karpathy/char-rnn/master/data/tinyshakespeare/input.txt
with open('input.txt', 'r', encoding='utf-8') as f:
text = f.read()
# here are all the unique characters that occur in this text
chars = sorted(list(set(text)))
vocab_size = len(chars)
# create a mapping from characters to integers
stoi = { ch:i for i,ch in enumerate(chars) }
itos = { i:ch for i,ch in enumerate(chars) }
encode = lambda s: [stoi[c] for c in s] # encoder: take a string, output a list of integers
decode = lambda l: ''.join([itos[i] for i in l]) # decoder: take a list of integers, output a string
# Train and test splits
data = torch.tensor(encode(text), dtype=torch.long)
n = int(0.9*len(data)) # first 90% will be train, rest val
train_data = data[:n]
val_data = data[n:]
# data loading
def get_batch(split):
# generate a small batch of data of inputs x and targets y
data = train_data if split == 'train' else val_data
ix = torch.randint(len(data) - block_size, (batch_size,))
x = torch.stack([data[i:i+block_size] for i in ix])
y = torch.stack([data[i+1:i+block_size+1] for i in ix])
x, y = x.to(device), y.to(device)
return x, y
@torch.no_grad()
def estimate_loss():
out = {}
model.eval()
for split in ['train', 'val']:
losses = torch.zeros(eval_iters)
for k in range(eval_iters):
X, Y = get_batch(split)
logits, loss = model(X, Y)
losses[k] = loss.item()
out[split] = losses.mean()
model.train()
return out
class Head(nn.Module):
""" one head of self-attention """
def __init__(self, head_size):
super().__init__()
self.key = nn.Linear(n_embd, head_size, bias=False)
self.query = nn.Linear(n_embd, head_size, bias=False)
self.value = nn.Linear(n_embd, head_size, bias=False)
self.register_buffer('tril', torch.tril(torch.ones(block_size, block_size)))
self.dropout = nn.Dropout(dropout)
def forward(self, x):
B,T,C = x.shape
k = self.key(x) # (B,T,C)
q = self.query(x) # (B,T,C)
# compute attention scores ("affinities")
wei = q @ k.transpose(-2,-1) * C**-0.5 # (B, T, C) @ (B, C, T) -> (B, T, T)
wei = wei.masked_fill(self.tril[:T, :T] == 0, float('-inf')) # (B, T, T)
wei = F.softmax(wei, dim=-1) # (B, T, T)
wei = self.dropout(wei)
# perform the weighted aggregation of the values
v = self.value(x) # (B,T,C)
out = wei @ v # (B, T, T) @ (B, T, C) -> (B, T, C)
return out
class MultiHeadAttention(nn.Module):
""" multiple heads of self-attention in parallel """
def __init__(self, num_heads, head_size):
super().__init__()
self.heads = nn.ModuleList([Head(head_size) for _ in range(num_heads)])
self.proj = nn.Linear(n_embd, n_embd)
self.dropout = nn.Dropout(dropout)
def forward(self, x):
out = torch.cat([h(x) for h in self.heads], dim=-1)
out = self.dropout(self.proj(out))
return out
class FeedFoward(nn.Module):
""" a simple linear layer followed by a non-linearity """
def __init__(self, n_embd):
super().__init__()
self.net = nn.Sequential(
nn.Linear(n_embd, 4 * n_embd),
nn.ReLU(),
nn.Linear(4 * n_embd, n_embd),
nn.Dropout(dropout),
)
def forward(self, x):
return self.net(x)
class Block(nn.Module):
""" Transformer block: communication followed by computation """
def __init__(self, n_embd, n_head):
# n_embd: embedding dimension, n_head: the number of heads we'd like
super().__init__()
head_size = n_embd // n_head
self.sa = MultiHeadAttention(n_head, head_size)
self.ffwd = FeedFoward(n_embd)
self.ln1 = nn.LayerNorm(n_embd)
self.ln2 = nn.LayerNorm(n_embd)
def forward(self, x):
x = x + self.sa(self.ln1(x))
x = x + self.ffwd(self.ln2(x))
return x
# super simple bigram model
class BigramLanguageModel(nn.Module):
def __init__(self):
super().__init__()
# each token directly reads off the logits for the next token from a lookup table
self.token_embedding_table = nn.Embedding(vocab_size, n_embd)
self.position_embedding_table = nn.Embedding(block_size, n_embd)
self.blocks = nn.Sequential(*[Block(n_embd, n_head=n_head) for _ in range(n_layer)])
self.ln_f = nn.LayerNorm(n_embd) # final layer norm
self.lm_head = nn.Linear(n_embd, vocab_size)
def forward(self, idx, targets=None):
B, T = idx.shape
# idx and targets are both (B,T) tensor of integers
tok_emb = self.token_embedding_table(idx) # (B,T,C)
pos_emb = self.position_embedding_table(torch.arange(T, device=device)) # (T,C)
x = tok_emb + pos_emb # (B,T,C)
x = self.blocks(x) # (B,T,C)
x = self.ln_f(x) # (B,T,C)
logits = self.lm_head(x) # (B,T,vocab_size)
if targets is None:
loss = None
else:
B, T, C = logits.shape
logits = logits.view(B*T, C)
targets = targets.view(B*T)
loss = F.cross_entropy(logits, targets)
return logits, loss
def generate(self, idx, max_new_tokens):
# idx is (B, T) array of indices in the current context
for _ in range(max_new_tokens):
# crop idx to the last block_size tokens
idx_cond = idx[:, -block_size:]
# get the predictions
logits, loss = self(idx_cond)
# focus only on the last time step
logits = logits[:, -1, :] # becomes (B, C)
# apply softmax to get probabilities
probs = F.softmax(logits, dim=-1) # (B, C)
# sample from the distribution
idx_next = torch.multinomial(probs, num_samples=1) # (B, 1)
# append sampled index to the running sequence
idx = torch.cat((idx, idx_next), dim=1) # (B, T+1)
return idx
model = BigramLanguageModel()
m = model.to(device)
# print the number of parameters in the model
print(sum(p.numel() for p in m.parameters())/1e6, 'M parameters')
# create a PyTorch optimizer
optimizer = torch.optim.AdamW(model.parameters(), lr=learning_rate)
for iter in range(max_iters):
# every once in a while evaluate the loss on train and val sets
if iter % eval_interval == 0 or iter == max_iters - 1:
losses = estimate_loss()
print(f"step {iter}: train loss {losses['train']:.4f}, val loss {losses['val']:.4f}")
# sample a batch of data
xb, yb = get_batch('train')
# evaluate the loss
logits, loss = model(xb, yb)
optimizer.zero_grad(set_to_none=True)
loss.backward()
optimizer.step()
# random
#context = torch.zeros((1, 1), dtype=torch.long, device=device)
#print(decode(m.generate(context, max_new_tokens=100)[0].tolist()))
# prompt
#context = torch.tensor([encode("Who is the king?")], dtype=torch.long, device=device)
#print(decode(m.generate(context, max_new_tokens=100)[0].tolist()))
# completion
def complete(prompt, max_new_tokens=200, temperature=1.0):
idx = torch.tensor([encode(prompt)], dtype=torch.long, device=device)
with torch.no_grad():
for _ in range(max_new_tokens):
idx_cond = idx[:, -block_size:]
logits, _ = m(idx_cond)
logits = logits[:, -1, :] / temperature
probs = F.softmax(logits, dim=-1)
idx_next = torch.multinomial(probs, num_samples=1)
idx = torch.cat((idx, idx_next), dim=1)
full = decode(idx[0].tolist())
return full # full[len(prompt):]
print(complete("To be, or not to be: ", max_new_tokens=100, temperature=0.8))