復習日:
回顧神經網絡的相關信息
1. 梯度下降的思想
梯度下降的本質是一種迭代優化算法,用于尋找函數的極小值點(比如損失函數的最小值)其關鍵的要素如下
- 梯度:函數在某點變化率最大方向
- 學習率:每一步的“步長”,用以控制更新幅度
- 迭代更新:設參數為
,損失函數為
,則更新公式為:
,沿著梯度的反方向更新參數,是損失不斷減少
2. 激活函數的作用
? ? ? ? 若神經網絡僅由線性層組成,本質就是線性變換的疊加,只能你和線性關系,無法解決非線性問題(比如圖像識別、自然語言處理),因此使用激活函數為神經網絡引入非線性表達能力,能找你和更為復雜的數據分布。常見的激活函數有:ReLU、Sigmoid、Tanh等等。
3. 損失函數的作用
? ? ? ? 損失函數(Loss Function)是衡量模型預測值與真實值之間差異函數,用于量化模型的“錯誤程度”。常見的損失函數有
回歸任務
- 均方誤差、平均絕對誤差
分類任務
- 交叉熵損失
- 稀疏交叉熵
4. 優化器
? ? ? ? 優化器是控制模型參數更新策略的組件,負責根據損失函數的梯度調整參數,以最小化損失。可以這樣理解:梯度下降是“下山的方向”,優化器則是“調整步長和路線的策略”。
? ? ? ? 常見的優化器有SDG、Adam等等。
5. 神經網絡的概念
? ? ? ? 神經網絡是一種模仿生物神經元結構的計算模型,由多層神經元相互連接,用于自動提取數據特征并完成預測任務。
? ? ? ? 基本組成:
- 神經元(Neuron):接受輸入信號,進行線性變換和非線性激活,輸出結果
- 層(Layer):
- 輸入層:接收原始數據(如圖片像素值),不參與計算。
- 隱藏層:介于輸入層和輸出層之間,負責特征提取(層數和神經元數量決定模型復雜度)。
- 輸出層:產生最終結果(如分類概率、回歸值),激活函數根據任務選擇(如分類用 Softmax,回歸用線性激活)
- 連接權重(Weight)和偏置(Bias):
- 權重:控制信號傳遞的 “強度”,通過訓練學習得到
- 偏置:允許激活函數平移,增加模型靈活性
? ? ? ? 神經網絡的工作流程:
- 前向傳播(Forward Propagation):輸入數據經各層線性變換 + 激活函數,逐層傳遞至輸出層,得到預測值。
- 損失計算:用損失函數衡量預測值與真實值的差異。
- 反向傳播(Backpropagation):從輸出層向輸入層反向傳遞梯度,利用鏈式法則計算各層參數的梯度,指導優化器更新參數。
典型的神經網絡類型:全連接神經網絡(Fully Connected NN)、卷積神經網絡(CNN)、循環神經網絡(RNN)、Transformer
針對之前的信貸項目,利用神經網絡訓練下,用到目前的知識點讓代碼更加規范和美觀。
# 導包
import pandas as pd #用于數據處理和分析,可處理表格數據。
import numpy as np #用于數值計算,提供了高效的數組操作。
import matplotlib.pyplot as plt #用于繪制各種類型的圖表
import seaborn as sns #基于matplotlib的高級繪圖庫,能繪制更美觀的統計圖形。
import warnings
warnings.filterwarnings("ignore")# 設置中文字體(解決中文顯示問題)
plt.rcParams['font.sans-serif'] = ['SimHei'] # Windows系統常用黑體字體
plt.rcParams['axes.unicode_minus'] = False # 正常顯示負號data = pd.read_csv('data.csv') #讀取數據#數據預處理# 先篩選字符串變量
discrete_features = data.select_dtypes(include=['object']).columns.tolist()
# Home Ownership 標簽編碼
home_ownership_mapping = {'Own Home': 1,'Rent': 2,'Have Mortgage': 3,'Home Mortgage': 4
}
data['Home Ownership'] = data['Home Ownership'].map(home_ownership_mapping)# Years in current job 標簽編碼
years_in_job_mapping = {'< 1 year': 1,'1 year': 2,'2 years': 3,'3 years': 4,'4 years': 5,'5 years': 6,'6 years': 7,'7 years': 8,'8 years': 9,'9 years': 10,'10+ years': 11
}
data['Years in current job'] = data['Years in current job'].map(years_in_job_mapping)# Purpose 獨熱編碼,記得需要將bool類型轉換為數值
data = pd.get_dummies(data, columns=['Purpose'])
data2 = pd.read_csv("data.csv") # 重新讀取數據,用來做列名對比
list_final = [] # 新建一個空列表,用于存放獨熱編碼后新增的特征名
for i in data.columns:if i not in data2.columns:list_final.append(i) # 這里打印出來的就是獨熱編碼后的特征名
for i in list_final:data[i] = data[i].astype(int) # 這里的i就是獨熱編碼后的特征名# Term 0 - 1 映射
term_mapping = {'Short Term': 0,'Long Term': 1
}
data['Term'] = data['Term'].map(term_mapping)
data.rename(columns={'Term': 'Long Term'}, inplace=True) # 重命名列
continuous_features = data.select_dtypes(include=['int64', 'float64']).columns.tolist() #把篩選出來的列名轉換成列表# 連續特征用中位數補全
for feature in continuous_features: mode_value = data[feature].mode()[0] #獲取該列的眾數。data[feature].fillna(mode_value, inplace=True) #用眾數填充該列的缺失值,inplace=True表示直接在原數據上修改。data.drop(columns=['Id'], inplace=True) # 刪除 Loan ID 列# 分離特征數據和標簽數據
X = data.drop(['Credit Default'], axis=1) # 特征數據
y = data['Credit Default'] # 標簽數據X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)scaler = MinMaxScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test) # 確保訓練集和測試集是相同的縮放X_train = torch.FloatTensor(X_train).to(device)
y_train = torch.LongTensor(y_train.values).to(device)
X_test = torch.FloatTensor(X_test).to(device)
y_test = torch.LongTensor(y_test.values).to(device)class MLP(nn.Module):def __init__(self):super(MLP, self).__init__()self.fc1 = nn.Linear(30, 64) # 增加第一層神經元數量self.relu = nn.ReLU()self.dropout = nn.Dropout(0.3) # 添加Dropout防止過擬合self.fc2 = nn.Linear(64, 32)self.relu = nn.ReLU()self.fc3 = nn.Linear(32, 2) # 減少隱藏層數,保持輸出層不變def forward(self, x):out = self.fc1(x)out = self.relu(out)out = self.dropout(out) # 應用Dropoutout = self.fc2(out)out = self.relu(out)out = self.fc3(out)return out# 實例化模型并移至GPU
model = MLP().to(device)# 分類問題使用交叉熵損失函數
criterion = nn.CrossEntropyLoss()# 使用隨機梯度下降優化器
optimizer = optim.Adam(model.parameters(), lr=0.001)# 訓練模型
num_epochs = 20000 # 訓練的輪數# 用于存儲每200個epoch的損失值和對應的epoch數
losses = []
epochs = []start_time = time.time() # 記錄開始時間# 創建tqdm進度條
with tqdm(total=num_epochs, desc="訓練進度", unit="epoch") as pbar:# 訓練模型for epoch in range(num_epochs):# 前向傳播outputs = model(X_train) # 隱式調用forward函數loss = criterion(outputs, y_train)# 反向傳播和優化optimizer.zero_grad()loss.backward()optimizer.step()# 記錄損失值并更新進度條if (epoch + 1) % 200 == 0:losses.append(loss.item())epochs.append(epoch + 1)# 更新進度條的描述信息pbar.set_postfix({'Loss': f'{loss.item():.4f}'})# 每1000個epoch更新一次進度條if (epoch + 1) % 1000 == 0:pbar.update(1000) # 更新進度條# 確保進度條達到100%if pbar.n < num_epochs:pbar.update(num_epochs - pbar.n) # 計算剩余的進度并更新time_all = time.time() - start_time # 計算訓練時間
print(f'Training time: {time_all:.2f} seconds')# 繪制損失曲線
plt.figure(figsize=(10, 6))
plt.plot(epochs, losses, 'r-', linewidth=2)
plt.title('Training Loss over Epochs')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.grid(True)
plt.show()# # 在測試集上評估模型
# model.eval() # 設置模型為評估模式
# with torch.no_grad(): # 禁用梯度計算
# outputs = model(X_test) # 對測試數據進行前向傳播
# _, predicted = torch.max(outputs, 1) # 獲取預測結果# correct = (predicted == y_test).sum().item() # 計算預測正確的樣本數
# accuracy = correct / y_test.size(0)
# print(f'測試集準確率: {accuracy * 100:.2f}%')
嘗試進入nn.Module中,查看他的方法:
可以查看官方文檔module
或者使用 Python 內置函數:
import torch.nn as nn# 查看nn.Module的所有屬性和方法
print(dir(nn.Module))# 獲取某個方法的詳細幫助信息
# 例如查看forward方法
help(nn.Module.forward)
創建自己的神經網絡模塊時,需要繼承nn.Module
類,并且可以重寫或使用其中的方法。
import torch
import torch.nn as nnclass MyNetwork(nn.Module):def __init__(self):super().__init__()# 定義網絡層self.fc1 = nn.Linear(10, 20)self.fc2 = nn.Linear(20, 1)def forward(self, x):# 定義前向傳播過程x = torch.relu(self.fc1(x))x = self.fc2(x)return x# 創建模型實例
model = MyNetwork()# 使用nn.Module的方法
print(model.parameters()) # 返回模型參數的迭代器
print(model.state_dict()) # 返回模型的狀態字典
在這個例子中,MyNetwork
類繼承了nn.Module
,并且可以使用nn.Module
的所有方法,像parameters()
、state_dict()
等。
@浙大疏錦行