去年在做一个智能园艺项目时,需要自动识别不同品种的花卉。经过对比测试,发现经典的AlexNet网络在小样本花卉数据集上表现优异。这个项目完整实现了从数据准备、模型训练到预测部署的全流程,最终在验证集上达到了92%的准确率。下面我会详细解析代码实现中的关键设计,并分享一些实际训练中的调参经验。
AlexNet的特征提取部分包含5个卷积层和3个最大池化层,这种交替结构能逐步提取从低级到高级的图像特征:
python复制self.features = nn.Sequential(
nn.Conv2d(3, 48, kernel_size=11, stride=4, padding=2), # 输入3通道(RGB),输出48通道
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=3, stride=2),
...
)
几个关键设计选择:
实际测试发现,将第一个卷积层的输出通道从原论文的96减半到48,在花卉数据集上效果相当但训练更快
特征提取后接3个全连接层构成分类器:
python复制self.classifier = nn.Sequential(
nn.Dropout(p=0.5),
nn.Linear(128 * 6 * 6, 2048), # 输入4608维,输出2048维
nn.ReLU(inplace=True),
...
)
关键点解析:
python复制data_transform = {
"train": transforms.Compose([
transforms.RandomResizedCrop(224),
transforms.RandomHorizontalFlip(), # 50%概率水平翻转
transforms.ToTensor(),
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))]),
"val": transforms.Compose([
transforms.Resize((224, 224)), # 验证集不做随机裁剪
transforms.ToTensor(),
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])
}
针对花卉数据的特点:
python复制batch_size = 32
nw = min([os.cpu_count(), batch_size if batch_size > 1 else 0, 8])
train_loader = torch.utils.data.DataLoader(
train_dataset, batch_size=batch_size, shuffle=True, num_workers=nw)
经验技巧:
python复制loss_function = nn.BCEWithLogitsLoss() # 二元交叉熵
optimizer = optim.AdamW(net.parameters(), lr=0.0002)
选择依据:
python复制for epoch in range(epochs):
net.train()
for step, data in enumerate(train_bar):
optimizer.zero_grad()
outputs = net(images.to(device))
labels_onehot = torch.nn.functional.one_hot(labels, num_classes=5).float()
loss = loss_function(outputs, labels_onehot.to(device))
loss.backward()
optimizer.step()
关键细节:
scaler.scale(loss).backward()torch.nn.utils.clip_grad_norm_python复制net.eval()
with torch.no_grad():
for val_data in val_bar:
outputs = net(val_images.to(device))
predict_y = torch.max(outputs, dim=1)[1]
acc += torch.eq(predict_y, val_labels.to(device)).sum().item()
注意事项:
python复制if val_accurate > best_acc:
best_acc = val_accurate
torch.save(net.state_dict(), save_path)
最佳实践:
python复制img = Image.open(img_path)
img = data_transform(img)
img = torch.unsqueeze(img, dim=0)
model.eval()
with torch.no_grad():
output = torch.squeeze(model(img.to(device))).cpu()
predict = torch.softmax(output, dim=0)
predict_cla = torch.argmax(predict).numpy()
常见问题处理:
python复制plt.imshow(img)
plt.title(f"class: {class_indict[str(predict_cla)]} prob: {predict[predict_cla]:.3f}")
for i in range(len(predict)):
print(f"class: {class_indict[str(i)]:10} prob: {predict[i]:.3f}")
plt.show()
可视化技巧:
pin_memory=True加速CPU到GPU传输在实际项目中,经过量化的模型在Jetson Nano上推理速度从120ms提升到35ms,完全满足实时性要求。
可能原因:
解决方案:
在调试过程中,曾因为忘记no_grad()导致验证阶段显存溢出,这个教训值得牢记。
这个基础框架可以轻松扩展到:
最近我在一个商业项目中,基于此代码实现了100+种花卉的识别系统,核心架构仍然保持稳定。