迁移学习篇之如何迁移经典CNN网络-附迁移学习Alexnet,VGG,Googlenet,Resnet详细代码注释和方法-pytorch

简介: 迁移学习篇之如何迁移经典CNN网络-附迁移学习Alexnet,VGG,Googlenet,Resnet详细代码注释和方法-pytorch

鸽了好久的迁移学习篇学习终于打算更新,这次我们来学习一个机器学习中经典常用的简单快速提高网络指标的trick,迁移学习,迁移学习本身是机器学习中的一个trick,但是近些年在深度学习中应用广泛。之前我在学习迁移学习的时候想做到随便迁移任何一个网络但是我又看不太懂CNN的代码,然后就很懵,这篇博客的目的在于让大家只需要简单修改代码即可实现各种经典CNN网络的迁移。当然迁移学习是一门很大的学科,我们这里只介绍微调的方法。


一般来说不管针对任何数据集,使用迁移学习的方法一定是比不使用迁移学习要效果好的,记住我这里说的是


一定,一定,一定!!!重要的事情说三遍。


好的,废话少说,我们来简单介绍一下迁移学习的概念,迁移学习的思想可以理解成为,我们人类的学习,简单来说如果一个人需要学习python编程语言,但是他从来没有学过任何编程语言,这样他重新开始学编程语言就会学的很慢,但是如果他之前就学过C语言,或者C++,亦或者matlab的脚本语言,那么学python的时候就会很快,对,没错,我们基于已有的知识去重新学习新知识的过程便是迁移学习。


不论是深度学习模型还是各种神经网络,我们都可以理解成人类的大脑,大脑如果最开始一片空白(即模型还未开始训练,没有任何信息),然后开始学习一个知识(识别一个简单的目标)会学的非常慢,因为我们都知道从0开始学习是非常慢的,但是如果这个人已经学过数学,比如说高等数学,那么我们再开始学习线性代数,概率论,我们学习的速度一定是要快于什么都没学过的人的(假设双方智力相等),而且我们也会学的比没学过的人好。


对,如果我们的模型在训练之前,不是新的模型,是已经训练过可以识别其他对象的模型,那么我们在这个的基础上再次训练这个模型识别一个新对象的时候我们也许简单跑几个epoch就能达到很高的识别率。


好的,到这里我想我们经对迁移学习的概念有所了解,所谓迁移学习,就是我们在已经学会旧事物的基础上去学习类似的新事物,这样会让我们学的更快更好。


事实上这也是为什么我们经常将迁移学习用在数据量较少的数据上,因为我们完全可以将模型在数据量较大的数据上进行集中训练,训练出很好的效果,对于我们目标数据集量很少的情况,我们只需要迁移学习一下,很少的数据就能达到很好的效果。


说到这里,我们就需要介绍一下Imagenet数据集了(详细的自行百度),身为最庞大的开源数据集之一,他包含1000类数据,这也是没什么我们从他上面下载的预训练模型的结构的输出都是1000的原因。


              image.png


好,到这里我们又提出了预训练模型的概念,所谓预训练模型是个比较专业的叫法,其实说白了就是我们提到的已经训练过的模型。但是面临一个问题,每当我们需要训练模型的时候,需要采用迁移学习方法的时候我们需要去哪里寻找好的预训练模型呢?


这个时候Imagenet数据集的重要性已经体现了出来,按照我们经常使用的TensorFlow和pytorch来说,这些深度学习框架里面已经在Imagenet数据集上训练好了各种常见的CNN模型的预训练模型,我们只需要在代码上稍作修改,就可以在训练的时候下载相应的预训练模型,并且在他的最后再加一层全连接层,全连接层的输出改成我们数据集的种类,即可得到我们想要的结果。


例如我们常见的Resnet模型的迁移学习,


image.png


这就是Resnet预训练模型的下载过程


下面以alexnet为例:预训练模型下载代码

alexnet1 = torchvision.models.alexnet(pretrained=True) #下载预训练模型,pretrained=True则是下载预训练模型,如果下载好了就设置为False
    #这里是下载的alexnet预训练模型,你想下载那个,就把这个alexnet修改成相应模型的名字即可
    num_calss = 5  #数据种类,你有几种数据,就设置为几
    alexnet1.add_module("linear", nn.Linear(1000, num_calss)) #我们一般需要在模型的最后添加一个全连接层,然后这里的

下面附上完整的基于迁移学习的alexnet,VGG,Googlenet,Resnet代码:

import torch
import torchvision
import torchvision.models
from matplotlib import pyplot as plt
from tqdm import tqdm
from torch import nn
from torch.utils.data import DataLoader
from torchvision.transforms import transforms
data_transform = {
    "train": transforms.Compose([transforms.RandomResizedCrop(120),
                                 transforms.RandomHorizontalFlip(),
                                 transforms.ToTensor(),
                                 transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))]),
    "val": transforms.Compose([transforms.Resize((120, 120)),  # cannot 224, must (224, 224)
                               transforms.ToTensor(),
                               transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])}
def main():
    train_data = torchvision.datasets.ImageFolder(root = "./data/train" ,   transform = data_transform["train"])
    #导入自己的数据,自己的数据放在跟代码相同的文件夹下新建一个data文件夹,data文件夹里的新建一个train文件夹用于放置训练集的图片。同理新建一个val文件夹用于放置测试集的图片。
    traindata = DataLoader(dataset= train_data , batch_size= 32 , shuffle= True , num_workers=0 ) # 将训练数据以每次32张图片的形式抽出进行训练
    test_data = torchvision.datasets.ImageFolder(root = "./data/val" , transform = data_transform["val"])
    train_size = len(train_data) # 训练集的长度
    test_size = len(test_data) # 测试集的长度
    print(train_size)  # 输出训练集长度看一下,相当于看看有几张图片
    print(test_size)  # 输出测试集长度看一下,相当于看看有几张图片
    testdata = DataLoader(dataset = test_data , batch_size= 32 , shuffle= True , num_workers=0 )# 将训练数据以每次32张图片的形式抽出进行测试
    device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
    print("using {} device.".format(device))
    # class alexnet(nn.Module):
    #     def __init__(self):
    #         super(alexnet , self).__init__()
    #         self.model = nn.Sequential(
    #
    #             nn.Conv2d(3, 48, kernel_size=11, stride=4, padding=2),  # input[3, 120, 120]  output[48, 55, 55]
    #
    #             nn.ReLU(inplace=True),
    #             nn.MaxPool2d(kernel_size=3, stride=2),  # output[48, 27, 27]
    #             nn.Conv2d(48, 128, kernel_size=5, padding=2),  # output[128, 27, 27]
    #
    #             nn.ReLU(inplace=True),
    #             nn.MaxPool2d(kernel_size=3, stride=2),  # output[128, 13, 13]
    #             nn.Conv2d(128, 192, kernel_size=3, padding=1),  # output[192, 13, 13]
    #
    #             nn.ReLU(inplace=True),
    #             nn.Conv2d(192, 192, kernel_size=3, padding=1),  # output[192, 13, 13]
    #
    #             nn.ReLU(inplace=True),
    #             nn.Conv2d(192, 128, kernel_size=3, padding=1),  # output[128, 13, 13]
    #
    #             nn.ReLU(inplace=True),
    #             nn.MaxPool2d(kernel_size=3, stride=2),  # output[128, 6, 6]
    #             nn.Flatten(),
    #             nn.Dropout(p=0.5),
    #             nn.Linear(512, 2048),
    #             nn.ReLU(inplace=True),
    #             nn.Dropout(p=0.5),
    #             nn.Linear(2048, 1024),
    #             nn.ReLU(inplace=True),
    #             nn.Linear(1024, 7),
    #
    #         )
    #     def forward(self , x):
    #         x = self.model(x)
    #         return x
    alexnet1 = torchvision.models.alexnet(pretrained=True) #下载预训练模型,pretrained=True则是下载预训练模型,如果下载好了就设置为False
    #这里是下载的alexnet预训练模型,你想下载那个,就把这个alexnet修改成相应模型的名字即可
    num_calss = 5  #数据种类,你有几种数据,就设置为几
    alexnet1.add_module("linear", nn.Linear(1000, num_calss)) #我们一般需要在模型的最后添加一个全连接层,然后这里的
    print(alexnet1) #打印模型结构,看看模型的构成
    alexnet1.to(device)
    test1 = torch.ones(64, 3, 120, 120)  #输出一个测试数据看看模型的输出
    test1 = alexnet1(test1.to(device))
    print(test1.shape)
    epoch = 15  # 迭代次数即训练次数
    learning = 0.001  # 学习率
    optimizer = torch.optim.Adam(alexnet1.parameters(), lr=learning)  # 使用Adam优化器-写论文的话可以具体查一下这个优化器的原理
    loss = nn.CrossEntropyLoss()  # 损失计算方式,交叉熵损失函数
    train_loss_all = []  # 存放训练集损失的数组
    train_accur_all = []  # 存放训练集准确率的数组
    test_loss_all = []  # 存放测试集损失的数组
    test_accur_all = []  # 存放测试集准确率的数组
    for i in range(epoch):  # 开始迭代
        train_loss = 0  # 训练集的损失初始设为0
        train_num = 0.0  #
        train_accuracy = 0.0  # 训练集的准确率初始设为0
        alexnet1.train()  # 将模型设置成 训练模式
        train_bar = tqdm(traindata)  # 用于进度条显示,没啥实际用处
        for step, data in enumerate(train_bar):  # 开始迭代跑, enumerate这个函数不懂可以查查,将训练集分为 data是序号,data是数据
            img, target = data  # 将data 分位 img图片,target标签
            optimizer.zero_grad()  # 清空历史梯度
            outputs = alexnet1(img.to(device))  # 将图片打入网络进行训练,outputs是输出的结果
            loss1 = loss(outputs, target.to(device))  # 计算神经网络输出的结果outputs与图片真实标签target的差别-这就是我们通常情况下称为的损失
            outputs = torch.argmax(outputs, 1)  # 会输出10个值,最大的值就是我们预测的结果 求最大值
            loss1.backward()  # 神经网络反向传播
            optimizer.step()  # 梯度优化 用上面的abam优化
            train_loss += loss1.item() # 将所有损失的绝对值加起来
            accuracy = torch.sum(outputs == target.to(device))  # outputs == target的 即使预测正确的,统计预测正确的个数,从而计算准确率
            train_accuracy = train_accuracy + accuracy  # 求训练集的准确率
            train_num += img.size(0)  #
        print("epoch:{} , train-Loss:{} , train-accuracy:{}".format(i + 1, train_loss / train_num,  # 输出训练情况
                                                                    train_accuracy / train_num))
        train_loss_all.append(train_loss / train_num)  # 将训练的损失放到一个列表里 方便后续画图
        train_accur_all.append(train_accuracy.double().item() / train_num)  # 训练集的准确率
        test_loss = 0  # 同上 测试损失
        test_accuracy = 0.0  # 测试准确率
        test_num = 0
        alexnet1.eval()  # 将模型调整为测试模型
        with torch.no_grad():  # 清空历史梯度,进行测试  与训练最大的区别是测试过程中取消了反向传播
            test_bar = tqdm(testdata)
            for data in test_bar:
                img, target = data
                outputs = alexnet1(img.to(device))
                loss2 = loss(outputs, target.to(device))
                outputs = torch.argmax(outputs, 1)
                test_loss = test_loss + loss2.item()
                accuracy = torch.sum(outputs == target.to(device))
                test_accuracy = test_accuracy + accuracy
                test_num += img.size(0)
        print("test-Loss:{} , test-accuracy:{}".format(test_loss / test_num, test_accuracy / test_num))
        test_loss_all.append(test_loss / test_num)
        test_accur_all.append(test_accuracy.double().item() / test_num)
    # 下面的是画图过程,将上述存放的列表  画出来即可
    plt.figure(figsize=(12, 4))
    plt.subplot(1, 2, 1)
    plt.plot(range(epoch), train_loss_all,
             "ro-", label="Train loss")
    plt.plot(range(epoch), test_loss_all,
             "bs-", label="test loss")
    plt.legend()
    plt.xlabel("epoch")
    plt.ylabel("Loss")
    plt.subplot(1, 2, 2)
    plt.plot(range(epoch), train_accur_all,
             "ro-", label="Train accur")
    plt.plot(range(epoch), test_accur_all,
             "bs-", label="test accur")
    plt.xlabel("epoch")
    plt.ylabel("acc")
    plt.legend()
    plt.show()
    torch.save(alexnet1, "alexnet-transfer-learning.pth")
    print("模型已保存")
if __name__ == '__main__':
    main()

完整的基于迁移学习的VGG代码:

import torch
import torchvision
import torchvision.models
from matplotlib import pyplot as plt
from tqdm import tqdm
from torch import nn
from torch.utils.data import DataLoader
from torchvision.transforms import transforms
data_transform = {
    "train": transforms.Compose([transforms.RandomResizedCrop(120),
                                 transforms.RandomHorizontalFlip(),
                                 transforms.ToTensor(),
                                 transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))]),
    "val": transforms.Compose([transforms.Resize((120, 120)),  # cannot 224, must (224, 224)
                               transforms.ToTensor(),
                               transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])}
def main():
    train_data = torchvision.datasets.ImageFolder(root = "./data/train" ,   transform = data_transform["train"])
    #导入自己的数据,自己的数据放在跟代码相同的文件夹下新建一个data文件夹,data文件夹里的新建一个train文件夹用于放置训练集的图片。同理新建一个val文件夹用于放置测试集的图片。
    traindata = DataLoader(dataset= train_data , batch_size= 32 , shuffle= True , num_workers=0 ) # 将训练数据以每次32张图片的形式抽出进行训练
    test_data = torchvision.datasets.ImageFolder(root = "./data/val" , transform = data_transform["val"])
    train_size = len(train_data) # 训练集的长度
    test_size = len(test_data) # 测试集的长度
    print(train_size)  # 输出训练集长度看一下,相当于看看有几张图片
    print(test_size)  # 输出测试集长度看一下,相当于看看有几张图片
    testdata = DataLoader(dataset = test_data , batch_size= 32 , shuffle= True , num_workers=0 )# 将训练数据以每次32张图片的形式抽出进行测试
    device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
    print("using {} device.".format(device))
    VGG = torchvision.models.vgg16(pretrained=True) #下载预训练模型,pretrained=True则是下载预训练模型,如果下载好了就设置为False
    #这里是下载的alexnet预训练模型,你想下载那个,就把这个alexnet修改成相应模型的名字即可
    num_calss = 5  #数据种类,你有几种数据,就设置为几
    VGG.add_module("linear", nn.Linear(1000, num_calss)) #我们一般需要在模型的最后添加一个全连接层,然后这里的
    print(VGG) #打印模型结构,看看模型的构成
    VGG.to(device)
    test1 = torch.ones(64, 3, 120, 120)  #输出一个测试数据看看模型的输出
    test1 = VGG(test1.to(device))
    print(test1.shape)
    epoch = 15  # 迭代次数即训练次数
    learning = 0.0001  # 学习率
    optimizer = torch.optim.Adam(VGG.parameters(), lr=learning)  # 使用Adam优化器-写论文的话可以具体查一下这个优化器的原理
    loss = nn.CrossEntropyLoss()  # 损失计算方式,交叉熵损失函数
    train_loss_all = []  # 存放训练集损失的数组
    train_accur_all = []  # 存放训练集准确率的数组
    test_loss_all = []  # 存放测试集损失的数组
    test_accur_all = []  # 存放测试集准确率的数组
    for i in range(epoch):  # 开始迭代
        train_loss = 0  # 训练集的损失初始设为0
        train_num = 0.0  #
        train_accuracy = 0.0  # 训练集的准确率初始设为0
        VGG.train()  # 将模型设置成 训练模式
        train_bar = tqdm(traindata)  # 用于进度条显示,没啥实际用处
        for step, data in enumerate(train_bar):  # 开始迭代跑, enumerate这个函数不懂可以查查,将训练集分为 data是序号,data是数据
            img, target = data  # 将data 分位 img图片,target标签
            optimizer.zero_grad()  # 清空历史梯度
            outputs = VGG(img.to(device))  # 将图片打入网络进行训练,outputs是输出的结果
            loss1 = loss(outputs, target.to(device))  # 计算神经网络输出的结果outputs与图片真实标签target的差别-这就是我们通常情况下称为的损失
            outputs = torch.argmax(outputs, 1)  # 会输出10个值,最大的值就是我们预测的结果 求最大值
            loss1.backward()  # 神经网络反向传播
            optimizer.step()  # 梯度优化 用上面的abam优化
            train_loss += loss1.item() # 将所有损失的绝对值加起来
            accuracy = torch.sum(outputs == target.to(device))  # outputs == target的 即使预测正确的,统计预测正确的个数,从而计算准确率
            train_accuracy = train_accuracy + accuracy  # 求训练集的准确率
            train_num += img.size(0)  #
        print("epoch:{} , train-Loss:{} , train-accuracy:{}".format(i + 1, train_loss / train_num,  # 输出训练情况
                                                                    train_accuracy / train_num))
        train_loss_all.append(train_loss / train_num)  # 将训练的损失放到一个列表里 方便后续画图
        train_accur_all.append(train_accuracy.double().item() / train_num)  # 训练集的准确率
        test_loss = 0  # 同上 测试损失
        test_accuracy = 0.0  # 测试准确率
        test_num = 0
        VGG.eval()  # 将模型调整为测试模型
        with torch.no_grad():  # 清空历史梯度,进行测试  与训练最大的区别是测试过程中取消了反向传播
            test_bar = tqdm(testdata)
            for data in test_bar:
                img, target = data
                outputs = VGG(img.to(device))
                loss2 = loss(outputs, target.to(device))
                outputs = torch.argmax(outputs, 1)
                test_loss = test_loss + loss2.item()
                accuracy = torch.sum(outputs == target.to(device))
                test_accuracy = test_accuracy + accuracy
                test_num += img.size(0)
        print("test-Loss:{} , test-accuracy:{}".format(test_loss / test_num, test_accuracy / test_num))
        test_loss_all.append(test_loss / test_num)
        test_accur_all.append(test_accuracy.double().item() / test_num)
    # 下面的是画图过程,将上述存放的列表  画出来即可
    plt.figure(figsize=(12, 4))
    plt.subplot(1, 2, 1)
    plt.plot(range(epoch), train_loss_all,
             "ro-", label="Train loss")
    plt.plot(range(epoch), test_loss_all,
             "bs-", label="test loss")
    plt.legend()
    plt.xlabel("epoch")
    plt.ylabel("Loss")
    plt.subplot(1, 2, 2)
    plt.plot(range(epoch), train_accur_all,
             "ro-", label="Train accur")
    plt.plot(range(epoch), test_accur_all,
             "bs-", label="test accur")
    plt.xlabel("epoch")
    plt.ylabel("acc")
    plt.legend()
    plt.show()
    torch.save(VGG, "VGG-transfer-learning.pth")
    print("模型已保存")
