学习率调度(Learning Rate Scheduling)是在训练深度学习模型时,动态地调整学习率的策略。适当的学习率调度可以帮助模型更快地收敛并获得更好的性能。
10.4.1 学习率调度的方法
学习率调度的选择取决于您的模型、数据集和训练任务。通常,您可以尝试不同的方法并根据训练的效果选择最合适的调度策略。在实际应用中,动态地调整学习率可以帮助模型更好地适应不同的训练阶段和数据分布。常用的学习率调度方法如下所示:
- 固定学习率(Fixed Learning Rate):最简单的方法是使用固定的学习率,不随训练进行而变化。这对于小型数据集和简单模型可能有效,但在训练的后期可能会导致收敛速度变慢。
- 学习率衰减(Learning Rate Decay):在训练的每个epoch或一定步数之后,将学习率进行衰减。常见的衰减方式包括按固定比例减小学习率,或者按指数、余弦等方式调整学习率。
- Step衰减(Step Decay):学习率在训练的每个固定步数进行一次衰减,例如每隔10个epoch减小一次学习率。
- 指数衰减(Exponential Decay):学习率按指数方式衰减,例如每个epoch将学习率乘以一个小于1的因子。
- 余弦退火(Cosine Annealing):学习率按余弦函数的方式进行周期性调整,这可以帮助模型跳出局部最优并更好地探索搜索空间。
- 自适应方法(Adaptive Methods):一些自适应方法,如Adam、Adagrad和RMSProp,可以根据参数的变化动态调整学习率,这也是一种形式的学习率调度。
- 学习率查找(Learning Rate Finder):在训练的初期,通过尝试不同的学习率,找到一个初始学习率,然后再应用其他的学习率调度方法。
- One Cycle学习率策略:在训练过程中,将学习率从一个小值快速增加到一个较大值,然后再逐渐减小。这有助于快速探索搜索空间并稳定模型训练。
10.4.2 TensorFlow学习率调度优化实践
在TensorFlow中,学习率调度优化是通过调整优化器的学习率参数来实现的。TensorFlow提供了多种学习率调度的方法和优化器,下面是一些常用的学习率调度方法及其使用例子:
(1)学习率衰减(Learning Rate Decay): 在训练的每个epoch或一定步数之后,将学习率进行衰减。tf.keras.optimizers.schedules模块提供了多种学习率衰减的方式,例如tf.keras.optimizers.schedules.ExponentialDecay和tf.keras.optimizers.schedules.StepDecay。
import tensorflow as tf
initial_learning_rate = 0.1
lr_schedule = tf.keras.optimizers.schedules.ExponentialDecay(
initial_learning_rate, decay_steps=1000, decay_rate=0.9
)
optimizer = tf.keras.optimizers.SGD(learning_rate=lr_schedule)
(2)余弦退火(Cosine Annealing): 余弦退火将学习率按余弦函数的方式进行周期性调整。
import tensorflow as tf
initial_learning_rate = 0.1
lr_schedule = tf.keras.experimental.CosineDecay(
initial_learning_rate, decay_steps=1000
)
optimizer = tf.keras.optimizers.SGD(learning_rate=lr_schedule)
(3)自适应方法(Adaptive Methods): TensorFlow的优化器中,如Adam、Adagrad和RMSProp,会根据参数的变化动态调整学习率,因此可以视为一种学习率调度。
import tensorflow as tf
optimizer = tf.keras.optimizers.Adam(learning_rate=0.001)
(4)学习率查找(Learning Rate Finder): 可以通过尝试不同的学习率来找到一个合适的初始学习率,然后再应用其他的学习率调度方法。
import tensorflow as tf
from tensorflow.keras.optimizers.schedules import OneCycleSchedule
class LearningRateFinder(OneCycleSchedule):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.learning_rates = []
def __call__(self, step):
lr = super().__call__(step)
self.learning_rates.append(lr)
return lr
# Create a learning rate finder schedule
lr_finder_schedule = LearningRateFinder(
initial_learning_rate=1e-7, max_learning_rate=1e-1, step_size=1000
)
optimizer = tf.keras.optimizers.SGD(learning_rate=lr_finder_schedule)
以上例子展示了一些TensorFlow中的学习率调度方法。大家根据自己项目的任务和数据集,可以选择适合的学习率调度策略来优化模型的训练过程。例如下面是一个完整的TensorFlow学习率调度优化的例子,在例子中创建了一个简单的神经网络模型,然后使用学习率衰减来调整优化器的学习率。
实例10-1:TensorFlow使用学习率衰减来调整优化器的学习率(源码路径:daima/10/xue.py)
实例文件xue.py的具体实现代码如下所示。
import tensorflow as tf
from tensorflow.keras import layers, models
from tensorflow.keras.datasets import mnist
from tensorflow.keras.optimizers.schedules import ExponentialDecay
import numpy as np
# 加载并预处理MNIST数据集
(train_images, train_labels), (test_images, test_labels) = mnist.load_data()
train_images, test_images = train_images / 255.0, test_images / 255.0
# 构建一个简单的神经网络模型
model = models.Sequential([
layers.Flatten(input_shape=(28, 28)),
layers.Dense(128, activation='relu'),
layers.Dropout(0.2),
layers.Dense(10, activation='softmax')
])
# 使用指数衰减学习率调度来定义学习率
初始学习率 = 0.1
衰减步数 = len(train_images) // 32
衰减率 = 0.95
学习率调度 = ExponentialDecay(
初始学习率, decay_steps=衰减步数, decay_rate=衰减率
)
# 使用学习率调度编译模型的优化器
优化器 = tf.keras.optimizers.SGD(learning_rate=学习率调度)
model.compile(optimizer=优化器,
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
# 训练模型
history = model.fit(train_images, train_labels, epochs=5,
validation_data=(test_images, test_labels))
# 评估模型
测试损失, 测试准确率 = model.evaluate(test_images, test_labels, verbose=2)
print("\n测试准确率:", 测试准确率)
在上述代码中,首先加载了MNIST数据集并构建了一个简单的神经网络模型。然后,我们使用ExponentialDecay学习率调度来定义一个衰减的学习率,并将其应用于优化器。最后,我们通过model.fit训练模型,并使用model.evaluate评估模型的性能。大家可以根据需要调整学习率衰减的参数,例如initial_learning_rate、decay_steps和decay_rate,以获得更好的训练效果。执行后会输出:
Epoch 1/5
1875/1875 [==============================] - 14s 6ms/step - loss: 0.3305 - accuracy: 0.9031 - val_loss: 0.1645 - val_accuracy: 0.9538
Epoch 2/5
1875/1875 [==============================] - 11s 6ms/step - loss: 0.1740 - accuracy: 0.9493 - val_loss: 0.1244 - val_accuracy: 0.9623
Epoch 3/5
1875/1875 [==============================] - 12s 6ms/step - loss: 0.1352 - accuracy: 0.9603 - val_loss: 0.1039 - val_accuracy: 0.9699
Epoch 4/5
1875/1875 [==============================] - 12s 7ms/step - loss: 0.1145 - accuracy: 0.9669 - val_loss: 0.0900 - val_accuracy: 0.9724
Epoch 5/5
1875/1875 [==============================] - 15s 8ms/step - loss: 0.0990 - accuracy: 0.9708 - val_loss: 0.0849 - val_accuracy: 0.9742
313/313 - 1s - loss: 0.0849 - accuracy: 0.9742
Test accuracy: 0.9742000102996826
10.4.3 PyTorch学习率调度优化实践
当使用PyTorch进行深度学习模型训练时,经常需要调整学习率以提高训练效果。PyTorch提供了多种学习率调度器,用于根据训练的进程动态地调整学习率。例如下面是一个使用PyTorch学习率调度器的例子。
实例10-2:PyTorch使用学习率调度器来调整优化器的学习率(源码路径:daima\10\pyxue.py)
实例文件pyxue.py的具体实现代码如下所示。
import torch
import torch.nn as nn
import torch.optim as optim
from torch.optim.lr_scheduler import StepLR
import torchvision
import torchvision.transforms as transforms
# 设置随机种子以保证可复现性
torch.manual_seed(42)
# 加载并预处理CIFAR-10数据集
transform = transforms.Compose(
[transforms.ToTensor(), transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))]
)
trainset = torchvision.datasets.CIFAR10(root='./data', train=True, download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=64, shuffle=True)
# 定义一个简单的神经网络模型
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv = nn.Sequential(
nn.Conv2d(3, 6, 5),
nn.ReLU(),
nn.MaxPool2d(2, 2),
)
self.fc = nn.Sequential(
nn.Linear(6 * 14 * 14, 120),
nn.ReLU(),
nn.Linear(120, 84),
nn.ReLU(),
nn.Linear(84, 10),
)
def forward(self, x):
x = self.conv(x)
x = x.view(-1, 6 * 14 * 14)
x = self.fc(x)
return x
# 实例化模型和损失函数
net = Net()
criterion = nn.CrossEntropyLoss()
# 使用随机梯度下降(SGD)优化器
optimizer = optim.SGD(net.parameters(), lr=0.1)
# 使用StepLR学习率调度器,每个step_size个epoch将学习率降低为gamma倍
scheduler = StepLR(optimizer, step_size=30, gamma=0.1)
# 训练模型
for epoch in range(50):
running_loss = 0.0
for i, data in enumerate(trainloader, 0):
inputs, labels = data
optimizer.zero_grad()
outputs = net(inputs)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
running_loss += loss.item()
# 每个epoch结束后,使用学习率调度器更新学习率
scheduler.step()
print(f"Epoch {epoch+1}, Loss: {running_loss/len(trainloader)}")
print("Finished Training")
在上述代码中,定义了一个简单的神经网络模型,使用随机梯度下降(SGD)优化器进行训练,并使用StepLR学习率调度器在每个指定的step_size个epoch后将学习率降低为gamma倍,以帮助模型更好地收敛。
执行后会输出:
Fold 1 Accuracy: 0.6667