神经网络入门实战:(二十二)只训练 (多层网络的) 指定层 / (单层网络的) 指定参数

[复制链接]
发表于 2025-11-18 03:59:21 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
只训练 (多层网络的) 指定层 / (单层网络的) 指定参数

在训练的时间,偶然间并不须要将网络层每次都重新训练,对于只训练指定层的情况,可以通过设置该层参数的 requires_grad =True ,别的层通过设置 requires_grad = False 来冻结(不更新权重)。
【留意】:此时就不要使用 self.model = nn.Sequential(...) 函数将全部层都放在一起,酿成一个团体了。
1)多层网络

在界说模子时,在 __init__ 函数后, forward 函数前,加上下方这段代码:
  1. # 初始化时先冻结所有层
  2. for name, param in self.named_parameters():
  3.     param.requires_grad = False
  4. # 然后单独设置指定层的 requires_grad 为 True
  5. for param in self.layer_name.parameters(): # layer_name 就是要单独训练的层的自定义名字
  6.     param.requires_grad = True
复制代码
随后在创建优化器时,只输入指定层的参数。【假如想要训练全部层的话,优化器的输入一样寻常是 model_Instance.parameters() 】
  1. optimizer = torch.optim.SGD(model_instance.layer_name.parameters(), lr=0.01)
复制代码
具体示例:

以 CIFAR10 配套网络模子为例(只训练第三个卷积层):
  1. import torch
  2. import torch.nn as nn
  3. import torch.optim as optim
  4. class CIFAR10_NET(nn.Module):
  5.     def __init__(self):
  6.         super(CIFAR10_NET, self).__init__()
  7.         self.conv1 = nn.Conv2d(3, 32, 5, padding=2)
  8.         self.pool1 = nn.MaxPool2d(2, 2)
  9.         self.conv2 = nn.Conv2d(32, 32, 5, padding=2)
  10.         self.pool2 = nn.MaxPool2d(2, 2)
  11.         self.conv3 = nn.Conv2d(32, 64, 5, padding=2)  # 这是我们要训练的层
  12.         self.pool3 = nn.MaxPool2d(2, 2)
  13.         self.flatten = nn.Flatten()
  14.         self.fc1 = nn.Linear(1024, 64)  # 注意:这里的1024是基于输入图像大小和前面的卷积+池化层计算得出的
  15.         self.fc2 = nn.Linear(64, 10)
  16.         # 初始化时先冻结所有层
  17.         for name, param in self.named_parameters():
  18.             param.requires_grad = False
  19.         # 然后单独设置第三个卷积层的requires_grad为True
  20.         for param in self.conv3.parameters():
  21.             param.requires_grad = True
  22.     def forward(self, x):
  23.         x = self.pool1(torch.relu(self.conv1(x)))
  24.         x = self.pool2(torch.relu(self.conv2(x)))
  25.         x = self.pool3(torch.relu(self.conv3(x)))  # 第三个卷积层
  26.         x = self.flatten(x)
  27.         x = torch.relu(self.fc1(x))
  28.         x = self.fc2(x)
  29.         return x
  30. # 实例化模型
  31. model_instance = CIFAR10_NET()
  32. # 创建优化器,只包含第三个卷积层的参数
  33. optimizer = optim.SGD(model_instance.conv3.parameters(), lr=0.01)
  34. # 损失函数
  35. criterion = nn.CrossEntropyLoss()
  36. # 示例输入和目标(这里需要真实的CIFAR-10数据,但这里只是示例)
  37. inputs = torch.randn(1, 3, 32, 32)  # 假设输入图像大小为32x32
  38. targets = torch.tensor([1])  # 假设目标类别为1
  39. # 训练循环(简化版)
  40. model.train()
  41. for epoch in range(10):  # 假设训练10个epoch
  42.     optimizer.zero_grad()
  43.     outputs = model(inputs)
  44.     loss = criterion(outputs, targets)
  45.     loss.backward()
  46.     optimizer.step()
  47.     print(f'Epoch {epoch+1}, Loss: {loss.item()}')
复制代码
2)从官网或本地加载预训练模子,并修改或添加某个层,而且只训练该层

