1.卷積層
1.1torch.nn.Conv2d()類式接口
1 torch.nn.Conv2d(self, in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True))
參數:
- in_channel:輸入數據的通道數,例RGB圖片通道數為3;
- out_channel:輸出數據的通道數,也就是kernel數量;
- kernel_size: 卷積核大小,可以是int,或tuple;kernel_size=2,意味着卷積大小(2,2),kernel_size=(2,3),意味着卷積大小(2,3)即非正方形卷積
- stride:步長,默認為1,與kernel_size類似,stride=2,意味着步長上下左右掃描皆為2, stride=(2,3),左右掃描步長為2,上下為3;
- padding:零填充
1 import torch 2 import torch.nn as nn 3 4 x=torch.rand(1,1,28,28) #batch, channel, height, width 5 layer=nn.Conv2d(1,3,kernel_size=3,stride=2,padding=1) #in_channel(和上面x中的channel數量一致), out_channel(kernel個數) 6 7 out=layer.forward(x) #或者直接out=layer(x) 8 print(out.shape) #torch.Size([1, 3, 14, 14]) 1指一張圖片,3指三個kernel,14*14指圖片大小
- 第五行layer的相關屬性:
- layer.weight.shape = torch.Size([3,1,3,3]) 第一個3指out_channel,即輸出數據的通道數(kernel個數),第二個1指in_channel,即輸入數據的通道數,這個值必須和x的channel數目一致。(Tip:前兩個參數順序是和Conv2d函數的前兩個參數順序相反的)
- layer.bias.shape = torch.Size([3]) 這個3指kernel個數,不同的通道共用一個偏置。
- out輸出維度的計算:$(n+2p)*(n+2p) $ 與 $f*f$ 做卷積操作= $\left \lfloor \frac{n+2p}{s}+1 \right \rfloor *\left \lfloor \frac{n+2p}{s}+1 \right \rfloor $
- n表示圖片尺寸,p表示padding,f表示kernel尺寸,s表示slide步長,(28+2-3)/2+1=14.5,向下取整,即14
1.2F.conv2d()函數式接口
PyTorch里一般小寫的都是函數式的接口,相應的大寫的是類式接口。函數式的更加low-level一些,如果不需要做特別復雜的配置只要用類式接口即可。
1 import torch 2 from torch.nn import functional as F 3 4 #手動定義卷積核(weight)和偏置 5 w = torch.rand(16, 3, 5, 5) #16種3通道的5*5卷積核 6 b = torch.rand(16) 7 8 #定義輸入樣本 9 x = torch.randn(1, 3, 28, 28) #1張3通道的28*28的圖像 10 11 #2D卷積得到輸出 12 out = F.conv2d(x, w, b, stride=1, padding=1) 13 print(out.shape) #torch.Size([1, 16, 26, 26]) 14 15 out = F.conv2d(x, w, b, stride=2, padding=2) 16 print(out.shape) #torch.Size([1, 16, 14, 14])
2.池化層Pooling(下采樣)
1 torch.nn.MaxPool2d(kernel_size, stride=None, padding=0, dilation=1, return_indices=False, ceil_mode=False)
參數:
- kernel_size(int or tuple) - max pooling的窗口大小,
- stride(int or tuple, optional) - max pooling的窗口移動的步長。默認值是kernel_size
- padding(int or tuple, optional) - 輸入的每一條邊補充0的層數
- dilation(int or tuple, optional) – 一個控制窗口中元素步幅的參數
- return_indices - 如果等於True,會返回輸出最大值的序號,對於上采樣操作會有幫助
- ceil_mode - 如果等於True,計算輸出信號大小的時候,會使用向上取整,代替默認的向下取整的操作
接着上面卷積運算得到的1張16通道的14*14的圖像,在此基礎上做池化。
torch.MaxPool2d類式接口
1 x=out #torch.Size([1, 16, 14, 14]) 2 layer=nn.MaxPool2d(2,stride=2) #池化層(池化核為2*2,步長為2),最大池化 3 4 out=layer(x) 5 print(out.shape) #torch.Size([1, 16, 7, 7])
F.avg_pool2d()函數式接口
1 x = out #torch.Size([1, 16, 14, 14]) 2 out = F.avg_pool2d(x, 2, stride=2) 3 print(out.shape) #torch.Size([1, 16, 7, 7])
Tip:池化后通道數不變。
3.upsample(上采樣)

