《pytorch深度学习实战》学习笔记第2章

第2章 预训练网络

讨论3种常用的预训练模型:

        1、根据内容对图像进行标记(识别)

        2、从真实图像中生成新图像(GAN)

        3、使用正确的英语句子来描述图像内容(自然语言)

2.1 获取一个预训练好的网络用于图像识别

ImageNet数据集,用于大规模视觉识别挑战赛。

所有预训练好的模型都在TorchVision中。

2.1.1 导入已有的模型

所有模型都在torchvison的models中。导入并查看。

from torchvision import models
dir(models)

输出的是所有torchvison里面集成的模型框架。其中首字母大写的是一些流行的模型小写的名字是快捷函数,返回实例化模型函数

1.1.1 AlexNet模型

实例化AlexNet。

alexnet=models.AlexNet()
alexnet

可以像函数一样调用它。给alexnet输入数据,就会通过正向传播(forward pass)得到输出。比如output=alexnet(input)。由于网络没有初始化,没有经过训练。所以一般先要将模型从头训练或者加载训练好的网络。然后再调用。

1.1.2 Resnet模型

(1)加载在ImageNet数据集上训练好的权重,来实例化ResNet101
resnet=models.resnet101(pretrained=True)
resnet

然后就开始下载,下载完成后查看resnet101的结构。

神经网络由许多模块构成,包含过滤器和非线性函数,fc层结束,输出每个类的分数。

预训练好的模型可以跟函数一样调用,并输入图片实现预测。

(2)定义预处理函数:
from torchvision import transforms
preprocess = 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]
    )
])

预处理包括:图像缩放到256*256像素,围绕中心裁剪到224*224像素,转为张量,归一化处理,使用定义的均值和标准差。

(3)导入图片并进行预处理

导入一张狗的照片并显示

from PIL import Image
img = Image.open('bobby.jpg')
img

待用预处理函数对图片进行预处理。

img_t=preprocess(img)
img_t.shape

输出为一个3维的张量。

给张量前面再增加一个维度。

import torch
batch_t = torch.unsqueeze(img_t,0)#加一个维度,数字0代表增加在第0维前面,如果为1就代表维度1前面
batch_t.shape

输出在第0维前面增加了一个1.

(4)运行模型

在新数据上运行训练过的模型的过程被称为推理(inference),为了推理需要先将网络放到eval模式。执行代码:

resnet.eval()

进行推理:

out=resnet(batch_t)
out

产生了一个1000分类的向量,每个ImageNet对应一个分数。

(5)查看预测结果

加载定义好的ImageNet标签。

with open('imagenet_classes.txt') as f:
    labels = [line.strip() for line in f.readlines()]

需要找出out输出在labels标签中的索引。可以利用max()函数输出张量中最大值以及最大值的索引。代码如下:

_,index=torch.max(out,1)
index

输出的索引不是一个数字,而是一个一维张量。

使用index[0]获得实际的数字作为标签列表的索引,用torch.nn.functional.softmax()将输出归一化到[0,1],然后除以总和。可以求出模型在预测中的置信度。

代码:

percentage = torch.nn.functional.softmax(out,dim=1)[0]*100
labels[index[0]],percentage[index[0]].item()

输出:('golden retriever', 96.29335021972656)

分类结果维金毛犬,置信度为96%。

也可以对预测结果的其它值进行排序输出。比如输出前5个。

_,indices = torch.sort(out,descending=True)
[(labels[idx],percentage[idx].item()) for idx in indices[0][:5]]

输出:

2.2 一个足以以假乱真的预训练模型

GAN是生成式对抗网络(generative adversarial network)的缩写。

cycleGAN是循环生成式对抗网络的缩写,可以将一个领域的图像转换为另一个领域的图像。

2.2.1 将马变为斑马的网络

CycleGAN从ImageNet数据集中提取的马和斑马的数据集进行训练。该网络学习获取一匹或多匹马的图像,并将它们全部变成斑马,图像的其余部分尽可能不被修改。

