第九周机器学习周报
- 摘要
- Abstract
- 机器学习——Spatial Transformer
- 1.1 How to transform an image/feature map?(怎么做)
- 1.2 Interpolation(插值)
- 1.3 spatial Transformer的应用
- Pytorch学习
- 1. 线性层
- 2. 其他层的介绍
- 3. 搭建小实战以及Sequential
- 总结
摘要
本周主要对李宏毅的机器学习视频进行了学习,其中学习了CNN的一个特殊的网络结构——spatial Transformer,学会了其怎么完成平移、缩放以及旋转的原理以及期间了解到了Interpolation(插值)算法,最后还了解了其应用场景。此外,继续对Pytorch进行了学习,重点学习了线性层,了解了其改变shape的作用,然后还了解了其他层,例如,归一化层、循环层等特定的网络结构。最后,做了一个小项目,把CIFAR-10的Model复现出来,并学会了使用Sequential。
Abstract
This week, I mainly studied Li Hongyi’s machine learning videos, in which I learned about a special network structure of CNN - the spatial transformer. I learned how to complete the principles of translation, scaling, and rotation, and learned about the Interpolation algorithm during the process. Finally, I also learned about its application scenarios. In addition, I continued to study Pytorch, focusing on the linear layer and understanding its role in changing shape. I also learned about other layers, such as normalization layers, loop layers, and other specific network structures. Finally, a small project was completed to reproduce the CIFAR-10 model and learned how to use Sequential.
机器学习——Spatial Transformer
CNN对缩放(scaling)和旋转(rotation)不是不变的
原因如下
图片里面有一狗,如果把那个狗放大至满整个图片或者缩小到很小或
如果经过以上操作CNN都可以识别出来那个是狗,那CNN是scaling的。很显然CNN并不能做到,所以它不具备scaling invariance
如果可以识别出来,那只是因为你training data里面有大只的狗,也有小只的狗而已。因为它的 receptive field(感受野)是固定的,不会随着图像的改变而改变。
CNN也不是rotation invariance的
比如说你给它画写一个数字三3,然后你把这个数字2放倒,变成那个变成一个麦当劳。那对他来说,那个就是麦当劳而不是数字3,对它来说那个就是不一样的东西。
所以CNN不能够真的做到rotation invariance
CNN有一些translation invariance(移动不变性)
就是image里面的某一个物体,挪动一点点对他来说可能是一样。
但是如果今天这物体从左上角移到右下角,对CNN来说,是不一样。
所以CNN没有完全的translational invariance
假设我们现在要做数字的classification,那么下面图中就只能识别出5跟6
但如果我们把它放大或者缩小就未必了
那要怎么办呢?
所以就有了special transformer layer,它可以对input image做旋转缩放
也就是本来的5它会对这一小块呢做放大让,它变成下图所示。
再丢到CNN里面,CNN就可以认出他是5
6也是同理
所以special transformer layer也是一个neural network(相当于在CNN叠多了一个特别的layer)
它不止可以transform input image,其实也可以transform CNN的每一个feature map(特征图)
(因为其实一个feature map你也可以把它想成是一个image)
1.1 How to transform an image/feature map?(怎么做)
那我们要怎么对一个image做transform呢?
我们假设:
左边这个image是transform前的结果
右边这个image是transform后的结果
可以很明显的看出这个transform是把image由上往下呢做一个平移。
1.2 Interpolation(插值)
1.3 spatial Transformer的应用
Pytorch学习
1. 线性层
线性层(Linear Layer),在神经网络中也被称为全连接层或密集层,是神经网络中最基本的层之一。
它的主要作用是对输入数据进行线性变换,这一变换过程主要包括矩阵乘法和加上偏置。
线性层通过执行线性变换,将输入数据映射到一个新的空间,从而改变数据的维度,便于后续层进一步处理。
这一功能使得线性层在连接神经网络中的不同层次时起到关键作用
有助于模型对输入数据进行有效的特征提取和转换
其参数如下:
下图是非常经典的一张图,也就是我们一开始学习的全连接图(fully connected),其采用的就是一种线性连接的方式
in_feature与out_feature的图示如下所示:
这里in_feature的个数为d
out_feature个数为L
bias就是偏置值(就是加上去的那个值)【参数当为true的时候+bias 为false的时候不+bias】
如下图所示
其中k与b都是通过分布采样得到的
接下来我们进入代码实战:
我们要做的事情大致如下:
平铺操作实际上就是将H变为1
import torch
import torchvision
from torch import nn
from torch.utils.data import DataLoader
# 准备的测试数据集
test_data = torchvision.datasets.CIFAR10(root='./datasets', train=False, transform=torchvision.transforms.ToTensor(),
download=True)
# dataloader
test_loader = DataLoader(dataset=test_data, batch_size=64)
class Net(nn.Module):
def __init__(self):
super().__init__()
self.linear1 = nn.Linear(196608, 10) # 输入特征数为196608,输出特征数为10
def forward(self, input):
output = self.linear1(input)
return output
net = Net()
for data in test_loader:
imgs, labels = data
print(imgs.shape)
# -1是计算机自动计算,结果为196608
output = torch.reshape(imgs, (1, 1, 1, -1))
print(output.shape)
output = net(imgs)
print(output.shape)
我们除了使用reshape函数其实还可以使用flatten函数
import torch
import torchvision
from torch import nn
from torch.utils.data import DataLoader
# 准备的测试数据集
test_data = torchvision.datasets.CIFAR10(root='./datasets', train=False, transform=torchvision.transforms.ToTensor(),
download=True)
# dataloader
test_loader = DataLoader(dataset=test_data, batch_size=64)
class Net(nn.Module):
def __init__(self):
super().__init__()
self.linear1 = nn.Linear(196608, 10) # 输入特征数为196608,输出特征数为10
def forward(self, input):
output = self.linear1(input)
return output
net = Net()
for data in test_loader:
imgs, labels = data
print(imgs.shape)
# flatten
output = torch.flatten(imgs)
print(output.shape)
output = net(imgs)
print(output.shape)
理解误区:
最近越学越迷糊,没搞懂batch_size和channel以及H与W之间的变换关系
我以为reshape只是对一张图片做处理(以为只是改变了一个图片的形状)
其实reshape是对一组图片做处理的。
其实他们的关系如下:
原batch_size × 原channel × 原H × 原W = 变化后batch_size × 变化后channel × 变化后H × 变化后W
这就是为什么 (64,3,32,32)变为(1,1,1,W)的时候,W计算得出的结果算到为196608,因为64 × 3 × 32 × 32 = 1996608
我原来是理解错误的了,忘记了dataloader的data提取的是一组图片,我还奇怪一张图片怎么能有batch_size这个说法呢?
之前学习dataloader时候,我们定义了batch_size为多少就是封装了张图片多少进去,就是组成了一个图片集合(这个集合有4张图)
所以如下代码中,data对应imgs(加s证明不止一张图)
所以它的输出就是batch_size = 4
单纯输出一张图片是没有batch_size的
所以上面的reshape
其实就是把1组64张3232的3通道图片变为了1张有1196608的1通道图片
2. 其他层的介绍
以下层先做一个简单的了解,后续在进行深入学习
1、归一化层
Normalization是对输入数据进行处理
可以看到官网中,对归一化层的介绍:
其原理如下:
而在实际应用中我们只关注第一个参数,其他的默认即可
2、Recurrent Layers(循环层)
主要用于自然语言的处理,是一种特定的网络结构
3、Dropout层
在训练过程中,使用伯努利分布中的样本以概率p随机让输入张量的某些元素归零
用于防止过拟合
4、Transformer层
Transformer是一种基于自注意力机制的深度学习模型,主要用于自然语言处理,是一种特定结构的层
自注意力机制是Transformer的核心思想,它允许模型在处理序列数据时关注到不同位置的信息。
具体来说,自注意力机制通过计算序列中每个位置与其他位置之间的相关性,得到一个注意力权重分布,从而实现对不同位置信息的关注。
5、Sparse Layers(稀疏层)
在特定的网络中才需要用到,主要用于自然语言处理
3. 搭建小实战以及Sequential
关于Sequential实际上就是一个序列的概念:
下面我们会结合Sequential以及前面所学的东西做一个实战小项目
这个项目就是对CIFAR-10数据集进行一个分类的神经网络
来回顾一下CIFAR-10数据集的内容
CIFAR-10的模型结构如下:
注意:最大池化层不改变通道数,只改变尺寸(下图中,每次经过池化层,尺寸都变小)
32@ 表示 32channel
接下来,我们就用代码来实现这个模型
需要注意的是:
以此类推,后面的kernel size的padding与stride皆为2与1
同时我们也要注意有两个线性层:
from torch import nn
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv1 = nn.Conv2d(3, 32, 5, 1, 2)
self.pool1 = nn.MaxPool2d(2, 2)
self.conv2 = nn.Conv2d(32, 32, 5, 1, 2)
self.pool2 = nn.MaxPool2d(2, 2)
self.conv3 = nn.Conv2d(32, 64, 5, 1, 2)
self.pool3 = nn.MaxPool2d(2, 2)
self.flatten = nn.Flatten()
self.linear1 = nn.Linear(1024, 64)
self.linear2 = nn.Linear(64, 10)
def forward(self, x):
x = self.conv1(x)
x = self.pool1(x)
x = self.conv2(x)
x = self.pool2(x)
x = self.conv3(x)
x = self.pool3(x)
x = self.flatten(x)
x = self.linear1(x)
x = self.linear2(x)
return x
net = Net()
print(net)
可以看到我们的网络结构搭建完成了
接下来,我们随便给一个输入模仿是图片,代码如下:
import torch
from torch import nn
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv1 = nn.Conv2d(3, 32, 5, 1, 2)
self.pool1 = nn.MaxPool2d(2, 2)
self.conv2 = nn.Conv2d(32, 32, 5, 1, 2)
self.pool2 = nn.MaxPool2d(2, 2)
self.conv3 = nn.Conv2d(32, 64, 5, 1, 2)
self.pool3 = nn.MaxPool2d(2, 2)
self.flatten = nn.Flatten()
self.linear1 = nn.Linear(1024, 64)
self.linear2 = nn.Linear(64, 10)
def forward(self, x):
x = self.conv1(x)
x = self.pool1(x)
x = self.conv2(x)
x = self.pool2(x)
x = self.conv3(x)
x = self.pool3(x)
x = self.flatten(x)
x = self.linear1(x)
x = self.linear2(x)
return x
net = Net()
# 输入 batch_size = 64 , channel = 3 , H = 32 , W = 32
input = torch.ones((64, 3, 32, 32))
output = net(input)
print(output)
可以看到输出结果如下:
flatten的效果就是平铺
我们把层数定义到flatten,再输出,可以看到宽度变为了1024
我们还可以在tensorboard上看到这个网络结构
代码如下:
import torch
from torch import nn
from torch.utils.tensorboard import SummaryWriter
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv1 = nn.Conv2d(3, 32, 5, 1, 2)
self.pool1 = nn.MaxPool2d(2, 2)
self.conv2 = nn.Conv2d(32, 32, 5, 1, 2)
self.pool2 = nn.MaxPool2d(2, 2)
self.conv3 = nn.Conv2d(32, 64, 5, 1, 2)
self.pool3 = nn.MaxPool2d(2, 2)
self.flatten = nn.Flatten()
self.linear1 = nn.Linear(1024, 64)
self.linear2 = nn.Linear(64, 10)
def forward(self, x):
x = self.conv1(x)
x = self.pool1(x)
x = self.conv2(x)
x = self.pool2(x)
x = self.conv3(x)
x = self.pool3(x)
x = self.flatten(x)
return x
# 引入tensorboard
writer = SummaryWriter("logs_CIFAR-10_model")
net = Net()
# 输入 batch_size = 64 , channel = 3 , H = 32 , W = 32
input = torch.ones((64, 3, 32, 32))
output = net(input)
print(output.shape)
writer.add_graph(net, input)
writer.close()
在终端中启动tensorboard
tensorboard --logdir=logs_CIFAR-10_model --port=6007
可以看到双击net后,这个网络结构就展示出来,非常可观
还可以放大查看细节
前面我们提到了Sequential,于是我们用其来实现以上功能
import torch
from torch import nn
from torch.utils.tensorboard import SummaryWriter
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.model1 = nn.Sequential(
nn.Conv2d(3, 32, 5, 1, 2),
nn.MaxPool2d(2, 2),
nn.Conv2d(32, 32, 5, 1, 2),
nn.MaxPool2d(2, 2),
nn.Conv2d(32, 64, 5, 1, 2),
nn.MaxPool2d(2, 2),
nn.Flatten(),
nn.Linear(1024, 64),
nn.Linear(64, 10),
)
def forward(self, x):
x = self.model1(x)
return x
# 引入tensorboard
writer = SummaryWriter("logs_CIFAR-10_model")
net = Net()
# 输入 batch_size = 64 , channel = 3 , H = 32 , W = 32
input = torch.ones((64, 3, 32, 32))
output = net(input)
print(output.shape)
writer.add_graph(net, input)
writer.close()
可以看到使用Sequential后,代码变得简洁、高效,这就是Sequential的好处
总结
因为开学需要筹划的原因,这一周的进度比较缓慢。希望开学后能够加快进度学习。
这一周主要在机器学习部分主要学习了Spatial Transformer,因为我们CNN不能自行对图片进行放缩、旋转、平移来更精准的识别图片中的物体,它只能所见即所得,所以我们需要引入Spatial Transformer层来帮助我们完成这些事情,以保证更高识别的准确度。Spatial Transformer主要是通调整全连接中的W(权重)来完成对图像处理的,也可以理解为其中有x、y分别对应pixel中的索引,然后通过NN得出的六个参数,来完成对图片的处理。然后为了解决6个参数不为整数时,产生的结果采用四舍五入而导致Gradient descent失效的问题,引入了interpolation(插值)算法,使得其l层对应的索引值不再重复,这样这个网络Gradient不为0,就可以训练了。最后还引入了门牌号识别,了解到了这个层的实际应用。
在Pytorch学习部分,主要对线性层进行学习,线性层主要有助于模型对输入数据进行有效的特征提取和转换,其size中的H(in)要等于1,然后还纠正了之前在dataloader中对batch_size的理解错误,还补充了池化层不改变通道数的规则。然后还对一些在特定场景下才要用到的层进行了解,如在自然语言处理时需要用到Recurrent Layers(循环层)、在物体识别中需要用到Transformer层等
最后还结合前面的知识,搭建了CIFAR-10的Model,学习了使用Sequential后,代码变得简洁、高效,提升了自己的代码能力。
因为下一周的周三要开学,所以下一周学的内容可能会少一点,计划了解一下注意力机制(self-attention)是什么,然后Pytorch继续学习反向传播的代码实战。然后开学全力投入到学习中,开学后争取把注意力机制学完,Pytorch争取能做一个可以物体识别的项目,前面的知识也有很多遗忘了,开学也要多回顾。