Шпаргалка по 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 AI Pulse

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