過(guò)擬合陶衅、欠擬合及其解決方案
模型復(fù)雜度
為了解釋模型復(fù)雜度灶体,我們以多項(xiàng)式函數(shù)擬合為例晒骇。給定一個(gè)由標(biāo)量數(shù)據(jù)特征和對(duì)應(yīng)的標(biāo)量標(biāo)簽
組成的訓(xùn)練數(shù)據(jù)集,多項(xiàng)式函數(shù)擬合的目標(biāo)是找一個(gè)
階多項(xiàng)式函數(shù)
來(lái)近似 浙于。在上式中,
是模型的權(quán)重參數(shù)挟纱,
是偏差參數(shù)羞酗。與線性回歸相同,多項(xiàng)式函數(shù)擬合也使用平方損失函數(shù)紊服。特別地檀轨,一階多項(xiàng)式函數(shù)擬合又叫線性函數(shù)擬合。
給定訓(xùn)練數(shù)據(jù)集欺嗤,模型復(fù)雜度和誤差之間的關(guān)系:
權(quán)重衰減
方法
權(quán)重衰減等價(jià)于 范數(shù)正則化(regularization)参萄。正則化通過(guò)為模型損失函數(shù)添加懲罰項(xiàng)使學(xué)出的模型參數(shù)值較小,是應(yīng)對(duì)過(guò)擬合的常用手段煎饼。
L2 范數(shù)正則化(regularization)
范數(shù)正則化在模型原損失函數(shù)基礎(chǔ)上添加
范數(shù)懲罰項(xiàng)讹挎,從而得到訓(xùn)練所需要最小化的函數(shù)。
范數(shù)懲罰項(xiàng)指的是模型權(quán)重參數(shù)每個(gè)元素的平方和與一個(gè)正的常數(shù)的乘積吆玖。以線性回歸中的線性回歸損失函數(shù)為例
其中是權(quán)重參數(shù)筒溃,
是偏差參數(shù),樣本
的輸入為
沾乘,標(biāo)簽為
怜奖,樣本數(shù)為
。將權(quán)重參數(shù)用向量
表示意鲸,帶有
范數(shù)懲罰項(xiàng)的新?lián)p失函數(shù)為
其中超參數(shù)烦周。當(dāng)權(quán)重參數(shù)均為0時(shí),懲罰項(xiàng)最小怎顾。當(dāng)
較大時(shí)读慎,懲罰項(xiàng)在損失函數(shù)中的比重較大,這通常會(huì)使學(xué)到的權(quán)重參數(shù)的元素較接近0槐雾。當(dāng)
設(shè)為0時(shí)夭委,懲罰項(xiàng)完全不起作用。上式中
范數(shù)平方
展開(kāi)后得到
募强。
有了范數(shù)懲罰項(xiàng)后株灸,在小批量隨機(jī)梯度下降中崇摄,我們將線性回歸一節(jié)中權(quán)重
和
的迭代方式更改為
可見(jiàn),范數(shù)正則化令權(quán)重
和
先自乘小于1的數(shù)慌烧,再減去不含懲罰項(xiàng)的梯度逐抑。因此,
范數(shù)正則化又叫權(quán)重衰減屹蚊。權(quán)重衰減通過(guò)懲罰絕對(duì)值較大的模型參數(shù)為需要學(xué)習(xí)的模型增加了限制厕氨,這可能對(duì)過(guò)擬合有效。
丟棄法Dropout
多層感知機(jī)中神經(jīng)網(wǎng)絡(luò)圖描述了一個(gè)單隱藏層的多層感知機(jī)汹粤。其中輸入個(gè)數(shù)為4命斧,隱藏單元個(gè)數(shù)為5,且隱藏單元(
)的計(jì)算表達(dá)式為
這里是激活函數(shù)嘱兼,
是輸入国葬,隱藏單元
的權(quán)重參數(shù)為
,偏差參數(shù)為
芹壕。當(dāng)對(duì)該隱藏層使用丟棄法時(shí)汇四,該層的隱藏單元將有一定概率被丟棄掉。設(shè)丟棄概率為
踢涌,那么有
的概率
會(huì)被清零船殉,有
的概率
會(huì)除以
做拉伸。丟棄概率是丟棄法的超參數(shù)斯嚎。具體來(lái)說(shuō)利虫,設(shè)隨機(jī)變量
為0和1的概率分別為
和
。使用丟棄法時(shí)我們計(jì)算新的隱藏單元
由于堡僻,因此
即丟棄法不改變其輸入的期望值糠惫。讓我們對(duì)之前多層感知機(jī)的神經(jīng)網(wǎng)絡(luò)中的隱藏層使用丟棄法,一種可能的結(jié)果如圖所示钉疫,其中和
被清零硼讽。這時(shí)輸出值的計(jì)算不再依賴
和
,在反向傳播時(shí)牲阁,與這兩個(gè)隱藏單元相關(guān)的權(quán)重的梯度均為0固阁。由于在訓(xùn)練中隱藏層神經(jīng)元的丟棄是隨機(jī)的,即
都有可能被清零城菊,輸出層的計(jì)算無(wú)法過(guò)度依賴
中的任一個(gè)备燃,從而在訓(xùn)練模型時(shí)起到正則化的作用,并可以用來(lái)應(yīng)對(duì)過(guò)擬合凌唬。在測(cè)試模型時(shí)并齐,我們?yōu)榱四玫礁哟_定性的結(jié)果,一般不使用丟棄法
梯度消失和梯度爆炸
深度模型有關(guān)數(shù)值穩(wěn)定性的典型問(wèn)題是消失(vanishing)和爆炸(explosion)。
當(dāng)神經(jīng)網(wǎng)絡(luò)的層數(shù)較多時(shí)况褪,模型的數(shù)值穩(wěn)定性容易變差撕贞。
假設(shè)一個(gè)層數(shù)為的多層感知機(jī)的第
層
的權(quán)重參數(shù)為
,輸出層
的權(quán)重參數(shù)為
测垛。為了便于討論捏膨,不考慮偏差參數(shù),且設(shè)所有隱藏層的激活函數(shù)為恒等映射(identity mapping)
食侮。給定輸入
脊奋,多層感知機(jī)的第
層的輸出
。此時(shí)疙描,如果層數(shù)
較大,
的計(jì)算可能會(huì)出現(xiàn)衰減或爆炸讶隐。舉個(gè)例子起胰,假設(shè)輸入和所有層的權(quán)重參數(shù)都是標(biāo)量,如權(quán)重參數(shù)為0.2和5巫延,多層感知機(jī)的第30層輸出為輸入
分別與
(消失)和
(爆炸)的乘積效五。當(dāng)層數(shù)較多時(shí),梯度的計(jì)算也容易出現(xiàn)消失或爆炸炉峰。
隨機(jī)初始化模型參數(shù)
在神經(jīng)網(wǎng)絡(luò)中畏妖,通常需要隨機(jī)初始化模型參數(shù)。具體原因如下:
回顧多層感知機(jī)一節(jié)描述的多層感知機(jī)疼阔。為了方便解釋?zhuān)僭O(shè)輸出層只保留一個(gè)輸出單元(刪去
和
以及指向它們的箭頭)戒劫,且隱藏層使用相同的激活函數(shù)。如果將每個(gè)隱藏單元的參數(shù)都初始化為相等的值婆廊,那么在正向傳播時(shí)每個(gè)隱藏單元將根據(jù)相同的輸入計(jì)算出相同的值迅细,并傳遞至輸出層。在反向傳播中淘邻,每個(gè)隱藏單元的參數(shù)梯度值相等茵典。因此,這些參數(shù)在使用基于梯度的優(yōu)化算法迭代后值依然相等宾舅。之后的迭代也是如此统阿。在這種情況下,無(wú)論隱藏單元有多少筹我,隱藏層本質(zhì)上只有1個(gè)隱藏單元在發(fā)揮作用扶平。因此,正如在前面的實(shí)驗(yàn)中所做的那樣蔬蕊,我們通常將神經(jīng)網(wǎng)絡(luò)的模型參數(shù)蜻直,特別是權(quán)重參數(shù),進(jìn)行隨機(jī)初始化。
(1)PyTorch的默認(rèn)隨機(jī)初始化
隨機(jī)初始化模型參數(shù)的方法有很多概而。在線性回歸的簡(jiǎn)潔實(shí)現(xiàn)中呼巷,我們使用torch.nn.init.normal_()
使模型net
的權(quán)重參數(shù)采用正態(tài)分布的隨機(jī)初始化方式。不過(guò)赎瑰,PyTorch中nn.Module
的模塊參數(shù)都采取了較為合理的初始化策略(不同類(lèi)型的layer具體采樣的哪一種初始化方法的可參考源代碼)王悍,因此一般不用我們考慮。
(2)Xavier隨機(jī)初始化
還有一種比較常用的隨機(jī)初始化方法叫作Xavier隨機(jī)初始化餐曼。
假設(shè)某全連接層的輸入個(gè)數(shù)為压储,輸出個(gè)數(shù)為
,Xavier隨機(jī)初始化將使該層中權(quán)重參數(shù)的每個(gè)元素都隨機(jī)采樣于均勻分布
它的設(shè)計(jì)主要考慮到源譬,模型參數(shù)初始化后集惋,每層輸出的方差不該受該層輸入個(gè)數(shù)影響,且每層梯度的方差也不該受該層輸出個(gè)數(shù)影響踩娘。
卷積神經(jīng)網(wǎng)絡(luò)
卷積層與全連接層的對(duì)比
二維卷積層經(jīng)常用于處理圖像刮刑,與此前的全連接層相比,它主要有兩個(gè)優(yōu)勢(shì):
一是全連接層把圖像展平成一個(gè)向量养渴,在輸入圖像上相鄰的元素可能因?yàn)檎蛊讲僮鞑辉傧噜徖拙睿W(wǎng)絡(luò)難以捕捉局部信息。而卷積層的設(shè)計(jì)理卑,天然地具有提取局部信息的能力翘紊。
二是卷積層的參數(shù)量更少。不考慮偏置的情況下藐唠,一個(gè)形狀為的卷積核的參數(shù)量是
帆疟,與輸入圖像的寬高無(wú)關(guān)。假如一個(gè)卷積層的輸入和輸出形狀分別是
和
宇立,如果要用全連接層進(jìn)行連接鸯匹,參數(shù)數(shù)量就是
。使用卷積層可以以較少的參數(shù)數(shù)量來(lái)處理更大的圖像泄伪。
卷積層的簡(jiǎn)潔實(shí)現(xiàn)
我們使用Pytorch中的nn.Conv2d
類(lèi)來(lái)實(shí)現(xiàn)二維卷積層殴蓬,主要關(guān)注以下幾個(gè)構(gòu)造函數(shù)參數(shù):
-
in_channels
(python:int) – Number of channels in the input imag -
out_channels
(python:int) – Number of channels produced by the convolution -
kernel_size
(python:int or tuple) – Size of the convolving kernel -
stride
(python:int or tuple, optional) – Stride of the convolution. Default: 1 -
padding
(python:int or tuple, optional) – Zero-padding added to both sides of the input. Default: 0 -
bias
(bool, optional) – If True, adds a learnable bias to the output. Default: True
forward
函數(shù)的參數(shù)為一個(gè)四維張量,形狀為蟋滴,返回值也是一個(gè)四維張量染厅,形狀為
,其中
是批量大小津函,
分別表示通道數(shù)肖粮、高度、寬度尔苦。
代碼講解
X = torch.rand(4, 2, 3, 5)
print(X.shape)
conv2d = nn.Conv2d(in_channels=2, out_channels=3, kernel_size=(3, 5), stride=1, padding=(1, 2))
Y = conv2d(X)
print('Y.shape: ', Y.shape)
print('weight.shape: ', conv2d.weight.shape)
print('bias.shape: ', conv2d.bias.shape)
全連接層和卷積層
使用全連接層的局限性:
- 圖像在同一列鄰近的像素在這個(gè)向量中可能相距較遠(yuǎn)涩馆。它們構(gòu)成的模式可能難以被模型識(shí)別行施。
- 對(duì)于大尺寸的輸入圖像,使用全連接層容易導(dǎo)致模型過(guò)大魂那。
使用卷積層的優(yōu)勢(shì):
- 卷積層保留輸入形狀蛾号。
- 卷積層通過(guò)滑動(dòng)窗口將同一卷積核與不同位置的輸入重復(fù)計(jì)算,從而避免參數(shù)尺寸過(guò)大涯雅。
LeNet 模型
LeNet分為卷積層塊和全連接層塊兩個(gè)部分柑贞。下面我們分別介紹這兩個(gè)模塊描函。
卷積層塊里的基本單位是卷積層后接平均池化層:卷積層用來(lái)識(shí)別圖像里的空間模式咙边,如線條和物體局部剪决,之后的平均池化層則用來(lái)降低卷積層對(duì)位置的敏感性。
卷積層塊由兩個(gè)這樣的基本單位重復(fù)堆疊構(gòu)成蔗候。在卷積層塊中怒允,每個(gè)卷積層都使用的窗口,并在輸出上使用sigmoid激活函數(shù)锈遥。第一個(gè)卷積層輸出通道數(shù)為6纫事,第二個(gè)卷積層輸出通道數(shù)則增加到16。
全連接層塊含3個(gè)全連接層迷殿。它們的輸出個(gè)數(shù)分別是120、84和10咖杂,其中10為輸出的類(lèi)別個(gè)數(shù)庆寺。
#net
class Flatten(torch.nn.Module): #展平操作
def forward(self, x):
return x.view(x.shape[0], -1)
class Reshape(torch.nn.Module): #將圖像大小重定型
def forward(self, x):
return x.view(-1,1,28,28) #(B x C x H x W)
net = torch.nn.Sequential( #Lelet
Reshape(),
nn.Conv2d(in_channels=1, out_channels=6, kernel_size=5, padding=2), #b*1*28*28 =>b*6*28*28
nn.Sigmoid(),
nn.AvgPool2d(kernel_size=2, stride=2), #b*6*28*28 =>b*6*14*14
nn.Conv2d(in_channels=6, out_channels=16, kernel_size=5), #b*6*14*14 =>b*16*10*10
nn.Sigmoid(),
nn.AvgPool2d(kernel_size=2, stride=2), #b*16*10*10 => b*16*5*5
Flatten(), #b*16*5*5 => b*400
nn.Linear(in_features=16*5*5, out_features=120),
nn.Sigmoid(),
nn.Linear(120, 84),
nn.Sigmoid(),
nn.Linear(84, 10)
)
LeNet交替使用卷積層和最大池化層后接全連接層來(lái)進(jìn)行圖像分類(lèi)
AlexNet
首次證明了學(xué)習(xí)到的特征可以超越??設(shè)計(jì)的特征,從而?舉打破計(jì)算機(jī)視覺(jué)研究的前狀诉字。
特征:
- 8層變換懦尝,其中有5層卷積和2層全連接隱藏層,以及1個(gè)全連接輸出層壤圃。
- 將sigmoid激活函數(shù)改成了更加簡(jiǎn)單的ReLU激活函數(shù)陵霉。
- 用Dropout來(lái)控制全連接層的模型復(fù)雜度。
- 引入數(shù)據(jù)增強(qiáng)伍绳,如翻轉(zhuǎn)踊挠、裁剪和顏色變化,從而進(jìn)一步擴(kuò)大數(shù)據(jù)集來(lái)緩解過(guò)擬合冲杀。
import time
import torch
from torch import nn, optim
import torchvision
import numpy as np
import sys
sys.path.append("/home/kesci/input/")
import d2lzh1981 as d2l
import os
import torch.nn.functional as F
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
class AlexNet(nn.Module):
def __init__(self):
super(AlexNet, self).__init__()
self.conv = nn.Sequential(
nn.Conv2d(1, 96, 11, 4), # in_channels, out_channels, kernel_size, stride, padding
nn.ReLU(),
nn.MaxPool2d(3, 2), # kernel_size, stride
# 減小卷積窗口效床,使用填充為2來(lái)使得輸入與輸出的高和寬一致,且增大輸出通道數(shù)
nn.Conv2d(96, 256, 5, 1, 2),
nn.ReLU(),
nn.MaxPool2d(3, 2),
# 連續(xù)3個(gè)卷積層权谁,且使用更小的卷積窗口剩檀。除了最后的卷積層外,進(jìn)一步增大了輸出通道數(shù)旺芽。
# 前兩個(gè)卷積層后不使用池化層來(lái)減小輸入的高和寬
nn.Conv2d(256, 384, 3, 1, 1),
nn.ReLU(),
nn.Conv2d(384, 384, 3, 1, 1),
nn.ReLU(),
nn.Conv2d(384, 256, 3, 1, 1),
nn.ReLU(),
nn.MaxPool2d(3, 2)
)
# 這里全連接層的輸出個(gè)數(shù)比LeNet中的大數(shù)倍沪猴。使用丟棄層來(lái)緩解過(guò)擬合
self.fc = nn.Sequential(
nn.Linear(256*5*5, 4096),
nn.ReLU(),
nn.Dropout(0.5),
#由于使用CPU鏡像辐啄,精簡(jiǎn)網(wǎng)絡(luò),若為GPU鏡像可添加該層
#nn.Linear(4096, 4096),
#nn.ReLU(),
#nn.Dropout(0.5),
# 輸出層运嗜。由于這里使用Fashion-MNIST壶辜,所以用類(lèi)別數(shù)為10,而非論文中的1000
nn.Linear(4096, 10),
)
def forward(self, img):
feature = self.conv(img)
output = self.fc(feature.view(img.shape[0], -1))
return output
* 使用重復(fù)元素的網(wǎng)絡(luò)(VGG)
VGG:通過(guò)重復(fù)使?簡(jiǎn)單的基礎(chǔ)塊來(lái)構(gòu)建深度模型洗出。
Block:數(shù)個(gè)相同的填充為1士复、窗口形狀為的卷積層,接上一個(gè)步幅為2、窗口形狀為
的最大池化層翩活。
卷積層保持輸入的高和寬不變阱洪,而池化層則對(duì)其減半。
VGG11的簡(jiǎn)單實(shí)現(xiàn)
def vgg_block(num_convs, in_channels, out_channels): #卷積層個(gè)數(shù)菠镇,輸入通道數(shù)冗荸,輸出通道數(shù)
blk = []
for i in range(num_convs):
if i == 0:
blk.append(nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1))
else:
blk.append(nn.Conv2d(out_channels, out_channels, kernel_size=3, padding=1))
blk.append(nn.ReLU())
blk.append(nn.MaxPool2d(kernel_size=2, stride=2)) # 這里會(huì)使寬高減半
return nn.Sequential(*blk)
conv_arch = ((1, 1, 64), (1, 64, 128), (2, 128, 256), (2, 256, 512), (2, 512, 512))
# 經(jīng)過(guò)5個(gè)vgg_block, 寬高會(huì)減半5次, 變成 224/32 = 7
fc_features = 512 * 7 * 7 # c * w * h
fc_hidden_units = 4096 # 任意
net = vgg(conv_arch, fc_features, fc_hidden_units)
X = torch.rand(1, 1, 224, 224)
# named_children獲取一級(jí)子模塊及其名字(named_modules會(huì)返回所有子模塊,包括子模塊的子模塊)
for name, blk in net.named_children():
X = blk(X)
print(name, 'output shape: ', X.shape)
ratio = 8
small_conv_arch = [(1, 1, 64//ratio), (1, 64//ratio, 128//ratio), (2, 128//ratio, 256//ratio),
(2, 256//ratio, 512//ratio), (2, 512//ratio, 512//ratio)]
net = vgg(small_conv_arch, fc_features // ratio, fc_hidden_units // ratio)
print(net)
運(yùn)行結(jié)果:
Sequential(
(vgg_block_1): Sequential(
(0): Conv2d(1, 8, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(1): ReLU()
(2): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
)
(vgg_block_2): Sequential(
(0): Conv2d(8, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(1): ReLU()
(2): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
)
(vgg_block_3): Sequential(
(0): Conv2d(16, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(1): ReLU()
(2): Conv2d(32, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(3): ReLU()
(4): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
)
(vgg_block_4): Sequential(
(0): Conv2d(32, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(1): ReLU()
(2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(3): ReLU()
(4): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
)
(vgg_block_5): Sequential(
(0): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(1): ReLU()
(2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(3): ReLU()
(4): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
)
(fc): Sequential(
(0): FlattenLayer()
(1): Linear(in_features=3136, out_features=512, bias=True)
(2): ReLU()
(3): Dropout(p=0.5, inplace=False)
(4): Linear(in_features=512, out_features=512, bias=True)
(5): ReLU()
(6): Dropout(p=0.5, inplace=False)
(7): Linear(in_features=512, out_features=10, bias=True)
)
)
batchsize=16
#batch_size = 64
# 如出現(xiàn)“out of memory”的報(bào)錯(cuò)信息,可減小batch_size或resize
# train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size, resize=224)
lr, num_epochs = 0.001, 5
optimizer = torch.optim.Adam(net.parameters(), lr=lr)
d2l.train_ch5(net, train_iter, test_iter, batch_size, optimizer, device, num_epochs)
* ?絡(luò)中的?絡(luò)(NiN)
LeNet利耍、AlexNet和VGG:先以由卷積層構(gòu)成的模塊充分抽取空間特征蚌本,再以由全連接層構(gòu)成的模塊來(lái)輸出分類(lèi)結(jié)果。
NiN:串聯(lián)多個(gè)由卷積層和“全連接”層構(gòu)成的小?絡(luò)來(lái)構(gòu)建?個(gè)深層?絡(luò)隘梨。
?了輸出通道數(shù)等于標(biāo)簽類(lèi)別數(shù)的NiN塊程癌,然后使?全局平均池化層對(duì)每個(gè)通道中所有元素求平均并直接?于分類(lèi)。
1×1卷積核作用
(1).放縮通道數(shù):通過(guò)控制卷積核的數(shù)量達(dá)到通道數(shù)的放縮轴猎。
(2).增加非線性嵌莉。1×1卷積核的卷積過(guò)程相當(dāng)于全連接層的計(jì)算過(guò)程,并且還加入了非線性激活函數(shù)捻脖,從而可以增加網(wǎng)絡(luò)的非線性锐峭。
(3).計(jì)算參數(shù)少
def nin_block(in_channels, out_channels, kernel_size, stride, padding):
blk = nn.Sequential(nn.Conv2d(in_channels, out_channels, kernel_size, stride, padding),
nn.ReLU(),
nn.Conv2d(out_channels, out_channels, kernel_size=1),
nn.ReLU(),
nn.Conv2d(out_channels, out_channels, kernel_size=1),
nn.ReLU())
return blk
# 已保存在d2lzh_pytorch
class GlobalAvgPool2d(nn.Module):
# 全局平均池化層可通過(guò)將池化窗口形狀設(shè)置成輸入的高和寬實(shí)現(xiàn)
def __init__(self):
super(GlobalAvgPool2d, self).__init__()
def forward(self, x):
return F.avg_pool2d(x, kernel_size=x.size()[2:])
net = nn.Sequential(
nin_block(1, 96, kernel_size=11, stride=4, padding=0),
nn.MaxPool2d(kernel_size=3, stride=2),
nin_block(96, 256, kernel_size=5, stride=1, padding=2),
nn.MaxPool2d(kernel_size=3, stride=2),
nin_block(256, 384, kernel_size=3, stride=1, padding=1),
nn.MaxPool2d(kernel_size=3, stride=2),
nn.Dropout(0.5),
# 標(biāo)簽類(lèi)別數(shù)是10
nin_block(384, 10, kernel_size=3, stride=1, padding=1),
GlobalAvgPool2d(),
# 將四維的輸出轉(zhuǎn)成二維的輸出,其形狀為(批量大小, 10)
d2l.FlattenLayer())
X = torch.rand(1, 1, 224, 224)
for name, blk in net.named_children():
X = blk(X)
print(name, 'output shape: ', X.shape)
batch_size = 128
# 如出現(xiàn)“out of memory”的報(bào)錯(cuò)信息可婶,可減小batch_size或resize
#train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size, resize=224)
lr, num_epochs = 0.002, 5
optimizer = torch.optim.Adam(net.parameters(), lr=lr)
d2l.train_ch5(net, train_iter, test_iter, batch_size, optimizer, device, num_epochs)
NiN特點(diǎn)
NiN重復(fù)使?由卷積層和代替全連接層的1×1卷積層構(gòu)成的NiN塊來(lái)構(gòu)建深層?絡(luò)沿癞。
NiN去除了容易造成過(guò)擬合的全連接輸出層,而是將其替換成輸出通道數(shù)等于標(biāo)簽類(lèi)別數(shù) 的NiN塊和全局平均池化層矛渴。
NiN的以上設(shè)計(jì)思想影響了后??系列卷積神經(jīng)?絡(luò)的設(shè)計(jì)椎扬。
* GoogLeNet
- 由Inception基礎(chǔ)塊組成。
- Inception塊相當(dāng)于?個(gè)有4條線路的??絡(luò)具温。它通過(guò)不同窗口形狀的卷積層和最?池化層來(lái)并?抽取信息盗舰,并使?1×1卷積層減少通道數(shù)從而降低模型復(fù)雜度。
- 可以?定義的超參數(shù)是每個(gè)層的輸出通道數(shù)桂躏,我們以此來(lái)控制模型復(fù)雜度钻趋。
class Inception(nn.Module):
# c1 - c4為每條線路里的層的輸出通道數(shù)
def __init__(self, in_c, c1, c2, c3, c4):
super(Inception, self).__init__()
# 線路1,單1 x 1卷積層
self.p1_1 = nn.Conv2d(in_c, c1, kernel_size=1)
# 線路2剂习,1 x 1卷積層后接3 x 3卷積層
self.p2_1 = nn.Conv2d(in_c, c2[0], kernel_size=1)
self.p2_2 = nn.Conv2d(c2[0], c2[1], kernel_size=3, padding=1)
# 線路3蛮位,1 x 1卷積層后接5 x 5卷積層
self.p3_1 = nn.Conv2d(in_c, c3[0], kernel_size=1)
self.p3_2 = nn.Conv2d(c3[0], c3[1], kernel_size=5, padding=2)
# 線路4较沪,3 x 3最大池化層后接1 x 1卷積層
self.p4_1 = nn.MaxPool2d(kernel_size=3, stride=1, padding=1)
self.p4_2 = nn.Conv2d(in_c, c4, kernel_size=1)
def forward(self, x):
p1 = F.relu(self.p1_1(x))
p2 = F.relu(self.p2_2(F.relu(self.p2_1(x))))
p3 = F.relu(self.p3_2(F.relu(self.p3_1(x))))
p4 = F.relu(self.p4_2(self.p4_1(x)))
return torch.cat((p1, p2, p3, p4), dim=1) # 在通道維上連結(jié)輸出
GoogLeNet模型
完整模型結(jié)構(gòu)
b1 = nn.Sequential(nn.Conv2d(1, 64, kernel_size=7, stride=2, padding=3),
nn.ReLU(),
nn.MaxPool2d(kernel_size=3, stride=2, padding=1))
b2 = nn.Sequential(nn.Conv2d(64, 64, kernel_size=1),
nn.Conv2d(64, 192, kernel_size=3, padding=1),
nn.MaxPool2d(kernel_size=3, stride=2, padding=1))
b3 = nn.Sequential(Inception(192, 64, (96, 128), (16, 32), 32),
Inception(256, 128, (128, 192), (32, 96), 64),
nn.MaxPool2d(kernel_size=3, stride=2, padding=1))
b4 = nn.Sequential(Inception(480, 192, (96, 208), (16, 48), 64),
Inception(512, 160, (112, 224), (24, 64), 64),
Inception(512, 128, (128, 256), (24, 64), 64),
Inception(512, 112, (144, 288), (32, 64), 64),
Inception(528, 256, (160, 320), (32, 128), 128),
nn.MaxPool2d(kernel_size=3, stride=2, padding=1))
b5 = nn.Sequential(Inception(832, 256, (160, 320), (32, 128), 128),
Inception(832, 384, (192, 384), (48, 128), 128),
d2l.GlobalAvgPool2d())
net = nn.Sequential(b1, b2, b3, b4, b5,
d2l.FlattenLayer(), nn.Linear(1024, 10))
net = nn.Sequential(b1, b2, b3, b4, b5, d2l.FlattenLayer(), nn.Linear(1024, 10))
X = torch.rand(1, 1, 96, 96)
for blk in net.children():
X = blk(X)
print('output shape: ', X.shape)
#batchsize=128
batch_size = 16
# 如出現(xiàn)“out of memory”的報(bào)錯(cuò)信息,可減小batch_size或resize
#train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size, resize=96)
lr, num_epochs = 0.001, 5
optimizer = torch.optim.Adam(net.parameters(), lr=lr)
d2l.train_ch5(net, train_iter, test_iter, batch_size, optimizer, device, num_epochs)
這篇文字對(duì)Word2Vec的數(shù)學(xué)原理講解的不錯(cuò)