if __name__ == '__main__':
    main()

完整的基于迁移学习的Googlenet代码:

import torch
import torchvision
import torchvision.models
from matplotlib import pyplot as plt
from tqdm import tqdm
from torch import nn
from torch.utils.data import DataLoader
from torchvision.transforms import transforms
data_transform = {
    "train": transforms.Compose([transforms.RandomResizedCrop(120),
                                 transforms.RandomHorizontalFlip(),
                                 transforms.ToTensor(),
                                 transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))]),
    "val": transforms.Compose([transforms.Resize((120, 120)),  # cannot 224, must (224, 224)
                               transforms.ToTensor(),
                               transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])}
def main():
    train_data = torchvision.datasets.ImageFolder(root = "./data/train" ,   transform = data_transform["train"])
    #导入自己的数据,自己的数据放在跟代码相同的文件夹下新建一个data文件夹,data文件夹里的新建一个train文件夹用于放置训练集的图片。同理新建一个val文件夹用于放置测试集的图片。
    traindata = DataLoader(dataset= train_data , batch_size= 32 , shuffle= True , num_workers=0 ) # 将训练数据以每次32张图片的形式抽出进行训练
    test_data = torchvision.datasets.ImageFolder(root = "./data/val" , transform = data_transform["val"])
    train_size = len(train_data) # 训练集的长度
    test_size = len(test_data) # 测试集的长度
    print(train_size)  # 输出训练集长度看一下,相当于看看有几张图片
    print(test_size)  # 输出测试集长度看一下,相当于看看有几张图片
    testdata = DataLoader(dataset = test_data , batch_size= 32 , shuffle= True , num_workers=0 )# 将训练数据以每次32张图片的形式抽出进行测试
    device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
    print("using {} device.".format(device))
    Googlenet = torchvision.models.googlenet(pretrained=True) #下载预训练模型,pretrained=True则是下载预训练模型,如果下载好了就设置为False
    #这里是下载的alexnet预训练模型,你想下载那个,就把这个alexnet修改成相应模型的名字即可
    num_calss = 5  #数据种类,你有几种数据,就设置为几
    Googlenet.add_module("linear", nn.Linear(1000, num_calss)) #我们一般需要在模型的最后添加一个全连接层,然后这里的
    print(Googlenet) #打印模型结构,看看模型的构成
    Googlenet.to(device)
    test1 = torch.ones(64, 3, 120, 120)  #输出一个测试数据看看模型的输出
    test1 = Googlenet(test1.to(device))
    print(test1.shape)
    epoch = 15  # 迭代次数即训练次数
    learning = 0.0001  # 学习率
    optimizer = torch.optim.Adam(Googlenet.parameters(), lr=learning)  # 使用Adam优化器-写论文的话可以具体查一下这个优化器的原理
    loss = nn.CrossEntropyLoss()  # 损失计算方式,交叉熵损失函数
    train_loss_all = []  # 存放训练集损失的数组
    train_accur_all = []  # 存放训练集准确率的数组
    test_loss_all = []  # 存放测试集损失的数组
    test_accur_all = []  # 存放测试集准确率的数组
    for i in range(epoch):  # 开始迭代
        train_loss = 0  # 训练集的损失初始设为0
        train_num = 0.0  #
        train_accuracy = 0.0  # 训练集的准确率初始设为0
        Googlenet.train()  # 将模型设置成 训练模式
        train_bar = tqdm(traindata)  # 用于进度条显示,没啥实际用处
        for step, data in enumerate(train_bar):  # 开始迭代跑, enumerate这个函数不懂可以查查,将训练集分为 data是序号,data是数据
            img, target = data  # 将data 分位 img图片,target标签
            optimizer.zero_grad()  # 清空历史梯度
            outputs = Googlenet(img.to(device))  # 将图片打入网络进行训练,outputs是输出的结果
            loss1 = loss(outputs, target.to(device))  # 计算神经网络输出的结果outputs与图片真实标签target的差别-这就是我们通常情况下称为的损失
            outputs = torch.argmax(outputs, 1)  # 会输出10个值,最大的值就是我们预测的结果 求最大值
            loss1.backward()  # 神经网络反向传播
            optimizer.step()  # 梯度优化 用上面的abam优化
            train_loss += loss1.item() # 将所有损失的绝对值加起来
            accuracy = torch.sum(outputs == target.to(device))  # outputs == target的 即使预测正确的,统计预测正确的个数,从而计算准确率
            train_accuracy = train_accuracy + accuracy  # 求训练集的准确率
            train_num += img.size(0)  #
        print("epoch:{} , train-Loss:{} , train-accuracy:{}".format(i + 1, train_loss / train_num,  # 输出训练情况
                                                                    train_accuracy / train_num))
        train_loss_all.append(train_loss / train_num)  # 将训练的损失放到一个列表里 方便后续画图
        train_accur_all.append(train_accuracy.double().item() / train_num)  # 训练集的准确率
        test_loss = 0  # 同上 测试损失
        test_accuracy = 0.0  # 测试准确率
        test_num = 0
        Googlenet.eval()  # 将模型调整为测试模型
        with torch.no_grad():  # 清空历史梯度,进行测试  与训练最大的区别是测试过程中取消了反向传播
            test_bar = tqdm(testdata)
            for data in test_bar:
                img, target = data
                outputs = Googlenet(img.to(device))
                loss2 = loss(outputs, target.to(device))
                outputs = torch.argmax(outputs, 1)
                test_loss = test_loss + loss2.item()
                accuracy = torch.sum(outputs == target.to(device))
                test_accuracy = test_accuracy + accuracy
                test_num += img.size(0)
        print("test-Loss:{} , test-accuracy:{}".format(test_loss / test_num, test_accuracy / test_num))
        test_loss_all.append(test_loss / test_num)
        test_accur_all.append(test_accuracy.double().item() / test_num)
    # 下面的是画图过程,将上述存放的列表  画出来即可
    plt.figure(figsize=(12, 4))
    plt.subplot(1, 2, 1)
    plt.plot(range(epoch), train_loss_all,
             "ro-", label="Train loss")
    plt.plot(range(epoch), test_loss_all,
             "bs-", label="test loss")
    plt.legend()
    plt.xlabel("epoch")
    plt.ylabel("Loss")
    plt.subplot(1, 2, 2)
    plt.plot(range(epoch), train_accur_all,
             "ro-", label="Train accur")
    plt.plot(range(epoch), test_accur_all,
             "bs-", label="test accur")
    plt.xlabel("epoch")
    plt.ylabel("acc")
    plt.legend()
    plt.show()
    torch.save(Googlenet, "Googlenet-transfer-learning.pth")
    print("模型已保存")
