通過這個示例,可以了解邏輯回歸模型的基本原理和訓練過程,同時可以通過修改和優化代碼來進一步探索機器學習模型的訓練和調優方法。
過程:
- 生成了一個模擬的二分類數據集:通過隨機生成包含兩個特征的數據
data_x
,并基于一定規則生成對應的二分類標簽數據data_y
。 - 創建了一個手動實現的邏輯回歸模型
LogisticRegressionManually
,其中包括:- 初始化函數
__init__
:初始化模型的權重參數w
和偏置參數b
。 - 前向傳播函數
forward
:計算給定輸入數據的預測值。 - 損失函數
loss_func
:定義了交叉熵損失函數,用于評估模型的預測性能。 - 訓練函數
train
:在每個epoch中,遍歷數據集的每個樣本,計算預測值、損失值、梯度,并利用梯度下降法更新模型參數。
- 初始化函數
- 實例化
LogisticRegressionManually
類,然后調用train
方法對模型進行訓練。 - 在訓練過程中,打印每個epoch的損失值。
演示:
# 生成模擬的二分類數據集,其中X數據是隨機生成的,Y數據根據一定規則生成。import torch
import torch.nn.functional as Fn_items = 1000
n_features = 2
learning_rate = 0.001
epochs = 100# 置了隨機種子,以確保每次運行代碼時生成的隨機數相同,從而使結果具有可重現性。
torch.manual_seed(123)
# 生成了一個大小為(1000, 2)的張量data_x,其中包含1000個樣本,每個樣本具有2個特征。這里使用torch.randn生成標準正態分布的隨機數作為數據,并將數據類型轉換為float。
data_x = torch.randn(size=(n_items, n_features)).float()
# 成了標簽數據data_y,通過對第一個特征乘以0.5和第二個特征乘以1.5的差值進行判斷,如果差值大于0就將標簽設為1,否則為0。這樣生成了一個二分類標簽數據集,同樣將數據類型轉換為float。
data_y = torch.where(torch.subtract(data_x[:, 0]*0.5, data_x[:, 1]*1.5) > 0, 1., 0.).float()# print(data_x)
# print(data_y)
# 在每個epoch中,遍歷數據集的每個樣本,計算預測值、損失值、梯度,利用梯度下降法更新模型參數。通過這種方式訓練模型可以逐漸優化模型參數,以達到更好的預測效果。class LogisticRegressionManually(object):# 初始化函數__init__def __init__(self):# w是一個大小為(n_features, 1)的張量,用于存儲權重參數,并且設置了requires_grad=True表示需要計算梯度;self.w = torch.randn(size=(n_features, 1), requires_grad=True)# b是一個大小為(1, 1)的張量,用于存儲偏置參數,并且設置了requires_grad=Trueself.b = torch.zeros(size=(1, 1), requires_grad=True)# 前向傳播函數forwarddef forward(self, x):# 過矩陣乘法計算預測值y_hat:將參數w轉置后與輸入數據x相乘,并加上偏置b后通過F.sigmoid函數進行激活,最終返回激活后的預測值。y_hat = F.sigmoid(torch.matmul(self.w.transpose(0, 1), x) + self.b)return y_hat# 損失函數loss_func@staticmethoddef loss_func(y_hat, y):# 定義了交叉熵損失函數。通過計算實際標簽y和預測值y_hat之間的交叉熵損失來評估模型的預測性能。return -(torch.log(y_hat)*y + (1-y)*torch.log(1-y_hat))# 訓練函數traindef train(self):# 在每個epoch中,遍歷數據集中的每個樣本for epoch in range(epochs):for step in range(n_items):# 利用模型的前向傳播函數forward計算當前樣本的預測值y_hat。y_hat = self.forward(data_x[step])# 獲取當前樣本的真實標簽yy = data_y[step]# 調用損失函數loss_func計算預測值與真實標簽之間的損失。loss = self.loss_func(y_hat, y)# 利用反向傳播計算損失對模型參數的梯度loss.backward()# 進入torch.no_grad()上下文管理器,保證在該范圍內的操作不會被記錄用于自動微分。with torch.no_grad():# 更新權重參數w和偏置參數b,通過梯度下降法更新參數,learning_rate是學習率。self.w.data -= learning_rate * self.w.gradself.b.data -= learning_rate * self.b.grad# 清零梯度,以便進行下一次參數更新時重新計算梯度。self.w.grad.data.zero_()self.b.grad.data.zero_()print("Epoch: %03d, Loss: %.3f" % (epoch, loss.item()))
lrm = LogisticRegressionManually()
lrm.train()
結果: