引言
對於池化層和步長爲2的卷積層的思考源於前一段時間對於2.0文檔API的評估。自從ResNet開始,你們逐漸使用步長爲2的卷積層替代Size爲2的池化層,兩者都是對特徵圖進行下采樣的操做。池化層的主要意義(目前的主流見解,可是有相關論文反駁這個觀點)在於invariance(不變性),這個不變性包括平移不變性、尺度不變性、旋轉不變形。其過程以下圖所示。python
對於池化層和步長爲2的卷積層來講,我的的理解是這樣的,池化層是一種先驗的下采樣方式,即人爲的肯定好下采樣的規則;而對於步長爲2的卷積層來講,其參數是經過學習獲得的,採樣的規則是不肯定的。下面對兩種下采樣方式進行一組對比實驗,實驗設計的可能不夠嚴謹,歡迎你們在評論區討論。網絡
下載安裝命令 ## CPU版本安裝命令 pip install -f https://paddlepaddle.org.cn/pip/oschina/cpu paddlepaddle ## GPU版本安裝命令 pip install -f https://paddlepaddle.org.cn/pip/oschina/gpu paddlepaddle-gpu
實驗設計
本次對比實驗採用LeNet進行對比,目的在於簡單的說明池化層與步長爲2的卷積層以前的區別。採用MNIST數據集。ide
一、導入paddle,使用2.0版本的paddle
import paddle print(paddle.__version__)
2.0.0-rc0
二、導入訓練數據和測試數據
train_dataset = paddle.vision.datasets.MNIST(mode='train') test_dataset = paddle.vision.datasets.MNIST(mode='test')
三、查看數據
%matplotlib notebook import numpy as np import matplotlib.pyplot as plt train_data0, train_label_0 = train_dataset[0][0],train_dataset[0][1] train_data0 = train_data0.reshape([28,28]) plt.figure(figsize=(2,2)) plt.imshow(train_data0, cmap=plt.cm.binary) print('train_data0 label is: ' + str(train_label_0))
四、構建LeNet5網絡
import paddle.nn.functional as F class LeNet(paddle.nn.Layer): def __init__(self): super(LeNet, self).__init__() self.conv1 = paddle.nn.Conv2D(in_channels=1, out_channels=6, kernel_size=5, stride=1, padding=2) self.max_pool1 = paddle.nn.MaxPool2D(kernel_size=2, stride=2) self.conv2 = paddle.nn.Conv2D(in_channels=6, out_channels=16, kernel_size=5, stride=1) self.max_pool2 = paddle.nn.MaxPool2D(kernel_size=2, stride=2) self.linear1 = paddle.nn.Linear(in_features=16*5*5, out_features=120) self.linear2 = paddle.nn.Linear(in_features=120, out_features=84) self.linear3 = paddle.nn.Linear(in_features=84, out_features=10) def forward(self, x): x = self.conv1(x) x = F.relu(x) x = self.max_pool1(x) x = F.relu(x) x = self.conv2(x) x = self.max_pool2(x) # print(x.shape) x = paddle.flatten(x, start_axis=1,stop_axis=-1) x = self.linear1(x) x = F.relu(x) x = self.linear2(x) x = F.relu(x) x = self.linear3(x) return x
五、模型封裝與配置
from paddle.metric import Accuracy model2 = paddle.Model(LeNet()) # 用Model封裝模型 optim = paddle.optimizer.Adam(learning_rate=0.001, parameters=model2.parameters()) # 配置模型 model2.prepare( optim, paddle.nn.CrossEntropyLoss(), Accuracy(topk=(1, 2)) )
六、模型訓練,這裏進行10次迭代。
# 訓練模型 model2.fit(train_dataset, epochs=10, batch_size=64, verbose=1 )
七、驗證模型
model2.evaluate(test_dataset, batch_size=64, verbose=1)
Eval begin... step 157/157 [==============================] - loss: 1.4789e-05 - acc_top1: 0.9810 - acc_top2: 0.9932 - 3ms/step Eval samples: 10000 {'loss': [1.4788801e-05], 'acc_top1': 0.981, 'acc_top2': 0.9932}
八、構建使用步長爲2的卷積層替代池化層的LeNet5
import paddle.nn.functional as F class LeNet_nopool(paddle.nn.Layer): def __init__(self): super(LeNet_nopool, self).__init__() self.conv1 = paddle.nn.Conv2D(in_channels=1, out_channels=6, kernel_size=5, stride=1, padding=2) # self.max_pool1 = paddle.nn.MaxPool2D(kernel_size=2, stride=2) self.conv2 = paddle.nn.Conv2D(in_channels=6, out_channels=16, kernel_size=5, stride=2) self.conv3 = paddle.nn.Conv2D(in_channels=16, out_channels=16, kernel_size=3, stride=1, padding=1) self.conv4 = paddle.nn.Conv2D(in_channels=16, out_channels=16, kernel_size=3, stride=2) # self.max_pool2 = paddle.nn.MaxPool2D(kernel_size=2, stride=2) self.linear1 = paddle.nn.Linear(in_features=16*5*5, out_features=120) self.linear2 = paddle.nn.Linear(in_features=120, out_features=84) self.linear3 = paddle.nn.Linear(in_features=84, out_features=10) def forward(self, x): x = self.conv1(x) # print(x.shape) x = F.relu(x) x = self.conv2(x) # print(x.shape) x = F.relu(x) x = self.conv3(x) # print(x.shape) x = F.relu(x) x = self.conv4(x) # print(x.shape) x = paddle.flatten(x, start_axis=1,stop_axis=-1) x = self.linear1(x) x = F.relu(x) x = self.linear2(x) x = F.relu(x) x = self.linear3(x) return x
九、模型配置與訓練
from paddle.metric import Accuracy model3 = paddle.Model(LeNet_nopool()) # 用Model封裝模型 optim = paddle.optimizer.Adam(learning_rate=0.001, parameters=model3.parameters()) # 配置模型 model3.prepare( optim, paddle.nn.CrossEntropyLoss(), Accuracy(topk=(1, 2)) ) # 訓練模型 model3.fit(train_dataset, epochs=10, batch_size=64, verbose=1 )
十、模型驗證
model3.evaluate(test_dataset, batch_size=64, verbose=1)
Eval begin... step 157/157 [==============================] - loss: 1.7807e-06 - acc_top1: 0.9837 - acc_top2: 0.9964 - 3ms/step Eval samples: 10000 {'loss': [1.7806786e-06], 'acc_top1': 0.9837, 'acc_top2': 0.9964}
實驗結果分析
從二者在MNIST測試集上的結果來看,使用步長爲2的卷積層替代池化層,其模型的表現略高於原始的LeNet5。代表使用卷積層代替池化層是對模型表現有較好的提高。可是改進以後的LeNet5在參數量上是高於原始的LeNet5的,學習
十一、參數量對比
#改進的LeNet5 print('# model3 parameters:', sum(param.numel() for param in model3.parameters()))
# model3 parameters: Tensor(shape=[1], dtype=int64, place=CUDAPlace(0), stop_gradient=True, [66346])
#原始的LeNet5 , dtype=int64, place=CUDAPlace(0), stop_gradient=True, [66346]) ```python #原始的LeNet5 print('# model2 parameters:', sum(param.numel() for param in model.parameters()))
# model2 parameters: Tensor(shape=[1], dtype=int64, place=CUDAPlace(0), stop_gradient=True, [61706])
總結
(1)從圖像成像角度來看,圖像在成像過程當中接收模擬信號變成電信號再存儲的陣列都不是同時的。即圖片上每一點都是有時序的。結合圖像的時域信息進行多模態訓練可能會有突破。測試
(2)在圖像中應用香農定理,下采樣越多,信息丟失越多,對於CNN中池化層的討論,你們能夠參考:CNN真的須要下采樣(上採樣)嗎?lua
(3)對於池化層不同的見解,證僞:CNN中的圖片平移不變性url
(4)實際上已經有衆多大佬對這個進行過論證,可是對於你們來講,本身動手永遠比聽別人講來得更好,但願能和你們一塊兒成長。spa
下載安裝命令 ## CPU版本安裝命令 pip install -f https://paddlepaddle.org.cn/pip/oschina/cpu paddlepaddle ## GPU版本安裝命令 pip install -f https://paddlepaddle.org.cn/pip/oschina/gpu paddlepaddle-gpu
>> 訪問 PaddlePaddle 官網,瞭解更多相關內容。.net
一點小小的宣傳
我目前在上海,感興趣的領域包括模型壓縮、小目標檢測、嵌入式,歡迎交流關注。來AI Studio互粉吧等你哦 設計
本文同步分享在 博客「Mowglee」(CSDN)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。