簡單的神經網絡
數據的準備
# 仍然用4特征,3分類的鳶尾花數據集作為我們今天的數據集
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
import numpy as np# 加載鳶尾花數據集
iris = load_iris()
X = iris.data # 特征數據
y = iris.target # 標簽數據
# 劃分訓練集和測試集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)# 打印下尺寸
print(X_train.shape)
print(y_train.shape)
print(X_test.shape)
print(y_test.shape)
# 歸一化數據,神經網絡對于輸入數據的尺寸敏感,歸一化是最常見的處理方式
from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test) #確保訓練集和測試集是相同的縮放
# 將數據轉換為 PyTorch 張量,因為 PyTorch 使用張量進行訓練
# y_train和y_test是整數,所以需要轉化為long類型,如果是float32,會輸出1.0 0.0
X_train = torch.FloatTensor(X_train)
y_train = torch.LongTensor(y_train)
X_test = torch.FloatTensor(X_test)
y_test = torch.LongTensor(y_test)
模型架構定義
定義一個簡單的全連接神經網絡模型,包含一個輸入層、一個隱藏層和一個輸出層。
定義層數+定義前向傳播順序
import torch
import torch.nn as nn
import torch.optim as optim
class MLP(nn.Module): # 定義一個多層感知機(MLP)模型,繼承父類nn.Moduledef __init__(self): # 初始化函數super(MLP, self).__init__() # 調用父類的初始化函數# 前三行是八股文,后面的是自定義的self.fc1 = nn.Linear(4, 10) # 輸入層到隱藏層self.relu = nn.ReLU()self.fc2 = nn.Linear(10, 3) # 隱藏層到輸出層
# 輸出層不需要激活函數,因為后面會用到交叉熵函數cross_entropy,交叉熵函數內部有softmax函數,會把輸出轉化為概率def forward(self, x):out = self.fc1(x)out = self.relu(out)out = self.fc2(out)return out# 實例化模型
model = MLP()
# def forward(self,x): #前向傳播# x=torch.relu(self.fc1(x)) #激活函數# x=self.fc2(x) #輸出層不需要激活函數,因為后面會用到交叉熵函數cross_entropy# return x
模型訓練(CPU版本)
定義損失函數和優化器
# 分類問題使用交叉熵損失函數
criterion = nn.CrossEntropyLoss()# 使用隨機梯度下降優化器
optimizer = optim.SGD(model.parameters(), lr=0.01)# # 使用自適應學習率的化器
# optimizer = optim.Adam(model.parameters(), lr=0.001)
開始循環訓練
實際上在訓練的時候,可以同時觀察每個epoch訓練完后測試集的表現:測試集的loss和準確度
# 訓練模型
num_epochs = 20000 # 訓練的輪數# 用于存儲每個 epoch 的損失值
losses = []for epoch in range(num_epochs): # range是從0開始,所以epoch是從0開始# 前向傳播outputs = model.forward(X_train) # 顯式調用forward函數# outputs = model(X_train) # 常見寫法隱式調用forward函數,其實是用了model類的__call__方法loss = criterion(outputs, y_train) # output是模型預測值,y_train是真實標簽# 反向傳播和優化optimizer.zero_grad() #梯度清零,因為PyTorch會累積梯度,所以每次迭代需要清零,梯度累計是那種小的bitchsize模擬大的bitchsizeloss.backward() # 反向傳播計算梯度optimizer.step() # 更新參數# 記錄損失值losses.append(loss.item())# 打印訓練信息if (epoch + 1) % 100 == 0: # range是從0開始,所以epoch+1是從當前epoch開始,每100個epoch打印一次print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {loss.item():.4f}')
可視化結果
import matplotlib.pyplot as plt
# 可視化損失曲線
plt.plot(range(num_epochs), losses)
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.title('Training Loss over Epochs')
plt.show()