wordpress 無廣告東莞seo報(bào)價(jià)
7.1.1 學(xué)習(xí)表征
深度卷積神經(jīng)網(wǎng)絡(luò)的突破出現(xiàn)在2012年。突破可歸因于以下兩個(gè)關(guān)鍵因素:
- 缺少的成分:數(shù)據(jù)
數(shù)據(jù)集緊缺的情況在 2010 年前后興起的大數(shù)據(jù)浪潮中得到改善。ImageNet 挑戰(zhàn)賽中,ImageNet數(shù)據(jù)集由斯坦福大學(xué)教授李飛飛小組的研究人員開發(fā),利用谷歌圖像搜索對分類圖片進(jìn)行預(yù)篩選,并利用亞馬遜眾包標(biāo)注每張圖片的類別。這種數(shù)據(jù)規(guī)模是前所未有的。 - 缺少的成分:硬件
2012年,Alex Krizhevsky和Ilya Sutskever使用兩個(gè)顯存為3GB的NVIDIA GTX580 GPU實(shí)現(xiàn)了快速卷積運(yùn)算,推動(dòng)了深度學(xué)習(xí)熱潮。
7.1.2 AlexNet
2012年橫空出世的 AlexNet 首次證明了學(xué)習(xí)到的特征可以超越手動(dòng)設(shè)計(jì)的特征。
AlexNet 和 LeNet 的架構(gòu)非常相似(此書對模型稍微精簡了一下,取出來需要兩個(gè)小GPU同時(shí)運(yùn)算的設(shè)計(jì)特點(diǎn)):
全連接層(1000) |
---|
↑ \uparrow ↑
全連接層(4096) |
---|
↑ \uparrow ↑
全連接層(4096) |
---|
↑ \uparrow ↑
3 × 3 3\times3 3×3最大匯聚層,步幅2 |
---|
↑ \uparrow ↑
3 × 3 3\times3 3×3卷積層(384),填充1 |
---|
↑ \uparrow ↑
3 × 3 3\times3 3×3卷積層(384),填充1 |
---|
↑ \uparrow ↑
3 × 3 3\times3 3×3卷積層(384),填充1 |
---|
↑ \uparrow ↑
3 × 3 3\times3 3×3最大匯聚層,步幅2 |
---|
↑ \uparrow ↑
5 × 5 5\times5 5×5卷積層(256),填充2 |
---|
↑ \uparrow ↑
3 × 3 3\times3 3×3最大匯聚層,步幅2 |
---|
↑ \uparrow ↑
11 × 11 11\times11 11×11卷積層(96),步幅4 |
---|
↑ \uparrow ↑
輸入圖像( 3 × 224 × 224 3\times224\times224 3×224×224) |
---|
AlexNet 和 LeNet 的差異:
- AlexNet 比 LeNet 深的多
- AlexNet 使用 ReLU 而非 sigmoid 作為激活函數(shù)
以下為 AlexNet 的細(xì)節(jié)。
-
模型設(shè)計(jì)
由于 ImageNet 中的圖像大多較大,因此第一層采用了 11 × 11 11\times11 11×11 的超大卷積核。后續(xù)再一步一步縮減到 3 × 3 3\times3 3×3。而且 AlexNet 的卷積通道數(shù)是 LeNet 的十倍。
最后兩個(gè)巨大的全連接層分別各有4096個(gè)輸出,近 1G 的模型參數(shù)。因早期 GPU 顯存有限,原始的 AlexNet 采取了雙數(shù)據(jù)流設(shè)計(jì)。
-
激活函數(shù)
ReLU 激活函數(shù)是訓(xùn)練模型更加容易。它在正區(qū)間的梯度總為1,而 sigmoid 函數(shù)可能在正區(qū)間內(nèi)得到幾乎為 0 的梯度。
-
容量控制和預(yù)處理
AlexNet 通過暫退法控制全連接層的復(fù)雜度。此外,為了擴(kuò)充數(shù)據(jù),AlexNet 在訓(xùn)練時(shí)增加了大量的圖像增強(qiáng)數(shù)據(jù)(如翻轉(zhuǎn)、裁切和變色),這也使得模型更健壯,并減少了過擬合。
import torch
from torch import nn
from d2l import torch as d2l
net = nn.Sequential(# 這里使用一個(gè)11*11的更大窗口來捕捉對象。# 同時(shí),步幅為4,以減少輸出的高度和寬度。# 另外,輸出通道的數(shù)目遠(yuǎn)大于LeNetnn.Conv2d(1, 96, kernel_size=11, stride=4, padding=1), nn.ReLU(),nn.MaxPool2d(kernel_size=3, stride=2),# 減小卷積窗口,使用填充為2來使得輸入與輸出的高和寬一致,且增大輸出通道數(shù)nn.Conv2d(96, 256, kernel_size=5, padding=2), nn.ReLU(),nn.MaxPool2d(kernel_size=3, stride=2),# 使用三個(gè)連續(xù)的卷積層和較小的卷積窗口。# 除了最后的卷積層,輸出通道的數(shù)量進(jìn)一步增加。# 在前兩個(gè)卷積層之后,匯聚層不用于減少輸入的高度和寬度nn.Conv2d(256, 384, kernel_size=3, padding=1), nn.ReLU(),nn.Conv2d(384, 384, kernel_size=3, padding=1), nn.ReLU(),nn.Conv2d(384, 256, kernel_size=3, padding=1), nn.ReLU(),nn.MaxPool2d(kernel_size=3, stride=2),nn.Flatten(),# 這里,全連接層的輸出數(shù)量是LeNet中的好幾倍。使用dropout層來減輕過擬合nn.Linear(6400, 4096), nn.ReLU(),nn.Dropout(p=0.5),nn.Linear(4096, 4096), nn.ReLU(),nn.Dropout(p=0.5),# 最后是輸出層。由于這里使用Fashion-MNIST,所以用類別數(shù)為10,而非論文中的1000nn.Linear(4096, 10))
X = torch.randn(1, 1, 224, 224)
for layer in net:X=layer(X)print(layer.__class__.__name__,'output shape:\t',X.shape)
Conv2d output shape: torch.Size([1, 96, 54, 54])
ReLU output shape: torch.Size([1, 96, 54, 54])
MaxPool2d output shape: torch.Size([1, 96, 26, 26])
Conv2d output shape: torch.Size([1, 256, 26, 26])
ReLU output shape: torch.Size([1, 256, 26, 26])
MaxPool2d output shape: torch.Size([1, 256, 12, 12])
Conv2d output shape: torch.Size([1, 384, 12, 12])
ReLU output shape: torch.Size([1, 384, 12, 12])
Conv2d output shape: torch.Size([1, 384, 12, 12])
ReLU output shape: torch.Size([1, 384, 12, 12])
Conv2d output shape: torch.Size([1, 256, 12, 12])
ReLU output shape: torch.Size([1, 256, 12, 12])
MaxPool2d output shape: torch.Size([1, 256, 5, 5])
Flatten output shape: torch.Size([1, 6400])
Linear output shape: torch.Size([1, 4096])
ReLU output shape: torch.Size([1, 4096])
Dropout output shape: torch.Size([1, 4096])
Linear output shape: torch.Size([1, 4096])
ReLU output shape: torch.Size([1, 4096])
Dropout output shape: torch.Size([1, 4096])
Linear output shape: torch.Size([1, 10])
7.1.3 讀取數(shù)據(jù)集
如果真用 ImageNet 訓(xùn)練,即使是現(xiàn)在的 GPU 也需要數(shù)小時(shí)或數(shù)天的時(shí)間。在此僅作演示,仍使用 Fashion-MNIST 數(shù)據(jù)集,故在此需要解決圖像分辨率的問題。
batch_size = 128
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size, resize=224)
7.1.4 訓(xùn)練 AlexNet
lr, num_epochs = 0.01, 10
d2l.train_ch6(net, train_iter, test_iter, num_epochs, lr, d2l.try_gpu()) # 大約需要二十分鐘,慎跑
loss 0.330, train acc 0.879, test acc 0.878
592.4 examples/sec on cuda:0
練習(xí)
(1)嘗試增加輪數(shù)。對比 LeNet 的結(jié)果有什么不同?為什么?
lr, num_epochs = 0.01, 15
d2l.train_ch6(net, train_iter, test_iter, num_epochs, lr, d2l.try_gpu()) # 大約需要三十分鐘,慎跑
loss 0.284, train acc 0.896, test acc 0.887
589.3 examples/sec on cuda:0
相較于 LeNet 的增加輪次反而導(dǎo)致精度下降,AlexNet 具有更好的抗過擬合能力,增加輪次精度就會上升。
(2) AlexNet 模型對 Fashion-MNIST 可能太復(fù)雜了。
a. 嘗試簡化模型以加快訓(xùn)練速度,同時(shí)確保準(zhǔn)確性不會顯著下降。b. 設(shè)計(jì)一個(gè)更好的模型,可以直接在 $28\times28$ 像素的圖像上工作。
net_Better = nn.Sequential(nn.Conv2d(1, 64, kernel_size=5, stride=2, padding=2), nn.ReLU(),nn.MaxPool2d(kernel_size=3, stride=1),nn.Conv2d(64, 128, kernel_size=3, padding=1), nn.ReLU(),nn.Conv2d(128, 128, kernel_size=3, padding=1), nn.ReLU(),nn.Conv2d(128, 64, kernel_size=3, padding=1), nn.ReLU(),nn.MaxPool2d(kernel_size=3, stride=2),nn.Flatten(),nn.Linear(64 * 5 * 5, 1024), nn.ReLU(),nn.Dropout(p=0.3), nn.Linear(1024, 512), nn.ReLU(),nn.Dropout(p=0.3),nn.Linear(512, 10)
)X = torch.randn(1, 1, 28, 28)
for layer in net_Better:X=layer(X)print(layer.__class__.__name__,'output shape:\t',X.shape)
Conv2d output shape: torch.Size([1, 64, 14, 14])
ReLU output shape: torch.Size([1, 64, 14, 14])
MaxPool2d output shape: torch.Size([1, 64, 12, 12])
Conv2d output shape: torch.Size([1, 128, 12, 12])
ReLU output shape: torch.Size([1, 128, 12, 12])
Conv2d output shape: torch.Size([1, 128, 12, 12])
ReLU output shape: torch.Size([1, 128, 12, 12])
Conv2d output shape: torch.Size([1, 64, 12, 12])
ReLU output shape: torch.Size([1, 64, 12, 12])
MaxPool2d output shape: torch.Size([1, 64, 5, 5])
Flatten output shape: torch.Size([1, 1600])
Linear output shape: torch.Size([1, 1024])
ReLU output shape: torch.Size([1, 1024])
Dropout output shape: torch.Size([1, 1024])
Linear output shape: torch.Size([1, 512])
ReLU output shape: torch.Size([1, 512])
Dropout output shape: torch.Size([1, 512])
Linear output shape: torch.Size([1, 10])
batch_size = 128
train_iter28, test_iter28 = d2l.load_data_fashion_mnist(batch_size=batch_size)
lr, num_epochs = 0.01, 10
d2l.train_ch6(net_Better, train_iter28, test_iter28, num_epochs, lr, d2l.try_gpu()) # 快多了
loss 0.429, train acc 0.841, test acc 0.843
6650.9 examples/sec on cuda:0
(3)修改批量大小,并觀察模型精度和GPU顯存變化。
batch_size = 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size, resize=224)lr, num_epochs = 0.01, 10
d2l.train_ch6(net, train_iter, test_iter, num_epochs, lr, d2l.try_gpu()) # 大約需要二十分鐘,慎跑
loss 0.407, train acc 0.850, test acc 0.855
587.8 examples/sec on cuda:0
4G 顯存基本拉滿,精度略微下降,過擬合貌似嚴(yán)重了。
(4)分析 AlexNet 的計(jì)算性能。
a. 在 AlexNet 中主要是哪一部分占用顯存?b. 在AlexNet中主要是哪部分需要更多的計(jì)算?c. 計(jì)算結(jié)果時(shí)顯存帶寬如何?
a. 第一個(gè)全連接層占用顯存最多
b. 倒數(shù)第二個(gè)卷積層需要更多的計(jì)算
(5)將dropout和ReLU應(yīng)用于LeNet-5,效果有提升嗎?再試試預(yù)處理會怎么樣?
net_try = nn.Sequential(nn.Conv2d(1, 6, kernel_size=5, padding=2), nn.ReLU(),nn.AvgPool2d(kernel_size=2, stride=2),nn.Conv2d(6, 16, kernel_size=5), nn.ReLU(),nn.AvgPool2d(kernel_size=2, stride=2),nn.Flatten(),nn.Linear(16 * 5 * 5, 120), nn.ReLU(),nn.Dropout(p=0.2), nn.Linear(120, 84), nn.ReLU(),nn.Dropout(p=0.2), nn.Linear(84, 10))lr, num_epochs = 0.6, 10
d2l.train_ch6(net_try, train_iter28, test_iter28, num_epochs, lr, d2l.try_gpu()) # 淺調(diào)一下還挺好
loss 0.306, train acc 0.887, test acc 0.883
26121.2 examples/sec on cuda:0
淺淺調(diào)一下,效果挺好,精度有所提升。