由于这种情况,代码里不会再完备的界说一遍网络模子,以是无法直接在模子界说时选择该指定哪一层训练。
此时须要先导入预训练模子,然后到场下方代码举行选择:
  1. for name, param in model_name.named_parameters(): # model_name为模型名
  2.     # layer_name为指定层名
  3.     if 'layer_name' in name:
  4.         param.requires_grad = True
  5.     else:
  6.         param.requires_grad = False  # 冻结其他所有参数
复制代码
然后再指定优化器的输入参数即可:
  1. model_instance = model_name() # 实例化模型
  2. optimizer = optim.SGD(model_instance.layer_name.parameters(), lr=0.01)
复制代码
具体示例:

仍以 CIFAR10 配套网络模子为例(将末了的 nn.Linear(64, 10) 层改为 nn.Linear(64, 20) )。而且原先的网络模子已经训练好了并生存在本地了。
  1. import torch
  2. import torch.nn as nn
  3. import torch.optim as optim
  4. CIFAR10_NET_new = torch.load("E:\\5_NN_model\\CIFAR10_NET.pth") # 原先将整个预训练模型保存在了本地
  5. CIFAR10_NET_new.fc2 = nn.Linear(64, 20) # 修改最后一个全连接层,其名字为: fc2
  6. for name, param in CIFAR10_NET_new.named_parameters():
  7.     # 如果参数属于修改后的全连接层,则设置为可训练
  8.     if 'fc2' in name:
  9.         param.requires_grad = True
  10.     else:
  11.         param.requires_grad = False  # 冻结其他所有参数
  12. model_instance = CIFAR10_NET_new() # 实例化模型
  13.         
  14. # 创建优化器,只包含修改后的全连接层的参数
  15. optimizer = optim.SGD(model_instance.fc2.parameters(), lr=0.01)
  16. # 损失函数
  17. criterion = nn.CrossEntropyLoss()
  18. # 示例输入和目标(这里需要真实的CIFAR-10数据,但这里只是示例)
  19. inputs = torch.randn(1, 3, 32, 32)  # 假设输入图像大小为32x32
  20. targets = torch.tensor([1])  # 假设目标类别为1
  21. # 训练循环(简化版)
  22. model.train()
  23. for epoch in range(10):  # 假设训练10个epoch
  24.     optimizer.zero_grad()
  25.     outputs = model(inputs)
  26.     loss = criterion(outputs, targets)
  27.     loss.backward()
  28.     optimizer.step()
  29.     print(f'Epoch {epoch+1}, Loss: {loss.item()}')
复制代码
2)单层网络

   此单层网络须要是使用张量范例的。
  假如只训练某个参数,那么令其 requires_grad 属性为 True ,其他的参数该属性设置为 False 即可。
别的在训练过程中,只使用  w2.data -= learning_rate * w2.grad.data 来更新 w2 的值即可。
具体示例:

以线性模子 y = w1*x^2+w2*x+b 为例(只训练 w2 )。
  1. import torch
  2. x_data = [1.0, 2.0, 3.0]
  3. y_data = [2.0, 4.0, 6.0]
  4. # 初始化权重
  5. w1 = torch.tensor([0.5], requires_grad=False)  # 不需要训练
  6. w2 = torch.tensor([0.0], requires_grad=True)  # 需要训练,初始化为0.0以更清楚地看到训练效果
  7. b = torch.tensor([0.5], requires_grad=False)  # 不需要训练
  8. # 定义前向传播函数
  9. def forward(x):
  10.     return x * x * w1 + x * w2 + b
  11. # 定义损失函数(均方误差)
  12. def loss(x, y):
  13.     y_pred = forward(x)
  14.     return (y_pred - y) ** 2
  15. # 训练过程
  16. learning_rate = 0.01
  17. for epoch in range(100):
  18.     total_loss = 0.0
  19.     for x, y in zip(x_data, y_data):
  20.         l = loss(x, y)
  21.         l.backward()  # 反向传播,计算梯度
  22.         # 只更新w2
  23.         w2.data -= learning_rate * w2.grad.data
  24.         w2.grad.zero_()# 清零梯度,为下一次迭代做准备
  25.         total_loss += l.item()
  26.     average_loss = total_loss / len(x_data)
  27.     print(f"Epoch {epoch+1}, Average Loss: {average_loss}")
复制代码

上一篇下一篇神经网络入门实战(二十一)待发布
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表