MXNET深度学习框架-27-微调(Fine-tuning)-迁移学习

        众所周知,深度学习最重要的一个特性就是所需数据量大,一旦数据量比较小,而采用深度学习去训练的话,最终的结果只有一个:过拟合!但自己的数据集能达到上万的量吗?估计很少吧,就算有,也可能是斥巨资收集的吧。所以,为了应对这种情况,迁移学习(Transfer Learning)就被提出来了。它的主要思想是将从源数据集学到的知识迁移到目标数据集上

                                MXNET深度学习框架-27-微调(Fine-tuning)-迁移学习_第1张图片
        上图中,源数据是一个比较大的数据集如ImageNet,目标数据就是自己的数据集,除了最后一次需要初始化之外,把其它层的参数全部挪过来,这样就完成了迁移学习。

下面使用mxnet实现如何进行迁移学习(本文实现的是kaggle竞赛的猫狗分类大战):
相关图片如下:
MXNET深度学习框架-27-微调(Fine-tuning)-迁移学习_第2张图片
MXNET深度学习框架-27-微调(Fine-tuning)-迁移学习_第3张图片

1) 读取预训练模型

from mxnet.gluon import  model_zoo
pretrained_net = model_zoo.vision.resnet18_v2(pretrained=True)# 读取预训练模型,会自动下载
print(pretrained_net)

看看ResNet18_v2的结构:
MXNET深度学习框架-27-微调(Fine-tuning)-迁移学习_第4张图片
MXNET深度学习框架-27-微调(Fine-tuning)-迁移学习_第5张图片
MXNET深度学习框架-27-微调(Fine-tuning)-迁移学习_第6张图片
MXNET深度学习框架-27-微调(Fine-tuning)-迁移学习_第7张图片
        通常预训练好的模型包含两个模块:Features和Output,前者包含模型除输出层以外的所有层,后者包括最后一层全连接。

print("最后一层:",pretrained_net.output)

结果:
在这里插入图片描述
该模型文件里面不仅有结构,还包含了参数,比如,第一个卷积层的参数:

print("第一个卷积层的参数:",pretrained_net.features[1].params.get("weights").data()[0][0])

结果:
MXNET深度学习框架-27-微调(Fine-tuning)-迁移学习_第8张图片
2)创建模型
        在微调里,我们一般创建一个全新的模型,它跟之前训练好的模型一样,只是最后的分类数目不一样而已,并且最后一层需要重新初始化。微调代码如下:

# 微调
fine_tune_model=model_zoo.vision.resnet18_v2(classes=2) # 分类数为2
# 前面的(参数、结构)完全复制
fine_tune_model.features=pretrained_net.features
# 最后一层随机初始化
fine_tune_model.output.initialize(init=init.Xavier())

通过这种方式我们就已经创建好了模型。
3) 图像预处理

# 指定RGB三个通道的均值和方差来将图像通道归一化
normalize = gn.data.vision.transforms.Normalize(
    [0.485, 0.456, 0.406], [0.229, 0.224, 0.225])

train_augs = gn.data.vision.transforms.Compose([
    gn.data.vision.transforms.Resize(224),
    # gn.data.vision.transforms.RandomFlipLeftRight(),
    gn.data.vision.transforms.ToTensor(),
    normalize])

test_augs = gn.data.vision.transforms.Compose([
    gn.data.vision.transforms.Resize(224),
    # gn.data.vision.transforms.CenterCrop(224),
    gn.data.vision.transforms.ToTensor(),
    normalize])

4)加载图像
        我们创建两个ImageFolderDataset实例来分别读取训练数据集和测试数据集中的所有图像文件。训练集(测试集)文件夹下包含两个子文件夹,分别为"cat"和"dog"文件夹,大致如下:
MXNET深度学习框架-27-微调(Fine-tuning)-迁移学习_第9张图片

batch_size=32
train_imgs = gn.data.vision.ImageFolderDataset("F:/dog and cat/train")
test_imgs = gn.data.vision.ImageFolderDataset("F:/dog and cat/test")
train_iter = gn.data.DataLoader(dataset=train_imgs.transform_first(train_augs),batch_size=batch_size, shuffle=True)
test_iter = gn.data.DataLoader(dataset=test_imgs.transform_first(test_augs),batch_size=batch_size, shuffle=False)

接下来就是常规化操作了,loss定义、准确率定义以及模型训练均与前几章一样,接下来放上所有代码:

from mxnet.gluon import  model_zoo
import mxnet as mx
import mxnet.ndarray as nd
import mxnet.autograd as ag
import mxnet.gluon as gn
import mxnet.initializer as init
import zipfile
import matplotlib.pyplot as plt
import cv2 as cv
from mxnet.gluon import utils as gutils

