最近在学习pytorch,在学过了linear分类以后尝试入门cnn,但是网上的教程基本都是使用别人标注好的手写数据集。于是我看了下读入图片的数据格式,发现是一个n*1*size*size的数组,了解到这个基本情况以后,我们可以尝试不用导入mnist数据集而使用自己的训练模型来帮助我们更好的理解相关参数的意义。
我们主要使用pytorch包装好的nn.Module来训练我们的神经网络,手工做的暂不做讨论,同时我也推荐使用这种方式来训练神经网络。
由于简书不支持代码块的引入,我会把代码放在文末链接。
本教程适用于pytorch 0.3.0 python 3.6.5
首先在开头把需要的包引入
随后我们写下第一行:
torch.set_default_tensor_type("torch.DoubleTensor")
如果没有这句代码pytorch就会提示RuntimeError: Expected object of type torch.DoubleTensor but found type torch.FloatTensor for argument #2 'weight',大家可以试试去掉这一句
随后,我们就要开始定义我们的“训练模型了”
trainx就是两张要作为输入的5*5的图片,一个是1,一个是2。我先解释为什么有一个数字是0.0,因为pytorch要求均是小数格式,加了一个0.0,整个数组就会自动转换成为float了。trainy也有两组数据,第一组输出[1,0]表示输出的是1,第二组输出的是[0,1]表示输出的是2,10的话就往上推广即可。至此我们的训练数据就准备好了。按照前面所说是一个n*1*size*size的数组,满足这个条件就可以了,因为从mnist里面读取进来的数据也是这样的。
准备好训练数据以后,就要开始定义最重要的类了:
先来讲解__init__ 的内容:
第一步是执行父类的构造函数,没毛病
13行,定义第一个卷积层,我比较推荐使用nn.Sequential方式,这样当在调用的时候conv1(x),他就会自动按照顺序执行括号里的步骤:卷积归一激活池化
18行定义第二个卷积层,同上
23行定义一层全连接层,输出2个结果,即[1,0]还是[0,1]的形式
关键我要详细说说前两个卷积层的结构
第一个卷积层,1,16,其含义是我们将会给他输入一张5*5的图片,他会输出16个特征层,什么是特征层呢?类似下图
特征层就是左边第一个conv,看到了吧【当然这张图是我在网上找来参考的】,一张图片连了16根线到16个conv层上,这就是第一个步骤,代码中我们定义了kernel_size=5,padding=1,那么经过这一步以后,一张5*5的图片会输出3*3的一个结果
所谓padding,就是在图片周围补上一圈其他的数,kernel就是视野大小,如果不太清楚这两个概念的可以百度一下补补概念
在经过卷积以后,5*5变成了3*3,随后是归一化和激活,在最后一步是最大池化,池化的kernel为2,那么一个3*3的会变为2*2的输出
那么经过self.conv1函数以后,现在得到了16张2*2的特征图
那么给下一层的输入就是16张2*2的特征图了,第二个卷积层就要对输入作出一点改变了
我们可以看到,第二个卷积层接受来自上一层的16个特征图输入,同时输出32个特征图,那么此时kernel_size就要按照2*2来设计了,我们可以设置 kernel_size=2,padding=1,那么输出就为32个3*3的特征图,再经过池化以后,得到32个1*1的输出
那么最后一层就是一个全连接层把32个输出连接到2个输出节点来,这就是整个网络的结构
网络定义好了,我们接下来就要定义数据正向传播的forward函数,pytorch内部拥有自动求导机制,所以求导的机制不用我们特别理解,我们只需定义好正向传播即可
我们依次来解说:
第一步,直接把x放入conv1中运算
第二步,接着把第一层的输出放到第二层中运算
第三部,最重要的,out.view,在out=self.conv2(out),经过第二层卷积操作以后,现在我们得到的是一个2*32*1*1的矩阵,我们若要全连接,则要把矩阵从2*32*1*1化为2*32,那么我们就要用到view函数
其实pytorch和numpy里面关于矩阵reshape的函数很多,视情况使用。
在我们统一了矩阵以后,就可以接着把结果放入FullConnection层中进行运算了,函数的最后返回结果。
好了,这就是CLASS的核心定义,我们开始训练这个神经网络。
好了那大概就是这样了~滑稽
代码地址 点我进入!!!!!
有问题希望一起讨论。
码字不易,如果你觉得对你有帮助,希望可以动手赞助一下~你的支持是更新的动力