卷積神經網絡中所有的層結構都可以通過 nn這個包調用。
1.卷積層nn.Conv2d()
卷積在 pytorch 中有兩種方式,一種是
torch.nn.Conv2d()
,一種是
torch.nn.functional.conv2d()
,這兩種形式本質都是使用一個卷積操作。
這兩種形式的卷積對于輸入的要求都是一樣的,首先需要輸入是一個
torch.autograd.Variable()
的類型,大小是
(batch, channel, H, W)
,其中
batch
表示輸入的一批資料的數目,第二個是輸入的通道數,一般一張彩色的圖檔是 3,灰階圖是 1,而卷積網絡過程中的通道數比較大,會出現幾十到幾百的通道數,H 和 W 表示輸入圖檔的高度和寬度,
比如一個 batch 是 32 張圖檔,每張圖檔是 3 通道,高和寬分别是 50 和 100,那麼輸入的大小就是 (32, 3, 50, 100)
torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True)
nn.Conv2d()
就是PyTorch中的卷積子產品了,
裡面常用的參數有5個,分别是
in_channels,out_channels,kernel_size,stride,padding,
除此之外還有參數
dilation,groups,bias
。下面來解釋每個參數的含義。
in_channels
對應的是輸入資料體的深度;
out_channels
表示輸出資料體的深度;
kernel_size
表示濾波器(卷積核)的大小,可以使用一個數字來表示高和寬相同的卷積核,比如 kernel_size=3,也可以使用不同的數字來表示高和寬不同的卷積核,比如 kernel_size=(3,2);
stride
表示滑動的步長;
padding=0
表示四周不進行零填充,
padding=1
表示四周進行1個像素點的零填充;
bias
是一個布爾值,
預設 bias=True
,表示使用偏置;
groups
表示輸出資料體深度上和輸入資料體深度上的聯系,預設
groups=1
,也就是所有的輸出和輸入都是相關聯的,如果 groups=2,這表示輸入的深度被分割成兩份,輸出的深度也被分割成兩份,它們之間分别對應起來,是以要求輸出和輸入都必須要能被 groups整除;
dilation
表示卷積對于輸入資料體的空間間
隔,預設 dilation=1,
import numpy as np
import torch
from torch import nn
from torch.autograd import Variable
import torch.nn.functional as F
import matplotlib.pyplot as plt
from PIL import Image
import os
os.environ['KMP_DUPLICATE_LIB_OK'] = 'TRUE'
im = Image.open('cat.png').convert('L') # 讀入一張灰階圖檔
im = np.array(im, dtype='float32') # 将其轉換為一個矩陣
plt.imshow(im.astype('uint8'), cmap='gray') # 顯示圖像,輸出為灰階圖
plt.show()
# 将圖檔矩陣轉化為 pytorch tensor,并适配卷積輸入的要求
im = torch.from_numpy(im.reshape((1, 1, im.shape[0], im.shape[1])))
# 使用 nn.Conv2d
conv1 = nn.Conv2d(1, 1, 3, bias=False) # 定義卷積,輸入資料深度1,輸出深度1,卷積核大小3*3,不設定偏置
sobel_kernel = np.array([[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]], dtype='float32') # 定義邊緣檢測算子大小
sobel_kernel = sobel_kernel.reshape((1, 1, 3, 3)) # 1個卷積核,深度為1,大小3*3
conv1.weight.data = torch.from_numpy(sobel_kernel) # 給卷積的卷積核指派
edge1 = conv1(Variable(im)) # 卷積作用在圖檔上
edge1 = edge1.data.squeeze().numpy() # 将輸出轉化為圖檔格式
# 顯示邊緣檢測結果
plt.imshow(edge1, cmap='gray')
plt.show()
# 使用 F.conv2d
sobel_kernel = np.array([[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]], dtype='float32') # 定義輪廓檢測算子
sobel_kernel = sobel_kernel.reshape((1, 1, 3, 3)) # 适配卷積的輸入輸出
weight = Variable(torch.from_numpy(sobel_kernel))
edge2 = F.conv2d(Variable(im), weight) # 作用在圖檔上
edge2 = edge2.data.squeeze().numpy() # 将輸出轉換為圖檔的格式
plt.imshow(edge2, cmap='gray')
2.池化層
卷積網絡中另外一個非常重要的結構就是池化,這是利用了圖檔的下采樣不變性,即一張圖檔變小了還是能夠看出了這張圖檔的内容,而使用池化層能夠将圖檔大小降低,非常好地提高了計算效率,同時池化層也沒有參數。池化的方式有很多種,比如最大值池化,均值池化等等,在卷積網絡中一般使用最大值池化。
在 pytorch 中最大值池化的方式也有兩種,一種是
nn.MaxPool2d()
,一種是
torch.nn.functional.max_pool2d()
,他們對于圖檔的輸入要求跟卷積對于圖檔的輸入要求是一樣了,就不再贅述,下面我們也舉例說明
nn.MaxPool2d()
torch.nn.MaxPool2d(kernel_size, stride=None, padding=0, dilation=1, return_indices=False, ceil_mode=False)
nn.MaxPool2d()
表示網絡中的最大值池化,其中的參數有
kernel_size、stride、padding、dilation、return_indices、ceil_mode
下面解釋一下它們各自的含義。
· kernel_size,stride,padding,dilation之前卷積層已經介紹過了,是相同的含義;
·
return_indices
表示是否傳回最大值所處的下标,
預設return_indices=False
;
·
ceil_mode
表示使用一些方格代替層結構,預設
ceil_mode=False
,一般都不會設定這些參數。
nn.AvgPool2d()
torch.nn.AvgPool2d(kernel_size, stride=None, padding=0, dilation=1, ceil_mode=False),count_include_pad=True
·
nn.AvgPool2d()
表示均值池化,裡面的參數和
nn.MaxPool2d()類似,但
多一個參數count_incl ude_pad
,這個參數表示計算均值的時候是否包含零填充,預設
count_include_pad=True。
# 使用 nn.MaxPool2d
pool1 = nn.MaxPool2d(2, 2)
print('before max pool, image shape: {} x {}'.format(im.shape[2], im.shape[3]))
small_im1 = pool1(Variable(im))
small_im1 = small_im1.data.squeeze().numpy()
print('after max pool, image shape: {} x {} '.format(small_im1.shape[0], small_im1.shape[1]))
before max pool, image shape: 224 x 224
after max pool, image shape: 112 x 112
可以看到圖檔的大小減小了一半,但是圖檔不變
一般使用
nn.MaxPool2d()
3.提取層結構
對于一個給定的模型,如果不想要模型中所有的層結構,隻希望能夠提取網絡中的某一層或者幾層,應該如何來實作呢?