文章总结: 文章详细比较了LLM微调与从零训练的区别,解释了微调是在预训练模型基础上进行二次训练,而从零训练则是完全从随机初始化开始。文章从模型初始化、参数冻结、优化器设置和训练策略等方面进行了对比,并提供了代码示例。最后总结了何时使用哪种方法:从零训练适用于有大量数据或任务特殊的情况,而微调适用于数据有限或任务与预训练任务相似的情况。
综合评分: 88
文章分类: AI安全
简单说清:LLM 微调与从零训练的区别
原创
俗说君
鹿鸣安全团队
2025年11月21日 19:07
江苏
前言
之前读研的时候一直都是自己构建模型,从零训练模型,这几天打算微调一个NLP模型做一些任务练练手,在操作的过程中总是把微调跟之前的从零训练弄混,于是就打算整理一篇笔记记录一下二者区别
微调与从零训练
微调是指在已经预训练好的模型基础上,使用特定领域或任务的数据进行二次训练的过程。
从零训练则是不依赖任何预训练模型或已有权重,完全从随机初始化的模型参数开始,仅基于目标任务的数据集,对神经网络的所有层、所有参数进行完整训练的方式。
举个例子来通俗点解释:假如你买了一辆已经组装好的自行车,微调就是根据你的身高、体重等个人情况,调整座椅高度、把手角度等细节。
而从零训练就是从原材料和零件生产开始,设计完整的自行车结构,一步步组装所有部件,最终完全定制一辆适合你身高体重的自行车。
从代码层面分析
从代码实现的角度,微调和直接训练在模型初始化、参数处理、优化器设置和训练策略等方面存在明显差异
模型初始化差异
例如,如下一个简单的CNN网络的代码,从零训练需要自定义网络结构,所有参数随机初始化:
# 从头定义网络架构
class CustomCNN(nn.Module):
def __init__(self):
super(CustomCNN, self).__init__()
self.conv1 = nn.Conv2d(3, 16, 3, padding=1)
self.conv2 = nn.Conv2d(16, 32, 3, padding=1)
self.conv3 = nn.Conv2d(32, 64, 3, padding=1)
self.pool = nn.MaxPool2d(2, 2)
self.fc1 = nn.Linear(64 * 4 * 4, 512)
self.fc2 = nn.Linear(512, 10)
self.relu = nn.ReLU()
self.dropout = nn.Dropout(0.5)
def forward(self, x):
x = self.pool(self.relu(self.conv1(x)))
x = self.pool(self.relu(self.conv2(x)))
x = self.pool(self.relu(self.conv3(x)))
x = x.view(-1, 64 * 4 * 4)
x = self.dropout(self.relu(self.fc1(x)))
x = self.fc2(x)
return x
# 创建模型实例 - 完全从头开始
model = CustomCNN()
而微调需要加载预训练模型,使用在大规模数据集上训练好的权重
# 加载预训练模型 - 使用已有权重
model = models.resnet18(pretrained=True)
# 修改最后的全连接层 - 适应新任务
num_ftrs = model.fc.in_features
model.fc = nn.Sequential(
nn.Linear(num_ftrs, 512),
nn.ReLU(),
nn.Dropout(0.5),
nn.Linear(512, 10) # 假设是10分类任务
)
参数冻结
从零训练的模型的所有参数都参与训练和更新,不需要冻结操作
# 所有参数默认都参与训练
# 不需要额外的冻结操作
model = CustomCNN()
# 所有参数都在优化器中
optimizer = optim.Adam(
model.parameters(), # 所有参数
lr=0.001
)
微调则需要通过设置 requires_grad=False 冻结部分参数,只训练特定层
# 加载预训练模型
model = models.resnet18(pretrained=True)
# 冻结部分层 - 只训练最后几层
ct = 0
for child in model.children():
ct += 1
if ct < 7: # 冻结前7个层组
for param in child.parameters():
param.requires_grad = False
print(f"冻结层组 {ct}: {child.__class__.__name__}")
# 只优化未冻结的参数
optimizer = optim.Adam(
filter(lambda p: p.requires_grad, model.parameters()),
lr=0.001
)
优化器设置
- 从零训练通常所有参数使用相同的学习率
# 所有参数使用相同的学习率
optimizer = optim.Adam(
model.parameters(),
lr=0.001, # 单一学习率
betas=(0.9, 0.999),
eps=1e-08,
weight_decay=0,
amsgrad=False
)
- 微调常使用分层学习率,新层用较大学习率,预训练层用较小学习率
# 不同层使用不同学习率
optimizer = optim.Adam([
# 倒数第二层使用较小学习率
{'params': model.layer4.parameters(), 'lr': 0.001},
# 新的全连接层使用较大学习率
{'params': model.fc.parameters(), 'lr': 0.01}
], lr=0.0001) # 默认学习率
# 或者使用学习率调度器
scheduler = optim.lr_scheduler.ReduceLROnPlateau(
optimizer,
mode='min',
factor=0.1,
patience=10,
verbose=True
)
训练策略
- 从零训练需要更多训练轮次,使用较大学习率
# 训练配置
batch_size = 64
epochs = 50 # 更多轮次
learning_rate = 0.001
# 训练循环
for epoch in range(epochs):
model.train()
running_loss = 0.0
for inputs, labels in train_loader:
inputs, labels = inputs.to(device), labels.to(device)
optimizer.zero_grad()
outputs = model(inputs)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
running_loss += loss.item()
print(f'Epoch {epoch+1}/{epochs}, Loss: {running_loss/len(train_loader):.4f}')
- 微调常采用分阶段训练,总轮次更少,学习率更小
# 微调配置
batch_size = 32
epochs = 10 # 更少轮次
learning_rate = 0.0001 # 更小学习率
# 第一阶段:只训练新层
for epoch in range(5):
model.train()
# 训练代码...
# 第二阶段:解冻部分层继续微调
for param in model.layer4.parameters():
param.requires_grad = True
# 使用更小的学习率
optimizer = optim.Adam(
filter(lambda p: p.requires_grad, model.parameters()),
lr=0.00001 # 进一步减小学习率
)
for epoch in range(5, 10):
model.train()
# 训练代码...
总结
什么时候用哪种方法?
- 从零训练:当你有大量数据,或者任务很特殊(预训练模型不适合)
- 微调:当你数据有限,或者任务与预训练任务相似
目前打算做一个简单的诈骗短信分类的任务,最简单方法则感觉是微调一个中文的NLP模型来完成,因此本次先简单记录一下差异,便于后续任务探究~
| 方面 | 直接训练 | 微调 |
| — | — | — |
| 模型初始化 | class CustomModel(nn.Module): 或 models.Sequential([...]) | models.resnet18(pretrained=True) 或 applications.MobileNetV2(weights='imagenet') |
| 参数冻结 | 所有参数默认参与训练 | param.requires_grad = False 或 base_model.trainable = False |
| 优化器设置 | optimizer = optim.Adam(model.parameters(), lr=0.001) | optimizer = optim.Adam([{'params': layer1, 'lr': 0.001}, {'params': layer2, 'lr': 0.01}]) |
| 训练轮次 | 通常 30-100 轮 | 通常 5-20 轮 |
| 学习率 | 较大 (0.001) | 较小 (0.0001 或更小) |
| 数据增强 | 较强的增强策略 | 相对温和的增强策略 |
| 训练策略 | 单一阶段训练 | 常采用分阶段训练策略 |
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:鹿鸣安全团队 俗说君《简单说清:LLM 微调与从零训练的区别》