if __name__ == '__main__':
    main()


完整的基于迁移学习的Resnet代码:

import torch
import torchvision
import torchvision.models
from matplotlib import pyplot as plt
from tqdm import tqdm
from torch import nn
from torch.utils.data import DataLoader
from torchvision.transforms import transforms
data_transform = {
    "train": transforms.Compose([transforms.RandomResizedCrop(120),
                                 transforms.RandomHorizontalFlip(),
                                 transforms.ToTensor(),
                                 transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))]),
    "val": transforms.Compose([transforms.Resize((120, 120)),  # cannot 224, must (224, 224)
                               transforms.ToTensor(),
                               transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])}
def main():
    train_data = torchvision.datasets.ImageFolder(root = "./data/train" ,   transform = data_transform["train"])
    #导入自己的数据,自己的数据放在跟代码相同的文件夹下新建一个data文件夹,data文件夹里的新建一个train文件夹用于放置训练集的图片。同理新建一个val文件夹用于放置测试集的图片。
    traindata = DataLoader(dataset= train_data , batch_size= 32 , shuffle= True , num_workers=0 ) # 将训练数据以每次32张图片的形式抽出进行训练
    test_data = torchvision.datasets.ImageFolder(root = "./data/val" , transform = data_transform["val"])
    train_size = len(train_data) # 训练集的长度
    test_size = len(test_data) # 测试集的长度
    print(train_size)  # 输出训练集长度看一下,相当于看看有几张图片
    print(test_size)  # 输出测试集长度看一下,相当于看看有几张图片
    testdata = DataLoader(dataset = test_data , batch_size= 32 , shuffle= True , num_workers=0 )# 将训练数据以每次32张图片的形式抽出进行测试
    device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
    print("using {} device.".format(device))
    Resnet = torchvision.models.resnet18(pretrained=True) #下载预训练模型,pretrained=True则是下载预训练模型,如果下载好了就设置为False
    #这里是下载的alexnet预训练模型,你想下载那个,就把这个alexnet修改成相应模型的名字即可
    num_calss = 5  #数据种类,你有几种数据,就设置为几
    Resnet.add_module("linear", nn.Linear(1000, num_calss)) #我们一般需要在模型的最后添加一个全连接层,然后这里的
    print(Resnet) #打印模型结构,看看模型的构成
    Resnet.to(device)
    test1 = torch.ones(64, 3, 120, 120)  #输出一个测试数据看看模型的输出
    test1 = Resnet(test1.to(device))
    print(test1.shape)
    epoch = 15  # 迭代次数即训练次数
    learning = 0.0001  # 学习率
    optimizer = torch.optim.Adam(Resnet.parameters(), lr=learning)  # 使用Adam优化器-写论文的话可以具体查一下这个优化器的原理
    loss = nn.CrossEntropyLoss()  # 损失计算方式,交叉熵损失函数
    train_loss_all = []  # 存放训练集损失的数组
    train_accur_all = []  # 存放训练集准确率的数组
    test_loss_all = []  # 存放测试集损失的数组
    test_accur_all = []  # 存放测试集准确率的数组
    for i in range(epoch):  # 开始迭代
        train_loss = 0  # 训练集的损失初始设为0
        train_num = 0.0  #
        train_accuracy = 0.0  # 训练集的准确率初始设为0
        Resnet.train()  # 将模型设置成 训练模式
        train_bar = tqdm(traindata)  # 用于进度条显示,没啥实际用处
        for step, data in enumerate(train_bar):  # 开始迭代跑, enumerate这个函数不懂可以查查,将训练集分为 data是序号,data是数据
            img, target = data  # 将data 分位 img图片,target标签
            optimizer.zero_grad()  # 清空历史梯度
            outputs = Resnet(img.to(device))  # 将图片打入网络进行训练,outputs是输出的结果
            loss1 = loss(outputs, target.to(device))  # 计算神经网络输出的结果outputs与图片真实标签target的差别-这就是我们通常情况下称为的损失
            outputs = torch.argmax(outputs, 1)  # 会输出10个值,最大的值就是我们预测的结果 求最大值
            loss1.backward()  # 神经网络反向传播
            optimizer.step()  # 梯度优化 用上面的abam优化
            train_loss += loss1.item() # 将所有损失的绝对值加起来
            accuracy = torch.sum(outputs == target.to(device))  # outputs == target的 即使预测正确的,统计预测正确的个数,从而计算准确率
            train_accuracy = train_accuracy + accuracy  # 求训练集的准确率
            train_num += img.size(0)  #
        print("epoch:{} , train-Loss:{} , train-accuracy:{}".format(i + 1, train_loss / train_num,  # 输出训练情况
                                                                    train_accuracy / train_num))
        train_loss_all.append(train_loss / train_num)  # 将训练的损失放到一个列表里 方便后续画图
        train_accur_all.append(train_accuracy.double().item() / train_num)  # 训练集的准确率
        test_loss = 0  # 同上 测试损失
        test_accuracy = 0.0  # 测试准确率
        test_num = 0
        Resnet.eval()  # 将模型调整为测试模型
        with torch.no_grad():  # 清空历史梯度,进行测试  与训练最大的区别是测试过程中取消了反向传播
            test_bar = tqdm(testdata)
            for data in test_bar:
                img, target = data
                outputs = Resnet(img.to(device))
                loss2 = loss(outputs, target.to(device))
                outputs = torch.argmax(outputs, 1)
                test_loss = test_loss + loss2.item()
                accuracy = torch.sum(outputs == target.to(device))
                test_accuracy = test_accuracy + accuracy
                test_num += img.size(0)
        print("test-Loss:{} , test-accuracy:{}".format(test_loss / test_num, test_accuracy / test_num))
        test_loss_all.append(test_loss / test_num)
        test_accur_all.append(test_accuracy.double().item() / test_num)
    # 下面的是画图过程,将上述存放的列表  画出来即可
    plt.figure(figsize=(12, 4))
    plt.subplot(1, 2, 1)
    plt.plot(range(epoch), train_loss_all,
             "ro-", label="Train loss")
    plt.plot(range(epoch), test_loss_all,
             "bs-", label="test loss")
    plt.legend()
    plt.xlabel("epoch")
    plt.ylabel("Loss")
    plt.subplot(1, 2, 2)
    plt.plot(range(epoch), train_accur_all,
             "ro-", label="Train accur")
    plt.plot(range(epoch), test_accur_all,
             "bs-", label="test accur")
    plt.xlabel("epoch")
    plt.ylabel("acc")
    plt.legend()
    plt.show()
    torch.save(Resnet, "Resnet-transfer-learning.pth")
    print("模型已保存")
