Шпаргалка по training pipeline в PyTorch на одной странице

Краткая шпаргалка по базовому пайплайну обучения в PyTorch: tensors, nn.Module, autograd, backpropagation, gradient descent и optimizer step.

Шпаргалка по training pipeline в PyTorch на одной странице

Источник: пост kozue в X.

Вся «машина» deep learning работает за счёт крошечных, непрерывных корректировок весов модели.

Это шпаргалка по training pipeline в PyTorch. Если заметите ошибки или захотите предложить улучшения — оставляйте комментарии. Надеюсь, материал будет полезен.

1. Tensor

В PyTorch тензор — это базовая структура данных для хранения и обработки чисел, основной строительный блок нейронных сетей.

Input:

data= [[1,2,3],[4,5,6]]
x = torch.tensor(data)

Output:

tensor([[1, 2, 3],
        [4, 5, 6]])

Q. Что внутри тензора?

Три вещи: shape, dtype и device.

  • Shape: кортеж, описывающий размерности. Около 90% ошибок в PyTorch — это несовпадение shape.
  • DType: тип данных чисел.
  • Device: где находится тензор — CPU или CUDA/GPU.

Если код ломается, обычно причина в том, что одно из этих трёх свойств не совпало.

Input:

#attributes of tensor

tensor = torch.randn(2,3)
print("shape:", tensor.shape)
print("datatype:", tensor.dtype)
print("device:", tensor.device)

Output:

shape: torch.Size([2, 3])
datatype: torch.float32
device: cpu

По умолчанию тензор — это просто данные. Чтобы сделать его обучаемым параметром, нужно установить requires_grad=True. После этого PyTorch начинает строить вычислительный граф и записывать каждую операцию над тензором, чтобы затем автоматически вычислить градиенты при backpropagation.

Input:

#data vs parameter

#standard data tensor
x_data = torch.tensor([[1.,2.],[3.,4.]])

#parameter tensor 
w = torch.tensor([[1.0],[2.0]], requires_grad=True)

print("Data tensor requires_grad:",x_data.requires_grad)
print("Parameter tensor requires_grad:", w.requires_grad)

Output:

Data tensor requires_grad: False
Parameter tensor requires_grad: True

Q. Что такое параметр?

Это специальный тензор, у которого requires_grad=True по умолчанию. Он автоматически регистрируется внутри модели и берёт на себя служебную «бухгалтерию» обучения.

2. Models

Модель — это архитектура нейронной сети, описанная как Python-объект, наследующийся от базового класса torch.nn.Module.

  • Модель — это просто nn.Module, содержащий слои.
  • Слой — это контейнер параметров, выполняющих математическую операцию.
  • Обучение — это обновление параметров через zero_grad, backward, step.
  • Параметры модели — веса и bias — должны быть float-типа, обычно float32.

Q. Почему float32?

Веса должны изменяться на очень маленькие величины. С целыми числами это невозможно. Числа с плавающей точкой позволяют модели делать микроскопические улучшения на каждой итерации.


Самая простая нейронная сеть:

y = X @ W + b

где:

  • y → предсказание
  • X → вход
  • W → веса
  • b → bias/смещение

Prediction = Input × Knowledge + Adjustment

3. Matrix Multiplication

X @ W

Это сердце deep learning. Почти каждая современная нейронная сеть построена на повторяющихся матричных умножениях.

Используйте оператор @, когда строите линейный слой. В PyTorch @ выполняет matrix multiplication — ключевую операцию за каждым nn.Linear.

Правило: число столбцов M1 = числу строк M2.

Input:

#Matrix Multiplication

#shape (2,3)
m1 = torch.tensor([[1,2,3], [4,5,6]])

#shape {3,2)
m2 = torch.tensor([[7,8], [9,10], [11,12]])

#shape (2,2)
matrix_product = m1 @ m2
print(matrix_product)

Output:

tensor([[ 58,  64],
        [139, 154]])

Не путайте @ и *: @ делает матричное умножение, а * перемножает соответствующие элементы один к одному.

4. Autograd: автоматическое дифференцирование

torch.autograd — это движок автоматического дифференцирования PyTorch, на котором держится обучение нейронных сетей. Во время forward pass он динамически строит направленный ациклический граф (DAG), отслеживает операции над тензорами и позволяет автоматически вычислять градиенты через backpropagation.

Autograd фактически говорит: «пройди назад от loss и вычисли градиенты для всех параметров с requires_grad=True».

Input:

#y=2x+1
#batch of data has 10 points
N=10
#each data point has 1 input feature and 1 output value
D_in = 1
D_out = 1
#create out input data X
X = torch.randn(N, D_in)
#create our true target labels y by using the "true" W,B
#the "true" W is 2.0, the "true" b is 1.0
true_w = torch.tensor([[2.0]])
true_b = torch.tensor([[1.0]])
y_true = X @ true_w + true_b + torch.randn(N, D_out) * 1.0 #added littile noise

W = torch.randn(D_in, D_out, requires_grad = True)
b = torch.randn(1, requires_grad = True)
print("Initial Weight W:\n",W)
print("Initial bias b:\n",b)

y_hat = X @ W + b

print(y_hat)
#error
error = y_hat - y_true
squared_error = error ** 2
loss = squared_error.mean()

print("Loss:",loss,"\n")
loss.backward()
print("gradient for w:\n", W.grad)
print("gradient for b:\n", b.grad)

Output:

Initial Weight W:
 tensor([[-0.5669]], requires_grad=True)
Initial bias b:
 tensor([0.0011], requires_grad=True)
tensor([[ 0.0604],
        [ 0.5645],
        [ 0.6193],
        [-0.2863],
        [ 1.2082],
        [ 0.6468],
        [ 0.5936],
        [-0.2940],
        [ 0.6108],
        [ 0.8328]], grad_fn=<AddBackward0>)
Loss: tensor(6.5599, grad_fn=<MeanBackward0>) 

gradient for w:
 tensor([[-5.0230]])
gradient for b:
 tensor([1.8041])

5. Backpropagation: backward pass

loss.backward()
  • ∂L/∂w = градиент loss по весу w.
  • ∂L/∂b = градиент loss по bias b.

Они вычисляются автоматически через loss.backward().

6. Gradient Descent: оптимизация

После вычисления градиентов мы обновляем параметры модели, чтобы уменьшить loss.

Правило обновления:

New Weight = Old Weight - Learning Rate × Gradient

Где:

  • θ (theta) = параметры модели: веса и bias.
  • η (eta) = learning rate.
  • ∇θL = градиент loss по параметрам, например w.grad, b.grad.

Input:

#training (gradient descent)
#Hyperparameters
learning_rate, epochs = 0.01, 100
#re-initialize parameters
W,b = torch.randn(1,1, requires_grad=True), torch.randn(1, requires_grad=True)
#Training Loop
for epoch in range(epochs):
    #forward pass and loss
    y_hat = X @ W + b
    loss = torch.mean((y_hat - y_true)**2)
    #backward pass
    loss.backward()
    #update parameters
    with torch.no_grad():
        W -= learning_rate * W.grad; b -= learning_rate * b.grad
    #zero gradients (reset for new learning cycle)
    W.grad.zero_(); b.grad.zero_()
print(W.grad,"\n",b.grad)

7. nn.Module

Вместо того чтобы писать всё вручную, PyTorch предоставляет готовые строительные блоки:

  • nn.Linear
  • nn.ReLU
  • nn.GELU
  • nn.Softmax
  • nn.Embedding
  • nn.LayerNorm
  • nn.Dropout

Это переиспользуемые компоненты нейросетей.

Input:

#NN.LINEAR
#input has 1 feature ans the putput has 1 value
D_in = 1
D_out = 1

linear_layer = torch.nn.Linear(in_features=D_in, out_features=D_out)

print("Layer's weight (W):" ,linear_layer.weight)
print("Layer's bias (b):", linear_layer.bias)

#forward pass
y_hat_nn = linear_layer(X)
print("Output of nn.Liner (first 3):\n", y_hat_nn[:3])

Output:

Layer's weight (W): Parameter containing:
tensor([[0.5193]], requires_grad=True)
Layer's bias (b): Parameter containing:
tensor([-0.2911], requires_grad=True)
Output of nn.Liner (first 3):
 tensor([[-0.3454],
        [-0.8072],
        [-0.8574]], grad_fn=<SliceBackward0>)

Input:

#NN.RELU (RECTIFIED LINEAR UNIT)
#Rule: if an input is negative make it zero 'ReLU(x)=max(0,x)'

relu = torch.nn.ReLU()
sample_data = torch.tensor([-2.0,-5.0,0.0,0.5,2.0])
activated_data = relu(sample_data)

print("Original Data:", sample_data)
print("Data after ReLU:", activated_data)

Output:

Original Data: tensor([-2.0000, -5.0000,  0.0000,  0.5000,  2.0000])
Data after ReLU: tensor([0.0000, 0.0000, 0.0000, 0.5000, 2.0000])

Input:

