2.線性模型
3.梯度下降算法
4.反向傳播(用pytorch算梯度)
5.用pytorch實現線性回歸
6.logistic回歸
7.處理多維特征的輸入
8.加載數據集
9.多分類問題
10.卷積神經網絡(基礎篇)
11.卷積神經網絡(高級篇)_嗶哩嗶哩_bilibili
11.1 GoogleNet
????????GoogleNet其創新的Inception模塊而聞名,這種模塊允許網絡在同一層次中進行不同尺寸的卷積操作,從而捕捉不同尺度的特征。
11.1.2?Inception模塊
????????它的主要思想是在同一層次中使用不同大小的卷積核進行特征提取,從而能夠捕捉不同尺度的特征。設計神經網絡時以模塊為單位去組裝整個網絡結構,在神經網絡中多次重復使用該模塊,因此將其封裝為類,來減少代碼量。該模塊構成如下圖所示:
?
11.1.3 1*1convolution
? ? ? ??1x1卷積是一種在卷積神經網絡中使用的特殊類型的卷積操作。它的主要作用是調整特征圖的維度(即通道數),同時保持特征圖的空間尺寸(高度和寬度),此外,它還能跨通道的特征整合(不同通道的卷積結果最后求和)。例如,數據集為3*3*3經過3*1*1的卷積操作后,輸出結果為1*3*3,如下圖所示:
?
????????1x1卷積的計算量相對較小,因為卷積核的大小為1x1,只需要進行簡單的點乘和加法操作。這使得1x1卷積在深層網絡中非常有用,可以作為其他卷積操作的降維或升維層,提高整體網絡的計算效率。如下圖所示:經過1*1卷積后下方操作次數減少許多
?
11.1.4 Inception模塊的實現
課上的Inception模塊結構如下:?
- 平均池化路徑:
- 3x3平均池化。
- 1x1卷積降維。
- 1x1卷積:用于降維。
- 5x5卷積路徑:
- 1x1卷積降維。
- 5x5卷積提取特征。?
- 3x3卷積路徑:
- 1x1卷積降維。
- 3x3卷積提取特征。
- ?3x3卷積提取特征。
最后再將每條路徑所得張量,沿著channel的方向整合成一個張量?
????????
?????????代碼演示:
import torch
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets,transforms
from torch.utils.data import DataLoader
import matplotlib.pyplot as plt#1.準備數據
#1.1 定義transform
transform=transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.1307),(0.3081))])#1.2 下載數據
trainset = datasets.MNIST('../dataset/mnist',train=True,download=True,transform=transform)
#1.3 定義dataloader
train_loader = DataLoader(trainset,batch_size=64,shuffle=True)#1.4測試集
testset=datasets.MNIST(root='../dataset/mnist',train=False,download=True,transform=transform)
test_loader = DataLoader(testset,batch_size=64,shuffle=False)#2.定義網絡#2.1 定義inception模塊class Inception(torch.nn.Module):def __init__(self,in_channels):super(Inception,self).__init__()#2.1.1 平均池化路徑,所用到的1x1的卷積層self.branch_pool = torch.nn.Conv2d(in_channels,24,kernel_size=1)#輸入通道為in_channels,輸出通道為24,卷積核大小為1x1#2.1.2 1x1卷積路徑,僅用到1x1的卷積層self.branch1x1 = torch.nn.Conv2d(in_channels,16,kernel_size=1)#輸入通道為in_channels,輸出通道為16,卷積核大小為1x1#2.1.3 5x5卷積路徑 ,用到1X1和5x5的卷積層self.branch5x5_1 = torch.nn.Conv2d(in_channels,16,kernel_size=1)#輸入通道為in_channels,輸出通道為16,卷積核大小為1x1self.branch5x5_2 = torch.nn.Conv2d(16,24,kernel_size=5,padding=2)#輸入通道為16,輸出通道為24,卷積核大小為5x5,padding為2(保證輸出尺寸不變)#2.1.4 3x3卷積路徑,用到1x1、3x3的卷積層、3x3的卷積層self.branch3x3_1 = torch.nn.Conv2d(in_channels,16,kernel_size=1)#輸入通道為in_channels,輸出通道為16,卷積核大小為1x1self.branch3x3_2 = torch.nn.Conv2d(16,24,kernel_size=3,padding=1)#輸入通道為16,輸出通道為24,卷積核大小為3x3,padding為1(保證輸出尺寸不變)self.branch3x3_3 = torch.nn.Conv2d(24,24,kernel_size=3,padding=1)#輸入通道為24,輸出通道為24,卷積核大小為3x3,padding為1(保證輸出尺寸不變)def forward(self,x):#2.1.1 平均池化路徑,先經過平均池化,再經過1x1卷積branch_pool=F.avg_pool2d(x,kernel_size=3,stride=1,padding=1)#輸入為x,池化核大小為3x3,步長為1,padding為1branch_pool=self.branch_pool(branch_pool)#輸入為branch_pool,卷積核大小為1x1,輸出通道為24#2.1.2 1x1卷積路徑,直接經過1x1卷積branch1x1=self.branch1x1(x)#輸入為x,卷積核大小為1x1,輸出通道為16#2.1.3 5x5卷積路徑,先經過1x1卷積,再經過5x5卷積branch5x5=self.branch5x5_1(x)#輸入為x,卷積核大小為1x1,輸出通道為16branch5x5=self.branch5x5_2(branch5x5)#輸入為branch5x5,卷積核大小為5x5,輸出通道為24,padding為2#2.1.4 3x3卷積路徑,先經過1x1卷積,再經過3x3卷積,再經過3x3卷積branch3x3=self.branch3x3_1(x)#輸入為x,卷積核大小為1x1,輸出通道為16branch3x3=self.branch3x3_2(branch3x3)#輸入為branch3x3,卷積核大小為3x3,輸出通道為24,padding為1branch3x3=self.branch3x3_3(branch3x3)#輸入為branch3x3,卷積核大小為3x3,輸出通道為24,padding為1#2.1.5 將所有路徑的輸出拼接起來outputs=[branch_pool,branch1x1,branch5x5,branch3x3]return torch.cat(outputs,dim=1)#將outputs中的元素沿著dim=1方向(即通道維度)拼接起來,輸出為(batch_size,88,28,28)#2.2 定義網絡結構
class Net(torch.nn.Module):def __init__(self):super(Net,self).__init__()self.conv1=torch.nn.Conv2d(1,10,kernel_size=5)self.conv2=torch.nn.Conv2d(88,20,kernel_size=5)self.inception1=Inception(in_channels=10)self.inception2=Inception(in_channels=20)self.maxpool=torch.nn.MaxPool2d(2)self.fc1=torch.nn.Linear(88*4*4,10)def forward(self,x):#獲取batch_sizein_size=x.size(0)x=F.relu(self.maxpool(self.conv1(x)))x=self.inception1(x)x=F.relu(self.maxpool(self.conv2(x)))x=self.inception2(x)x=x.view(in_size,-1)x=self.fc1(x)return xmodel=Net()
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
model.to(device)#3.定義損失函數和優化器
criterion=torch.nn.CrossEntropyLoss()
optimizer=optim.SGD(model.parameters(),lr=0.01,momentum=0.5)#4.訓練網絡
#4.1 訓練函數
def train(epoch):running_loss=0.0for i,data in enumerate(train_loader,0):inputs,labels=datainputs,labels=inputs.to(device),labels.to(device)optimizer.zero_grad()#forward + backward + updateoutputs=model(inputs)loss=criterion(outputs,labels)loss.backward()optimizer.step()running_loss+=loss.item()if i%300==299:print('[%d, %5d] loss: %.3f' %(epoch+1,i+1,running_loss/300))running_loss=0.0#4.2 測試函數
acuracy_list=[]
def Net_test():correct=0total=0with torch.no_grad():for data in test_loader:inputs,targets=datainputs,targets=inputs.to(device),targets.to(device)outputs=model(inputs)_,predicted=torch.max(outputs.data,1)total+=targets.size(0)correct+=predicted.eq(targets.data).sum().item()print('Accuracy of the network test : %.2f %%' % (100.0*correct/total))acuracy_list.append(100.0*correct/total)#4.開始訓練
for epoch in range(10):train(epoch)Net_test()#5.繪制準確率變化圖
epochs=list(range(len(acuracy_list)))
plt.plot(epochs,acuracy_list)
plt.xlabel('Epoch')
plt.ylabel('Accuracy')
plt.title('Accuracy of the network')
plt.show()
????????運行結果:
?
11.2??ResidualNet(ResNet)
11.2.1深度帶來的問題
- 一是vanishing/exploding gradient,導致了訓練十分難收斂,這類問題能夠通過normalized initialization 和intermediate normalization layers解決;
- 另一個是被稱為degradation的退化現象。對合適的深度模型繼續增加層數,模型準確率會下滑(不是overfit造成),training error和test error都會很高,相應的現象在CIFAR-10和ImageNet都有出現。
????????當梯度小于1時,由于backword()求梯度時遵循鏈式法則,致使梯度相乘后不斷減小最終出現梯度消失,影響所求權重(),使得訓練不充分,最終導致準確率下降。下圖為深度增加而導致錯誤率增大
11.2.2 殘差結構
? ? ? ? 普通直連的卷積神經網絡和?ResNet?的最大區別在于,ResNet 有很多旁路的支線將輸入直接連到后面的層,使得后面的層可以直接學習殘差,這種結構也被稱shortcut connections。
????????傳統的卷積層或全連接層在信息傳遞時,或多或少會存在信息丟失、損耗等問題。ResNet 在某種程度上解決了這個問題,通過直接將輸入信息繞道傳到輸出,保護信息的完整性,整個網絡則只需要學習輸入、輸出差別的那一部分,簡化學習目標和難度。注意:實線部分是深度未發生變化的連接,虛線部分是深度發生變化的連接。 對應深度有變化的連接有兩種解決方案:?
- 使用 zero-pading 進行提升深度 parameter-free。
- 使用 1*1的卷積核提升維度 有卷積核的運算時間。
????????兩種方法,使用下面一種方法效果更好,但是運行會更耗時,一般還是更傾向于第一種方案節約運算成本。
?
11.2.3? 殘差塊
在正常的神經網絡中就是一層連一層,如下圖所示:
????????假定某段神經網絡的輸入是 x,期望輸出是 H(x),即 H(x) 是期望的復雜潛在映射,但學習難度大;如果我們直接把輸入 x 傳到輸出作為初始結果,通過下圖“shortcut connections”,那么此時我們需要學習的目標就是 F(x)=H(x)-x,于是 ResNet 相當于將學習目標改變了,不再是學習一個完整的輸出,而是最優解 H(X) 和全等映射 x 的差值,即殘差 F(x) = H(x) - x。
????????此時,梯度的計算公式,確保梯度大于等于1,就不會造成梯度消失。
?11.2.4 ResNet 結構
Residual Block 實現
值得注意的是,我們需要輸入通道和輸出通道一致
第一層中先做卷積在做relu(conv1(x)),第二層中做卷積conv2(y),最后返回relu(x+y)
????????代碼演示:
import torch
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets,transforms
from torch.utils.data import DataLoader
import matplotlib.pyplot as plt#1.準備數據
#1.1 定義transform
transform=transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.1307),(0.3081))])#1.2 下載數據
trainset = datasets.MNIST('../dataset/mnist',train=True,download=True,transform=transform)
#1.3 定義dataloader
train_loader = DataLoader(trainset,batch_size=64,shuffle=True)#1.4測試集
testset=datasets.MNIST(root='../dataset/mnist',train=False,download=True,transform=transform)
test_loader = DataLoader(testset,batch_size=64,shuffle=False)#2.定義網絡
#2.1 定義殘差塊
class ResidualBlock(torch.nn.Module):def __init__(self, channels):super(ResidualBlock, self).__init__()self.channels = channelsself.conv1 =torch.nn.Conv2d(channels, channels,kernel_size=3, padding=1)self.conv2 = torch.nn.Conv2d(channels, channels,kernel_size=3, padding=1)def forward(self, x):y = F.relu(self.conv1(x))y = self.conv2(y)return F.relu(x + y)# 注:這里的x + y是殘差單元的核心,即殘差單元的輸出等于輸入與殘差單元輸出的和,# 其中殘差單元輸出經過兩次卷積后與輸入相加,再經過激活函數ReLU。#2.2 定義網絡結構
class Net(torch.nn.Module):def __init__(self):super(Net, self).__init__()self.conv1 = torch.nn.Conv2d(1, 16, kernel_size=5)self.conv2 = torch.nn.Conv2d(16, 32, kernel_size=5)self.mp = torch.nn.MaxPool2d(2)self.rblock1 = ResidualBlock(16)self.rblock2 = ResidualBlock(32)self.fc =torch.nn.Linear(512, 10)def forward(self, x):in_size = x.size(0)x = self.mp(F.relu(self.conv1(x)))x = self.rblock1(x)x = self.mp(F.relu(self.conv2(x)))x = self.rblock2(x)x = x.view(in_size, -1)x = self.fc(x)return xmodel=Net()
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
model.to(device)#3.定義損失函數和優化器
criterion=torch.nn.CrossEntropyLoss()
optimizer=optim.SGD(model.parameters(),lr=0.01,momentum=0.5)#4.訓練網絡
#4.1 訓練函數
def train(epoch):running_loss=0.0for i,data in enumerate(train_loader,0):inputs,labels=datainputs,labels=inputs.to(device),labels.to(device)optimizer.zero_grad()#forward + backward + updateoutputs=model(inputs)loss=criterion(outputs,labels)loss.backward()optimizer.step()running_loss+=loss.item()if i%300==299:print('[%d, %5d] loss: %.3f' %(epoch+1,i+1,running_loss/300))running_loss=0.0#4.2 測試函數
acuracy_list=[]
def Net_test():correct=0total=0with torch.no_grad():for data in test_loader:inputs,targets=datainputs,targets=inputs.to(device),targets.to(device)outputs=model(inputs)_,predicted=torch.max(outputs.data,1)total+=targets.size(0)correct+=predicted.eq(targets.data).sum().item()print('Accuracy of the network test : %.2f %%' % (100.0*correct/total))acuracy_list.append(100.0*correct/total)#4.開始訓練
for epoch in range(10):train(epoch)Net_test()#5.繪制準確率變化圖
epochs=list(range(len(acuracy_list)))
plt.plot(epochs,acuracy_list)
plt.xlabel('Epoch')
plt.ylabel('Accuracy')
plt.title('Accuracy of the network')
plt.show()
????????運行結果:
?