Джеймс Дэвис – Нейросети: создание и оптимизация будущего (страница 5)
with torch.no_grad():
predictions = model(X_tensor).round()
plt.scatter(X[:, 0], X[:, 1], c=predictions.reshape(-1), cmap='coolwarm', marker='o', edgecolors='k')
plt.title("Классификация точек")
plt.show()
```
Пояснение к коду
1. Генерация данных: Мы создали случайные точки и разделили их на два класса в зависимости от их положения относительно прямой (x + y = 0).
2. Модель: Простая нейросеть с двумя слоями – входной слой с 2 нейронами (для двух координат) и один скрытый слой на 4 нейрона. На выходе – один нейрон с функцией активации `sigmoid`, который предсказывает вероятность принадлежности к классу.
3. Функция ошибки: Используем `BCELoss` (Binary Cross Entropy), поскольку это подходящий критерий для задач бинарной классификации.
4. Оптимизация: Параметры сети оптимизируются методом стохастического градиентного спуска (SGD).
5. Обучение: На каждом шаге выполняется прямой проход для вычисления ошибки, затем вычисляются градиенты и обновляются веса, что и является сутью обратного распространения ошибки.
6. Визуализация: Построение графика потерь для наблюдения за процессом обучения и визуализация предсказаний.
Результат
График потерь демонстрирует снижение ошибки, а классификация точек показывает, что сеть успешно научилась разделять классы, корректируя веса с каждым циклом обучения, основываясь на ошибках.
Этот процесс и есть результат обратного распространения ошибки: сеть обучается на ошибках, постепенно улучшая свои предсказания.
Градиентный спуск – это метод, который используется для минимизации функции ошибки в процессе обучения. Принцип градиентного спуска заключается в том, чтобы двигаться в направлении самого быстрого уменьшения ошибки, находя точки, где ошибка минимальна. Представьте это как спуск по склону горы: каждый шаг направлен туда, где рельеф понижается, с целью оказаться в самой низкой точке.
Градиентный спуск бывает нескольких типов:
– Обычный (batch) градиентный спуск: Он учитывает весь набор данных на каждом шаге и обновляет веса, основываясь на средней ошибке, что может быть вычислительно затратным.
– Стохастический градиентный спуск (SGD): Здесь обновление весов происходит на каждом отдельном примере, что делает обучение более быстрым, но с шумом, так как веса могут изменяться от случая к случаю.
– Мини-batch градиентный спуск: Здесь данные разделяются на небольшие группы (мини-батчи), на основе которых рассчитывается ошибка и корректируются веса, что позволяет использовать преимущества обоих методов.
Оптимизация параметров сети включает выбор скорости обучения и других гиперпараметров, таких как момент, чтобы корректировка весов происходила достаточно быстро, но без переборов. Существуют также адаптивные методы оптимизации, такие как Adam и RMSprop, которые динамически настраивают скорость обучения для каждого веса, учитывая историю изменений, что позволяет избежать проблем с оптимизацией и улучшает эффективность обучения.
Этот процесс позволяет сети с каждым шагом приближаться к решению задачи, становясь все более точной.
Для каждого типа градиентного спуска мы решим простую задачу регрессии: предскажем значение (y) для каждого (x) по уравнению ( y = 2x + 3 ) с добавлением небольшого шума.
1. Обычный (Batch) Градиентный Спуск
В этом случае мы используем весь набор данных для вычисления средней ошибки на каждом этапе, после чего обновляем веса.
```python
import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np
import matplotlib.pyplot as plt
# Генерация данных
np.random.seed(0)
X = np.linspace(-1, 1, 100)
Y = 2 * X + 3 + 0.1 * np.random.randn(100)
# Преобразование в тензоры
X_tensor = torch.FloatTensor(X).view(-1, 1)
Y_tensor = torch.FloatTensor(Y).view(-1, 1)
# Простая линейная модель
model = nn.Linear(1, 1)
criterion = nn.MSELoss()
optimizer = optim.SGD(model.parameters(), lr=0.01)
# Обучение с использованием batch градиентного спуска
epochs = 1000
losses = []
for epoch in range(epochs):
optimizer.zero_grad()
predictions = model(X_tensor)
loss = criterion(predictions, Y_tensor)
loss.backward()
optimizer.step()
losses.append(loss.item())
# График ошибки
plt.plot(losses)
plt.xlabel("Epoch")
plt.ylabel("Loss")
plt.title("Batch Gradient Descent")
plt.show()
```
Пояснение: Модель обновляет веса, используя весь набор данных для каждого шага. Такой подход может быть более точным, но затратен по времени на больших данных.
2. Стохастический Градиентный Спуск (SGD)
Теперь каждый пример обновляет веса независимо, что делает обучение более быстрым, но и более "шумным".