← Назад к вопросам

Что такое computational graph?

1.7 Middle🔥 111 комментариев
#Глубокое обучение#Машинное обучение

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Computational Graph (Граф вычислений)

Computational Graph — это граф, в котором вершины представляют операции (сложение, умножение, функции активации и т.д.), а рёбра — тензоры (данные), передаваемые между операциями. Это абстракция, которая позволяет фреймворкам вроде TensorFlow и PyTorch эффективно вычислять градиенты и оптимизировать вычисления.

В компьютерной графике говорят, что «computational graph — это мост между математикой и кодом».

Структура Computational Graph

Пример простого графика

Для функции: z = (x + y) * w

     x    y
      \  /
       +       <- сумма
       |
     [x+y]
       |
       *       <- умножение
      / \
   [x+y]  w
     |
     z       <- результат

Реализация в коде

import torch
import numpy as np

# PyTorch автоматически создаёт computational graph
x = torch.tensor(2.0, requires_grad=True)  # requires_grad=True отслеживает операции
y = torch.tensor(3.0, requires_grad=True)
w = torch.tensor(4.0, requires_grad=True)

# Каждая операция добавляется в граф
z = (x + y) * w

print(f'z = {z}')  # 20.0
print(f'z.grad_fn = {z.grad_fn}')  # MulBackward0 — говорит, как был получен z

# Просмотр полного графика
print(z.grad_fn)  # Показывает операцию умножения
print(z.grad_fn.next_functions)  # Показывает зависимые операции

Dynamic vs Static Graphs

Dynamic Computational Graph (PyTorch)

Граф создаётся на лету во время выполнения кода.

import torch

def compute_dynamic(x):
    y = x * 2
    if x > 1:
        z = y + 1
    else:
        z = y - 1
    return z

x = torch.tensor(2.0, requires_grad=True)
result = compute_dynamic(x)
print(f'Result: {result}')
result.backward()  # Автоматический дифференцирование
print(f'Gradient: {x.grad}')

Преимущества:

  • Гибкость: можно использовать Python условия и циклы
  • Легче дебажить (стандартные точки останова работают)
  • Подходит для сложных архитектур

Static Computational Graph (TensorFlow 1.x)

Граф определяется один раз, затем выполняется множество раз.

# TensorFlow 1.x (старый стиль)
import tensorflow as tf

# Определить граф
x = tf.placeholder(tf.float32)
y = tf.placeholder(tf.float32)
z = (x + y) * 2

# Создать сессию для выполнения
with tf.Session() as sess:
    result = sess.run(z, feed_dict={x: 2.0, y: 3.0})
    print(f'Result: {result}')

Преимущества:

  • Оптимизация: TensorFlow может анализировать граф перед выполнением
  • Распараллеливание и развёртывание на несколько устройств

Обратное распространение (Backpropagation)

Как работает обратное распространение

  1. Forward Pass — вычисляются все операции от входа к выходу, создаётся граф
  2. Backward Pass — вычисляются градиенты от выхода к входу

Пример с вычислением градиентов

import torch

# Forward pass
x = torch.tensor(2.0, requires_grad=True)
y = torch.tensor(3.0, requires_grad=True)

# z = (x^2 + y^3) * 2
z = (x**2 + y**3) * 2

print(f'z = {z}')  # z = (4 + 27) * 2 = 62

# Backward pass
z.backward()

# Градиенты
print(f'dz/dx = {x.grad}')  # dz/dx = 2 * 2 * 2 = 8
print(f'dz/dy = {y.grad}')  # dz/dy = 3 * y^2 * 2 = 3 * 9 * 2 = 54

Расчёт вручную для проверки

z = (x^2 + y^3) * 2

dz/dx = d/dx[(x^2 + y^3) * 2]
      = 2 * d/dx[x^2 + y^3]
      = 2 * (2x)
      = 4x
      = 4 * 2 = 8  ✓

dz/dy = d/dy[(x^2 + y^3) * 2]
      = 2 * d/dy[x^2 + y^3]
      = 2 * (3y^2)
      = 6y^2
      = 6 * 9 = 54  ✓

Computational Graph в нейросетях

Простой пример с нейросетью

import torch
import torch.nn as nn

