天天看點

Pytorch學習記錄(九):Pytorch中卷積神經網絡

卷積神經網絡中所有的層結構都可以通過 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.提取層結構

對于一個給定的模型,如果不想要模型中所有的層結構,隻希望能夠提取網絡中的某一層或者幾層,應該如何來實作呢?

繼續閱讀