pretrained_net = model_zoo.vision.resnet18_v2(pretrained=True)
print(pretrained_net)
print("最后一层:",pretrained_net.output)
print("第一个卷积层的参数:",pretrained_net.features[1].params.get("weight").data()[0][0])

# 微调
fine_tune_model=model_zoo.vision.resnet18_v2(classes=2) # 分类数为2
# 前面的(参数、结构)完全复制
# fine_tune_model.initialize(init=init.Xavier()) #从头开始训练
fine_tune_model.features=pretrained_net.features
# # 最后一层随机初始化
fine_tune_model.output.initialize(init=init.Xavier())

'''---数据读取---'''
batch_size=32
# 指定RGB三个通道的均值和方差来将图像通道归一化
normalize = gn.data.vision.transforms.Normalize(
    [0.485, 0.456, 0.406], [0.229, 0.224, 0.225])

train_augs = gn.data.vision.transforms.Compose([
    gn.data.vision.transforms.Resize(224),
    # gn.data.vision.transforms.RandomFlipLeftRight(),
    gn.data.vision.transforms.ToTensor(),
    normalize])

test_augs = gn.data.vision.transforms.Compose([
    gn.data.vision.transforms.Resize(224),
    # gn.data.vision.transforms.CenterCrop(224),
    gn.data.vision.transforms.ToTensor(),
    normalize])

train_imgs = gn.data.vision.ImageFolderDataset("F:/dog and cat/train")
test_imgs = gn.data.vision.ImageFolderDataset("F:/dog and cat/test")
train_iter = gn.data.DataLoader(dataset=train_imgs.transform_first(train_augs),batch_size=batch_size, shuffle=True)
test_iter = gn.data.DataLoader(dataset=test_imgs.transform_first(test_augs),batch_size=batch_size, shuffle=False)

ctx=mx.gpu()
fine_tune_model.collect_params().reset_ctx(ctx=ctx) # 因为要用GPU训练,而微调的模型被读取在CPU上
fine_tune_model.hybridize()

fine_tune_model.output.collect_params().setattr('lr_mult', 10)
# softmax和交叉熵分开的话数值可能会不稳定
cross_loss=gn.loss.SoftmaxCrossEntropyLoss()

# 定义准确率
def accuracy(output,label):
    return nd.mean(output.argmax(axis=1)==label).asscalar()

def evaluate_accuracy(data_iter,net):# 定义测试集准确率
    acc=0
    for data,label in data_iter:
        data, label = data.as_in_context(ctx), label.as_in_context(ctx)
        label=label.astype("float32")
        output=net(data)
        acc+=accuracy(output,label)
    return acc/len(data_iter)


# 优化

train_step=gn.Trainer(fine_tune_model.collect_params(),'sgd'
                      ,{"learning_rate":0.002}) # 如果从头开始训练,lr需要大一点

# 训练

epochs=20
for epoch in range(epochs):
    n=0
    train_loss=0
    train_acc=0
    for image,y in train_iter:
        image, y = image.as_in_context(ctx), y.as_in_context(ctx)
        y = y.astype("float32")
        with ag.record():
            output = fine_tune_model(image)
            loss = cross_loss(output, y)
        loss.backward()
        train_step.step(batch_size)
        train_loss += nd.mean(loss).asscalar()
        train_acc += accuracy(output, y)
    nd.waitall()
    test_acc = evaluate_accuracy(test_iter, fine_tune_model)
    print("Epoch %d, Loss:%f, Train acc:%f, Test acc:%f"
          %(epoch,train_loss/len(train_iter),train_acc/len(train_iter),test_acc))

训练结果:
在这里插入图片描述
        可以看到,模型准确率只跑了一个epoch就达到了98%,已经非常高了。这结果怕是在kaggle竞赛上也能拿到前5的名次了,放上现在kaggle之猫狗大战的的比赛名次(排名来源于kaggle网站:https://www.kaggle.com/c/dogs-vs-cats/leaderboard
截图至2020.5.1):
MXNET深度学习框架-27-微调(Fine-tuning)-迁移学习_第10张图片

为了对比迁移学习的优势,我们从头初始化所有参数,重新开始训练:

fine_tune_model.initialize(init=init.Xavier()) #从头开始训练

结果:
在这里插入图片描述
        可以看到,虽然准确率有在增加,但是很慢很慢,所以微调(Fine-tuning)确实是有效的加快深度学习训练、提升准确率的方法。

你可能感兴趣的:(mxnet,Fine-Tuning,迁移学习,mxnet,神经网络,深度学习)