# Определить простую нейросеть
class SimpleNet(nn.Module):
    def __init__(self):
        super().__init__()
        self.fc1 = nn.Linear(2, 4)     # Входной слой 2 -> скрытый 4
        self.fc2 = nn.Linear(4, 1)     # Скрытый 4 -> выход 1
    
    def forward(self, x):
        x = torch.relu(self.fc1(x))    # ReLU активация
        x = self.fc2(x)                # Линейный выход
        return x

model = SimpleNet()

# Входные данные
X = torch.tensor([[1.0, 2.0], [3.0, 4.0]])
y_true = torch.tensor([[1.0], [0.0]])

# Forward pass
y_pred = model(X)
print(f'Predictions: {y_pred}')

# Вычислить потерю
loss = nn.MSELoss()(y_pred, y_true)
print(f'Loss: {loss}')

# Backward pass: вычислить градиенты для всех параметров
loss.backward()

# Просмотреть градиенты
for name, param in model.named_parameters():
    if param.grad is not None:
        print(f'{name} gradient shape: {param.grad.shape}')

Визуализация Computational Graph

TensorBoard

import torch
from torch.utils.tensorboard import SummaryWriter

writer = SummaryWriter('runs/experiment1')

# Модель
model = SimpleNet()
X = torch.randn(1, 2)

# Записать граф в TensorBoard
writer.add_graph(model, X)
writer.close()

# Запустить: tensorboard --logdir=runs

Visualize в PyTorch

import torch
from torchviz import make_dot

x = torch.randn(1, 2, requires_grad=True)
model = SimpleNet()
y = model(x)

# Создать визуализацию графика
vis_graph = make_dot(y, params=dict(model.named_parameters()))
vis_graph.render('computational_graph', format='png')

Оптимизация Графика

Fреймворки оптимизируют computational graph:

# Умная оптимизация автоматическая, но можно контролировать

# 1. Отключить отслеживание градиентов (когда не нужны)
with torch.no_grad():
    predictions = model(X)  # Не создаёт граф

# 2. Использовать eval() для отключения dropout и batch norm
model.eval()

# 3. Отсоединить от графика
x = torch.randn(3, requires_grad=True)
y = x ** 2
z = y.detach()  # z больше не зависит от x

# 4. Использовать gradient checkpointing для больших моделей
# (экономит память, но медленнее)

Практическая работа с графиком

Полный пример обучения

import torch
import torch.nn as nn
import torch.optim as optim

# Модель
model = SimpleNet()
loss_fn = nn.MSELoss()
optimizer = optim.SGD(model.parameters(), lr=0.01)

# Данные
X = torch.randn(10, 2)
y = torch.randn(10, 1)

# Обучение
for epoch in range(100):
    # Forward pass: граф создаётся
    y_pred = model(X)
    loss = loss_fn(y_pred, y)
    
    # Backward pass: вычисляются градиенты
    optimizer.zero_grad()  # Очистить старые градиенты
    loss.backward()        # Обратное распространение
    
    # Обновить параметры
    optimizer.step()
    
    if (epoch + 1) % 20 == 0:
        print(f'Epoch {epoch+1}, Loss: {loss.item():.4f}')

print('Training complete!')

Ключевые концепции

Операции в графике

# Все эти операции добавляются в граф
a = torch.tensor([1.0], requires_grad=True)
b = torch.tensor([2.0], requires_grad=True)

c = a + b           # AddBackward
d = c * a           # MulBackward
e = torch.sin(d)    # SinBackward
f = e ** 2          # PowBackward

# Граф: a --|--|
#            +--> c --> d --> e --> f
#          b --|--|  |      |
#                 a--|------

Листья графика

x = torch.tensor([2.0], requires_grad=True)
y = x ** 2
z = y * 3

print(f'x.is_leaf: {x.is_leaf}')      # True (входная переменная)
print(f'y.is_leaf: {y.is_leaf}')      # False (результат операции)
print(f'z.is_leaf: {z.is_leaf}')      # False (результат операции)
print(f'z.grad_fn: {z.grad_fn}')      # MulBackward
print(f'x.grad_fn: {x.grad_fn}')      # None

Выводы

  • Computational Graph — это основа автоматического дифференцирования
  • Forward Pass создаёт граф, Backward Pass вычисляет градиенты
  • PyTorch использует динамические графики (удобнее для разработки)
  • TensorFlow (новая версия) тоже использует eager execution по умолчанию
  • Понимание графика помогает дебажить и оптимизировать нейросети
  • Используй requires_grad=True, backward() и no_grad() для контроля