2. Взрыв градиентов (Exploding Gradients):
На противоположном полюсе находится взрыв градиентов, когда значения производных резко увеличиваются. Это может происходить в глубоких или рекуррентных нейронных сетях, где ошибки распространяются назад многократно, что приводит к числовой нестабильности и невозможности корректного обучения, так как веса получают слишком большие обновления.
Для предотвращения этих проблем используются несколько методов:
– Нормализация (например, Batch Normalization):
Нормализация входов и промежуточных слоев помогает стабилизировать значения и улучшает эффективность обучения. Batch Normalization также снижает зависимость сети от начальных значений весов, ускоряя сходимость.
– Инициализация весов (например, He и Xavier):
Инициализация весов с учетом распределения значений помогает предотвратить как затухание, так и взрыв градиентов. Например, метод инициализации Xavier подходит для сигмоидных и гиперболических активаций, а He – для ReLU.
– Использование регуляризирующих методов (например, Dropout):
Dropout помогает избежать переобучения, уменьшая шансы на взрыв градиентов за счёт разреживания слоев, что также увеличивает устойчивость сети.
– Сокращение длины траектории ошибки (например, Gradient Clipping):
Метод Gradient Clipping ограничивает величину градиентов на каждом шаге, предотвращая их взрыв. Этот метод особенно эффективен в рекуррентных сетях, где ошибка распространяется по временной оси.
Рассмотрим эти методы на практических примерах.
Пример кода с использованием Batch Normalization можно реализовать в PyTorch. Этот метод нормализации стабилизирует обучение, нормализуя выходы слоя и добавляя обучаемые параметры смещения и масштабирования. Batch Normalization помогает улучшить сходимость и сделать обучение более стабильным, особенно в глубоких нейронных сетях.
```python
import torch
import torch.nn as nn
import torch.optim as optim
# Примерный класс нейронной сети с использованием Batch Normalization
class SimpleNet(nn.Module):
def __init__(self):
super(SimpleNet, self).__init__()
self.layer1 = nn.Linear(784, 256) # Первый полносвязный слой
self.bn1 = nn.BatchNorm1d(256) # Batch Normalization после первого слоя
self.layer2 = nn.Linear(256, 128) # Второй полносвязный слой
self.bn2 = nn.BatchNorm1d(128) # Batch Normalization после второго слоя
self.layer3 = nn.Linear(128, 10) # Выходной слой (10 классов, например, для MNIST)
def forward(self, x):
x = self.layer1(x)
x = self.bn1(x) # Применение Batch Normalization
x = torch.relu(x) # Активация ReLU
x = self.layer2(x)
x = self.bn2(x) # Применение Batch Normalization
x = torch.relu(x) # Активация ReLU
x = self.layer3(x) # Применение финального линейного слоя
return x
# Пример данных и оптимизации
model = SimpleNet()
criterion = nn.CrossEntropyLoss() # Функция потерь для классификации
optimizer = optim.Adam(model.parameters(), lr=0.001) # Оптимизатор Adam
# Пример одного шага обучения
inputs = torch.randn(64, 784) # Входной батч из 64 изображений размером 28x28 (784 = 28*28)
labels = torch.randint(0, 10, (64,)) # Случайные метки классов для примера
# Обнуление градиентов
optimizer.zero_grad()
# Прямой проход
outputs = model(inputs)
loss = criterion(outputs, labels)
# Обратное распространение и обновление весов
loss.backward()
optimizer.step()
print("Значение функции потерь:", loss.item())
```
Объяснение работы Batch Normalization в коде
– `nn.BatchNorm1d(256)` и `nn.BatchNorm1d(128)` добавлены после каждого линейного слоя. Они нормализуют выходы, уменьшая разброс значений и стабилизируя обратное распространение.