刚开始学AI,几乎没用过Python,听说PyTorch发展不错,且比TensorFlow更容易上手,调试也更简单,那就PyTorch吧。
在PyTorch官网文档指导下,安装好了PyTorch,接着就看官网的,这篇tutorial写得很不错,文字部分基本都能理解,但是到了第一个例子,虽然是及其简单的AI示例,但我看代码还是感觉吃力,又查了不少资料,才大概理解,这里就算是做了个笔记和总结吧。
示例代码是这样的:
import torch
import torch.nn as nn
import torch.nn.functional as F
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
# 1 input image channel, 6 output channels, 3x3 square convolution
# kernel
self.conv1 = nn.Conv2d(1, 6, 3)
self.conv2 = nn.Conv2d(6, 16, 3)
# an affine operation: y = Wx + b
self.fc1 = nn.Linear(16 * 6 * 6, 120) # 6*6 from image dimension
self.fc2 = nn.Linear(120, 84)
self.fc3 = nn.Linear(84, 10)
def forward(self, x):
# Max pooling over a (2, 2) window
x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2))
# If the size is a square you can only specify a single number
x = F.max_pool2d(F.relu(self.conv2(x)), 2)
x = x.view(-1, self.num_flat_features(x))
x = F.relu(self.fc1(x))
x = F.relu(self.fc2(x))
x = self.fc3(x)
return x
def num_flat_features(self, x):
size = x.size()[1:] # all dimensions except the batch dimension
num_features = 1
for s in size:
num_features *= s
return num_features
net = Net()
print(net)结合图片一起看
首先,要注意看示例里面的那个图,仔细看图发现代码里的参数和图片里面图形个数是对应的:
这样对照起来,就知道代码是在定义一个什么结构的网络了。
2. 卷积层(Convolution Layer) Kernel定义
# 1 input image channel, 6 output channels, 3x3 square convolution
# kernel
self.conv1 = nn.Conv2d(1, 6, 3)
self.conv2 = nn.Conv2d(6, 16, 3)
作为一个CNN,提取特征就要定义卷积核,PyTorch的nn.Conv2d就是定义一层卷积层,原数据是二维的,所以是Conv2d。
第一层卷积层nn.Conv2d(1, 6, 3)第一个参数值1,表示输入一个二维数组;第二个参数值6,表示提取6个特征,得到6个feature map,或者说是activation map;第三个参数值3,表示卷积核是一个3*3的矩阵。第二层卷积层的理解也类似。
至于卷积核具体是什么值,似乎是PyTorch自动设定并调优的,这个原理还需要找资料深入了解下。
卷积层的结构定义就完了。PyTorch确实简洁明了。
3. 全连接层(Fully Connected Layer) 定义
self.fc1 = nn.Linear(16 * 6 * 6, 120) # 6*6 from image dimension
self.fc2 = nn.Linear(120, 84)
self.fc3 = nn.Linear(84, 10)
这个例子是个线性模型,全连接层定义了三层线性转换。
nn.Linear(16 * 6 * 6, 120), 第一个参数的取值是来自于卷积层输出了16个feature map, 每个feature map是66的二维数据,16*6*6就是把这16个二维数组拍扁了后一维向量的size,第二个参数值120是说经过第一层全连接转换后得到120个神经元。第二层,84个神经元;第三层,10个神经元。这个线性模型的全连接层结构就定义好了。这么简单?那些权重啊Bias啊什么的呢怎么设定的?原来,Linear有三个参数,分别是输入特征数,输出特征数以及是否使用偏置(默认为True)。默认情况下Linear会自动生成权重参数和偏置,所以在模型中不需要单独定义权重参数,并且Linear提供比原先自定义权重参数时使用的randn随机正太分布更好的参数初始化方法。简直碉堡了!
4. Convolution Layer和Fully Connected Layer的对接
Convolution Layer输出了多个feature map,每个feature map都是二维的。而Fully Connected Layer的输入是一维向量。那Convolution Layer和Fully Connected Layer是怎么对接到一起的?关键看下面这行代码:
x = x.view(-1, self.num_flat_features(x))
通过这个view()函数我们把二维数据变成了一维向量。