使用预训练好的CycleGAN将使我们有机会更进一步了解网络是如何实现的,对于本例就是生成器。

(1)以ResNet为例,定义一个ResNetGenerator类。

import torch
import torch.nn as nn

class ResNetBlock(nn.Module): # <1>

    def __init__(self, dim):
        super(ResNetBlock, self).__init__()
        self.conv_block = self.build_conv_block(dim)

    def build_conv_block(self, dim):
        conv_block = []

        conv_block += [nn.ReflectionPad2d(1)]

        conv_block += [nn.Conv2d(dim, dim, kernel_size=3, padding=0, bias=True),
                       nn.InstanceNorm2d(dim),
                       nn.ReLU(True)]

        conv_block += [nn.ReflectionPad2d(1)]

        conv_block += [nn.Conv2d(dim, dim, kernel_size=3, padding=0, bias=True),
                       nn.InstanceNorm2d(dim)]

        return nn.Sequential(*conv_block)

    def forward(self, x):
        out = x + self.conv_block(x) # <2>
        return out


class ResNetGenerator(nn.Module):

    def __init__(self, input_nc=3, output_nc=3, ngf=64, n_blocks=9): # <3> 

        assert(n_blocks >= 0)
        super(ResNetGenerator, self).__init__()

        self.input_nc = input_nc
        self.output_nc = output_nc
        self.ngf = ngf

        model = [nn.ReflectionPad2d(3),
                 nn.Conv2d(input_nc, ngf, kernel_size=7, padding=0, bias=True),
                 nn.InstanceNorm2d(ngf),
                 nn.ReLU(True)]

        n_downsampling = 2
        for i in range(n_downsampling):
            mult = 2**i
            model += [nn.Conv2d(ngf * mult, ngf * mult * 2, kernel_size=3,
                                stride=2, padding=1, bias=True),
                      nn.InstanceNorm2d(ngf * mult * 2),
                      nn.ReLU(True)]

        mult = 2**n_downsampling
        for i in range(n_blocks):
            model += [ResNetBlock(ngf * mult)]

        for i in range(n_downsampling):
            mult = 2**(n_downsampling - i)
            model += [nn.ConvTranspose2d(ngf * mult, int(ngf * mult / 2),
                                         kernel_size=3, stride=2,
                                         padding=1, output_padding=1,
                                         bias=True),
                      nn.InstanceNorm2d(int(ngf * mult / 2)),
                      nn.ReLU(True)]

        model += [nn.ReflectionPad2d(3)]
        model += [nn.Conv2d(ngf, output_nc, kernel_size=7, padding=0)]
        model += [nn.Tanh()]

        self.model = nn.Sequential(*model)

    def forward(self, input): # <3>
        return self.model(input)

(2)实例化

netG = ResNetGenerator()

权重为随机权重。

(3)将预训练好的权重添加到ReNet Generator中。

model_path='horse2zebra_0.4.0.pth'
model_data = torch.load(model_path)
netG.load_state_dict(model_data)

执行后,netG就获得了训练中需要的所有知识。

(4)推理

netG.eval()

输出:

程序是将一匹或多匹马逐像素修改。

导入随机马的图像进行测试。

导入需要的库:

from PIL import Image
from torchvision import transforms

定义预处理函数:

preprocess = transforms.Compose([
    transforms.Resize(256),
    transforms.ToTensor()
])

导入马的图片:

img = Image.open('horse.jpg')
img

对图片预处理:

img_t = preprocess(img)
batch_t = torch.unsqueeze(img_t,0)

将变量传递给模型:

batch_out = netG(batch_t)

将生成器的输出转换为图像。

out_t = (batch_out.data.squeeze()+1.0)/2.0
out_img = transforms.ToPILImage()(out_t)
out_img

2.6 练习题

1.将金毛猎犬的图像输入马-斑马模型中。

参考资料:

1. 预训练网络 · 深度学习与PyTorch(中文版) (paper2fox.github.io)

4. PyTorch深度学习 Deep Learning with PyTorch ch.2, p2_哔哩哔哩_bilibili

  • 24
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值