project introduction
project使用的数据为皮肤癌的图片数据,分为了训练和测试集,两个数据集内图片没有重合,均为彩色图像,因为为良恶性皮肤癌的二分类任务,所以相对来讲比较简单。对于网络选择我个人不是很赞成使用算力很大的网络来提升参数指标,毕竟大算力可能会造成落地困难并且较大的算力并不亲民。
Approach
与分割任务不同,分类任务对应的label不会改变所以可以随心的添加许许多多的变换操作。对于皮肤癌的分类数据并没有做过多的预处理操作,仅仅使用的pytorch中自带的一些数据增强操作比如随机上下反转,随机左右翻转,随机旋转,说实话由于皮肤癌的图片大多都是居于中央的所以这些操作对于数据的增强效果并不显著。使用随机擦除以及随机仿射变换的操作就需要相应的提升训练的epoch才会达到较好的收敛效果。
在网络的选择上我选用的是ResNet,具体的搭建步骤参考的是B站一位大佬的视频代码搭建的,更改一下目录就可以用了。探讨了18层,34层,50层的网络的分类效果,因为数据量也没有很大所以50层已经可以做到较全面的提取图像特征。过深的网络反而可能会造成过拟合。
图1 ResNet的网络架构图
使用一些加速、以及提升算力的技巧来提升网络的性能,从而在有限的算力下获得更好的结果。
Tricks
使用了一系列的训练技巧的来提升网络性能,大部分都可以在pytorch的官网找到相应的调用代码
迁移学习
主要是将预训练好的模型权重加载进来
https://pytorch.org/hub/research-models
# 加载预训练预训练模型
model_weight_path = "./resnet34_pre.pth"
assert os.path.exists(model_weight_path), "file {} does not exist.".format(model_weight_path)
net.load_state_dict(torch.load(model_weight_path, map_location=device))
Auto Mix Precision
使用16位与32位存储混合精度训练,增加计算速度,但不会影响结果的准确度。
https://pytorch.org/docs/stable/amp.html
图2 在不同的网络中使用相同的训练超参数均没有出现准确率的下降
from torch.cuda.amp import autocast, GradScaler
scaler = GradScaler()
for step, data in enumerate(train_bar):
images, labels = data
with autocast():
logits = net(images.to(device))
loss = loss_function(logits, labels.to(device))/ accumulation_steps
scaler.scale(loss).backward()
if((step+1) % accumulation_steps)==0:
scaler.step(optimizer)
scaler.update()
optimizer.zero_grad()
梯度累计
内存不够,梯度累及来凑,计算多个轮次再更新一次权重。这里的accumulation_step用来决定多少个iteration更新一次权重。
loss = loss_function(logits, labels.to(device))
loss = loss / accumulation_steps
# 梯度累计训练
if((step+1) % accumulation_steps)==0:
optimizer.step()
optimizer.zero_grad()
预处理
添加预处理操作做数据增强
https://pytorch.org/vision/stable/transforms.html
from torchvision import transforms
transform = transforms.Compose([transforms.ToTensor(),
transforms.Normalize((0.5,), (0.5,))])
网络层数
调用一下18层、34层、还有50层,实在不行自己造一个10层,不过34层和18层我可以训练到0.9的准确率,auc可以达到0.97
动态学习率
https://pytorch.org/docs/stable/optim.html
optimizer = optim.Adam(params, lr=0.0001) #lr =0.0001
scheduler = optim.lr_scheduler.ExponentialLR(optimizer, gamma=0.98)
# 添加在epoch for循环的最后面
lr_rate.append(optimizer.state_dict()['param_groups'][0]['lr'])
scheduler.step()
Metrics
准确率(Accuracy): A c c = T P + T N T P + T N + F P + F N Acc = \frac{TP+TN}{TP+TN+FP+FN} Acc=TP+TN+FP+FNTP+TN
AUC_ROC
confusion matrix
使用的评价指标包括了准确率,AUC曲线,以及混淆矩阵
result
整体上分类的准确率可以达到0.9左右,使用梯度累计法可以有效的提高计算精度
使用AMP没有导致计算准确率的下降
Summary
总的来讲实现的过程比较简单,实现的结果也比较初级,感谢大佬提供参考的代码,大佬的B站id是霹雳吧啦Wz
小白上路还有很多不足请大家多多指教!
文中使用的图片来源于ResNet原论文以及NVIDIA官方的文档,侵权即删