реклама
Бургер менюБургер меню

Джеймс Дэвис – Нейросети: создание и оптимизация будущего (страница 19)

18

# Обучение

epochs = 1 # Одно обучение (можно увеличить количество эпох)

for epoch in range(epochs):

for data, target in train_loader: # Обрабатываем весь набор данных за одну эпоху

optimizer.zero_grad() # Обнуляем градиенты перед вычислением новых

output = model(data) # Прямой проход

loss = criterion(output, target) # Вычисляем потери

loss.backward() # Обратное распространение ошибок

optimizer.step() # Обновляем веса

print(f'Эпоха {epoch+1}, Потери: {loss.item()}')

# Пример завершения обучения

print("Обучение завершено.")

```

Объяснение:

1. Нейронная сеть:

– Мы создали простую сеть `SimpleNet` с двумя слоями: первый слой преобразует изображение размером 28x28 в 128 признаков, а второй слой производит выход размером 10 (для 10 классов).

2. Пакетный градиентный спуск:

– В `train_loader` используется параметр `batch_size=len(train_data)`, что означает, что все данные загружаются в одном пакете. Это соответствует пакетному градиентному спуску, где обновление весов происходит только после обработки всех данных.

3. Процесс обучения:

– Для каждой эпохи мы вычисляем градиенты на основе всего набора данных, затем обновляем веса модели. Этот процесс повторяется до завершения обучения.

Преимущества и недостатки пактного градиентного спуска:

Преимущество: Мы используем всю информацию для вычисления градиентов, что делает процесс обучения стабильным.

Недостаток: Для больших наборов данных этот метод может быть очень медленным и требовать много вычислительных ресурсов, так как приходится обрабатывать весь набор данных за один шаг.

2. Стохастический градиентный спуск:

– В этом методе сеть обновляет свои веса после каждого примера из набора данных, а не ждет, пока обработаются все данные.

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

Пример использования стоходастического градиентного спуска (SGD) в PyTorch. В этом методе сеть обновляет свои веса после каждого примера из набора данных, что делает обучение более быстрым, но также может привести к более "дрожащему" пути к минимизации ошибки.

Предположим, у нас есть та же задача классификации изображений из набора данных MNIST.

```python

import torch

import torch.nn as nn

import torch.optim as optim

from torch.utils.data import DataLoader

from torchvision import datasets, transforms

# Определяем простую нейронную сеть

class SimpleNet(nn.Module):

def __init__(self):

super(SimpleNet, self).__init__()

self.fc1 = nn.Linear(28*28, 128) # Первый полносвязный слой

self.fc2 = nn.Linear(128, 10) # Второй слой для классификации (10 классов)

def forward(self, x):

x = x.view(-1, 28*28) # Преобразуем изображение в одномерный вектор

x = torch.relu(self.fc1(x)) # Применяем ReLU активацию

x = self.fc2(x) # Выходной слой

return x

# Загружаем данные MNIST

transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5,), (0.5,))])

train_data = datasets.MNIST(root='./data', train=True, download=True, transform=transform)

train_loader = DataLoader(train_data, batch_size=1, shuffle=True) # Стохастический градиентный спуск (batch size = 1)

# Создаем модель, функцию потерь и оптимизатор

model = SimpleNet()

criterion = nn.CrossEntropyLoss() # Функция потерь для многоклассовой классификации

optimizer = optim.SGD(model.parameters(), lr=0.01) # Стохастический градиентный спуск

# Обучение

epochs = 1 # Одно обучение (можно увеличить количество эпох)

for epoch in range(epochs):

for data, target in train_loader: # Для каждого примера из набора данных

optimizer.zero_grad() # Обнуляем градиенты перед вычислением новых

output = model(data) # Прямой проход

loss = criterion(output, target) # Вычисляем потери

loss.backward() # Обратное распространение ошибок

optimizer.step() # Обновляем веса

print(f'Эпоха {epoch+1}, Потери: {loss.item()}')

# Пример завершения обучения

print("Обучение завершено.")