精华内容
下载资源
问答
  • 深度学习框架-PyTorch实战课程旨在帮助同学们快速掌握PyTorch框架核心模块使用方法与项目应用实例,让同学们熟练使用PyTorch框架进行项目开发。课程内容全部以实战为导向,基于当下计算机视觉与自然语言处理中经典...
  • 深度学习与PyTorch实战

    2021-06-17 18:44:05
    通俗讲解深度学习中两大经典网络架构CNN与RNN模型,结合当下最主流PyTorch框架进行实战演练,选择当下NLP与CV中经典项目与解决方案,全部基于真实数据集,结合项目源码展开网络架构分析与实例应用。课程风格通俗易懂...
  • 神经网络与PyTorch实战python代码.zip
  • NLP之pytorch实战(含pdf+源码+中文笔记),学习NLP相当不错的资料。
  • PyTorch实战指南

    2021-01-27 12:39:58
    本文不会深入讲解过多知识性的东西,更多的则是传授一些经验,关于如何使得自己的程序更pythonic,更符合pytorch的设计理念。这些内容可能有些争议,因其受我个人喜好和coding风格影响较大,你可以将这部分当成是一...
  • Pytorch Tensor基本运算 #加法运算 import torch a = torch.rand(3,4) b = torch.rand(4) #broadcasting机制 a+b tensor([[1.0349, 1.4042, 0.9662, 0.4812], [1.6120, 1.2008, 1.6819, 0.2741], [1.5190, 0.6663...
  • PyTorch从入门到实践 | (6) PyTorch实战指南:猫狗二分类-附件资源
  • Pytorch 实战

    2021-09-07 16:47:21
    1. unsqueeze(dim) 表示将 torch 在 dim 加一个维度,从 外 到 内 数起 [0, 1, 2] torch.unsqueeze(0) = [[0, 1, 2]] torch.unsqueeze(1) = [[0], [1], [2]]

    1. unsqueeze(dim)

    表示将 torch 在 dim 加一个维度,从 外 到 内 数起

    [0, 1, 2]

    torch.unsqueeze(0) = [[0, 1, 2]]

    torch.unsqueeze(1) = [[0], [1], [2]]

    2. view

    torch.view(),将其原 tensor 先转变成 1 维张量,然后依次按view设定的参数维度填值。

    import torch
    
    a = torch.tensor([
        [0, 1],
        [2, 3],
        [4, 5]
    ])
    
    a = a.view(2, 3)
    print(a)

     

    3. permute

    torch.permute(),将其原 tensor 的维度进行调换

    import torch
    
    a = torch.tensor([
        [0, 1],
        [2, 3],
        [4, 5]
    ])
    
    a = a.permute(1, 0)
    print(a)

     

    展开全文
  • 参考《深度学习之pytorch实战计算机视觉》 --唐进民编著 损失和梯度 损失值就是预测值与真实之间的误差,梯度就是多元函数的各个参数求导并以向量的形式出现。 梯度更新就是对损失函数求导, 每次计算损失值都是对...

    本文旨在对深度学习重要概念进行整理和对pytorch算法进行整理
    参考《深度学习之pytorch实战计算机视觉》

    损失和梯度

    损失值就是预测值与真实之间的误差,梯度就是多元函数的各个参数求导并以向量的形式出现。
    梯度更新就是对损失函数求导,
    每次计算损失值都是对参与训练的整个数据集而言的。出现了批量梯度下降,即将训练集划分为多个批次,每次计算损失函数选取一个批次并对全局参数进行梯度更新.直到所以批次数据使用完毕就是训练一轮,会使得计算损失函数的时间和训练的复杂度降低,但是很容易导致优化函数的最终结果是全局最优解。还有一个就是随机梯度下降,就是随机选择数据计算损失函数,并对损失函数求导梯度更新,缺点会受到随机训练数据集中噪声数据影响。

    激活函数

    为什么sigmoid 激活函数出现梯度消失

    sigmoid的导数的取值区间是0-0.25,在后向传播每经过一个节点就要乘以sigmoid导数,梯度大小就变为原来的1/4,随着模型层数加深,梯度值就越来越小,甚至会消失。

    tanh

    输出结果是以0为中心,解决了激活函数在模型优化过程中收敛速度慢的问题,取值为0-1,不够大,所以仍然会出现梯度消失的情况

    Relu(Rectified Linear Unit,修正线性单元)

    目前使用率最高的激活函数,输出结果小于0激活函数输出为0,否则就是本身,收敛速度非常快,因为Relu输出不是零中心数据,可能默写神经元永远不会被激活,这些神经元对应的参数不能被更新。因为模型参数在初始化的时候被设置为全正或者全负;在反向传播的时候设置学习率过大,收敛较快导致。目前改进版本是Leaky-ReLU,R-ReLU

    CNN

    参考之前的文章
    卷积神经网络
    深度卷积神经网络DCNN总结(AlexNet,ZFNet,VGGNet,GooleNet,ResNet)

    CNN中重要的组件就是Filter(卷积核),卷积核有三个元素,高度、宽度、深度,高度和宽度一般常用的是33和55,深度根据输入图像的通道数设置,如果是图像是3通道彩色的,就设置为3,如果输入图像是黑白的,就设置为1.
    三通道的卷积过程可以看成三个独立的单通道卷积过程,最后三个独立的单通道卷积过程相加即可。

    全连接层作用

    将输入图像在经过卷积层和池化层操作后提取的核心特征与全连接层定义的权重参数相乘,将输出的参数值输入到softmax激活函数中,激活函数输出的是各个类别的可能性。

    pytorch

    在学习pytorch框架之前,可以先参考我的python学习笔记专栏我之前的pytorch文章

    python运算符

    一些简单的加减乘除这里就不列举,列举常用但是看到不知道是什么的
    求幂运算符:**
    取整运算符://
    与:and
    或:or
    非:not
    成员运算符:in,返回值为布尔类型。
    身份运算符:is ;is not,只有内存地址一样,才返回True,跟==是不同的

    python中的类

    init():类的初始化方法,在创建实例的时候会调用此方法
    self:代表类的实例,在定义类的时候是必须有的,但是调用的时候不必传入参数。

    多维数组常用的属性

    ndim:数组的维度个数:2行3列的数组维度数ndim是2
    shape:数组的维度,2行3列shape是(2,3)
    size:数组中元素的总数量,2行3列为6
    dtype:数组中元素的类型
    itemsize:每个元素字节大小,比如dtype是float64,itemsize为8
    数组打印:直接print(数组名字)

    数组的运算

    min:最小值
    max:最大值
    sum:对数组进行求和,可以设置axis设置是对行还是列求和
    exp:指数运算
    sqrt:平方根运算
    square:平方运算

    随机数组

    seed:伪随机
    rand:在[0,1)满足均匀分布的随机样本
    randn:满足平均值为0,方差为1的正态分布
    randint:在给定的范围生成类型为整数的随机样本数

    matplotlib.pyplt

    线条颜色

    b 蓝色
    g 绿色
    r 红色
    c 蓝绿色
    m 洋红色
    y 黄色
    k 黑色
    w 白色

    标记参数点形状

    o 圆形
    ‘*’ *
    ‘+’ +
    x x

    线条形状

    ‘-’ 实线
    ‘–’虚线
    ‘-.’点实线
    ‘.’点线

    Tensor生成

    torch.FloatTensor可以是一个维度值,也可以是一个列表
    如果给的是一个维度值,可以根据维度值随机生成浮点型
    torch.IntTensor
    没有指定类型 torch.rand(2,3):生成2行3列的浮点型数据
    torch.randn 也是随机生成
    torch.range:生成自定义起始范围和结束范围的浮点型数据Tensor
    如torch.range(1,20,1):范围是1-20,间隔是1
    小节: 没有指定类型生成的Tensor都是浮点型

    Tensor的运算

    torch.abs:输入tensor数据,输出为绝对值
    torch.add:输入tensor数据,输出为两个tensor相加
    torch.clamp:对输入参数按照自定义的范围随机裁剪,参数为:tensor数据类型、裁剪的上边界、裁剪的下边界
    torch.div:求商
    torch.mul:求积
    torch.pow:求幂
    torch.mm:求矩阵的乘积
    torch.mv:第一个参数是矩阵,第二个参数是向量,返回乘积

    自动梯度

    torch.autograd包:用这个包中的variable包对Tensor对象封装,然后自动链式求导
    用X代表节点,x.data代表数据类型变量,x.grad是variable对象,x.grad.data是梯度值

    自定义传播函数

    可以构建一个继承torch.nn.Module的新类,完成对前向传播和后向传播的重写,使用forward作为前向传播的关键字,使用backward作为后向传播的关键字,

    模型搭建和参数优化

    torch.nn中有很多实现神经网络具体功能的类,比如卷积层,池化层,全连接层,参数归一化,Dropout,激活函数,

    torch.sequential

    是torch.nn中的序列容器,可以搭建网络,1、直接嵌套2、使用orderdict字典,前者从0开始对模块进行排序,后者可以自定义模块名字

    torch.nn.Linear

    用于定义模型的线性层,参数:输入特征数、输出特征数、是否使用偏置,默认是True

    torch.nn.ReLU:非线性激活

    torch.nn.MSELoss:L2

    使用均方误差对损失值进行计算,在定义类的时候不需要传入任何参数,在使用实例的时候需要传入两个维度一样的参数进行计算

    torch.nn.L1Loss

    使用平均绝对误差计算损失值,在定义类的时候不需要传入任何参数,在使用实例的时候需要传入两个维度一样的参数进行计算

    torch.nn.CrossEntropyLoss:

    计算交叉熵,在定义类的时候不需要传入任何参数,在使用实例的时候需要输入两个满足交叉熵计算条件的参数

    torch.nn.Conv2d

    参数输入通道,输出通道,卷积核大小,步长,paddingde

    torch.nn.MaxPool2d

    池化窗口大小,步长,paddingde

    torch.nn.Dropout

    以一定随机概率将部分参数归零,因为是随机的,所以每轮进行丢弃的神经元也不同,最后训练出来的模型不会对某部分参数过度依赖,防止过拟合,随机概率默认值是0.5

    全连接处理

    x.view(-1,1414128)进行扁平化处理,然后全连接层,如果不进行扁平化处理,全连接输出维度和输入维度不匹配;最后使用self.dense进行最后分类。

    遍历模型参数

    models.parameters()

    优化函数

    torch.optim里面有很多自动优化参数的类,如torch.optim.Adam里面可以传入被优化的参数models.parameters(),学习率初始值,并且可以根据梯度更新对学习率进行自动调节。

    torch和torchvision

    上面介绍使用torch.nn中线性层和激活函数配合torch.optim完成神经网络搭建和优化,并使用torch.auto完成自动梯度功能,
    torchvision主要功能是实现数据处理、导入和预览,一般会用到torchvision.datasets和torchvision.transforms,torchvision.datasets实现对数据集下载,root用于指定下载数据集存放路径,transforms指定在导入数据集对数据进行哪些变换,train是数据应该载入哪部分?

    torchvision.transforms

    torchvision.transforms.Compose对各种变换进行组合,传入的参数是一个列表,比如**transforms.ToTensor(),transforms.Normalize()**对数据标准化,需要使用均值和标准差进行数据标准化,经过标准化之后,默认是数据是均值为0,标准差为1的正态分布;
    其他参数大家用到自行查阅。

    数据装载和预览

    batch_size:确认每个包大小,shuffle:是否打乱
    使用torch,utils.data,DataLoader类

    预览

    # 获取一个批次的图片数据和标签
    images,labels=next(iter(data_loader_train))
    # 将一个批次图片构造成网格模式,参数是一个批次的装载数据,每个装载数据都是4维的,维度是batchsize,channel,height,weight,输出结果是channel,height,weight,图片被整合,height,weight改变,channel值不变
    img=torchvision.utils.make_grid(images)
    # 转换成数组形式,用plt显示,数组的维度是height,weight,channel
    img=img.numpy().transpose(1,2,0)
    std=[0.5]
    mean=[0.5]
    img=img*std+mean
    print(labels[i] for i in range(64))
    plt.imshow(img)
    

    迁移学习

    迁移VGG16

    下载模型
    model=models.vgg16(prepare=True)
    在迁移学习中调整最多的也就是全连接层,先冻结全连接层之前的部分,在学习过程中不进行参数更新,将参数中param.requires_grad全部设置为False,就不会进行梯度更新,就是之前的冻结操作;然后定义新的全连接层从新赋值给model.classifier,全连接层重新被定义之后,全连接层的参数会自动解冻。优化参数变成model.classifier.parameters,这样只需要训练很少就可以达到很高准确率,

    多模型融合

    设置每个模型不同权重,对结果预测结果进行加权平均。然后再和真实值进行比较

    RNN

    RNN也可以实现分类,在特征提取上没有CNN强大,RNN可以随意控制输入和输出的数量,

    自动编码器

    核心特征提取编码和数据重构解码

    #在原始图片山加上一个维度相同的随机数字对图像中的像素点进行扰乱
    noisy_images=images+0.5*np.random.randn(*images.shape)
    noisy_images=np.clip(noisy_images,0.,1.)
    
    展开全文
  • pytorch实战教学(一篇管够)

    千次阅读 多人点赞 2021-05-26 11:00:22
    PyTorch是一个开源的Python机器学习库,基于Torch,用于自然语言处理等应用程序。它是一个基于Python的可续计算包,提供两个高级功能:1、具有强大的GPU加速的张量计算(如NumPy)。2、包含自动求导系统的深度神经...

    参考B站视频使用更佳:《PyTorch深度学习实践》完结合集
    个人博客:https://tianjuewudi.gitee.io/
    如果代码有格式不对的地方请参考原文:https://tianjuewudi.gitee.io/2021/05/13/pytorch-jiao-xue-ji-shi-li/#toc-heading-10

    PyTorch是一个开源Python机器学习库,基于Torch,用于自然语言处理等应用程序。它是一个基于Python的可续计算包,提供两个高级功能:1、具有强大的GPU加速的张量计算(如NumPy)。2、包含自动求导系统的深度神经网络。

    PyTorch和TensorFlow作对比,PyTorch开发商是Facebook,TensorFlow是Google。PyTorch的接口有Python和C++,而TensorFlow接口有Python,C++,JavaScript,Swift。PyTorch调试较简单,TensorFlow在2.0以上版本调试较简单。PyTorch主要用于研究,TensorFlow主要用于生产

    张量(Tensor)相当于一个矩阵,它可以是比二维更高的。Tensor的目的是能够创造更高维度的矩阵、向量。举个简单的例子,彩色图像文件(RGB)一般都会处理成3-d tensor,每个2d array中的element表示一个像素,R代表Red,G代表Green,B代表Blue。

    具体可参考文档:https://pytorch.org/docs/stable/tensors.html

    建立Tensor的方法:

    #直接把List放进去
    x = torch.tensor([[1,-1],[-1,1]])
    #把numpy矩阵放进from_numpy函数中
    x = torch.from_numpy(np.array([[1,-1],[-1,1]]))
    
    #产生一个全零tensor(二维)
    x = torch.zeros([2,2])
    #产生一个全一tensor(三维)
    x = torch.ones([1,2,5])
    
    

    操作Tensor的方法:

    #看Tensor每一维的元素个数
    x.shape
    #把某一维去掉(这里去掉第一维,只有在这一维只有一个元素的情况下降维且不改变原数据)
    x = x.squeeze(0)
    #在某个位置新加入一个维度,元素个数为1,不改变原数据
    x = x.unsqueeze(1)
    #把两个维度对调,当只有两维的矩阵对调时即求转置
    x = x.transpose(0,1)
    
    
    #把几个矩阵的某一维度元素拼接在一起,前提是其他维度元素个数相同(下面拼成2*6*3的Tensor)
    x = torch.zeros([2,1,3])
    y = torch.zeros([2,3,3])
    z = torch.zeros([2,2,3])
    w = torch.cat([x,y,z],dim = 1)
    
    #常规运算
    z = x + y
    y = x.pow(2)
    #x矩阵中所有元素求和
    y = x.sum()
    #x矩阵中每一列元素相加
    y = x.sum(axis=0)
    #x矩阵中每一行元素相加
    y = x.sum(axis=1)
    
    #求每一列平均值(二维)(axis=1求行的平均值)
    y = x.mean(axis = 0)
    #重新塑造3*4矩阵(元素总个数必须一致,否则报错)
    x = x.reshape(3,4)
    #重新塑造2*2矩阵(元素总个数不用一致,可以只截取前面的一部分)
    x = x.resize_(2, 2)
    
    

    怎么计算梯度Gradient

    求梯度即求z对x矩阵的导数,结果是对x的各个元素求导,也是一个矩阵。其中z为x各个元素之和。

    #requires_grad=True表示需要计算梯度
    x = torch.tensor([[1.,0.],[-1.,1.]],requires_grad=True) 
    #Loss计算公式(构建计算图),这是前馈过程Forward
    z = x.pow(2).sum()
    #反向传播backward,计算各个梯度
    z.backward()
    #读出x的梯度
    x.grad
    

    注意tensor在进行运算时会构建计算图,之后.backward()之后这个图会从内存中释放。但是,不要在后面直接用张量来计算存标量数据,防止产生向量图,而是把标量取出来计算,应当使用.item()来取出数据或.data更新权重。最后要用到.grad.data.zero_()来对梯度进行清零,否则下一次计算会一直累加,一个简单的例子:

    在这里插入图片描述

    第一步:创建Dataset

    在这里插入图片描述

    Dataset需要调用到Dataloader里面。

    在这里插入图片描述

    shuffle的意思是每次读数据的顺序是乱的,Testing的时候应使其固定,否则结果会有误差。

    第二步:建立神经网络

    初始的方法可以参考我的另一篇文章《Python神经网络编程》。

    在这里插入图片描述

    layer = torch.nn.Linear(32,64)   #建立输入32节点,输出64节点的一部分神经网络
    layer.weight.shape   #输出为torch.Size([64,32])
    layer.bias.shape     #输出为torch.Size([64])
    #激活函数
    nn.Sigmoid()
    nn.ReLU()
    

    建立神经网络的具体例子:

    class LinearModel(torch.nn.Module):
        #初始化函数
        def __init__(self):
            #调用父类的__init__()函数,必用
            super(LinearModel,self).__init__()    
            #构建1输入1输出的线性层,即y=wx+b,可以设置bias=True/False
            self.linear = torch.nn.Linear(1,1) 
        
        #必须定义的函数,后面直接model(x)可以直接算出估计值y
        #这是因为这个函数是放在python的__call__()函数中的
        def forward(self,x):
            #函数重写,计算y=wx+b
            y_pred = self.linear(x)
            return y_pred
    model = LinearModel()    #model是callable可调用的,直接调用例:model(x)使用的是forward函数
    

    第三步:最优化

    criterion = torch.nn.MSELoss(size_average = False)
    optimizer = torch.optim.SGD(model.parameters(),lr = 0.01,momentum = 0)
    

    MSELoss即预测的数值和真实值之差求平方然后加和,后面的参数决定是否求平均。SGD即随机梯度下降,后面的第一个参数是传入需要进行训练优化的参数,直接用model.parameters可以直接把模型中定义的所以参数都加入训练中,lr是学习因子,决定学习速率,第三个参数是冲量。用这些参数构建了优化器之后,我们之后可以直接用这个封装好的optimizer对象对整个模型进行优化。

    训练过程如下:

    for epoch in range(100):
        #计算y的预测值
        y_pred = model(x_data)
        #用上面定义好的损失函数对象传入预测值和真实值来计算Loss值
        loss = criterion(y_pred,y_data)
        #打印Loss时自动调用__str__()函数,因此不会产生计算图
        print(epoch,loss)
        #梯度清零
        optimizer.zero_grad()
        #反向传播,计算梯度
        loss.backward()
        #对所有我们传入的参数进行梯度更新
        optimizer.step()
    

    第四步:测试

    # 打印权重和偏置值,.item()函数把矩阵转换为数值
    print('w=',model.linear.weight.item())
    print('b=',model.linear.bias.item())
    # 计算预测输出值
    x_test = torch.Tensor([[4.0]])
    y_test = model(x_test)
    print('y_pred = ',y_test.data)
    

    总体程序示例

    import torch
    x_data = torch.Tensor([[1.0],[2.0],[3.0]])
    y_data = torch.Tensor([[2.0],[4.0],[6.0]])
    class LinearModel(torch.nn.Module):    
    	def __init__(self):        
    		super(LinearModel,self).__init__()            
    		self.linear = torch.nn.Linear(1,1)     
    	def forward(self,x):        
    		y_pred = self.linear(x)        
    		return y_predmodel = LinearModel()    
    criterion = torch.nn.MSELoss(size_average = False)
    optimizer = torch.optim.SGD(model.parameters(),lr = 0.01,momentum = 0)
    for epoch in range(100):    
    	y_pred = model(x_data)    
    	loss = criterion(y_pred,y_data)    
    	print(epoch,loss)    
    	optimizer.zero_grad()    
    	loss.backward()    
    	optimizer.step()    
    	print('w=',model.linear.weight.item())
    	print('b=',model.linear.bias.item())
    	x_test = torch.Tensor([[4.0]])
    	y_test = model(x_test)
    	print('y_pred = ',y_test.data)   
    

    除了SGD优化器,Pytorch还提供了很多优化器。可以试一试它们的效果

    在这里插入图片描述

    逻辑回归(Logistic Regression)

    这是一个分类问题并非字面意义的回归问题。在做分类问题的时候,把神经网络输出的数值转化为分类的方法是计算每一个分类的概率,最后决定的分类是概率最大的一项。

    Mnist数据集是手写数字的一个数据集,是最基础的数据集之一,可以用来测量各个学习器的性能指标。

    Pytorch配套有torchvision的工具包,里面有一个模块可以提供数据集,常用的数据集在里面都有。在运行程序的时候会自动下载。第一个参数是存放的文件夹的位置,第二个参数设定是训练集还是测试集,第三个参数是是否自动下载。如果数据集已经存在则不会重新下载。

    import torchvision
    train_set = torchvision.datasets.MNIST(root='../dataset/mnist',train=True,download = True)
    test_set = torchvision.datasets.MNIST(root='../dataset/mnist',train=False,download = True)
    

    除了这个MNIST数据集,还有分类动物的CIFAR10数据集。

    为了找一个函数把实数空间的值映射到0到1的区间内代表概率,因此需要在线性模型后加入Sigmoid函数,这个叫做Logistic函数。 它的导数类似于正态分布函数。

    交叉熵损失函数公式(二分类):
    L = ∑ i − [ y l o g y ^ + ( 1 − y ) l o g ( 1 − y ^ ) ] L = \sum_i - [ylog\hat{y} + (1-y)log(1-\hat{y})] L=i[ylogy^+(1y)log(1y^)]
    首先L一定是正数。其中 y ^ \hat{y} y^和y都是0到1的值,为了明确分类y不是0就是1。当y=0时, y ^ \hat{y} y^尽可能趋近于0,才能使得L最小;当y=1时, y ^ \hat{y} y^需要尽可能趋近于0。这样预测值y才能趋近于真实值。

    编程上的改动

    搭建模型的函数中(一层线性+SIgmoid):

    import torch.nn.functional as F                          #载入函数包
    class LogisticRegressionModel(torch.nn.Module):    
    	def __init__(self):        
    		super(LogisticRegressionModel,self).__init__()            
    		self.linear = torch.nn.Linear(1,1)                
    	def forward(self):       			            
    		y_pred = F.sigmoid(self.linear(x))                      
    		return y_pred
    

    最优化:

    criterion = torch.nn.BCELoss(size_average=False)         #此处求不求均值会影响后面学习率的设置,不求均值学习率须设小一些
    

    最终结构:

    import torchimport torch.nn.functional as F                        
    x_data = torch.Tensor([[1.0],[2.0],[3.0]])
    y_data = torch.Tensor([[0.0],[0.0],[1.0]])                          
    class LogisticRegressionModel(torch.nn.Module):        
    	def __init__(self):                
    		super(LogisticRegressionModel,self).__init__()                    
    		self.linear = torch.nn.Linear(1,1)                    
    	def forward(self,x):                
    		y_pred = F.sigmoid(self.linear(x))                      
    		return y_predmodel = LogisticRegressionModel()    
    criterion = torch.nn.BCELoss(size_average=False)       
    optimizer = torch.optim.SGD(model.parameters(),lr = 0.01,momentum = 0)
    for epoch in range(100):    
    	y_pred = model(x_data)    
    	loss = criterion(y_pred,y_data)    
    	print(epoch,loss.item())    
    	optimizer.zero_grad()    
    	loss.backward()    
    	optimizer.step()  
    

    绘图:

    import numpy as npimport matplotlib.pyplot as plt
    #x的范围0到10,取200个点
    x = np.linspace(0,10,200)
    #把x变成200行1列的矩阵(张量)
    x_t = torch.Tensor(x).view((200,1))
    #输出预测值y的矩阵
    y_t = model(x_t)y = y_t.data.numpy()
    #打印图表
    plt.plot(x,y)plt.plot([0,10],[0.5,0.5],c='r')
    plt.xlabel('Hours')
    plt.ylabel('Probability of Pass')
    plt.grid()
    plt.show()
    

    在这里插入图片描述

    处理多维特征的输入

    上面的程序都是基于单输入的,下面讲解多输入。多输入时输出变成
    y ^ = σ ( ∑ i w i x i + b ) \hat{y} = \sigma (\sum_i w_i x_i +b) y^=σ(iwixi+b)
    这样我们就可以利用矩阵运算这种并行计算方式大大提高运算速度,也增加程序可读性。

    在这里插入图片描述

    读取数据

    import numpy as np
    #读取文件,第一个参数是文件名,也可以是压缩包,第二个参数是数据分隔符,第三个是数据类型,通常是float32
    xy = np.loadtxt('diabetes.csv',delimiter=',',dtype=np.float32)
    x_data = torch.from_numpy(xy{:,:-1})
    y_data = torch.from_numpy(xy[:,[-1]])         #用中括号是因为要用矩阵形式而非向量
    

    定义模型:

    import torch 
    class Model(torch.nn.Module):    
    	def __init__(self):        
    		super(Model,self).__init__()        
    		self.linear1 = torch.nn.Linear(8,6)        
    		self.linear2 = torch.nn.Linear(6,4)        
    		self.linear3 = torch.nn.Linear(4,1)        
    		self.sigmoid = torch.nn.Sigmoid()       #没有参数,只需要一个来构建计算图,这里可以改变激活函数            
    	def forward(self,x):        
    		x = self.sigmoid(self.linear1(x))        
    		x = self.sigmoid(self.linear2(x))        
    		x = self.sigmoid(self.linear3(x))        
    		return xmodel = Model()        
    

    优化器

    criterion = torch.nn.BCELoss(size_average = True)
    optimizer = torch.optim.SGD(model.parameters(),lr = 0.1)
    

    训练

    for epoch in range(100):    #这里没有使用Mini-Bash进行训练,而是全部数据一次训练完成,后面会用到DataLoader进行Mini-Batch的训练    
    	y_pred = model(x_data)              
    	loss = criterion(y_pred,y_data)    
    	print(epoch,loss.item())    
    	optimizer.zero_grad()    
    	loss.backward()    
    	optimizer.step()  
    

    可以尝试不同的激活函数,例如除了Sigmoid常用的是ReLU,对应的代码是torch.nn.ReLU()。它对应小于0的输入输出为0,大于0的则直接输出对应值。注意最后的输出层不能用ReLU,否则计算Loss的时候有可能因为ln0而出错。

    加载数据集

    为了训练时能够跨越鞍点达到全局最优,我们需要分堆进行训练,也就是Mini-Batch的训练。其中一个Epoch代表所有的样本都进行过一次训练,一个Iteration是一个Batch堆进行一次训练,Batch-Size指的是Batch中的样本数。

    首先我们要生成一个DataLoader,其中一个参数就是batch_size,第二个参数是shuffle,即是否每次epoch生成的batch都具有随机性,都有所不同,样本都是随机打乱的。还有一个num_workers参数,决定用几个线程读取数据。

    import torch 
    #Dataset为抽象类,不能实例化,只能继承
    from torch.utils.data 
    import Dataset
    #DataLoader帮助我们加载数据
    from torch.utils.data 
    import DataLoader
    class DiabetesDataset(Dataset):    
    	def __init__(self):        
    		pass        
    	#这个函数为了让我们能通过dataset[index]把数据拿出来    
    	def __getitem__(self,index):        
    		pass        
    	#这个函数为了让我们能通过len(dataset)返回数据条数    
    	def __len__(self):        
    		pass    
    dataset = DiabetesDataset()
    train_loader = DataLoader(dataset=dataset,batch_size=32,shuffle=True,num_workers=2)
    

    文件不大时可以通过init函数把数据都读到内存中,如果数据文件过大,通常只记载标签,然后在后面再把一个个文件读取进来。

    注意:Linux和Windows处理多线程的方式不一样,我们需要将用loader迭代的代码封装到if语句中,否则会报错:

    if __name__ == '__main__':    
    	for epoch in range(100):        
    	#enumerate把可迭代对象组合成索引序列,索引从0开始,同时输出索引和值        
    		for i,data in enumerate(train_loader,0):            # prepare data
    

    Database数据集实现:

    import torch 
    #Dataset为抽象类,不能实例化,只能继承
    from torch.utils.data 
    import Dataset
    #DataLoader帮助我们加载数据
    from torch.utils.data 
    import DataLoader
    class DiabetesDataset(Dataset):    
    	def __init__(self,filepath):        
    		xy = np.loadtxt(filepath,delimiter=',',dtype=np.float32)        
    		#shape[0]取出行数,即第一个维度值        
    		self.len = xy.shape[0]	    
    		self.x_data = torch.from_numpy(xy[:,:-1])	    
    		self.y_data = torch.from_numpy(xy[:,[-1]])         
    		#用中括号是因为要用矩阵形式而非向量        
    		#这个函数为了让我们能通过dataset[index]把数据拿出来    
    		def __getitem__(self,index):        
    			return self.x_data[index],self.y_data[index]  
    			#返回(x,y)形式的元组        
    			#这个函数为了让我们能通过len(dataset)返回数据条数    
    		def __len__(self):        
    			return self.len    
    dataset = DiabetesDataset('diabetes.csv.gz')
    train_loader = DataLoader(dataset=dataset,batch_size=32,shuffle=True,num_workers=2)
    

    训练:

    if __name__ == '__main__':    
    	for epoch in range(100):        #每次循环一个batch        
    		for i,data in enumerate(train_loader,0):            
    		#取出x,y数据的方法,每次取出的是一个batch的数据,并自行组合为两个Tensor赋给inputs和labels
    		inputs,label = data            		                  
    		#这个输入x的Tensor传给model进行计算,model会执行矩阵运算计算出y的Tensor            
    		y_pred = model(inputs)                      
    		loss = criterion(y_pred,labels)            
    		print(epoch,i,loss.item())            
    		optimizer.zero_grad()            
    		loss.backward()            
    		optimizer.step()  
    

    完整代码

    import torch from torch.utils.data 
    import Datasetfrom torch.utils.data 
    import DataLoader
    class DiabetesDataset(Dataset):    
    	def __init__(self,filepath):        
    		xy = np.loadtxt(filepath,delimiter=',',dtype=np.float32)        
    		self.len = xy.shape[0]	    
    		self.x_data = torch.from_numpy(xy[:,:-1])	    
    		self.y_data = torch.from_numpy(xy[:,[-1]])                 
    	def __getitem__(self,index):        
    		return self.x_data[index],self.y_data[index]          
    	def __len__(self):        
    		return self.len    
    dataset = DiabetesDataset('diabetes.csv.gz')
    train_loader = DataLoader(dataset=dataset,batch_size=32,shuffle=True,num_workers=2) 
    class Model(torch.nn.Module):    
    	def __init__(self):        
    		super(Model,self).__init__()        
    		self.linear1 = torch.nn.Linear(8,6)        
    		self.linear2 = torch.nn.Linear(6,4)        
    		self.linear3 = torch.nn.Linear(4,1)        
    		self.sigmoid = torch.nn.Sigmoid()                   
    	def forward(self,x):        
    		x = self.sigmoid(self.linear1(x))        
    		x = self.sigmoid(self.linear2(x))        
    		x = self.sigmoid(self.linear3(x))        
    		return xmodel = Model()   
    criterion = torch.nn.BCELoss(size_average = True)
    optimizer = torch.optim.SGD(model.parameters(),lr = 0.01)
    if __name__ == '__main__':    
    	for epoch in range(100):        
    		for i,data in enumerate(train_loader,0):            
    			inputs,labels = data                   
    			y_pred = model(inputs)                      
    			loss = criterion(y_pred,labels)            
    			print(epoch,i,loss.item())            
    			optimizer.zero_grad()            
    			loss.backward()            
    			optimizer.step()  
    

    官方数据集的使用方法:

    from torchvision import datasets
    #设置测试和训练集,是否下载,是否转换为张量,可以转换为0~1或-1~1
    train_dataset = datasets.MNIST(root='../dataset/mnist',train=True,transform = transforms.ToTensor(),download = True)
    test_dataset = datasets.MNIST(root='../dataset/mnist',train=False,transform = transforms.ToTensor(),download = True)
    #分batch训练,否则内存不够加载所有数据
    train_loader = DataLoader(dataset=train_dataset,batch_size=32,shuffle=True,num_workers=2)
    test_loader = DataLoader(dataset=test_dataset,batch_size=32,shuffle=False,num_workers=2)
    

    多分类问题

    在多分类问题上,于二分类不同的在于,二分类只有一个输出即概率,多分类中如果有10个分类,需要设置10个输出。我们希望输出具有竞争性,且符合分布。这里可以引入Softmax层,满足所有输出大于等于0且相加等于1。Softmax层的公式为:
    P ( y = i ) = e Z i ∑ j = 0 k − 1 e Z i P(y=i) = \frac{e^{Z_i}}{\sum_{j=0}^{k-1} e^{Z_i}} P(y=i)=j=0k1eZieZi
    其中 Z i Z_i Zi是最后一个线性层的输出。这就是Softmax函数。

    对于损失函数,参考二分类:
    L = − Y l o g Y ^ L = -Ylog\hat{Y} L=YlogY^
    其中 Y ^ \hat{Y} Y^是真实值输出为1的节点的预测值(概率),Y=1。

    算法举例:

    import numpy as np
    y = np.array([1,0,0])
    z = np.array([0.2,0.1,-0.1])
    y_pred = np.exp(z) / np.exp(z).sum()
    loss = (-y * np.log(y_pred)).sum()
    print(loss)
    

    实际运用举例:

    import torch
    #y必须是长整形的张量,当中存放的是最后真实分类的索引,范围是0到输出节点数-1
    y = torch.LongTensor([0])
    z = torch.Tensor([0.2,0.1,-0.1]) 
    #交叉熵损失,注意:神经网络最后一层直接是线性层即可
    criterion = torch.nn.CrossEntropyLoss()   
    loss = criterion(z,y)print(loss)
    

    NLLLoss损失函数是CrossEntropyLoss损失函数的最后一步,即Softmax和log之后的,所有项相加,去掉负号,再求均值。

    实例:MNIST数据集

    下面是对手写MNIST数据集进行训练的例子,原式方法可以查看我另一篇文章《Python神经网络编程》。

    导入数据:

    import torch
    #这是一个对图像进行原始数据处理的工具
    from torchvision 
    import transforms 
    from torchvision import datasetsfrom 
    torch.utils.data 
    import DataLoader
    import torch.nn.functional as F
    import torch.optim as optim
    

    准备数据:

    神经网络要求输入最好比较小,并且遵从正态分布,因此要先把PIL图片转换成Tensor做归一化处理。在多通道图像中有RGB,因此转换的Tensor是三维,第一维是选择RGB,后面的两维就是整张图片灰度。这里的单通道图片变成的是1 * 28 * 28。这里构建Compose类实例,上面的整个过程可以通过第一个ToTensor对象来实现,后面的Normalize中的两个数是进行数据标准化中常用的量,这里均值用0.1307,标准差用0.3081,这些是对整个样本计算的结果,这样可以把样本映射到(0,1)分布上,便于训练。公式为 P i x e l n o r m = p r x e l o r g i n − m e a n s t d Pixel_{norm} = \frac{prxel_{orgin} - mean}{std} Pixelnorm=stdprxelorginmean,mean是均值,std是标准差。用映射后的数据去做训练能够得到更好的训练效果。

    batch_size= 64
    transform = transforms.Compose([    transforms.ToTensor(),    transforms.Normalize((0.1307,),(0.3081,))])
    train_dataset = datasets.MNIST(root='../dataset/mnist',train=True,transform = transform,download = True)
    test_dataset = datasets.MNIST(root='../dataset/mnist',train=False,transform = transform,download = True)
    train_loader = DataLoader(dataset=train_dataset,batch_size=batch_size,shuffle=True)
    test_loader = DataLoader(dataset=test_dataset,batch_size=batch_size,shuffle=False)
    

    可以用以下程序计算平均值标准差:

    #算一下数据的均值和标准差
    sum1 = 0
    sum2 = 0
    for record in training_data_list:        
    	all_values = record.split(',')        
    	inputs = (numpy.asfarray(all_values[1:]) / 255.0)        
    	sum1 += inputs.sum()        
    	sum2 += ((inputs - mean)**2).sum()        
    	mean = sum1 /784 /len(training_data_list)
    	print("平均值:",mean)
    	std = (sum2 / 784 /len(training_data_list)) ** 0.5
    	print("标准差:",std)
    

    模型

    激活函数采用ReLU函数,view函数把Tensor转换为元素总数不变,列数为784的Tensor。

    class Net(torch.nn.Module):    
    	def __init__(self):        
    		super(Net,self).__init__()        
    		self.l1 = torch.nn.Linear(784,512)        
    		self.l2 = torch.nn.Linear(512,256)        
    		self.l3 = torch.nn.Linear(256,128)        
    		self.l4 = torch.nn.Linear(128,64)        
    		self.l5 = torch.nn.Linear(64,10)            
    	def forward(self,x):        
    		x = x.view(-1,784)        
    		x = F.relu(self.l1(x))        
    		x = F.relu(self.l2(x))        
    		x = F.relu(self.l3(x))        
    		x = F.relu(self.l4(x))        
    		return self.l5(x)model = Net()
    

    优化器

    损失函数为交叉熵函数,优化器带冲量momentum可以优化训练过程

    criterion = torch.nn.CrossEntropyLoss()
    optimizer = torch.optim.SGD(model.parameters(),lr = 0.01,momentum=0.5)
    

    训练

    def train(epoch):    
    	running_loss = 0.0      
    	for batch_idx,data in enumerate(train_loader,0):            
    		inputs,target = data                   
    		optimizer.zero_grad()            
    		outputs = model(inputs)                      
    		loss = criterion(outputs,target)            
    		loss.backward()            
    		optimizer.step()                          
    		running_loss += loss.item()            
    		if batch_idx % 300 == 299:                
    			print('[%d,%5d] loss: %.3f' % (epoch + 1,batch_idx + 1,running_loss / 300))                				   
    			running_loss = 0
    

    测试

    def test():    
    	correct = 0    
    	total = 0    
    	with torch.no_grad():     
    	#这部分代码不会计算梯度        
    		for data in test_loader:            
    			images,labels = data            
    			outputs = model(images)            
    			#这里用max函数找输出节点中的最大值(即输出矩阵中每一行的最大值),返回该值和对应下标
    			_,predicted = torch.max(outputs.data,dim=1)            
    			#labels.size(0)返回行数,也即是样本个数            
    			total += labels.size(0)            
    			#把两个N*1的Tensor做比较相等是1否则是0,把所有结果相加就是正确的个数
    			correct += (predicted == labels).sum().item()    
    			print('Accuracy on test set: %d %%' % (100 * correct / total))    
    

    整体程序

    import torch
    from torchvision import transforms
    from torchvision import datasets
    from torch.utils.data import DataLoader
    import torch.nn.functional as F
    import torch.optim as optim
    
    batch_size= 64
    transform = transforms.Compose([
        transforms.ToTensor(),
        transforms.Normalize((0.1307,),(0.3081,))
    ])
    
    train_dataset = datasets.MNIST(root='../dataset/mnist',train=True,transform = transform,download = True)
    test_dataset = datasets.MNIST(root='../dataset/mnist',train=False,transform = transform,download = True)
    train_loader = DataLoader(dataset=train_dataset,batch_size=batch_size,shuffle=True)
    test_loader = DataLoader(dataset=test_dataset,batch_size=batch_size,shuffle=False)
    
    class Net(torch.nn.Module):
        def __init__(self):
            super(Net,self).__init__()
            self.l1 = torch.nn.Linear(784,512)
            self.l2 = torch.nn.Linear(512,256)
            self.l3 = torch.nn.Linear(256,128)
            self.l4 = torch.nn.Linear(128,64)
            self.l5 = torch.nn.Linear(64,10)
            
        def forward(self,x):
            x = x.view(-1,784)
            x = F.relu(self.l1(x))
            x = F.relu(self.l2(x))
            x = F.relu(self.l3(x))
            x = F.relu(self.l4(x))
            return self.l5(x)
    model = Net()
    criterion = torch.nn.CrossEntropyLoss()
    optimizer = torch.optim.SGD(model.parameters(),lr = 0.01,momentum=0.5)
    
    def train(epoch):
        running_loss = 0.0
          for batch_idx,data in enumerate(train_loader,0):
                inputs,target = data       
                optimizer.zero_grad()
    
                outputs = model(inputs)          
                loss = criterion(outputs,target)
                loss.backward()
                optimizer.step()  
                
                running_loss += loss.item()
                if batch_idx % 300 == 299:
                    print('[%d,%5d] loss: %.3f' % (epoch + 1,batch_idx + 1,running_loss / 300))
                    running_loss = 0
                    
    def test():
        correct = 0
        total = 0
        with torch.no_grad():     #这部分代码不会计算梯度
            for data in test_loader:
                images,labels = data
                outputs = model(images)
                #这里用max函数找输出节点中的最大值(即输出矩阵中每一行的最大值),返回该值和对应下标
                _,predicted = torch.max(outputs.data,dim=1)
                #labels.size(0)返回行数,也即是样本个数
                total += labels.size(0)
                #把两个N*1的Tensor做比较相等是1否则是0,把所有结果相加就是正确的个数
                correct += (predicted == labels).sum().item()
        print('Accuracy on test set: %d %%' % (100 * correct / total))    
        
    if __name__ == '__main__':
        for epoch in range(10):
            train(epoch)
            test()
    

    当自己拥有数据集时的根据上面改写的程序:

    import torch
    from torch.utils.data import Dataset
    from torch.utils.data import DataLoader
    import torch.nn.functional as F
    import torch.optim as optim
    import numpy as np
    
    batch_size = 64
    class DiabetesDataset(Dataset):
        def __init__(self, filepath):
            xy = np.loadtxt(filepath, delimiter=',', dtype=np.float32)
            self.len = xy.shape[0]
            self.x_data = torch.from_numpy(xy[:, 1:])
            self.y_data = torch.from_numpy(xy[:, [0]])
            self.y_data = self.y_data .squeeze(1).long()
        def __getitem__(self, index):
            return self.x_data[index], self.y_data[index]
    
    
        def __len__(self):
            return self.len
    
    
    train_dataset = DiabetesDataset('mnist_train.csv')
    train_loader = DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=True)
    test_dataset = DiabetesDataset('mnist_test.csv')
    test_loader = DataLoader(dataset=test_dataset, batch_size=batch_size, shuffle=False)
    
    
    class Net(torch.nn.Module):
        def __init__(self):
            super(Net, self).__init__()
            self.l1 = torch.nn.Linear(784, 512)
            self.l2 = torch.nn.Linear(512, 256)
            self.l3 = torch.nn.Linear(256, 128)
            self.l4 = torch.nn.Linear(128, 64)
            self.l5 = torch.nn.Linear(64, 10)
    
        def forward(self, x):
            x = x.view(-1, 784)
            x = F.relu(self.l1(x))
            x = F.relu(self.l2(x))
            x = F.relu(self.l3(x))
            x = F.relu(self.l4(x))
            return self.l5(x)
    model = Net()
    criterion = torch.nn.CrossEntropyLoss()
    optimizer = torch.optim.SGD(model.parameters(),lr = 0.01,momentum=0.5)
    
    def train(epoch):
        running_loss = 0.0
        for batch_idx, data in enumerate(train_loader, 0):
            inputs, target = data
            optimizer.zero_grad()
            outputs = model(inputs)
            loss = criterion(outputs, target)
            loss.backward()
            optimizer.step()
    
            running_loss += loss.item()
            if batch_idx == 0:
                print('The initial loss: %.3f' %  running_loss )
            if batch_idx % 150 == 149:
                print('[%d,%5d] loss: %.3f' % (epoch + 1, batch_idx + 1, running_loss / 300))
                running_loss = 0
    
    
    def test():
        correct = 0
        total = 0
        with torch.no_grad():  # 这部分代码不会计算梯度
            for data in test_loader:
                images, labels = data
                outputs = model(images)
                # 这里用max函数找输出节点中的最大值(即输出矩阵中每一行的最大值),返回该值和对应下标
                _, predicted = torch.max(outputs.data, dim=1)
                # labels.size(0)返回行数,也即是样本个数
                total += labels.size(0)
                # 把两个N*1的Tensor做比较相等是1否则是0,把所有结果相加就是正确的个数
                correct += (predicted == labels).sum().item()
        print("Total:",total)
        print("Corrcet:",correct)
        print('Accuracy on test set: %.2f %%' % (100 * correct / total))
    
    
    if __name__ == '__main__':
        for epoch in range(20):
            train(epoch)
            test()
    

    如果把上面的ReLU函数变成Sigmoid函数,则收敛速度会大大降低,ReLU函数能让Loss在20代收敛到0,准确率达到98.33%,Sigmoid函数则500个epoch都不能完全收敛,准确率97.14%。而且Loss的下降速度和batch_size的取值也有很大关系,上面batch_size取值是64能得到很好的收敛速度,不能取得过小,取成10都会使Loss的值出现nan的情况,而且训练速度过慢。因此取大一些是有好处的,取128和256的结果没有太多改变但训练速度大大加快。

    卷积神经网络(Convolutional Neural Network)

    全连接的神经网络,意思是网络中用的都是线性层串行的方式连接,如上面学过的内容。这里来探讨处理图像时用到的二维卷积神经网络。上面的手写数字是1*28*28的张量,但是我们强行把它拆成一维来训练了。这里我们建议先通过一个卷积层,保留图像的空间结构。可以先把它5*5卷积成4*24*24的三维张量,然后可以进行2*2的下采样,变成4*12*12,下采样不改变通道数,但改变图像的宽高,这样可以减少数据量,降低运算需求。然后再进行5*5卷积变成8*8*8,进行2*2下采样变成8*4*4,然后按一定顺序把它们展开成一维Tensor,通过全连接层,最终映射到10个输出节点,通过交叉熵损失解决分类问题。前面的卷积下采样的工作称为特征提取(Feature Extraction),后面的全连接网络称为分类器(Classification)。

    在这里插入图片描述

    成像的原理:

    在这里插入图片描述

    利用透镜把一束束光打到光敏电阻上,通过电流的变化可以求得电阻值,从而求得对应的光照强度。一个像素就需要红绿蓝三种不同的光敏传感器,从而得到彩色图像。这就是RGB图片。每个颜色都有0到255的灰度级别,这就是栅格图像。还有一种矢量图像,不能直接捕获大部分靠人工生成。描述的时候按照图片的圆心、直径、边框颜色、填充颜色等,因此放大时也是圆滑的而不是栅格的,因为这就是现画的。

    卷积层

    我们每次取一个小区域做卷积,从左到右从上到下依次卷积,每一个小区域都含三通道,最后把每一个区域输出的卷积结果拼到一起。

    其中一个区域做3*3的卷积运算过程如下:

    在这里插入图片描述

    首先中间第二列的矩阵是3*3卷积核,RGB每一个通道各有一个卷积核。每个通道从左到右从上到下依次拿出和卷积核大小相同的矩阵,和卷积核做乘法,这个乘法是矩阵中的每个元素和另一个矩阵相同位置的元素相乘,得到9个数,然后把它们相加得到一个数,因此做3*3的卷积可以把原矩阵减小两行两列,5*5的矩阵做3*3的卷积可以得到3*3的矩阵。最后把三个通道卷积出来的矩阵相加,就可以得到输出结果,并使通道数减小到1。相同通道的图像块用的是一个卷积核,这也叫做共享权重的机制。

    如果想要得到多个输出通道,把上面的过程再进行重复即可,输出通道有几个,就需要几组卷积核。

    在这里插入图片描述

    因此卷积核是一个四维的张量,形式是:输出通道数 * 输入通道数 * 卷积核宽度 * 卷积核高度。

    程序的计算过程:

    import torch 
    in_channels,out_channels = 5,10    #输入输出通道数
    width,height = 100,100             #图像大小
    kernel_size = 3                    #卷积核大小
    batch_size = 1                     
    
    #注意输入是四维的,第一维是第几个batch
    inputs = torch.randn(batch_size,in_channels,width,height)         
    #用Conv2d模块来生成卷积核
    conv_layer = torch.nn.Conv2d(in_channels,out_channels,kernel_size=kernel_size)
    output = conv_layer(inputs)
    
    print(inputs.shape)                 #torch.Size([1,5,100,100])
    print(output.shape)                 #torch.Size([1,10,98,98])
    print(conv_layer.weight.shape)      #torch.Size([10,5,3,3])
    

    输出图像宽高等于输入图像(padding参数的使用)

    如果需要输出图像的大小要等于输入图像,我们需要在输入图像外面填充一圈0数据再做卷积,具体的填充层数和卷积核大小有关。

    在这里插入图片描述

    程序:

    import torch
    
    in_channels,out_channels = 1,1   
    width,height = 5,5             
    kernel_size = 3                    
    batch_size = 1 
    
    inputs = torch.randn(batch_size,in_channels,width,height)         
    #这里多了一个padding也就是填充的层数,bias是是否设置卷积后有偏置值
    conv_layer = torch.nn.Conv2d(in_channels,out_channels,kernel_size=kernel_size,padding = 1,bias = False)
    kernel = torch.Tensor([1,2,3,4,5,6,7,8,9]).view(1,1,3,3)
    #设定卷积核的值
    conv_layer.weight.data = kernel.data
    output = conv_layer(inputs)
    
    print(inputs)                 
    print(output)                   
    

    调整步长(stride参数的使用)

    卷积是的步长是指,在卷积核对输入的一个通道做卷积时,往左右上下移动的时候都是挑一格来进行。

    在这里插入图片描述

    例如上图的卷积中心就在输入的4,8,7,6四个点处,因此输出的图像是2*2的。可以有效降低图像的数据量。代码只需要添加参数即可:

    conv_layer = torch.nn.Conv2d(in_channels,out_channels,kernel_size=kernel_size,stride = 2,bias = False)
    

    下采样

    用得最多的叫最大池化层(MaxPooling),这个层是没有权重的。

    在这里插入图片描述

    这里使用2*2的MaxPooling是将原来的矩阵数据划分为一个个2*2的区域,然后每个区域取其中最大值,这样可以把数据量减少4倍。

    import torch
    
    inputs = torch.randn(batch_size,in_channels,width,height)         
    maxpooling_layer = torch.nn.MaxPool2d(kernel_size = 2)    #kernel_size决定划分的区域是几乘几
    output = maxpooling_layer(inputs)
    
    print(inputs)                 
    print(output)    
    

    总体实现

    在这里插入图片描述

    在这里插入图片描述

    模型

    class Net(torch.nn.Module):
        def __init__(self):
            super(Net, self).__init__()
            self.conv1 = torch.nn.Conv2d(1, 10,kernel_size = 5)
            self.conv2 = torch.nn.Conv2d(10, 20,kernel_size = 5)
            self.pooling = torch.nn.MaxPool2d(2)
            self.fc = torch.nn.Linear(320, 10)
    
        def forward(self, x):
            #这里拿出第1维的个数即(n,1,28,28)中的第一个元素,是样本一个batch的样本个数
            #注意输入数据是四维的
            batch_size = x.size(0)
            x = F.relu(self.pooling(self.conv1(x)))
            x = F.relu(self.pooling(self.conv2(x)))
            #把它变成全连接网络batch * 320
            x = x.view(batch_size,-1)
            x = self.fc(x)
            return x
    model = Net()
    

    除了模型以外,其他程序都和上一章的多分类问题一致。如果要切换到显卡计算,提高运算速度,程序如下:

    #这里cuda:0指用的第一块显卡,把模型的参数缓存都放到cuda里计算
    device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
    model.to(device)
    

    还需要把输入和输出迁移到GPU上,注意模型和数据使用同一块显卡:

    def train(epoch):    
        --snip--    
        inputs,target = data    
        inputs,target = inputs.to(device),target.to(device)
        --snip--
    
    def test(epoch):    
        --snip--    
        inputs,target = data    
        inputs,target = inputs.to(device),target.to(device)
        --snip--
    

    最终模型改进:

    class Net(torch.nn.Module):
        def __init__(self):
            super(Net, self).__init__()
            self.conv1 = torch.nn.Conv2d(1, 10,kernel_size = 5)
            self.conv2 = torch.nn.Conv2d(10, 20,kernel_size = 5)
            self.pooling = torch.nn.MaxPool2d(2)
            self.l1 = torch.nn.Linear(320, 256)
            self.l2 = torch.nn.Linear(256, 64)
            self.l3 = torch.nn.Linear(64, 10)
    
        def forward(self, x):
            #这里拿出第1维的个数即(n,1,28,28)中的第一个元素,是样本一个batch的样本个数
            #注意输入数据是四维的
            batch_size = x.size(0)
            x = F.relu(self.pooling(self.conv1(x)))
            x = F.relu(self.pooling(self.conv2(x)))
            #把它变成全连接网络batch * 320
            x = x.view(batch_size,-1)
            x = F.relu(self.l1(x))
            x = F.relu(self.l2(x))
            x = self.l3(x)
            return x
    

    经过改进后,经过30个epoch的训练,MINIST数据集的准确率达到了99.11%!!!这是一个巨大的提升。

    卷积神经网络(高级篇)(Advanced CNN)

    GoogleNet

    在这里插入图片描述

    如上图就是GoogleNet的结构,由非常多的分支组成,但是其中有迹可循,很多结构都是重复的。我们可以把这种重复的结构封装使用,进行响应特征提取处理,减少代码冗余,这种结构叫做Inception Module。

    Inception Module有各种各样的构建方式,由于我们在选择卷积核的时候不知道哪个结构是最优的,因此我们把几个结构拼接到一起,让模型自己选择。

    在这里插入图片描述

    四条路径是四个张量,最后沿着通道拼成一个张量。这就要要求图像和高度一致,经过卷积和下采样都不变化,卷积可以通过设置对应的pedding来保证宽高不变,均值池化(Average Pooling),不用默认的步长,设为Stride = 1即可避免缩小一半宽高,然后再通过pedding进行调整,例如3*3的AveragePooling可以通过Stride = 1,Pedding = 1,然后求得的是九个格子的均值。然后是1*1的卷积:

    在这里插入图片描述

    这个卷积把每个通道的灰度值加权求和,得出的宽高不变,每个通道的卷积代表一个通道色彩在分类中的重要程度。

    在这里插入图片描述

    可以看出在加了一层1*1的卷积层之后,把通道数先降下来,计算结果没变计算量反而减少了一个数量级,因此1*1的卷积对减少计算量有着显著作用,这种计算量的减少意味着我们可以尝试更多地权重组合,做出更加复杂的网络。

    InceptionModule程序实现:

    在这里插入图片描述

    这样均值池化和三种卷积核的优化路径都齐了,拼在一起,梯度下降算法会自行选择最为合适的参数进行优化。

    Inception模型:

    class InceptionA(torch.nn.Module):
        def __init__(self,in_channels):
            super(InceptionA, self).__init__()
            self.branch1x1 = nn.Conv2d(in_channels,16,kernel_size=1)
            
            self.branch5x5_1 = nn.Conv2d(in_channels,16,kernel_size=1)
            self.branch5x5_2 = nn.Conv2d(16,24,kernel_size=5,padding=2)
            
            self.branch3x3_1 = nn.Conv2d(in_channels,16,kernel_size=1)
            self.branch3x3_2 = nn.Conv2d(16,24,kernel_size=3,padding=1)
            self.branch3x3_3 = nn.Conv2d(24,24,kernel_size=3,padding=1)
            
            self.branch_pool = nn.Conv2d(in_channels,24,kernel_size=1)
            
        def forward(self, x):
            branch1x1 = self.branch1x1(x)
            
            branch5x5 = self.branch5x5_1(x)
            branch5x5 = self.branch5x5_2(branch5x5)
            
            branch3x3 = self.branch3x3_1(x)
            branch3x3 = self.branch3x3_2(branch3x3)
            branch3x3 = self.branch3x3_3(branch3x3)
            
            branch_pool = F.avg_pool2d(x,kernel_size=3,stride=1,padding=1)
            branch_pool = self.branch_pool(branch_pool)
            
            outputs = [branch1x1,branch5x5,branch3x3,branch_pool]
            return torch.cat(outputs,dim=1)
                  
    

    把四个路径得出来的通道都合在一起,根据梯度下降算法,有利于降低Loss的通道中的值会升高,不利于降低Loss的会降低,这就是四条路径的好处。另外,构造函数中包含了输入通道数,这样就可以适应各种输入。输出通道数是88。

    整体网络

    class Net(torch.nn.Module):
        def __init__(self):
            super(Net, self).__init__()
            self.conv1 = torch.nn.Conv2d(1, 10,kernel_size = 5)
            self.conv2 = torch.nn.Conv2d(88, 20,kernel_size = 5)
            self.incep1 = InceptionA(in_channels = 10)
            self.incep2 = InceptionA(in_channels = 20)
            
            self.mp = nn.MaxPool2d(2)      
            self.fc = torch.nn.Linear(1408, 10)
            
        def forward(self, x):
            in_size = x.size(0)
            #变成10*12*12
            x = F.relu(self.mp(self.conv1(x)))
            #变成88*12*12
            x = self.incep1(x)
            #变成20*4*4
            x = F.relu(self.mp(self.conv2(x)))
            #变成88*4*4
            x = self.incep2(x)
            #展开成全连接层
            x = x.view(in_size,-1)
            x = self.fc(x)
            return x
    

    换了这个网络之后,正确率是98.9%。。。而上一个CNN是99.1%,因此我们应当选取合适的网络,不是越复杂越好。

    注意:如果Loss输出为nan说明训练不收敛,学习率太大导致梯度爆炸。因此需要降低学习率。

    深度残差学习Deep Residual Learning

    在这里插入图片描述

    如上图所示,这是一个残差网络(ResNet),其存在的意义在于解决梯度消失问题,当网络做得越深,靠近输入端的权重因为求导的链式法则使得其值接近于0,导数权值不更新,这样相当于只设置了后面的层而前面的层失去意义,这就是梯度消失。为了解决这个问题,可以把前面层的输出直接跨越一些层加到后面当中,前提数张量大小须一致,这样求梯度时后面加进来的一项相当于一个较为浅层的神经网络,前面的梯度依旧可以更新。

    在这里插入图片描述

    在这里插入图片描述

    ResidualBlock的编程实现

    class ResidualBlock(nn.Module):
        def __init__(self,channels):
            super(ResidualBlock, self).__init__()
            self.channels = channels
            self.conv1 = torch.nn.Conv2d(channels, channels,kernel_size = 3,padding=1)
            self.conv2 = torch.nn.Conv2d(channels, channels,kernel_size = 3,padding=1)
            
        def forward(self, x):
            y = F.relu(self.conv1(x))
            y = self.conv2(y)
            return F.relu(x + y)
    

    整体网络:

    class Net(torch.nn.Module):
        def __init__(self):
            super(Net, self).__init__()
            self.conv1 = torch.nn.Conv2d(1, 16,kernel_size = 5)
            self.conv2 = torch.nn.Conv2d(16, 32,kernel_size = 5)
            self.rblock1 = ResidualBlock(16)
            self.rblock2 = ResidualBlock(32)    
            self.mp = nn.MaxPool2d(2)      
            self.fc = torch.nn.Linear(512, 10)
            
        def forward(self, x):
            in_size = x.size(0)
            #变成16*12*12
            x = F.relu(self.mp(self.conv1(x)))
            #变成16*12*12
            x = self.rblock1(x)
            #变成32*4*4
            x = F.relu(self.mp(self.conv2(x)))
            #变成32*4*4
            x = self.rblock2(x)
            #展开成全连接层
            x = x.view(in_size,-1)
            x = self.fc(x)
            return x
    

    这个网络的效果异常显著,可以将正确率提高到99.2%!!还可以将全连接层多加线性层,可以再次优化网络结构!

    我们从以上程序还能学习到的是如果网络结构非常复杂,可以用新的类进行封装。

    论文推荐

    1、 I d e n t i t y M a p p i n g s i n D e e p R e s i d u a l N e t w o r k s Identity Mappings in Deep Residual Networks IdentityMappingsinDeepResidualNetworks

    论文中给了非常多的ResidualBlock的设计。可以自己尝试去实现几种看看效果。

    在这里插入图片描述

    2、 D e s e l y C o n n e c t e d C o n v o l u t i o n a l N e t w o r k s Desely Connected Convolutional Networks DeselyConnectedConvolutionalNetworks

    在这里插入图片描述

    这也是一种值得探究的实现方式。

    循环神经网络(RNN)

    以前使用的全连接网络叫做Dense或Deep网络,也叫DNN。

    现在假如我们要预测明天的天气情况,我们是拿不到明天的温度气压等信息的,我们的输入信息只能是前几天的温度气压等信息,然后输出明天的天气情况,这时候把几天的数据拼接在一起使用全连接网络也可以,但是全连接网络的权重信息是非常多的,比CNN都还要多得多。这是DNN因为输入的每一个节点都和输出节点建立权重,而CNN是因为是卷积核共享权重的机制使得权重数量较少。

    因此RNN专门用来处理这种序列模式的数字,我们也要用这种权重共享的概念来减少需要训练的权重数字。如果我们拥有前三天的天气数据,我们假定第一天和第二天有联系,第二天和第三天有联系,也就是说后一天的情况依赖于前一天,也就是说这种带有序列,后者依赖前者的数据是RNN的处理对象。

    在这里插入图片描述

    RNN的本质上是一个线性层,不同于CNN它的权重是共享的,流程可以看右边的图,输入和线性层和前面的先验值进行线性变换,进行输出并且传递到下一层,下一层的x,和这一层的x进行某种融合。第一个先验值可以通过CNN+FC进行生成(例如图像到文本),或者设置全0,注意里面进行运算的RNN Cell是同一个线性层。

    在这里插入图片描述

    上图是CNN Cell的构造,首先先验证 h − h^- h是h*1的矩阵,这一次的输入是 i * 1的矩阵,输出必须也是h*1的矩阵,因此和先验值相乘的权值矩阵 w 1 w_1 w1是h*h,和输入x相乘的权重矩阵 w 2 w_2 w2是h*i,在进行这样的线性变换后,再通过一个激活函数tanh,输出值
    h = t a n h ( w 1 h − + b 1 + w 2 x + b 2 ) = t a n h ( [ w 1 w 2 ] [ b 1 b 2 ] ) h = tanh(w_1 h^- + b_1 + w_2x + b_2) = tanh(\left[ \begin{matrix} w_1 & w_2 \end{matrix} \right] \left[ \begin{matrix} b_1 \\ b_2 \end{matrix} \right]) h=tanh(w1h+b1+w2x+b2)=tanh([w1w2][b1b2])
    不断循环这个过程,就可以不断输出下一天的预测值。

    定义RNN:

    #input_size是输入的维度i,hidden_size是先验值的维度h
    cell = torch.nn.RNNCell(input_size = input_size , hidden_size = hidden_size) 
    

    使用RNN:

    #第一个是输入的向量,第二个是先验值的向量
    hidden = cell(inputs,hidden)
    

    注意:由于数据是分batch进行训练的,一个batch中有多条数据,因此实际上程序中输入的维度应该为batch_size * i,h的维度是batch_size * h。要注意这种数据的构造形式,否则程序会发生错误。

    处理RNN时,整个序列构造成:

    dataset.shape = (seqLen,batchSize,inputSize)
    

    这种形式,第一维是序列长度,第二个是batch长度,最后第三个才是输入的维度。

    举例:

    import torch
    
    batch_size = 1
    seq_len = 3
    input_size = 4
    hidden_size = 2
    
    cell = torch.nn.RNNCell(input_size = input_size , hidden_size = hidden_size) 
    dataset = torch.randn(seq_len,batch_size,input_size)
    hidden = torch.zeros(batch_size,hidden_size)
    
    #对dataset进行遍历,这样把数据一组组拿出来,从三维变成二维,就能进行RNNCell的运算
    for idx,inputs in enumerate(dataset):
        print('=' * 20,idx '=' * 20)
        print('input.size:',input.shape)
        hidden = cell(inputs,hidden)
        
        print('outputs size:',hidden.shape)
        print(hidden)
    

    注意里面的hidden是输出值,是不断迭代变化的,输出后进入下一个RNNCell运算。

    在这里插入图片描述

    实际应用时如果使用RNN类而不是RNNCell类,还需要在后面加一个num_layers参数,代表RNN向上叠的层数,但不建议太多层因为RNN运算非常耗时。在执行

    cell = torch.nn.RNN(input_size = input_size , hidden_size = hidden_size,num_layers = num_layers) 
    out,hidden = cell(inputs,hidden)
    

    的代码时,这时我们不用自己写循环,只需要传入的inputs是三维seqLen*batchSize*inputSize的,输入的hidden是numLayers*batch*input_size,numLayer是RNN的层数,因为有可能RNN有多层,一个RNNCell就需要输入多个h。然后它会自己进行迭代。其中out的输出是h的序列seqLen*batchSize*hidden_size,而hidden输出的是最后一个h,维度是numLayers*batch*input_size。下面是多层RNN的图。

    在这里插入图片描述

    改进的程序:

    import torch
    
    batch_size = 1
    seq_len = 3
    input_size = 4
    hidden_size = 2
    num_layers = 1
    
    cell = torch.nn.RNN(input_size = input_size , hidden_size = hidden_size,num_layers = num_layers) 
    inputs = torch.randn(seq_len,batch_size,input_size)
    hidden = torch.zeros(num_layers,batch_size,hidden_size)
    
    
    out,hidden = cell(inputs,hidden)
        
    print('outputs size:',out.shape)
    print("Output:",out)
    print('Hidden size:',hidden.shape)
    print("Hidden",hidden)
    

    RNN类的其他参数,例如batch_first = true,可以设置batch_size在第一个维度,将它和第一个维度进行交换。这样方便在输出时再接一层线性层。这样设置后注意要把输入的维度进行转置以适应改变。

    实例

    我们的目标是训练一个循环神经网络来适应一个序列变化规律,例如把hello变成ohlol。

    在这里插入图片描述

    首先,把字符进行向量化。在做自然语言处理时要把字符构造成词典,把每一个分配索引。

    在这里插入图片描述

    分配索引后,每一个字母都可以用一个one-hot向量代表,词典中有几个字母这个向量就有几个元素(这里是四个),然后把这个one-hot向量作为输入input。hello有五个字母,输入序列长度是5。因此输出也是一个四维的one-hot向量。这个向量可以接交叉熵来进行分类。

    在这里插入图片描述

    import torch
    
    input_size = 4
    hidden_size = 4
    batch_size = 1
    #准备数据
    idx2char = ['e','h','l','o']
    x_data = [1,0,2,2,3]
    y_data = [3,1,2,3,2]
    #查询one-hot向量
    one_hot_lookup = [[1,0,0,0],
                     [0,1,0,0],
                     [0,0,1,0],
                     [0,0,0,1]]
    #根据数据构建one-hot向量组
    x_one_hot = [one_hot_lookup[x] for x in x_data]
    
    inputs = torch.Tensor(x_one_hot).view(-1,batch_size,input_size)
    #在直接输入的是标签而非one-hot向量时要用LongTensor否则出错
    labels = torch.LongTensor(y_data).view(-1,1)
    
    
    class Model(torch.nn.Module):
        def __init__(self,input_size,hidden_size,batch_size):
            super(Model, self).__init__()
            self.batch_size = batch_size
            self.input_size = input_size
            self.hidden_size = hidden_size
            self.rnncell = torch.nn.RNNCell(input_size=self.input_size,hidden_size = self.hidden_size)
            
        def forward(self, inputs,hidden):
            #注意这只做了一个RNNCell,输入注意是batchSize*inputSize,输出batch_size*hiddenSize
            hidden = self.rnncell(inputs,hidden)
            return hidden
        
        #这个函数用来生成默认的h0
        def init_hidden(self):
            return torch.zeros(self.batch_size,self.hidden_size)
        
    net = Model(input_size,hidden_size,batch_size)
    
    criterion = torch.nn.CrossEntropyLoss()
    #这里用的是改进的随机梯度下降的优化器
    optimizer = torch.optim.Adam(net.parameters(),lr = 0.1)
    
    for epoch in range(15):
        loss = 0
        optimizer.zero_grad()
        hidden = net.init_hidden()
        print('Predicted string:',end="")
        for inputs,label in zip(inputs,labels):
        	hidden = net(inputs,hidden)
            loss += criterion(hidden,label)
            #这里用max函数找输出节点中的最大值(即输出矩阵中每一行的最大值dim=1),列是batch_size,此处仅有一行
            #返回该值和对应下标的列表,此处列表元素只有一个
            _,idx = hidden.max(dim=1)
            print(idx2char[idx.item()],end = "")
        loss.backward()
        optimizer.step()
        print(',Epoch [%d/15] loss=%.4f' % (epoch+1,loss.item()))
    

    而不用RNNCell,而是用RNN程序会简介很多:

    import torch
    
    input_size = 4
    hidden_size = 4
    batch_size = 1
    #准备数据
    idx2char = ['e','h','l','o']
    x_data = [1,0,2,2,3]
    y_data = [3,1,2,3,2]
    #查询one-hot向量
    one_hot_lookup = [[1,0,0,0],
                     [0,1,0,0],
                     [0,0,1,0],
                     [0,0,0,1]]
    #根据数据构建one-hot向量组
    x_one_hot = [one_hot_lookup[x] for x in x_data]
    
    inputs = torch.Tensor(x_one_hot).view(-1,batch_size,input_size)
    #输出直接用一维的,因为后面已经将维度合并
    labels = torch.LongTensor(y_data)
    
    
    class Model(torch.nn.Module):
        def __init__(self,input_size,hidden_size,batch_size,num_layers = 1):
            super(Model, self).__init__()
            self.num_layers = num_layers
            self.batch_size = batch_size
            self.input_size = input_size
            self.hidden_size = hidden_size
            self.rnn = torch.nn.RNN(input_size=self.input_size,hidden_size = self.hidden_size,num_layers=self.num_layers)
            
        def forward(self, inputs):
            hidden = torch.zeros(self.num_layers,self.batch_size,self.hidden_size)
            #我们要的是整个序列的输出,而不是最后的输出
            out,_ = self.rnn(inputs,hidden)
            #batch_size=1,因此用二维即可,好处是用交叉熵方便,输出标签直接是一维的即可
            return out.view(-1,self.hidden_size)
        
        
    net = Model(input_size,hidden_size,batch_size)
    
    criterion = torch.nn.CrossEntropyLoss()
    optimizer = torch.optim.Adam(net.parameters(),lr = 0.05)
    
    for epoch in range(15):
        optimizer.zero_grad()
        outputs = net(inputs)
        loss = criterion(outputs,labels)
        loss.backward()
        optimizer.step()
        _,idx = outputs.max(dim=1)
        #变成numpy数组
        idx = idx.data.numpy()
        #join把列表中的元素练成一个
        print(   'Predicted string:',''.join([idx2char[x] for x in idx]),end = "")
        print(',Epoch [%d/15] loss=%.4f' % (epoch+1,loss.item()))
    

    One-hot编码的缺点:维度太高,一旦种类过多将很难训练。且向量过于稀疏,只有一个元素是1。而且是硬编码的,哪个字符对应的编码固定,不是学习出来的。

    因此我们考虑的改进方向是:低维、稠密、可学习。一个流行的方法是嵌入层(EMBEDDING)。意思是把高维稀疏的样本映射到低维稠密的空间中中,这就是数据降维

    在这里插入图片描述

    嵌入层可以把数据降维,也可以升维。上图是一个升维的例子,行数是原来的one-hot向量的维度,列数是转换的新的向量的向量的维度,生成这个矩阵W后,只需要进行查询,one-hot向量哪个元素为1把对应行向量取出来即可,设one-hot向量为A,转换之后向量为E,转换公式为:
    E = W T A E = W^TA E=WTA
    这样即可升维或降维。

    进行降维后,模型改变如下:

    在这里插入图片描述

    模型在输入x的上方加入一个嵌入层进行降维,有时候需要在序列中的每一个输出后面加一个线性层,这是因为输出的维度不一定和分类数量一致,我们可以将输出的维度放大一些增强拟合能力,然后用线性层进行转换,变成分类的维度。需要注意的是Embed的输入层必须是LongTensor类型。

    embedding的初始化:

    在这里插入图片描述

    其中前两个参数是必须的,构成转换矩阵的高度和宽度。输出会在原来的Tensor的维度上加上一维表示embedding_dim。

    线性层可以是任意维度,输出的维度和输入维度一致,除了最后一个维度之外输出和输入每个维度的元素个数一致。交叉熵的计算同理。

    模型程序:

    import torch
    
    num_class = 4
    input_size = 4
    hidden_size = 8
    embedding_size = 10
    #这里用了两层RNN
    num_layers = 2
    batch_size = 1
    seq_len = 5
    #准备数据
    idx2char = ['e','h','l','o']
    #注意x需要变成二维即(batch,seq_len)
    x_data = [[1,0,2,2,3]]
    #y是一维的即 batch*seq_len
    y_data = [3,1,2,3,2]
    
    #embedding输入长整形,直接是下标的Tensor即可,自动转换成one-hot
    inputs = torch.LongTensor(x_data)
    labels = torch.LongTensor(y_data)
    
    class Model(torch.nn.Module):
        def __init__(self):
            super(Model, self).__init__()
            self.emb = torch.nn.Embedding(input_size,embedding_size)
            #这里既然把batch放在第一个,后面就需要按照这个顺序排列
            self.rnn = torch.nn.RNN(input_size = embedding_size, hidden_size = hidden_size,num_layers = num_layers,batch_first=True)
            self.fc = torch.nn.Linear(hidden_size,num_class)
    
        def forward(self, x):
            hidden = torch.zeros(num_layers,x.size(0),hidden_size)
            x = self.emb(x)
            x,_ = self.rnn(x,hidden)
            x = self.fc(x)
            return x.view(-1,num_class)
        
    net = Model()
    criterion = torch.nn.CrossEntropyLoss()
    optimizer = torch.optim.Adam(net.parameters(),lr = 0.05)
    
    for epoch in range(15):
        optimizer.zero_grad()
        outputs = net(inputs)
        loss = criterion(outputs,labels)
        loss.backward()
        optimizer.step()
        
        _,idx = outputs.max(dim=1)
        #变成numpy数组
        idx = idx.data.numpy()
        #join把列表中的元素练成一个
        print(   'Predicted string:',''.join([idx2char[x] for x in idx]),end = "")
        print(',Epoch [%d/15] loss=%.4f' % (epoch+1,loss.item()))
    

    因为输入的维数较低,所以可以从四维升到十维,这个嵌入层可以调节的,避免了硬编码,梯度下降可以寻找适合的嵌入层参数。输入嵌入层的数据是二维batch_size * seq_len的,输出是三维的 batch_size * seq_len * embedding ,这是由于x中的每一个数都变成了一个10维向量。batch_first=true的变化是inputs和outputs都把batch_size放在第一个维度。注意RNN的序列输出是三维的,model中直接强制变成两位,是因为labels只有一维,只有一个样本,这样就可以做交叉熵,如果有多个batch,则需要labels有二维,输出outputs三维。

    使用LSTM

    LSTM是RNN的变种,该算法运算复杂复杂度高,运算时间长,但效果比RNN好得多。由于独特的设计结构,LSTM适合于处理和预测时间序列中间隔和延迟非常长的重要事件。

    https://www.jianshu.com/p/4b4701beba92

    使用GRU

    GRU是一种基于LSTM和RNN之间的算法,是折中的方案。是LSTM网络的一种效果很好的变体,它较LSTM网络的结构更加简单,而且效果也很好,因此也是当前非常流形的一种网络。GRU既然是LSTM的变体,因此也是可以解决RNN网络中的长依赖问题。

    https://zhuanlan.zhihu.com/p/32481747

    循环神经网络(高级篇)

    现在我们需要做一个名字分类,通过人的名字来分辨具体的国别。

    在这里插入图片描述

    网络的结构可以变成如上图所示,我们只需要在最后输出一个国别的分类即可,中间的RNNCell的输出不做要求也无法做要求。这就是处理自然语言的一个方法。

    在这里插入图片描述

    中间我们使用更为优秀的GRU来代替传统的RNN。另外每个人的名字也是长度不一的,我们要根据不同长度进行不同处理。首先是分隔字符,我们要将名字分割成一个个字符做成列表,然后制作词典,我们可以用ASCII码表来作为它的词典,这个词典共128个字符,然后查找每个字符对应的ASCII值来拼成对应的Tensor。刚好Embedding层输入需要的是LongTensor而不是one-hot向量,所以这个可以直接作为输入。然后由于每个人们字符串长度不一,我们统一把它们用零填充成最长字符的长度,这样就可以统一处理了。然后再把分类的国家做成一个词典。

    在这里插入图片描述

    在这里插入图片描述

    什么是双向循环神经网络

    在以往RNN中,后面hidden的输出只包含前面输入的信息,而前面的输出不包含后面的信息。但是在自然语言处理中我们也要考虑后面输入的信息,因为后面将要输入的信息也会对前面造成影响,因此我们需要反向再做一次RNN,然后把它们拼接在一起,拼成一个Tensor。这就是双向循环神经网络。

    在这里插入图片描述

    因此双向循环神经网络输出是最上面的序列,Tensor长度是原来hidden的两倍,而hidden的输出是 [ h N f , h N b ] [h_N^f,h_N^b] [hNf,hNb]。同时出示的hidden也要是这个形式和长度。

    数据送入GRU是做的优化

    为了提高运行效率,后面填充的0参数是没必要参与运算的,原理是0 embedding转换成的向量都是一致的,我们把原来的输入的名字按照长度从大到小排列经过embedding以后,把0的列去掉,然后打包成一个平面,再保存一个关于每一个名字的长度信息即可。这样保存的信息大大减少,以后根据这个长度信息把数据重新拿出来即可。

    在这里插入图片描述

    import gzip
    import csv
    import torch
    from torch.utils.data import Dataset
    from torch.utils.data import DataLoader
    from torch.nn.utils.rnn import pack_padded_sequence
    import time
    import math
    
    
    HIDDEN_SIZE = 100
    BATCH_SIZE = 256
    N_LAYER = 2
    N_EPOCHS = 100
    N_CHARS = 128
    USE_GPU = True
    
    
    # 数据处理,处理后是未经数据化的和排序的人名,经过数据化按人名对应顺序的的国家
    class NameDataset(Dataset):
        def __init__(self, is_train_set=True):
            filename = 'names_train.csv.gz' if is_train_set else 'names_test.csv.gz'
            # 读zip文件的方法
            with gzip.open(filename, 'rt') as f:
                # csv文件的读取的方法
                reader = csv.reader(f)
                # csv文件读成一个列表
                rows = list(reader)
            self.names = [row[0] for row in rows]
            self.len = len(self.names)
            self.countries = [row[1] for row in rows]
            # set把列表取除重复的元素,sorted进行排序,赋给新的变量
            self.country_list = list(sorted(set(self.countries)))
            # 把上面的列表转换成词典,__getitem__提供索引访问
            self.country_dict = self.getCountryDict()
            self.country_num = len(self.country_list)
    
        def __getitem__(self, index):
            # 注意这里是怎么把国家转换成对应索引的
            return self.names[index], self.country_dict[self.countries[index]]
    
        def __len__(self):
            return self.len
    
        #建立一个国家的字典,国家名和数字标签对应上
        def getCountryDict(self):
            # 建立空字典
            country_dict = dict()
            # enumerate() 函数用于将一个可遍历的数据对象组合为一个索引序列,同时返回数据下标和数据
            for idx, country_name in enumerate(self.country_list, 0):
                country_dict[country_name] = idx
            return country_dict
    
        # 通过国家名返回一个索引
        def idx2country(self, index):
            return self.country_list[index]
    
        # 返回国家个数
        def getCountriesNum(self):
            return self.country_num
    
    
    trainset = NameDataset(is_train_set=True)
    trainloader = DataLoader(trainset,batch_size=BATCH_SIZE, shuffle=True)
    testset = NameDataset(is_train_set=False)
    testloader = DataLoader(testset,batch_size=BATCH_SIZE, shuffle=False)
    N_COUNTRY = trainset.getCountriesNum()
    
    
    # 输入未经数据化的的字母名字Tensor和国家索引Tensor,输出经过转换、填充、排序处理的名字Tensor,名字长度Tensor,国家索引Tensor
    def make_tensors(names, countries):
        # 由一个个元组组成的列表
        sequences_and_lengths = [name2list(name) for name in names]
        # 拿出列表中每个元组的第一个元素,即名字ASCII码列表组成新的列表
        name_sequences = [sl[0] for sl in sequences_and_lengths]
        # 拿出列表中每个元组的第二个元素,即名字长度组成新的列表,注意是LongTensor
        seq_lengths = torch.LongTensor([sl[1] for sl in sequences_and_lengths])
        # 转换成LongTensor
        countries = countries.long()
    
        # 用0填充名字到长度一致
        seq_tensor = torch.zeros(len(name_sequences), seq_lengths.max()).long()
        for idx, (seq, seq_len) in enumerate(zip(name_sequences, seq_lengths), 0):
            seq_tensor[idx, :seq_len] = torch.LongTensor(seq)
    
        # 倒序排序,返回排序好的Tensor以及对应的排完序的索引
        seq_lengths, perm_idx = seq_lengths.sort(dim=0, descending=True)
        # 用索引对原来的名字和国家序列进行排序,排完序后名字长度就是倒序的了
        seq_tensor = seq_tensor[perm_idx]
        countries = countries[perm_idx]
        # seq_lengths需要放在CPU上否则报错。。
        return create_tensor(seq_tensor), seq_lengths, create_tensor(countries)
    
    
    # 如果使用GPU就把tensor放到GPU上
    def create_tensor(tensor):
        if USE_GPU:
            device = torch.device("cuda:0")
            tensor = tensor.to(device)
        return tensor
    
    
    # 把名字转换为ASCII值的列表,返回列表和列表长度的元组
    def name2list(name):
        arr = [ord(c) for c in name]
        return arr, len(arr)
    
    
    class RNNClassifier(torch.nn.Module):
        # bidrectional选择循环神经网络单向还是双向
        def __init__(self, input_size, hidden_size, output_size, n_layers=1, bidirectional=True):
            super(RNNClassifier, self).__init__()
            self.hidden_size = hidden_size
            self.n_layers = n_layers
            self.n_directions = 2 if bidirectional else 1
            self.embedding = torch.nn.Embedding(input_size, hidden_size)
            self.gru = torch.nn.GRU(hidden_size, hidden_size, n_layers, bidirectional=bidirectional)
            self.fc = torch.nn.Linear(hidden_size * self.n_directions, output_size)
    
        def _init_hidden(self, batch_size):
            hidden = torch.zeros(self.n_layers * self.n_directions,batch_size,self.hidden_size)
            return create_tensor(hidden)
    
        # 这里多了一个序列的长度的参数
        def forward(self, inputs, seq_lengths):
            # 做矩阵的转置,把batch_size * seq_len变成seqLen * batch_size
            inputs = inputs.t()
            batch_size = inputs.size(1)
    
            hidden = self._init_hidden(batch_size)
            embedding = self.embedding(inputs)
            # 为了提高运行效率,所做的优化,这是RNN,LSTM,GRU都能接受的输入
            gru_input = pack_padded_sequence(embedding, seq_lengths)
            # 这里要的输出是hidden
            output, hidden = self.gru(gru_input, hidden)
    
            # 如果是双向的,那么就需要把两个hidden连起来作为输出
            if self.n_directions == 2:
                hidden_cat = torch.cat([hidden[-1], hidden[-2]], dim=1)
            else:
                hidden_cat = hidden[-1]
    
            fc_output = self.fc(hidden_cat)
            return fc_output
    
    
    def trainModel():
        total_loss = 0
        for i, (names, countries) in enumerate(trainloader, 1):
            inputs, seq_lengths, target = make_tensors(names, countries)
            output = classifier(inputs, seq_lengths)
            loss = criterion(output, target)
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()
    
            total_loss += loss.item()
            if i % 10 == 0:
                print(f'[{time_since(start)}] Epoch {epoch} ', end='')
                print(f'[{i * len(inputs)}/{len(trainset)}]', end='')
                print(f'loss = {total_loss / (i * len(inputs))}')
    
        return total_loss
    
    
    def testModel():
        correct = 0
        total = len(testset)
        print("evaluating trained model ...")
        # 不求梯度
        with torch.no_grad():
            for i, (names, countries) in enumerate(testloader, 1):
                inputs, seq_lengths, target = make_tensors(names, countries)
                output = classifier(inputs, seq_lengths)
                # 输出最大值节点的索引是分类国家的索引,keepdim保持原有的维度不变
                # 最后有个[1]是因为返回值实际上有两个tansor,第一个存储是值,第二个存储索引,我们只需要索引
                pred = output.max(dim=1, keepdim=True)[1]
                # view_as把Tensor转变成对应Tensor的形式
                # eq看两个Tensor对应的位置是否相当,返回相同形式的Tensor,对应位置相同为True,不相同为FALSE
                correct += pred.eq(target.view_as(pred)).sum().item()
    
            percent = '%.2f' % (100 * correct / total)
            print(f'Test set: Accuracy {correct}/{total} {percent}%')
        return correct / total
    
    # 计算训练时长
    def time_since(since):
        s = time.time() - since
        m = math.floor(s / 60)
        s -= m * 60
        return '%dm %ds' % (m, s)
    
    if __name__ == '__main__':
        # N_CHARS是输入字符的长度,N_CHARS是GRU输出隐藏的维度,N_COUNTRY是具体国家的分类数,N_LAYER是GRU的层数
        classifier = RNNClassifier(N_CHARS, HIDDEN_SIZE, N_COUNTRY, N_LAYER)
        if USE_GPU:
            device = torch.device("cuda:0")
            classifier.to(device)
    
        criterion = torch.nn.CrossEntropyLoss()
        optimizer = torch.optim.Adam(classifier.parameters(), lr=0.001)
    
        # 记录开始训练的时间
        start = time.time()
        print("Train for %d epochs..." % N_EPOCHS)
        acc_list = []
        for epoch in range(1, N_EPOCHS + 1):
            trainModel()
            acc = testModel()
            # 把准确率记录到列表中
            acc_list.append(acc)
    

    如果需要绘制Loss变化曲线,需要加上以下代码:

    import matplotlib.pyplot as plt
    import numpy as np
    
    # arange第一个参数是起点,第二个是重点,第三个是步长
    epoch = np.arange(1,len(acc_list) + 1,1)
    acc_list = np.array(acc_list)
    plt.plot(epoch,acc_list)
    plt.xlabel("Epoch")
    plt.ylabel('Accuracy')
    plt.grid()
    plt.show()
    

    注意:模型的输入为(seqLen,batchSize),Embedding的输出为(seqLen,batchSize,hiddenSize)同时也是GRU的输入,GRU的输入输出都和原始RNN相同。

    如果训练准确度是最高的,我们需要保存模型,可以用

    #保存
    torch.save(model,PATH)
    #载入
    model = torch.load(PATH)
    

    拓展

    Kaggle上一个数据集:https://www.kaggle.com/c/setiment-analysis-on-movie-reviews/data

    这个数据集的训练任务是根据电影评论的文本判断用户对电影的态度。

    当掌握了RNN后,我们可以用RNN做很多不同的语言模型,例如作诗的神经网络,只需要输入第一个字,就能自动做出一首诗。

    我们首先先做一个关于汉字的词典,还要加一个休止符,这个符号代表诗已经作完了。首先需要大量的诗句进行训练,前面的字作为RNNCell输入,输出必须是下一个字,然后把下一个字再送进RNNCell中反复循环,以此类推。因此,只要有足够的数据,我们就能做各种文本的生成器。

    后记

    至此深度学习图像识别的基础知识基本讲解完毕,本文是从实践的角度进行讲解。

    • 将来如果想更深一步,需要从理论方面着手,可以看一下深度学习的花书。或者其他理论书籍。
    • 如果想写更加复杂网络,需要阅读pytorch文档。
    • 复现经典工作,看经典的论文复现其中的工作,需要通读代码,从中学习写法,然后自己尝试自己去写。
    • 选特定的研究领域大量阅读论文,看大家的设计神经网络的技巧。看多了才能有自己的创新点并避免重复工作。扩充自己的视野。解决自己知识上的盲点,并解决自己编程上的盲点。把别人的工作变成自己的知识点,形成体系。
    展开全文
  • AI 书汇总-深度学习之PyTorch实战计算机视觉 - 2018 计算机视觉
  • 《深度学习之PyTorch实战计算机视觉》第8章代码 内容图片: 风格图片: 网络结构: 手绘网络结构: 代码 import torch import torchvision from torchvision import transforms, models from PIL import Image ...

    《深度学习之PyTorch实战计算机视觉》第8章代码

    内容图片:
    Content.jpg
    风格图片:

    Style.jpg
    网络结构:
    网络结构
    手绘网络结构:
    在这里插入图片描述

    代码

    import torch
    import torchvision
    from torchvision import transforms, models
    from PIL import Image
    import matplotlib.pyplot as plt
    from torch.autograd import Variable
    import copy
    import time
    
    
    
    transform = transforms.Compose(
        [
            transforms.Scale([224,224]),
            transforms.ToTensor()
        ]
    )
    
    
    
    def loadimg(path = None):
        img = Image.open(path)
        if img.mode != "RGB":
            img = img.convert('RGB')
        img = transform(img)
        img = img.unsqueeze(0)
        return img
    
    content_img = loadimg("images/3.jpg") #注意,images文件夹在当前文件夹的上一层文件夹中
    #print("陈旭旗",content_img.shape)
    content_img = Variable(content_img).cuda()#torch.Size([1, 3, 224, 224])
    style_img = loadimg("images/8.jpg")   #注意,images文件夹在当前文件夹的上一层文件夹中
    style_img = Variable(style_img).cuda()  #torch.Size([1, 3, 224, 224])
    
    print("陈旭旗",style_img.shape)
    
    
    # plt.imshow(style_img.cpu().squeeze(0).numpy().transpose([1,2,0]))
    # plt.show()
    
    class Content_loss(torch.nn.Module):
        def __init__(self, weight, target):
            # target是通过卷积获取到的输入图像中的内容
            # weight是我们设置的一个权重参数,用来控制内容和风格对最后合成图像的影响程度
            super(Content_loss,self).__init__()
            self.weight = weight
            self.target = target.detach()*weight  
            # target.detach()用于对提取到的内容进行锁定,不需要进行梯度
            self.loss_fn = torch.nn.MSELoss()
    
        def forward(self, input):# forward函数用于计算输入图像和内容图像之间的损失值
            # input代表输入图像,
            self.loss = self.loss_fn(input*self.weight, self.target)
            return input
        
        def backward(self):
            # backward函数根据计算得到的损失值进行后向传播,并返回损失值
            self.loss.backward(retain_graph = True)
            # 每次 backward() 时,默认会把整个计算图free掉。一般情况下是
            # 每次迭代,只需一次 forward() 和一次 backward() ,前向运算forward()
            # 和反向传播backward()是成对存在的,一般一次backward()也是够用的。但
            # 是不排除,由于自定义loss等的复杂性,需要一次forward(),多个不同loss的
            # backward()来累积同一个网络的grad,来更新参数。于是,若在当前backward()后,
            # 不执行forward() 而可以执行另一个backward(),需要在当前backward()时,
            # 指定保留计算图,即backward(retain_graph)return self.loss
    
    
    #实现的是格拉姆矩阵(Gram matrix)的功能
    class Gram_matrix(torch.nn.Module):
    # 我们通过卷积神经网络提取了风格图片的风格,这些风格其实是由数字组成的,数字的大小代表了
    # 图片中风格的突出程度,而Gram矩阵是矩阵的内积运算,在运算过后输入到该矩阵的特征图中的大
    # 的数字会变得更大,这就相当于图片的风格被放大了,放大的风格再参与损失计算,便能够对最后
    # 的合成图片产生更大的影响。
        def forward(self, input):
            a,b,c,d = input.size()
            feature = input.view(a*b, c*d)
            gram = torch.mm(feature,feature.t()) #返回矩阵乘积
            return gram.div(a*b*c*d)
    
    class Style_loss(torch.nn.Module):
        def __init__(self,weight,target):
            super(Style_loss,self).__init__()
            self.weight = weight
            self.target = target.detach()*weight
            self.loss_fn = torch.nn.MSELoss()
            self.gram = Gram_matrix()
    
        def forward(self,input):
            self.Gram = self.gram(input.clone())
            self.Gram.mul_(self.weight)#原地操作,矩阵对应位相乘
            self.loss = self.loss_fn(self.Gram,self.target)
            return input
        
        def backward(self):
            self.loss.backward(retain_graph = True)
            return self.loss
    
    use_gpu = torch.cuda.is_available()
    cnn = models.vgg16(pretrained=True).features
    #print(cnn)
    #print(models.vgg16(pretrained=True))
    
    
    if use_gpu:
        cnn = cnn.cuda()
    
    model = copy.deepcopy(cnn)
    
    
    
    content_losses = []
    style_losses = []
    
    conten_weight = 1
    style_weight = 1000
    new_model = torch.nn.Sequential()
    
    
    gram = Gram_matrix()
    
    if use_gpu:
        new_model = new_model.cuda()
        gram = gram.cuda()
    
    
    content_layer = ["Conv_3"]
    style_layer = ["Conv_1","Conv_2","Conv_3","Conv_4"]
    index = 1
    
    # print("cxq陈旭旗")
    # print(list(model)[:8])
    # print("cxq陈旭旗")
    
    # cxq = 0
    for layer in list(model)[:8]:
        if isinstance(layer, torch.nn.Conv2d):
            name = "Conv_"+str(index)
            new_model.add_module(name, layer)
            if name in content_layer:            #["Conv_3"]
                target = new_model(content_img).clone()
                content_loss = Content_loss(conten_weight,target)
                new_model.add_module("content_loss_"+str(index),content_loss)
                content_losses.append(content_loss)
            
            if name in style_layer:              #["Conv_1","Conv_2","Conv_3","Conv_4"]
                target = new_model(style_img).clone()
                target = gram(target)
                style_loss = Style_loss(style_weight, target)
                new_model.add_module("style_loss_"+str(index), style_loss)
                style_losses.append(style_loss)
    
        if isinstance(layer, torch.nn.ReLU):
            name = "Relu_"+str(index)
            new_model.add_module(name,layer)
            index = index+1
    
        if isinstance(layer, torch.nn.MaxPool2d):
            name = "MaxPool_"+str(index)
            new_model.add_module(name, layer)
        # cxq +=1
        # if cxq == 9:
        #     print(new_model)
    
    # print(new_model)
    
    # print("陈旭旗content_losses:\n")
    # print(content_losses)
    
    
    # print("\n\n\n陈旭旗style_losses:\n")
    # print(style_losses)
    
    
    
    
    input_img = content_img.clone()#torch.Size([1, 3, 224, 224])
    parameter = torch.nn.Parameter(input_img.data)#含义是将一个固定不可训练的tensor转换成可以训练的类型parameter
    optimizer = torch.optim.LBFGS([parameter])
    
    
    
    epoch_n = 300    
    epoch = 0
    time_open = time.time()
    while epoch <= epoch_n:
    
        def closure():
            optimizer.zero_grad()
            style_score = 0
            content_score = 0
            parameter.data.clamp_(0,1)#torch.Size([1, 3, 224, 224])
            new_model(parameter)
            for sl in style_losses:
                style_score += sl.backward()
            
            for cl in content_losses:
                content_score += cl.backward()
            
            global epoch
            epoch += 1
            if epoch % 50 == 0:
                print("Epoch:{} Style Loss: {:4f} Content Loss:{:4f}".format(
                        epoch,
                        style_score.item(),
                        content_score.item()
                    )
                )
            return style_score+content_score
        optimizer.step(closure)
    
    
    time_end = time.time() - time_open
    print("程序运行时间:{}秒...".format(int(time_end)))
    
    
    plt.figure("内容图像")
    plt.imshow(content_img.data.cpu().squeeze(0).numpy().transpose([1,2,0]))
    
    plt.figure("风格图像")
    plt.imshow(style_img.data.cpu().squeeze(0).numpy().transpose([1,2,0]))
    
    
    plt.figure("风格迁移图像")
    plt.imshow(parameter.data.cpu().squeeze(0).numpy().transpose([1,2,0]))
    plt.show()
    
    

    实验效果:
    在这里插入图片描述

    展开全文
  • 深度学习与PyTorch实战 计算机博士,专注于机器学习与计算机视觉领域,深...
  • 加载models提供的模型,并直接用训练好的权重当做初始化参数 开源: YOLOV 物体检测 Mark-R-CNN 实例分割,抠图 ...Bert 文本处理,NLP ...访问不了查看:查找论文对应开源代码的神器(Papers with Code) ...
  • 这部分是利用pytorch 进行实战,利用迁移vgg16、resnet50 来实现多模型融合,实现猫狗的分类 代码基于python3.7, pytorch 1.0,cuda 10.0 . PyTorch之多模型融合实战 基于PyTorch实现一个多模型的融合,使用的是多...
  • Pytorch实战:手写数字识别 1、数据导入 #实战手写数字识别 #************************************************************导入包********************************************************************* import...
  • 《深度学习之PyTorch实战计算机视觉》第3章代码 代码如下 import time import torch ################################################## for i in range(1,10): start = time.time() a = torch.FloatTensor(i...
  • 分享视频教程——深度学习-PyTorch框架实战系列,完整版16章,附源码+数据+课件;课程内容全部以实战为导向,基于当下计算机视觉与自然语言处理中经典项目进行实例讲解,通过Debug模式详解项目中每一行代码的作用与...
  • 这里利用的是cifar10数据集,具体数据集操作请参考我的另一篇博文基于LeNet网络结构实战:链接入口 2. 残差网络 作者发现,随着网络层数的增加,网络发生了退化(degradation)的现象:随着网络层数的增多,训练集...
  • 主要介绍了简单易懂Pytorch实战实例VGG深度网络
  • 这部分是利用pytorch 进行实战,利用RNN(循环神经网络)来实现手写字体的识别问题 代码基于python3.7, pytorch 1.0,cuda 10.0 . PyTorch之循环神经网络实战 利用循环神经网络中的LSTM搭建网络实现手写字体的识别 ...
  • pytorch实战.zip

    2021-03-10 17:41:32
    内含数据集,完整代码,整个实现过程的全套文档讲解,总共1.6g,由于内容过多,所以用百度云给出,地址永久有效。 欢迎有这方面需要的小伙伴下载学习!
  • PyTorch 实战

    2019-10-27 12:21:55
    https://github.com/doudouhhh/Stanford_dogs-classification-by-CNN
  • 第一章 浅谈人工智能、神经网络和计算机视觉1.3.1 生物神经网络1.3.2 M-P模型 弱人工智能 强调人工 强人工智能 强调智能 机器学习也被称为统计学习方法,机器学习中的大部分学习算法都是基于统计学原理的。...
  • Pytorch实战(1)

    2021-10-20 20:03:14
    需要指出的是,本文第一部分的代码完全来自于Datawhale团队,感谢~~第二部分是自己独立搭建的第一个小的网络模型。...现在,我们通过一个基础实战案例,将第一部分所涉及的PyTorch入门知识串起来,便于大家加深
  • 总结了AlexNet的相关原理、网络结构,pytorch代码实现,以及如何创建自定义数据集,并对自定义花类数据集进行训练和测试。
  • 总结了ResNet的相关原理、网络结构,pytorch代码实现,并对自定义花类数据集进行训练和测试。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 12,713
精华内容 5,085
关键字:

pytorch实战