迁移学习微调训练图像分类模型
图像预处理
from torchvision import transforms
# 训练集图像预处理:缩放裁剪、图像增强、转 Tensor、归一化
train_transform = transforms.Compose([transforms.RandomResizedCrop(224),
transforms.RandomHorizontalFlip(),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
])
# 测试集图像预处理-RCTN:缩放、裁剪、转 Tensor、归一化
test_transform = transforms.Compose([transforms.Resize(256),
transforms.CenterCrop(224),
transforms.ToTensor(),
transforms.Normalize(
mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225])
])
载入图像分类数据集
# 数据集文件夹路径
dataset_dir = 'fruit30_split'
train_path = os.path.join(dataset_dir, 'train')
test_path = os.path.join(dataset_dir, 'val')
print('训练集路径', train_path)
print('测试集路径', test_path)
训练集路径 fruit30_split/train
测试集路径 fruit30_split/val
from torchvision import datasets
# 载入训练集
train_dataset = datasets.ImageFolder(train_path, train_transform)
# 载入测试集
test_dataset = datasets.ImageFolder(test_path, test_transform)
类别编码
index 编码
index 编码用来对离散的类型特征进行编码,如,不连续的数值、文本,将离散的特征转换成连续的数值型变量。基于索引的编码可以起到数据归一化的作用,如,id为1和10000,当id作为LR的特征时,id为1的用户和id为10000的用户基本属性一样,但LR算法中10000权重过大,会导致id=1的特征基本不起作用,必须进行归一化,类似特征都应单独进行归一化。
如特征A取值共有9种情况,如,[1, 200, 10000, 30000, 100000],则索引编码后为[0, 1, 2, 3, 4]。
onehot 编码
OneHot编码也叫独热编码或哑编码,可以解决某些分类器不好处理离散属性数据的问题,在一定长度上也起到了对特征进行扩充的作用。
大部分算法是基于向量空间中的距离度量来进行计算的,为了使非偏序关系的变量取值不具有偏序性,并且到圆点是等距的。使用one-hot编码,将离散特征的取值扩展到了欧式空间,离散特征的某个取值就对应欧式空间的某个点。将离散型特征使用one-hot编码,会让特征之间的距离计算更加合理。离散特征进行one-hot编码后,编码后的特征,其实每一维度的特征都可以看做是连续的特征。跟对连续型特征的归一化方法一样,对每一维特征进行归一化。比如归一化到[-1,1]或归一化到均值为0,方差为1。
为什么特征向量要映射到欧式空间?
在回归,分类,聚类等机器学习算法中,特征之间距离的计算或相似度的计算是非常重要的,而我们常用的距离或相似度的计算都是在欧式空间的相似度计算,如,计算余弦相似性,就是基于欧式空间。
独热编码优缺点
优点:独热编码解决了分类器不好处理属性数据的问题,在一定程度上也起到了扩充特征的作用。它的值只有0和1,不同的类型存储在垂直的空间。
缺点:当类别的数量很多时,特征空间会变得非常大。在这种情况下,一般可以用PCA来减少维度。而且one hot encoding+PCA这种组合在实际中也非常有用。
数据加载器
from torch.utils.data import DataLoader
BATCH_SIZE = 32
# 训练集的数据加载器
train_loader = DataLoader(train_dataset,
batch_size=BATCH_SIZE,
shuffle=True,
num_workers=4
)
# 测试集的数据加载器
test_loader = DataLoader(test_dataset,
batch_size=BATCH_SIZE,
shuffle=False,
num_workers=4
)
选择迁移学习训练方式
1. 优先微调最后一层全连接层
优先调节最后一个全连接层,通过调节最后一个全连接层去改善训练效果。
2. 观察训练集和验证集的结果并对比,从而调整相应得层
将训练集和验证集上的效果可视化,从而去判断该如果微调。比如:
- 发现过拟合,则可以在适当层添加正则化层,比如BN层或者Dropout。
- 发现过拟合,并且无法通过BN和Dropout改善,则可能是数据集的分布出现问题,考虑重新预处理数据集
- 发现过拟合,并通过上述效果不佳,则可以考虑通过减少网络广度
- 未发现过拟合,但效果不佳,则考虑加深、加宽网络
- …
- …
3. 初始化模型参数
模拟一个batch的训练
# 获得一个 batch 的数据和标注
images, labels = next(iter(train_loader))
images = images.to(device)
labels = labels.to(device)
# 输入模型,执行前向预测
outputs = model(images)