?2.線性模型
3.梯度下降算法
4.反向傳播(用pytorch算梯度)
5.用pytorch實現線性回歸
6.logistic回歸
7.處理多維特征的輸入
8.加載數據集
9.多分類問題
10.卷積神經網絡(基礎篇)_嗶哩嗶哩_bilibili
10.1卷積神經網絡
10.1.1 卷積神經網絡工作流程:
????????
- 輸入數據:輸入通常是圖像等網格結構數據,通常經過歸一化等預處理。
- 卷積層:通過卷積核在輸入上滑動,提取局部特征,輸出特征圖,通常接ReLU等非線性激活函數。
- 池化層:對特征圖進行下采樣,減少尺寸,保留重要特征,常用最大池化或平均池化。
- 多層堆疊:卷積層和池化層交替堆疊,逐層提取更抽象的特征。
- 全連接層:將特征圖展平為一維向量,通過全連接層(僅由線性層串行構成)進行分類。
- 輸出層:根據任務輸出結果,如分類任務通過Softmax輸出概率分布。
10.2 卷積層(Convolutional Layer)
10.2.1 單通道卷積
????????在單通道二維圖像處理中,卷積操作涉及一個卷積核在圖像上滑動,計算卷積核與圖像局部區域的內積(僅數乘)。具體來說,假設有圖像?I和卷積核?K,2D卷積操作可以表示為,如下圖所示:
卷積層作用測試:
import torch
in_channels=5 # 輸入通道數
out_channels=10 # 輸出通道數
kernel_size=3 # 卷積核大小
batch_size=1 # 批大小
width=100 # 圖像寬度
height=100 # 圖像高度# 輸入數據 批大小 ,輸入通道數,圖像寬度,圖像高度
input=torch.randn(batch_size,in_channels,width,height)
#torch.randn函數會根據給定的形狀生成一個服從標準正態分布(均值為0,標準差為1)的隨機張量。# 卷積層 輸入通道數,輸出通道數,卷積核大小
#卷積層作用:對輸入數據進行特征提取,提取出圖像中有用的特征,并輸出到下一層進行進一步處理。
conv_layer=torch.nn.Conv2d(in_channels,out_channels,kernel_size)# 卷積輸出
output=conv_layer(input)print(f"輸入數據尺寸:{input.shape}")
print(f"卷積層權重尺寸:{conv_layer.weight.shape}")
print(f"卷積輸出尺寸:{output.shape}")
運行結果:
? ? ? ? ?卷積后的
?
10.2.2?多通道卷積
????????如圖所示,是多通道的卷積基本原理:圖像分配一個多通道卷積核,圖像的的每個通道分配到多通道卷積核的一個通道,而后每個通道根據單通道的計算方式計算,得到一個矩陣,一共可以得到多個矩陣,將這多個個矩陣求和,最終得到的結果就是多通道卷積的結果。下圖為3通道和n通道卷積工作圖:
注:圖像通道數=卷積核通道數?
? ? ? ? 若想要輸出的通道數不止一個,可以增加m個同種類型的卷積核,依次進行卷積運算,將得到的m個單層通道的卷積結果羅列起來,就得到了m個通道的輸出,過程如下圖所示:
?10.2.3 卷積層常用參數:
? ? ? ? padding:
????????當想要改變輸出結果的width、height時,就需要padding,如下圖所示,原輸出為一個 3 x 3 的矩陣,若想要將其一個 5 x 5 的矩陣時,padding操作就是在輸入圖像周圍進行填充,填充數值為0。
????????測試代碼:
import torchinput = [3,4,6,5,7,
2,4,6,8,2,
1,6,7,8,4,
9,7,4,6,2,
3,7,5,4,1]input=torch.Tensor(input).view(1,1,5,5)
#使用torch.Tensor(input)將這個列表轉換為PyTorch的張量。
#view(1,1,5,5)將這個一維張量轉換為一個四維張量,形狀為1x1x5x5,
#即一個批次(batch size為1)輸入通道(input channels為1)、5x5大小的圖像。conv_layer=torch.nn.Conv2d(1,1,kernel_size=3,padding=1,bias=False)
#使用torch.nn.Conv2d創建一個二維卷積層。
#輸入通道數為1,輸出通道數為1。
#kernel_size=3表示卷積核的大小為3x3。
#padding=1表示在輸入的每個維度上填充一層寬度為1的邊界(用零填充),這樣輸出的大小與輸入的大小相同。
#bias=False表示不使用偏置參數。kernel=torch.Tensor([1,2,3,4,5,6,7,8,9]).view(1,1,3,3)
# 定義了一個3x3的卷積核,其值為1到9。
# 使用view(1,1,3,3)將一維張量轉換為四維張量,形狀為1x1x3x3,符合Conv2d層的權重形狀要求。
# 將這個卷積核賦值給卷積層的權重conv_layer.weight.data。conv_layer.weight.data=kerneloutput=conv_layer(input)
print(output)
????????運行結果:?
? ? ? ? ?stride:
????????stride就是卷積核窗口在遍歷圖像時,每走一步的步長。如下圖所示,是stride=2時的卷積步驟:
? ? ? ?
?????????測試代碼:
input = [3,4,6,5,7,
2,4,6,8,2,
1,6,7,8,4,
9,7,4,6,2,
3,7,5,4,1]input=torch.Tensor(input).view(1,1,5,5)
#使用torch.Tensor(input)將這個列表轉換為PyTorch的張量。
#view(1,1,5,5)將這個一維張量轉換為一個四維張量,形狀為1x1x5x5,
#即一個批次(batch size為1)輸入通道(input channels為1)、5x5大小的圖像。conv_layer=torch.nn.Conv2d(1,1,kernel_size=3,stride=2,bias=False)
#使用torch.nn.Conv2d創建一個二維卷積層。
#輸入通道數為1,輸出通道數為1。
#kernel_size=3表示卷積核的大小為3x3。
#stride=2表示在輸入的寬度和高度方向上,每隔2個元素移動一次。
#bias=False表示不使用偏置參數。kernel=torch.Tensor([1,2,3,4,5,6,7,8,9]).view(1,1,3,3)
# 定義了一個3x3的卷積核,其值為1到9。
# 使用view(1,1,3,3)將一維張量轉換為四維張量,形狀為1x1x3x3,符合Conv2d層的權重形狀要求。
# 將這個卷積核賦值給卷積層的權重conv_layer.weight.data。conv_layer.weight.data=kerneloutput=conv_layer(input)
print(output)
? ? ? ? ?運行結果:
?10.3 最大池化層(Max Pooling Layer)
????????最大池化通過在特征圖的局部區域內取最大值來生成新的特征圖。它在空間維度(高度和寬度)上進行操作,但不改變通道數。
????????假設輸入特征圖的形狀為 [H×W×C],其中 H 是高度,W 是寬度,C 是通道數。最大池化的操作過程如下:
- 劃分窗口:將特征圖劃分為多個不重疊的局部區域(窗口)。窗口的大小(例如 2×2)和步幅(通常與窗口大小相同)是預先設定的參數。
- 取最大值:在每個局部窗口內,取所有元素的最大值。
- 生成輸出特征圖:將這些最大值組成新的特征圖。輸出特征圖的形狀為 [H′×W′×C],其中 H′ 和 W′ 是輸出特征圖的高度和寬度。
? ? ? ? ?測試代碼:
import torchinput = [3,4,6,5,
2,4,6,8,
1,6,7,8,
9,7,4,6,
]input = torch.Tensor(input).view(1, 1, 4, 4)
maxpooling_layer = torch.nn.MaxPool2d(kernel_size=2)
#這里創建了一個最大池化層(MaxPool2d),kernel_size=2表示池化窗口的大小為2x2。
#最大池化層的作用是從輸入的每個2x2區域中選擇最大的值,
#以此來縮減特征圖(feature map)的尺寸。output = maxpooling_layer(input)
print(output)
? ? ? ? 運行結果:?
10.4 課上練習:
? ? ? ? 課上代碼:
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 加載訓練數據集
train_dataset = datasets.MNIST('../dataset/mnist',train=True,download=True,transform=transform)
#1.3 定義訓練數據加載器
train_loader=DataLoader(train_dataset, batch_size=64, shuffle=True)#測試集
test_dataset = datasets.MNIST('../dataset/mnist',train=False,transform=transform)
test_loader=DataLoader(test_dataset, batch_size=64, shuffle=False)#2.定義網絡結構
# 兩個卷積層(conv1和conv2),分別用于提取圖像特征。
# 一個池化層(pool),用于減少特征圖的尺寸,保留重要信息。
# 一個全連接層(fc1),用于將提取的特征映射到10維的輸出向量,對應于MNIST數據集中的10個數字類別。
class Net(torch.nn.Module):def __init__(self):super(Net, self).__init__()#輸入通道為1,輸出通道為10,卷積核大小為5self.conv1 = torch.nn.Conv2d(1, 10, kernel_size=5)# 定義第一個卷積層,輸入通道數為1(因為MNIST圖像為灰度圖),# 輸出通道數為10(即提取10種特征),卷積核大小為5x5。# H*W的圖像轉換為10個H*W的特征圖(H`=H-5+1, W`=W-5+1)。#輸入通道為10,輸出通道為20,卷積核大小為5self.conv2 = torch.nn.Conv2d(10, 20, kernel_size=5)# 定義第二個卷積層,輸入通道數為10(來自conv1的輸出),輸出通道數為20(即提取20種特征),卷積核大小為5x5。# H*W的圖像轉換為10個H*W的特征圖(H`=H-5+1, W`=W-5+1)。#池化層,池化核大小為2self.pool = torch.nn.MaxPool2d(2)# 定義一個最大池化層,池化核大小為2x2。# 池化層的主要作用是減少特征圖的尺寸,同時保留重要信息。# 圖像的尺寸減半H`=H/2, W`=W/2#全連接層,輸入維度為320,輸出維度為10self.fc1 = torch.nn.Linear(320, 10)# 定義一個全連接層,輸入維度為320# (計算方法為20 * 4 * 4,因為經過兩次卷積和池化后,輸出的特征圖尺寸為20x4x4),# 輸出維度為10(對應于MNIST數據集中的10個數字類別)。def forward(self, x):batch_size = x.size(0) #獲取batch_sizex=F.relu(self.pool(self.conv1(x)))#圖像10x28x28,經過第一個卷積層后,圖像變為 10x24x24,經過池化層后,圖像變為 10x12x12。#ReLU函數的作用是將輸入小于0的部分歸零,大于0的部分保持不變,有助于提高模型的訓練效率。x=F.relu(self.pool(self.conv2(x)))#圖像10x12x12,經過第二個卷積層后,圖像變為 20x8x8,經過池化層后,圖像變為 20x4x4。#展平特征圖x=x.view(batch_size,-1)# -1 表示自動計算展平后的維度大小。# 對于第二個卷積層后的特征圖,形狀為 (batch_size, 20, 4, 4),# 展平后的形狀為 (batch_size, 20 * 4 * 4),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 every 300 mini-batchesprint('[%d, %5d] loss: %.3f' % (epoch + 1, i + 1, running_loss / 300))running_loss = 0.0#4.2定義測試函數
preRate_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, dim=1)total += targets.size(0)correct += (predicted == targets).sum().item()preRate_list.append(100 * correct / total)print('Accuracy of the network test images: %d %% [ %d / %d ]' % (100 * correct / total, correct, total))#4.3開始訓練與測試
for epoch in range(10):train(epoch)Net_test()#5.繪制準確率與輪數的關系圖
epoch_list=list(range(len(preRate_list)))
plt.plot(epoch_list,preRate_list)
plt.xlabel('Epoch')
plt.ylabel('Accuracy')
plt.title('Accuracy vs Epoch')
plt.show()
? ? ? ? 運行結果: