Pytorch入门笔记:CNN卷积神经网络(哔哩哔哩刘二大人)

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()

之前一直搞不懂全连接层到底是啥,为什么叫全连接层,刘老师在视频里讲清楚了,全连接层就是类似上面这种的线性层连接的网络,那么为啥叫全连接呢?

上图所示,任意两组节点之间都会含有一个权重,也就是上下层的节点之间是有联系的,全相联了所以叫做全连接,线性层就是全连接层。

 二维卷积:

        假如输入一个这个,当成一个R\in1*28*28的张量。

把这个图像通过卷积层(这个卷积层保留空间特征,因为全连接层把这个图像直接给弄成了一长串,做成全连接之后丧失了一些原有的空间信息),

 

 上图图片卷积操作需要明白输入和输出到底是什么样的维度。卷积出来依然是3维

 

 在进行Subsampling的时候,通道数Channels是没有变化的。

 

  图像的结构:

如图所示:这张可爱的小猫照片,作为输入是有3个Channel的。

他是个R ^{3*width*height},其实这样看来Output Channel也和普通的网络差不多,也就是个卷积操作。做卷积之后,通道数可能会变,高度宽度也可能会变。需要注意,输出通道里的每一个值,比如变成1*1得了,这里的像素值包含了计算的时候要拿patch里的所有像素值和权重相乘,乘完之后进行求和,包含了pacth里面的所有信息,因为这是用这些信息进行加权求和的,包含了所有信息,再对这些Output Channel的输出进行再次卷积,不断把这些信息进行融合,只要权重选的合适,就代表了把某种特征的信息扫描出来,满足这个特征算出来就比较大,不满足就比较小。

( 插播一则自己的小疑惑,刚接触AI相关的知识,感觉真的好玄学~狗头~,这是从另一种角度来解决问题的,比如Transformer和Bert,操作也就那回事,但是为啥他就能,干出那么多的事情,好神奇啊,还有这个神经网络也是,就通过一个损失函数梯度下降,这就可以找到合适的权重了,啥都不用管可是也解释不清,它就是能完成这么一个事情,可能是我刚开始看接触的太少了,到现在也没看到什么文章是证明Transformer和Bert那些操作是怎样生效的,哈哈哈好神奇。不是很能理解,和同学讨论的时候也是说把它当个模型就好了)

卷积的运算过程:

        这个网上很多写的比较不错的动图,我这里只截图刘二老师的视频PPT。

 

 上图是单通道的一个卷积,看红色标注部分,上图中的Kernel对346126167这九个格子,分别相乘,然后进行相加,得到的就是211,放在了箭头所示位置。同样的,这个Kernel继续移动,我们可以看到,这样Output降维了。但是在实际卷积的时候,上面那只可爱的小猫,是3通道的。

并且可能不止3个通道,以3通道的为例,展示一下多通道怎么操作。

(卷积的过程和上述一样)

每一个通道配一个核。

刘二老师的视频真的强推。注意观察维度哦,Channel = 3(不同颜色的)width = 5 height = 5

经过3 * 3的卷积核之后维度变成了3 * 3,很好理解吧,左右上下去掉了嘛。然后相加。

下图中下半部分就是将3个Channel换了个视角,注意,在相加的过程中channel变成了1~

 

 

上面已经介绍过了维度的变化(再次为刘二老师打call)

那么实际上卷积并不是把它变成1个channel,而是下图所示的操作,一个filter对应的上面那样的操作,得到一个1channel的薄片片,在卷积的时候有很多个filter。(然后就是套娃,套前面的娃)。这里提醒一下,filter嘛,这个卷积核的个数和通道的个数是一样的,前面也提到了,就比如说filter1就有n个kernal,这种卷积核的总数(filter的总数)和输出通道的总数是一样的,图里面很容易看出来。

 在得到了那个1channel的薄框框之后,进行一个Cat(拼接操作),如图所示拼到一起了。额,感觉看文字就很恶心,多看看图有助于理解。

上面这个图表示的是,filter有m个嘛,把filter堆在一起了,变成一个4维的张量(就向量差不多理解就行,只是维度不一样)

import torch
in_channels, out_channels= 5, 10 
#上文中的n和m

width, height = 100, 100
#图像的大小

kernel_size = 3
#卷积核的大小

batch_size = 1
#pytorch里面所有输入数据必须是小批量,图像是n*w*h的,但是前面要加一个batch


input = torch.randn(batch_size,
                    in_channels,
                    width,
                    height)
#从正态分布进行采样的随机数
#正态分布采样的随机数

conv_layer = torch.nn.Conv2d(in_channels,
                            out_channels,
                            kernel_size=kernel_size)
#卷积层的module
#输入通道的数量,输出通道的数量和卷积核的大小

output = conv_layer(input)

print(input.shape)
print(output.shape)
print(conv_layer.weight.shape)
torch.Size([1, 5, 100, 100])
torch.Size([1, 10, 98, 98])
torch.Size([10, 5, 3, 3])

上述代码段上上一个代码的运行结果,主要是观察每个维度对应的什么。

Padding:

        

 这个很简单,就是说外面填充一圈嘛,保持output和input唯独相等啊。easy

也不是什么时候都需要padding,也不是说padding一圈就好了,具体情况具体分析。

也可能不用padding,也可以padding两圈。

import torch

input = [3, 4, 6, 5, 7, 2, 4, 6, 8, 2, 1, 6, 7, 8, 4, 9, 7, 4, 6, 2, 3, 7, 5, 4, 1]
input = torch.Tensor(input).view(1, 1, 5, 5)
conv_layer = torch.nn.Conv2d(1, 1, kernel_size=3, 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(input)
print(output)

#下面是输出结果

tensor([[[[ 91., 168., 224., 215., 127.],
          [114., 211., 295., 262., 149.],
          [192., 259., 282., 214., 122.],
          [194., 251., 253., 169.,  86.],
          [ 96., 112., 110.,  68.,  31.]]]], grad_fn=<ThnnConv2DBackward>)

 这段代码描述的是下图所示操作,输出都是一模一样的。

 也可以在运算的时候搞一个step = 2

 从第一个框框到第二个框框的意思。这样的好处是,可以有效地减少宽度。只需要在conv_layer里面添加一个参数,stride,点开该Conv2d的函数看下,可以看到参数如下,有这么些个,改一下stride = 2就可以了。


 下采样:

        用得比较多的是MaxPooling,是没有权重的。

2 * 2的MaxPooling默认stride = 2(默认的哦)

 分成不同颜色的4组,在这里面找到最大的,然后拼成这个。所以在MaxPooling的时候,只能在Channel里面做MaxPooling,MaxPooling通道数量是不变的,。

import torch
input = [3,4,6,5, 2,4,6,8, 1,6,7,8, 9,7,4,6, ]
input = torch.Tensor(input).view(1, 1, 4, 4)
maxpooling_layer = torch.nn.MaxPool2d(kernel_size=2)
output = maxpooling_layer(input)
print(output)

 上面是MaxPooling层的代码。


 下面来实现一下简单的神经网络来实现MINIST

下面就是维度考试了。

 听了刘老师的课之后,这些维度自然不算什么问题,简单回顾一下(我怕我到时候忘记哈哈哈,还可以回来看看),首先输入的是一个图片,1channel的,28*28的一个图片,卷积层的C_{in}是输入的通道数,C_{out}是出去之后要几个Channel,和filter的个数保持一致。所以输出之后10个channel(我喜欢把channel叫成薄片,因为就薄薄一层和纸一样),24是啥呢,意思就是5 * 5 的filter少两圈,左右各两圈就少了4列,上下两圈就少了4行,也就是说width和length少了4.

Pooling Layer没啥好说的,你来啥玩意儿对半砍就完了,然后又经过一个卷积层,又经过一个Pooling。

这时候稍稍注意,batch,20,4,4,这一层之后,20*4*4 = 320,经过输出之后映射成10。(这个我不是很懂具体怎么弄的)

神经网络感觉这里是比较麻烦的一个点了,每个都要保证维度相对应。

总结:卷积层输入的channel要和上层保持对应,输出的,爷随意

        池化层压根不在乎,来啥玩意儿全对半砍

        最在乎的是最后的LinearLayer,可以提前计算好然后再给参数。


 把前面的神经网络改成CNN网络


将上述问题迁移到显卡上面。

model = Net()
device = torch.device( "cuda:0" if torch.cuda.is_available() else "cpu" )
model.to(device)

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值