1 F.interpolate(input, size=None, scale_factor=None, mode='nearest', align_corners=None)
參數:
- size(int):輸出的spatial大小;
- scale_factor(float): spatial尺寸的縮放因子;
- mode(string):上采樣算法:nearest,linear,bilinear,trilinear,area,默認nearest;
- align_corners(bool, optional):如果align_corners=True,則對齊input和output的角點像素,只會對 mode=linear, bilinear 和 trilinear 有作用。默認是 False。
1 x = out #torch.Size([1, 16, 7, 7]) 2 3 out = F.interpolate(x, scale_factor=2, mode='nearest') #向上采樣,放大2倍,最近插值 4 print(out.shape) #torch.Size([1, 16, 14, 14])
4.RELU激活函數
4.1torch.nn.RELU()類式接口
1 x = out #torch.Size([1, 16, 14, 14]) 2 3 layer = nn.ReLU(inplace=True) #ReLU激活,inplace=True表示直接覆蓋掉ReLU目標的內存空間 4 out = layer(x) 5 print(out.shape) #torch.Size([1, 16, 14, 14])
4.2F.relu()函數式接口
1 x = out #torch.Size([1, 16, 14, 14]) 2 3 out = F.relu(x) 4 print(x.shape) #torch.Size([1, 16, 14, 14])
5.Batch Norm
歸一化可以使代價函數平均起來看更對稱,使用梯度下降法更方便。
通常分為兩步:調整均值、方差歸一化
5.1Batch Norm
一個Batch的圖像數據shape為[樣本數N, 通道數C, 高度H, 寬度W],將其最后兩個維度flatten,得到的是[N, C, H*W],標准的Batch Normalization就是在通道channel這個維度上進行移動,對所有樣本的所有值求均值和方差,所以有幾個通道,得到的就是幾個均值和方差。
eg.[6, 3, 784]會生成[3],代表當前batch中每一個channel的特征均值,3個channel有3個均值和3個方差,只保留了channel維度,所以是[3]。
5.2Layer Norm
樣本N的維度上滑動,對每個樣本的所有通道的所有值求均值和方差,所以一個Batch有幾個樣本實例,得到的就是幾個均值和方差。
eg.[6, 3, 784]會生成[6]
5.3Instance Norm
在樣本N和通道C兩個維度上滑動,對Batch中的N個樣本里的每個樣本n,和C個通道里的每個樣本c,其組合[n, c]求對應的所有值的均值和方差,所以得到的是N*C個均值和方差。
5.4Batch Norm詳解
輸入數據是6張3通道784個像素點的數據,將其分到三個通道上,在每個通道上也就是[6, 784]的數據,然后分別得到和通道數一樣多的統計數據均值μ和方差σ,將每個像素值減去μ除以σ也就變換到了接近N(0,1)的分布,后面又使用參數β和γ將其變換到接近N(β,γ)的分布。

Tip:μ和σ只是樣本中的統計數據,是沒有梯度信息的,不過會保存在運行時參數里。而γ和β屬於要訓練的參數,他們是有梯度信息的。
正式計算:

nn.BatchNorm1d()
1 import torch 2 from torch import nn 3 4 x = torch.rand(100, 16, 784) #100張16通道784像素點的數據,均勻分布 5 6 layer = nn.BatchNorm1d(16) #傳入通道數,因為H和W已經flatten過了,所以用1d 7 out = layer(x) 8 9 print(layer.running_mean) 10 #tensor([0.0499, 0.0501, 0.0501, 0.0501, 0.0501, 0.0502, 0.0500, 0.0499, 0.0499, 11 # 0.0501, 0.0500, 0.0500, 0.0500, 0.0501, 0.0500, 0.0500]) 12 print(layer.running_var) 13 #tensor([0.9083, 0.9083, 0.9083, 0.9084, 0.9083, 0.9083, 0.9084, 0.9083, 0.9083, 14 # 0.9083, 0.9083, 0.9083, 0.9084, 0.9084, 0.9083, 0.9083])
Tip:layer.running_mean和layer.running_var得到的是全局的均值和方差,不是當前Batch上的,只不過這里只跑了一個Batch而已所以它就是這個Batch上的。
nn.BatchNorm2d()
1 import torch 2 from torch import nn 3 4 x = torch.rand(1, 16, 7, 7) #1張16通道的7*7的圖像 5 6 layer = nn.BatchNorm2d(16) #傳入通道數(必須和上面的通道數目一致) 7 out = layer(x) 8 9 print(out.shape) #torch.Size([1, 16, 7, 7]) 10 print(layer.running_mean) 11 print(layer.running_var) 12 print(layer.weight.shape) #torch.Size([16])對應上面的γ 13 print(layer.bias.shape) #torch.Size([16])對應上面的β 14 print(vars(layer)) #查看網絡中一個層上的所有參數 15 # {'training': True, 16 # '_parameters': 17 # OrderedDict([('weight', Parameter containing: 18 # tensor([1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.], requires_grad=True)), 19 # ('bias', Parameter containing: 20 # tensor([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], requires_grad=True))]), 21 # '_buffers': 22 # OrderedDict([('running_mean', tensor([0.0527, 0.0616, 0.0513, 0.0488, 0.0484, 0.0510, 0.0590, 0.0459, 0.0448, 0.0586, 0.0535, 0.0464, 0.0581, 0.0481, 0.0420, 0.0549])), 23 # ('running_var', tensor([0.9089, 0.9075, 0.9082, 0.9079, 0.9096, 0.9098, 0.9079, 0.9086, 0.9081, 0.9075, 0.9052, 0.9081, 0.9093, 0.9075, 0.9086, 0.9073])), 24 # ('num_batches_tracked', tensor(1))]), 25 # '_backward_hooks': OrderedDict(), 26 # '_forward_hooks': OrderedDict(), 27 # '_forward_pre_hooks': OrderedDict(), 28 # '_state_dict_hooks': OrderedDict(), 29 # '_load_state_dict_pre_hooks': OrderedDict(), 30 # '_modules': OrderedDict(), 31 # 'num_features': 16, 32 # 'eps': 1e-05, 33 # 'momentum': 0.1, 34 # 'affine': True, 35 # 'track_running_stats': True}
Tip:
- layer.weight和layer.bias是當前batch上的;
-
如果在定義層時使用了參數affine=False,那么就是固定γ=1和β=0不自動學習,這時參數layer.weight和layer.bias將是None。
5.5Train和Test
類似於Dropout,Batch Normalization在訓練和測試時的行為不同。
測試模式下,$\mu$和$\sigma ^{2}$使用訓練集得到的全局$\mu$和$\sigma ^{2}$,歸一化前調用layer.eval()設置Test模式。