if __name__ == '__main__':
    main()
相关文章
|
1天前
|
弹性计算 监控 数据库
制造企业ERP系统迁移至阿里云ECS的实例,详细介绍了从需求分析、数据迁移、应用部署、网络配置到性能优化的全过程
本文通过一个制造企业ERP系统迁移至阿里云ECS的实例,详细介绍了从需求分析、数据迁移、应用部署、网络配置到性能优化的全过程,展示了企业级应用上云的实践方法与显著优势,包括弹性计算资源、高可靠性、数据安全及降低维护成本等,为企业数字化转型提供参考。
14 5
|
5月前
|
机器学习/深度学习
【从零开始学习深度学习】23. CNN中的多通道输入及多通道输出计算方式及1X1卷积层介绍
【从零开始学习深度学习】23. CNN中的多通道输入及多通道输出计算方式及1X1卷积层介绍
【从零开始学习深度学习】23. CNN中的多通道输入及多通道输出计算方式及1X1卷积层介绍
|
5月前
|
机器学习/深度学习 Shell
【从零开始学习深度学习】22. 卷积神经网络(CNN)中填充(padding)与步幅(stride)详解,填充、步幅、输入及输出之间的关系
【从零开始学习深度学习】22. 卷积神经网络(CNN)中填充(padding)与步幅(stride)详解,填充、步幅、输入及输出之间的关系
|
5月前
|
机器学习/深度学习
【从零开始学习深度学习】21. 卷积神经网络(CNN)之二维卷积层原理介绍、如何用卷积层检测物体边缘
【从零开始学习深度学习】21. 卷积神经网络(CNN)之二维卷积层原理介绍、如何用卷积层检测物体边缘
|
5月前
|
机器学习/深度学习 算法 PyTorch
【从零开始学习深度学习】45. Pytorch迁移学习微调方法实战:使用微调技术进行2分类图片热狗识别模型训练【含源码与数据集】
【从零开始学习深度学习】45. Pytorch迁移学习微调方法实战:使用微调技术进行2分类图片热狗识别模型训练【含源码与数据集】
|
6月前
|
机器学习/深度学习 数据可视化 数据挖掘
【视频】少样本图像分类?迁移学习、自监督学习理论和R语言CNN深度学习卷积神经网络实例
【视频】少样本图像分类?迁移学习、自监督学习理论和R语言CNN深度学习卷积神经网络实例
|
6月前
|
数据可视化 定位技术
通过SAS网络分析对人口迁移进行可视化分析
通过SAS网络分析对人口迁移进行可视化分析
|
6月前
|
机器学习/深度学习 PyTorch 算法框架/工具
PyTorch与迁移学习:利用预训练模型提升性能
【4月更文挑战第18天】PyTorch支持迁移学习,助力提升深度学习性能。预训练模型(如ResNet、VGG)在大规模数据集(如ImageNet)训练后,可在新任务中加速训练,提高准确率。通过选择模型、加载预训练权重、修改结构和微调,可适应不同任务需求。迁移学习节省资源,但也需考虑源任务与目标任务的相似度及超参数选择。实践案例显示,预训练模型能有效提升小数据集上的图像分类任务性能。未来,迁移学习将继续在深度学习领域发挥重要作用。
|
6月前
|
机器学习/深度学习 编解码 PyTorch
Pytorch迁移学习使用MobileNet v3网络模型进行猫狗预测二分类
MobileNet v1是MobileNet系列中的第一个版本,于2017年由Google团队提出。其主要目标是设计一个轻量级的深度神经网络,能够在移动设备和嵌入式系统上进行图像分类和目标检测任务,并且具有较高的计算效率和较小的模型大小。
297 0
|
6月前
|
机器学习/深度学习 PyTorch 语音技术
Pytorch迁移学习使用Resnet50进行模型训练预测猫狗二分类
深度学习在图像分类、目标检测、语音识别等领域取得了重大突破,但是随着网络层数的增加,梯度消失和梯度爆炸问题逐渐凸显。随着层数的增加,梯度信息在反向传播过程中逐渐变小,导致网络难以收敛。同时,梯度爆炸问题也会导致网络的参数更新过大,无法正常收敛。 为了解决这些问题,ResNet提出了一个创新的思路:引入残差块(Residual Block)。残差块的设计允许网络学习残差映射,从而减轻了梯度消失问题,使得网络更容易训练。
559 0

热门文章

最新文章