文章目錄
Barebones PyTorch
Three-Layer ConvNet
使用pytorch抽象等級1的方式實現卷積神經網絡。
three_layer_convnet()
out1 = F.conv2d(x, conv_w1, bias=conv_b1, stride=1, padding=(2,2))
relu1 = F.relu(out1)
out2 = F.conv2d(relu1, conv_w2, bias=conv_b2, stride=1, padding=(1,1))
relu2 = F.relu(out2)
scores = torch.mm(flatten(relu2), fc_w) + fc_b
Training a ConvNet
使用上面完成的卷積神經網絡,訓練模型。下面需要完成初始化參數。
conv_w1 = random_weight((channel_1,3,5,5))
conv_b1 = zero_weight((channel_1,))
conv_w2 = random_weight((channel_2,channel_1,3,3))
conv_b2 = zero_weight((channel_2,))
fc_w = random_weight((32*32*channel_2,10))
fc_b = zero_weight((10,))
PyTorch Module API
接下來的代碼使用nn.Module來完成,與上面的代碼進行比較可以發現,使用nn.Module的代碼更具有層次性,符合面向對象的編程思想。並且在上面的代碼中,需要手動實現參數初始化,但是在下面的代碼中可以直接通過nn的函數來實現。
class ThreeLayerConvNet
def __init__(self, in_channel, channel_1, channel_2, num_classes):
super().__init__()
self.conv1 = nn.Conv2d(in_channel, channel_1, kernel_size=5,stride=1, padding=2)
nn.init.kaiming_normal_(self.conv1.weight)
self.conv2 = nn.Conv2d(channel_1, channel_2, kernel_size=3, stride=1,padding=1)
nn.init.kaiming_normal_(self.conv2.weight)
self.fc = nn.Linear(channel_2 * 32 * 32, num_classes)
nn.init.kaiming_normal_(self.fc.weight)
def forward(self, x):
scores = None
relu1 = F.relu(self.conv1(x))
relu2 = F.relu(self.conv2(relu1))
scores = self.fc(flatten(relu2)
return scores
Module API: Train a Three-Layer ConvNet
使用已經寫好的網絡,訓練一個模型,使之在CIFAR10的準確率達到45%以上。
PyTorch.ipynb
in_channel = 3
num_classes = 10
model = ThreeLayerConvNet(in_channel=in_channel, channel_1=channel_1, channel_2=channel_2, num_classes=num_classes)
optimizer = optim.SGD(model.parameters(), lr=learning_rate, momentum=0.9)
Part IV. PyTorch Sequential API
可以從上面的代碼中發現,使用模塊API需要完成在__init__中的定義,以及在forward函數中實現每一層的連接。下面使用Sequential API,它把所有步驟合成爲一個了,這也就決定了他的靈活性不如Module API,但是對於絕大多數場景來說是夠用了。
model = nn.Sequential(
nn.Conv2d(3,channel_1,kernel_size=5, padding=2, bias=True),
nn.ReLU(),
nn.Conv2d(channel_1, channel_2, kernel_size=3, padding=1, bias=True),
nn.ReLU(),
Flatten(),
nn.Linear(channel_2 * 32 * 32, 10, bias=True)
)
optimizer = optim.SGD(model.parameters(), momentum=0.9, lr=learning_rate, nesterov=True)
Part V. CIFAR-10 open-ended challenge
使用自定義的網絡結構,完成對CIFAR-10數據集的訓練和分類,使之準確率達到70%以上,我才用的結構爲
[conv-relu-pool]xN -> [affine]xM -> [softmax or SVM]
channel_1 = 20
channel_2 = 30
learning_rate=0.001
model = nn.Sequential(
nn.Conv2d(3, 32, kernel_size=5, stride=1, padding=2),
nn.ReLU(),
nn.MaxPool2d(2, 2),
nn.Conv2d(32, 64, kernel_size=5, stride=1, padding=2),
nn.ReLU(),
nn.MaxPool2d(2, 2),
nn.Conv2d(64, 128, kernel_size=5, stride=1, padding=2),
nn.ReLU(),
nn.MaxPool2d(2, 2),
Flatten(),
nn.Linear(128 * 4 * 4, 20),
nn.Linear(20, 10)
)
optimizer = optim.Adam(model.parameters(), lr=learning_rate)
最後的準確率有76%
搭建卷積神經網絡需要注意的事項
在搭建網絡的過程中,要注意每一層的結構大小,需要按照一定的公式進行計算。
卷積層:
F爲卷積核大小,W爲圖片的寬,H爲圖片的高,S爲步長,P爲padding大小
D:圖像深度(通道數),N:卷積核(過濾器)個數
卷積層後輸出的大小爲:
W' = (W - F + 2P)/S + 1
H' = (H - F + 2P)/S + 1
卷積後輸出圖像深度:
N' = N
池化層:
W:圖像寬,H:圖像高,D:圖像深度(通道數)
F:卷積核寬高,S:步長
池化後的大小爲:
W=(W-F)/S+1
H=(H-F)/S+1
池化後輸出圖像深度:
N' = D(保持上一層不變)