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