马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
只训练 (多层网络的) 指定层 / (单层网络的) 指定参数
在训练的时间,偶然间并不须要将网络层每次都重新训练,对于只训练指定层的情况,可以通过设置该层参数的 requires_grad =True ,别的层通过设置 requires_grad = False 来冻结(不更新权重)。
【留意】:此时就不要使用 self.model = nn.Sequential(...) 函数将全部层都放在一起,酿成一个团体了。
1)多层网络
在界说模子时,在 __init__ 函数后, forward 函数前,加上下方这段代码:
- # 初始化时先冻结所有层
- for name, param in self.named_parameters():
- param.requires_grad = False
- # 然后单独设置指定层的 requires_grad 为 True
- for param in self.layer_name.parameters(): # layer_name 就是要单独训练的层的自定义名字
- param.requires_grad = True
复制代码 随后在创建优化器时,只输入指定层的参数。【假如想要训练全部层的话,优化器的输入一样寻常是 model_Instance.parameters() 】
- optimizer = torch.optim.SGD(model_instance.layer_name.parameters(), lr=0.01)
复制代码 具体示例:
以 CIFAR10 配套网络模子为例(只训练第三个卷积层):
- import torch
- import torch.nn as nn
- import torch.optim as optim
- class CIFAR10_NET(nn.Module):
- def __init__(self):
- super(CIFAR10_NET, self).__init__()
- self.conv1 = nn.Conv2d(3, 32, 5, padding=2)
- self.pool1 = nn.MaxPool2d(2, 2)
- self.conv2 = nn.Conv2d(32, 32, 5, padding=2)
- self.pool2 = nn.MaxPool2d(2, 2)
- self.conv3 = nn.Conv2d(32, 64, 5, padding=2) # 这是我们要训练的层
- self.pool3 = nn.MaxPool2d(2, 2)
- self.flatten = nn.Flatten()
- self.fc1 = nn.Linear(1024, 64) # 注意:这里的1024是基于输入图像大小和前面的卷积+池化层计算得出的
- self.fc2 = nn.Linear(64, 10)
- # 初始化时先冻结所有层
- for name, param in self.named_parameters():
- param.requires_grad = False
- # 然后单独设置第三个卷积层的requires_grad为True
- for param in self.conv3.parameters():
- param.requires_grad = True
- def forward(self, x):
- x = self.pool1(torch.relu(self.conv1(x)))
- x = self.pool2(torch.relu(self.conv2(x)))
- x = self.pool3(torch.relu(self.conv3(x))) # 第三个卷积层
- x = self.flatten(x)
- x = torch.relu(self.fc1(x))
- x = self.fc2(x)
- return x
- # 实例化模型
- model_instance = CIFAR10_NET()
- # 创建优化器,只包含第三个卷积层的参数
- optimizer = optim.SGD(model_instance.conv3.parameters(), lr=0.01)
- # 损失函数
- criterion = nn.CrossEntropyLoss()
- # 示例输入和目标(这里需要真实的CIFAR-10数据,但这里只是示例)
- inputs = torch.randn(1, 3, 32, 32) # 假设输入图像大小为32x32
- targets = torch.tensor([1]) # 假设目标类别为1
- # 训练循环(简化版)
- model.train()
- for epoch in range(10): # 假设训练10个epoch
- optimizer.zero_grad()
- outputs = model(inputs)
- loss = criterion(outputs, targets)
- loss.backward()
- optimizer.step()
- print(f'Epoch {epoch+1}, Loss: {loss.item()}')
复制代码 2)从官网或本地加载预训练模子,并修改或添加某个层,而且只训练该层
由于这种情况,代码里不会再完备的界说一遍网络模子,以是无法直接在模子界说时选择该指定哪一层训练。
此时须要先导入预训练模子,然后到场下方代码举行选择:
- for name, param in model_name.named_parameters(): # model_name为模型名
- # layer_name为指定层名
- if 'layer_name' in name:
- param.requires_grad = True
- else:
- param.requires_grad = False # 冻结其他所有参数
复制代码 然后再指定优化器的输入参数即可:
- model_instance = model_name() # 实例化模型
- optimizer = optim.SGD(model_instance.layer_name.parameters(), lr=0.01)
复制代码 具体示例:
仍以 CIFAR10 配套网络模子为例(将末了的 nn.Linear(64, 10) 层改为 nn.Linear(64, 20) )。而且原先的网络模子已经训练好了并生存在本地了。
- import torch
- import torch.nn as nn
- import torch.optim as optim
- CIFAR10_NET_new = torch.load("E:\\5_NN_model\\CIFAR10_NET.pth") # 原先将整个预训练模型保存在了本地
- CIFAR10_NET_new.fc2 = nn.Linear(64, 20) # 修改最后一个全连接层,其名字为: fc2
- for name, param in CIFAR10_NET_new.named_parameters():
- # 如果参数属于修改后的全连接层,则设置为可训练
- if 'fc2' in name:
- param.requires_grad = True
- else:
- param.requires_grad = False # 冻结其他所有参数
- model_instance = CIFAR10_NET_new() # 实例化模型
-
- # 创建优化器,只包含修改后的全连接层的参数
- optimizer = optim.SGD(model_instance.fc2.parameters(), lr=0.01)
- # 损失函数
- criterion = nn.CrossEntropyLoss()
- # 示例输入和目标(这里需要真实的CIFAR-10数据,但这里只是示例)
- inputs = torch.randn(1, 3, 32, 32) # 假设输入图像大小为32x32
- targets = torch.tensor([1]) # 假设目标类别为1
- # 训练循环(简化版)
- model.train()
- for epoch in range(10): # 假设训练10个epoch
- optimizer.zero_grad()
- outputs = model(inputs)
- loss = criterion(outputs, targets)
- loss.backward()
- optimizer.step()
- 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 )。
- import torch
- x_data = [1.0, 2.0, 3.0]
- y_data = [2.0, 4.0, 6.0]
- # 初始化权重
- w1 = torch.tensor([0.5], requires_grad=False) # 不需要训练
- w2 = torch.tensor([0.0], requires_grad=True) # 需要训练,初始化为0.0以更清楚地看到训练效果
- b = torch.tensor([0.5], requires_grad=False) # 不需要训练
- # 定义前向传播函数
- def forward(x):
- return x * x * w1 + x * w2 + b
- # 定义损失函数(均方误差)
- def loss(x, y):
- y_pred = forward(x)
- return (y_pred - y) ** 2
- # 训练过程
- learning_rate = 0.01
- for epoch in range(100):
- total_loss = 0.0
- for x, y in zip(x_data, y_data):
- l = loss(x, y)
- l.backward() # 反向传播,计算梯度
- # 只更新w2
- w2.data -= learning_rate * w2.grad.data
- w2.grad.zero_()# 清零梯度,为下一次迭代做准备
- total_loss += l.item()
- average_loss = total_loss / len(x_data)
- print(f"Epoch {epoch+1}, Average Loss: {average_loss}")
复制代码 上一篇下一篇神经网络入门实战(二十一)待发布 |