一、層和塊
通過實體化nn.Sequential來構建我們的模型,下面的代碼生成一個網路,其中包含一個具有256個單元和ReLU激活函式的全連接的隱藏層,然后是一個具有10個隱藏單元且不帶激活函式的全連接的輸出層,net(X)呼叫我們的模型來獲得模型的輸出,
import torch
from torch import nn
from torch.nn import functional as F
net = nn.Sequential(nn.Linear(20, 256), nn.ReLU(), nn.Linear(256, 10))
X = torch.rand(2, 20)
net(X)
正向傳播(forward)函式也非常簡單:它將串列中的每個塊連接在一起,將每個塊的輸出作為下一個塊的輸入,
1、自定義塊
二、卷積層
卷積是一種有效提取圖片特征的方法 , 一般用一個正方形卷積核,遍歷圖片上的每一個像素點,圖片與卷積核重合區域內相對應的每一個像素值,乘卷積核內相對應點的權重,然后求和, 再加上偏置后,最后得到輸出圖片中的一個像素值,
圖片分灰度圖和彩色圖,卷積核可以是單個也可以是多個,因此卷積操作分以下三種情況:
1、單通道輸入,單卷積核
這里單通道指的是輸入為灰度圖,單卷積核值卷積核個數是1個

2、多通道輸入,單卷積核
多數情況下,輸入的圖片是 RGB 三個顏色組成的彩色圖,輸入的圖片包含了紅、綠、藍三層資料,卷積核的深度(通道數)應該等于輸入圖片的通道數,所以使用 3x3x3的卷積核,最后一個 3 表示匹配輸入影像的 3 個通道,這樣這個卷積核有三通道,每個通道都會隨機生成 9 個待優化的引數,一共有 27 個待優化引數 w 和一個偏置 b,
卷積計算方法和單層卷積核相似,卷積核為了匹配紅綠藍三個顏色,把三層的卷積核套在三層的彩色圖片上,重合的 27 個像素進行對應點的乘加運算,最后的結果再加上偏置項 b,求得輸出圖片中的一個值,

3、多通道輸入,多卷積核
(1)先取出一個卷積核與3通道的輸入進行卷積,這個程序就和多通道輸入,單卷積核一樣,得到一個1通道的輸出output1,同樣再取出第二個卷積核進行同樣的操作,得到第二個輸出output2
(2)將相同size的output1與output2進行堆疊,就得到2通道的輸出output,
圖中輸入X:[1,h,w,3]指的是:輸入1張高h寬w的3通道圖片,
卷積核W:[k,k,3,2]指的是:卷積核尺寸為3*3,通道數為3,個數為2,
三、池化層
專門的網路層可以實作尺寸縮減功能,通過從區域相關的一組元素中進行采樣或資訊聚合,從而得到新的元素值,通常我們用到兩種池化進行下采樣:
(1)最大池化(Max Pooling),從區域相關元素集中選取最大的一個元素值,
(2)平均池化(Average Pooling),從區域相關元素集中計算平均值并回傳,
全連接層
之所以叫全連接,是因為每個神經元與前后相鄰層的每一個神經元都有連接關系,

引數個數:(前層*后層+后層)
按照上圖搭建的兩層全連接網路,要訓練解析度僅僅是 28x28=784 的黑白影像,就有近 40 萬個待優化的引數,現實生活中高解析度的彩色影像,像素點更多,且為紅綠藍三通道資訊,待優化的引數過多, 容易導致模型過擬合,為避免這種現象,實際應用中一般不會將原始圖片直接喂入全連接網路,
在實際應用中,會先對原始影像進行卷積特征提取,把提取到的特征喂給全連接網路,再讓全連接網路計算出分類評估值,
四、卷積神經網路LeNet
LeNet(LeNet-5)由兩個部分組成: * 卷積編碼器:由兩個卷積層組成; * 全連接層密集塊:由三個全連接層組成,


