迁移学习篇之如何迁移经典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()
相关文章
用MASM32按Time Protocol(RFC868)协议编写网络对时程序中的一些有用的函数代码
用MASM32按Time Protocol(RFC868)协议编写网络对时程序中的一些有用的函数代码
|
3月前
|
机器学习/深度学习 PyTorch 算法框架/工具
CNN中的注意力机制综合指南:从理论到Pytorch代码实现
注意力机制已成为深度学习模型的关键组件,尤其在卷积神经网络(CNN)中发挥了重要作用。通过使模型关注输入数据中最相关的部分,注意力机制显著提升了CNN在图像分类、目标检测和语义分割等任务中的表现。本文将详细介绍CNN中的注意力机制,包括其基本概念、不同类型(如通道注意力、空间注意力和混合注意力)以及实际实现方法。此外,还将探讨注意力机制在多个计算机视觉任务中的应用效果及其面临的挑战。无论是图像分类还是医学图像分析,注意力机制都能显著提升模型性能,并在不断发展的深度学习领域中扮演重要角色。
133 10
|
4月前
|
机器学习/深度学习 存储 算法
回声状态网络(Echo State Networks,ESN)详细原理讲解及Python代码实现
本文详细介绍了回声状态网络(Echo State Networks, ESN)的基本概念、优点、缺点、储层计算范式,并提供了ESN的Python代码实现,包括不考虑和考虑超参数的两种ESN实现方式,以及使用ESN进行时间序列预测的示例。
245 4
回声状态网络(Echo State Networks,ESN)详细原理讲解及Python代码实现
|
16天前
|
机器学习/深度学习 算法 信息无障碍
基于GoogleNet深度学习网络的手语识别算法matlab仿真
本项目展示了基于GoogleNet的深度学习手语识别算法,使用Matlab2022a实现。通过卷积神经网络(CNN)识别手语手势,如"How are you"、"I am fine"、"I love you"等。核心在于Inception模块,通过多尺度处理和1x1卷积减少计算量,提高效率。项目附带完整代码及操作视频。
|
2月前
|
机器学习/深度学习 网络架构 计算机视觉
目标检测笔记(一):不同模型的网络架构介绍和代码
这篇文章介绍了ShuffleNetV2网络架构及其代码实现,包括模型结构、代码细节和不同版本的模型。ShuffleNetV2是一个高效的卷积神经网络,适用于深度学习中的目标检测任务。
112 1
目标检测笔记(一):不同模型的网络架构介绍和代码
|
3月前
|
安全 C#
某网络硬盘网站被植入传播Trojan.DL.Inject.xz等的代码
某网络硬盘网站被植入传播Trojan.DL.Inject.xz等的代码
|
4月前
|
安全 网络安全 开发者
探索Python中的装饰器:简化代码,增强功能网络安全与信息安全:从漏洞到防护
【8月更文挑战第30天】本文通过深入浅出的方式介绍了Python中装饰器的概念、用法和高级应用。我们将从基础的装饰器定义开始,逐步深入到如何利用装饰器来改进代码结构,最后探讨其在Web框架中的应用。适合有一定Python基础的开发者阅读,旨在帮助读者更好地理解并运用装饰器来优化他们的代码。
|
4月前
|
数据采集 量子技术 双11
【2023 年第十三届 MathorCup 高校数学建模挑战赛】C 题 电商物流网络包裹应急调运与结构优化问题 建模方案及代码实现
本文提供了2023年第十三届MathorCup高校数学建模挑战赛C题的详细建模方案及代码实现,针对电商物流网络中的包裹应急调运与结构优化问题,提出了包括时间序列分析在内的多种数学模型,并探讨了物流网络的鲁棒性。
76 2
【2023 年第十三届 MathorCup 高校数学建模挑战赛】C 题 电商物流网络包裹应急调运与结构优化问题 建模方案及代码实现
完成切换网络+修改网络连接图标提示的代码框架
完成切换网络+修改网络连接图标提示的代码框架
|
4月前
|
机器学习/深度学习 PyTorch 算法框架/工具
PyTorch代码实现神经网络
这段代码示例展示了如何在PyTorch中构建一个基础的卷积神经网络(CNN)。该网络包括两个卷积层,分别用于提取图像特征,每个卷积层后跟一个池化层以降低空间维度;之后是三个全连接层,用于分类输出。此结构适用于图像识别任务,并可根据具体应用调整参数与层数。