#NN.GELU (GAUSSIAN ERROR LINEAR UNIT)
#modern standard for transformers (GPT,Llama). A smoother, gently curving version of ReLU
gelu = torch.nn.GELU()
sample_data = torch.tensor([-2.0,-0.5,0.0,0.5,2.0])
activated_data = gelu(sample_data)

print("Original Data:", sample_data)
print("Data after gelu:",activated_data)

Output:

Original Data: tensor([-2.0000, -0.5000,  0.0000,  0.5000,  2.0000])
Data after gelu: tensor([-0.0455, -0.1543,  0.0000,  0.3457,  1.9545])

Input:

#NN.SOFTMAX
#used on final output layer for classification
#converts logits -> probability distribution

softmax = torch.nn.Softmax(dim=-1)
logits = torch.tensor([[1.0,3.0,0.5,1.5],[-1.0,2.0,1.0,0.0]])
prob = softmax(logits)
print("output prob:", prob)
print("sum of prob:", prob[0].sum())

Output:

output prob: tensor([[0.0939, 0.6942, 0.0570, 0.1549],
        [0.0321, 0.6439, 0.2369, 0.0871]])
sum of prob: tensor(1.)

Input:

#NN.EMBEDDING
#turns word -> numbers

vocab_size = 10
embedding_dim = 3
embedding_layer = torch.nn.Embedding(vocab_size, embedding_dim)

input_ids = torch.tensor([[1,5,0,8]])
word_vector = embedding_layer(input_ids)
word_vector

Output:

tensor([[[-0.3875, -1.7026, -0.8399],
         [-0.3027, -0.0060,  0.7160],
         [-2.0736,  0.3490, -0.0605],
         [ 1.3206,  0.8779,  0.4340]]], grad_fn=<EmbeddingBackward0>)

Input:

#nn.layernorm
#prevents values from exploding/vanishing, it rescales to stable range
norm_layer = torch.nn.LayerNorm(normalized_shape=3)
input_features = torch.tensor([[1.0,2.0,3.0],[4.0,5.0,6.0]])
normalized_features = norm_layer(input_features)

print("Mean (should be ~0):", normalized_features.mean(dim=-1))
print("std dev (should be ~1):", normalized_features.std(dim=-1))

Output:

Mean (should be ~0): tensor([0., 0.], grad_fn=<MeanBackward1>)
std dev (should be ~1): tensor([1.2247, 1.2247], grad_fn=<StdBackward0>)

Input:

#NN.DROPOUT
#prevent overfitting, randomly zero neurons during training forces network robustness

dropout_layer = torch.nn.Dropout(p=0.5)
input_tensor = torch.ones(1,10)

dropout_layer.train()
output_during_train = dropout_layer(input_tensor)

dropout_layer.eval()
output_during_eval = dropout_layer(input_tensor)

8. Правило трёх

  1. optimizer.zero_grad()
  2. loss.backward()
  3. optimizer.step()

9. Demo toy model

import torch
import torch.nn as nn

print(torch.cuda.is_available())

class LinearRegressionModel(nn.Module):
    def __init__(self,in_features,out_features):
        super().__init__()
        #inside the constructor, we define the layer
        self.linear_layer = nn.Linear(in_features, out_features)

    def forward(self, x):
        #in the forward pass, we connect the layers
        return self.linear_layer(x)
model = LinearRegressionModel(in_features=1, out_features=1)
print("Model Architecture:")
print(model)

#torch.optim

import torch.optim as optim

#hyperaramater
learning_rate = 0.01
optimizer = optim.Adam(model.parameters(), lr=learning_rate)
loss_fn = nn.MSELoss()

epochs = 100

for epoch in range(epochs):
    #forward pass
    y_hat = model(X)

    loss = loss_fn(y_hat,y_true)

    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

    if epoch % 10 ==0:
        print("Epoch:",epoch,"Loss:",loss.item())

Output:

TRUE
Model Architecture:
LinearRegressionModel(
  (linear_layer): Linear(in_features=1, out_features=1, bias=True)
)
Epoch: 0 Loss: 11.082582473754883
Epoch: 10 Loss: 9.987239837646484
Epoch: 20 Loss: 8.982141494750977
Epoch: 30 Loss: 8.073999404907227
Epoch: 40 Loss: 7.263952732086182
Epoch: 50 Loss: 6.5487494468688965
Epoch: 60 Loss: 5.9224066734313965
Epoch: 70 Loss: 5.377523899078369
Epoch: 80 Loss: 4.90612268447876
Epoch: 90 Loss: 4.500123500823975

Надеюсь, это поможет чуть лучше понять PyTorch. Удачной сборки.

Subscribe to Temperature 0.7 - AI блог об AI и роботах

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
jamie@example.com
Subscribe