import torch
from torch import nn
from d2l import torch as d2l
class Reshape(torch.nn.Module):
def forward(self, x):
return x.view(-1, 1, 28, 28)
net = torch.nn.Sequential(
Reshape(),
nn.Conv2d(1, 6, kernel_size=5, padding=2), nn.Sigmoid(),
nn.AvgPool2d(kernel_size=2, stride=2),
nn.Conv2d(6, 16, kernel_size=5), nn.Sigmoid(),
nn.AvgPool2d(kernel_size=2, stride=2),
nn.Flatten(),
nn.Linear(16 * 5 * 5, 120), nn.Sigmoid(),
nn.Linear(120, 84), nn.Sigmoid(),
nn.Linear(84, 10))
stride步幅:卷積核經過輸入特征圖的采樣間隔,不會重疊在一起
padding填充:在輸入特征圖的每一邊添加一定數目的行列,使得輸出的特征圖的長、寬 = 輸入的特征圖的長、寬
kernel_size:視窗大小
Flatten():拉成一維向量
X = torch.rand(size=(1, 1, 28, 28), dtype=torch.float32)
for layer in net:
X = layer(X)
print(layer.__class__.__name__,'output shape: \t',X.shape)

訓練模型
import torch
from torch import nn
from d2l import torch as d2l
batch_size = 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size=batch_size)
class Reshape(torch.nn.Module):
def forward(self, x):
return x.view(-1, 1, 28, 28)
net = torch.nn.Sequential(
Reshape(),
nn.Conv2d(1, 6, kernel_size=5, padding=2), nn.Sigmoid(),
nn.AvgPool2d(kernel_size=2, stride=2),
nn.Conv2d(6, 16, kernel_size=5), nn.Sigmoid(),
nn.AvgPool2d(kernel_size=2, stride=2),
nn.Flatten(),
nn.Linear(16 * 5 * 5, 120), nn.Sigmoid(),
nn.Linear(120, 84), nn.Sigmoid(),
nn.Linear(84, 10))
def evaluate_accuracy_gpu(net, data_iter, device=None):
"""使用GPU計算模型在資料集上的精度,"""
if isinstance(net, torch.nn.Module):
net.eval() # 設定為評估模式
if not device:
device = next(iter(net.parameters())).device
# 正確預測的數量,總預測的數量
metric = d2l.Accumulator(2)
for X, y in data_iter:
if isinstance(X, list):
# BERT微調所需的(之后將介紹)
X = [x.to(device) for x in X]
else:
X = X.to(device)
y = y.to(device)
metric.add(d2l.accuracy(net(X), y), y.numel())
return metric[0] / metric[1]
def train_ch6(net, train_iter, test_iter, num_epochs, lr, device):
"""用GPU訓練模型(在第六章定義),"""
def init_weights(m):
if type(m) == nn.Linear or type(m) == nn.Conv2d:
nn.init.xavier_uniform_(m.weight)
net.apply(init_weights)
print('training on', device)
net.to(device)
optimizer = torch.optim.SGD(net.parameters(), lr=lr)
loss = nn.CrossEntropyLoss()
animator = d2l.Animator(xlabel='epoch', xlim=[1, num_epochs],
legend=['train loss', 'train acc', 'test acc'])
timer, num_batches = d2l.Timer(), len(train_iter)
for epoch in range(num_epochs):
# 訓練損失之和,訓練準確率之和,范例數
metric = d2l.Accumulator(3)
net.train()
for i, (X, y) in enumerate(train_iter):
timer.start()
optimizer.zero_grad()
X, y = X.to(device), y.to(device)
y_hat = net(X)
l = loss(y_hat, y)
l.backward()
optimizer.step()
with torch.no_grad():
metric.add(l * X.shape[0], d2l.accuracy(y_hat, y), X.shape[0])
timer.stop()
train_l = metric[0] / metric[2]
train_acc = metric[1] / metric[2]
if (i + 1) % (num_batches // 5) == 0 or i == num_batches - 1:
animator.add(epoch + (i + 1) / num_batches,
(train_l, train_acc, None))
test_acc = evaluate_accuracy_gpu(net, test_iter)
animator.add(epoch + 1, (None, None, test_acc))
print(f'loss {train_l:.3f}, train acc {train_acc:.3f}, '
f'test acc {test_acc:.3f}')
print(f'{metric[2] * num_epochs / timer.sum():.1f} examples/sec '
f'on {str(device)}')
lr, num_epochs = 0.9, 10
train_ch6(net, train_iter, test_iter, num_epochs, lr, d2l.try_gpu())
實體分析 “貓狗大戰”
1、首先參考學習之前的代碼,結合李沐老師課程中的LeNet-5網路進行了改進,進行簡單的調整,
2、還需要增加輸出在訓練集和測驗集上的acc圖,
3、因為時間開銷過大,train和test資料集使用了原始資料集的一部分;最終實作效果不好,需要進一步改進網路,
4、對于LeNet整體的把味訓有些問題,對于一些細節的處理沒有完全理解,多學習幾個實體,希望能有進步,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/301855.html
標籤:其他
