一、使用框架的線性回歸方法
1. 基礎原理
????????在自求導線性回歸中,我們需要先自定義參數,并且需要通過數學公式來對w和b進行求導,然后在反向傳播過程中通過梯度下降的方式來更新參數,從而降低損失值。
2. 實現步驟
① 散點輸入
????????有一些散點,將它們繪制在一個二維坐標中,其分布如下圖所示:
② 定義前向模型
????????準備好數據之后,就需要定義前向模型了。在這里給出了“定義前向模型”組件,如下圖所示。
③ 定義損失函數和優化器
????????在選擇好前向的模型后,需要定義反向傳播過程中用到的一些超參數。在深度學習的三種框架中,關于損失函數和優化器的代碼實現都已經封裝好了,只需要選擇使用哪種即可。
④ 開始迭代
在選擇好損失函數及優化器之后,我們就可以進行迭代了。通過不斷的迭代更新,使w和b的值不斷更新,從而降低損失函數值,使直線的擬合效果更好,本實驗中,“開始迭代”組件中默認選擇的迭代次數是1000次,可以選擇不同的迭代次數來觀察直線的擬合效果。
⑤ 顯示頻率設置
????????迭代次數選好之后,就開始進行迭代了,為了能夠觀察到迭代過程中的現象,給出了“顯示頻率設置”的組件,該組件能夠設置每迭代多少次,顯示一次當前的參數值和損失值。
⑥?擬合線顯示與輸出
????????選擇好顯示頻率之后,通過“擬合線顯示與輸出”組件來查看我們的迭代過程中參數、直線及損失值的變化,內容如下圖所示:
二、pytorch框架線性回歸
1. 數據部分:
- 首先自定義了一個簡單的數據集,特征?
X
?是 100 個隨機樣本,每個樣本一個特征,目標值?y
?基于線性關系并添加了噪聲。 - 將?
numpy
?數組轉換為 PyTorch 張量,方便后續在模型中使用。
2. 模型定義部分:
方案 1:使用?nn.Sequential
?直接按順序定義了一個線性層,簡潔直觀。
import torch
import torch.nn as nn
import numpy as np
from sklearn.metrics import mean_squared_error, r2_score# 自定義數據集
X = np.random.rand(100, 1).astype(np.float32)
y = 2 * X + 1 + 0.3 * np.random.randn(100, 1).astype(np.float32)# 轉換為 PyTorch 張量
X_tensor = torch.from_numpy(X)
y_tensor = torch.from_numpy(y)# 定義線性回歸模型
model = nn.Sequential(nn.Linear(1, 1)
)# 定義損失函數和優化器
criterion = nn.MSELoss()
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)# 訓練模型
num_epochs = 1000
for epoch in range(num_epochs):# 前向傳播outputs = model(X_tensor)loss = criterion(outputs, y_tensor)# 反向傳播和優化optimizer.zero_grad()loss.backward()optimizer.step()if (epoch + 1) % 100 == 0:print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.item():.4f}')# 模型評估
with torch.no_grad():y_pred = model(X_tensor).numpy()mse = mean_squared_error(y, y_pred)
r2 = r2_score(y, y_pred)
print(f"均方誤差 (MSE): {mse}")
print(f"決定系數 (R2): {r2}")# 輸出模型的系數和截距
print("模型系數:", model[0].weight.item())
print("模型截距:", model[0].bias.item())
方案 2:使用?nn.ModuleList
?存儲線性層,在?forward
?方法中依次調用層進行前向傳播,適合動態構建層序列。
import torch
import torch.nn as nn
import numpy as np
from sklearn.metrics import mean_squared_error, r2_score# 自定義數據集
X = np.random.rand(100, 1).astype(np.float32)
y = 2 * X + 1 + 0.3 * np.random.randn(100, 1).astype(np.float32)# 轉換為 PyTorch 張量
X_tensor = torch.from_numpy(X)
y_tensor = torch.from_numpy(y)# 定義線性回歸模型
class LinearRegression(nn.Module):def __init__(self):super(LinearRegression, self).__init__()self.layers = nn.ModuleList([nn.Linear(1, 1)])def forward(self, x):for layer in self.layers:x = layer(x)return xmodel = LinearRegression()# 定義損失函數和優化器
criterion = nn.MSELoss()
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)# 訓練模型
num_epochs = 1000
for epoch in range(num_epochs):# 前向傳播outputs = model(X_tensor)loss = criterion(outputs, y_tensor)# 反向傳播和優化optimizer.zero_grad()loss.backward()optimizer.step()if (epoch + 1) % 100 == 0:print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.item():.4f}')# 模型評估
with torch.no_grad():y_pred = model(X_tensor).numpy()mse = mean_squared_error(y, y_pred)
r2 = r2_score(y, y_pred)
print(f"均方誤差 (MSE): {mse}")
print(f"決定系數 (R2): {r2}")# 輸出模型的系數和截距
print("模型系數:", model.layers[0].weight.item())
print("模型截距:", model.layers[0].bias.item())
方案 3:使用?nn.ModuleDict
?以字典形式存儲層,通過鍵名調用層,適合需要對層進行命名和靈活訪問的場景。
import torch
import torch.nn as nn
import numpy as np
from sklearn.metrics import mean_squared_error, r2_score# 自定義數據集
X = np.random.rand(100, 1).astype(np.float32)
y = 2 * X + 1 + 0.3 * np.random.randn(100, 1).astype(np.float32)# 轉換為 PyTorch 張量
X_tensor = torch.from_numpy(X)
y_tensor = torch.from_numpy(y)# 定義線性回歸模型
class LinearRegression(nn.Module):def __init__(self):super(LinearRegression, self).__init__()self.layers = nn.ModuleDict({'linear': nn.Linear(1, 1)})def forward(self, x):x = self.layers['linear'](x)return xmodel = LinearRegression()# 定義損失函數和優化器
criterion = nn.MSELoss()
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)# 訓練模型
num_epochs = 1000
for epoch in range(num_epochs):# 前向傳播outputs = model(X_tensor)loss = criterion(outputs, y_tensor)# 反向傳播和優化optimizer.zero_grad()loss.backward()optimizer.step()if (epoch + 1) % 100 == 0:print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.item():.4f}')# 模型評估
with torch.no_grad():y_pred = model(X_tensor).numpy()mse = mean_squared_error(y, y_pred)
r2 = r2_score(y, y_pred)
print(f"均方誤差 (MSE): {mse}")
print(f"決定系數 (R2): {r2}")# 輸出模型的系數和截距
print("模型系數:", model.layers['linear'].weight.item())
print("模型截距:", model.layers['linear'].bias.item())
方案 4:直接繼承?nn.Module
,在?__init__
?方法中定義線性層,在?forward
?方法中實現前向傳播邏輯,是最常見和基礎的定義模型方式。
import torch
import torch.nn as nn
import numpy as np
from sklearn.metrics import mean_squared_error, r2_score# 自定義數據集
X = np.random.rand(100, 1).astype(np.float32)
y = 2 * X + 1 + 0.3 * np.random.randn(100, 1).astype(np.float32)# 轉換為 PyTorch 張量
X_tensor = torch.from_numpy(X)
y_tensor = torch.from_numpy(y)# 定義線性回歸模型
class LinearRegression(nn.Module):def __init__(self):super(LinearRegression, self).__init__()self.linear = nn.Linear(1, 1)def forward(self, x):return self.linear(x)model = LinearRegression()# 定義損失函數和優化器
criterion = nn.MSELoss()
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)# 訓練模型
num_epochs = 1000
for epoch in range(num_epochs):# 前向傳播outputs = model(X_tensor)loss = criterion(outputs, y_tensor)# 反向傳播和優化optimizer.zero_grad()loss.backward()optimizer.step()if (epoch + 1) % 100 == 0:print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.item():.4f}')# 模型評估
with torch.no_grad():y_pred = model(X_tensor).numpy()mse = mean_squared_error(y, y_pred)
r2 = r2_score(y, y_pred)
print(f"均方誤差 (MSE): {mse}")
print(f"決定系數 (R2): {r2}")# 輸出模型的系數和截距
print("模型系數:", model.linear.weight.item())
print("模型截距:", model.linear.bias.item())
3. 訓練和評估部分:
- 定義了均方誤差損失函數?
nn.MSELoss
?和隨機梯度下降優化器?torch.optim.SGD
。 - 通過多個 epoch 進行訓練,每個 epoch 包含前向傳播、損失計算、反向傳播和參數更新。
- 訓練結束后,在無梯度計算模式下進行預測,并使用?
scikit-learn
?的指標計算均方誤差和決定系數評估模型性能,最后輸出模型的系數和截距。
三、tensorflow框架線性回歸
1. 數據部分:
- 首先自定義了一個簡單的數據集,特征?
X
?是 100 個隨機樣本,每個樣本一個特征,目標值?y
?基于線性關系并添加了噪聲。 - tensorflow框架不需要
numpy
?數組轉換為相應的張量,可以直接在模型中使用數據集。
2. 模型定義部分:
方案 1:model = tf.keras.Sequential([tf.keras.layers.Dense(1, input_shape=(1,))])
解釋:
- 此方案使用?
tf.keras.Sequential
?構建模型,在列表中直接定義了一個?Dense
?層,input_shape=(1,)
?表明輸入數據的形狀。 - 編譯模型時,選擇隨機梯度下降(SGD)優化器和均方誤差損失函數。
- 訓練完成后,使用?
sklearn
?的指標評估模型,并輸出模型的系數和截距。
import tensorflow as tf
import numpy as np
from sklearn.metrics import mean_squared_error, r2_score# 自定義數據集
X = np.random.rand(100, 1).astype(np.float32)
y = 2 * X + 1 + 0.3 * np.random.randn(100, 1).astype(np.float32)# 構建模型
model = tf.keras.Sequential([tf.keras.layers.Dense(1, input_shape=(1,))
])# 編譯模型
model.compile(optimizer=tf.keras.optimizers.SGD(learning_rate=0.01),loss='mean_squared_error')# 訓練模型
history = model.fit(X, y, epochs=1000, verbose=0)# 模型評估
y_pred = model.predict(X)
mse = mean_squared_error(y, y_pred)
r2 = r2_score(y, y_pred)
print(f"均方誤差 (MSE): {mse}")
print(f"決定系數 (R2): {r2}")# 輸出模型的系數和截距
weights, biases = model.layers[0].get_weights()
print(f"模型系數: {weights[0][0]}")
print(f"模型截距: {biases[0]}")
方案 2:model = tf.keras.Sequential()
解釋:
- 這種方式先創建一個空的?
Sequential
?模型,再使用?add
?方法添加?Dense
?層。 - 后續編譯、訓練、評估和輸出模型參數的步驟與方案 1 類似。
import tensorflow as tf
import numpy as np
from sklearn.metrics import mean_squared_error, r2_score# 自定義數據集
X = np.random.rand(100, 1).astype(np.float32)
y = 2 * X + 1 + 0.3 * np.random.randn(100, 1).astype(np.float32)# 構建模型
model = tf.keras.Sequential()
model.add(tf.keras.layers.Dense(1, input_shape=(1,)))# 編譯模型
model.compile(optimizer=tf.keras.optimizers.SGD(learning_rate=0.01),loss='mean_squared_error')# 訓練模型
history = model.fit(X, y, epochs=1000, verbose=0)# 模型評估
y_pred = model.predict(X)
mse = mean_squared_error(y, y_pred)
r2 = r2_score(y, y_pred)
print(f"均方誤差 (MSE): {mse}")
print(f"決定系數 (R2): {r2}")# 輸出模型的系數和截距
weights, biases = model.layers[0].get_weights()
print(f"模型系數: {weights[0][0]}")
print(f"模型截距: {biases[0]}")
方案 3:自定義模型類
解釋:
- 繼承?
Model
?基類創建自定義模型類?Linear
,在?__init__
?方法中定義?Dense
?層。 call
?方法用于實現前向傳播邏輯,類似于 PyTorch 中的?forward
?方法。- 后續的編譯、訓練、評估和參數輸出流程和前面方案一致。
import tensorflow as tf
from tensorflow.keras import Model
import numpy as np
from sklearn.metrics import mean_squared_error, r2_score# 自定義數據集
X = np.random.rand(100, 1).astype(np.float32)
y = 2 * X + 1 + 0.3 * np.random.randn(100, 1).astype(np.float32)# 自定義模型類
class Linear(Model):def __init__(self):super(Linear, self).__init__()self.linear = tf.keras.layers.Dense(1)def call(self, x, **kwargs):x = self.linear(x)return x# 構建模型
model = Linear()# 編譯模型
model.compile(optimizer=tf.keras.optimizers.SGD(learning_rate=0.01),loss='mean_squared_error')# 訓練模型
history = model.fit(X, y, epochs=1000, verbose=0)# 模型評估
y_pred = model.predict(X)
mse = mean_squared_error(y, y_pred)
r2 = r2_score(y, y_pred)
print(f"均方誤差 (MSE): {mse}")
print(f"決定系數 (R2): {r2}")# 輸出模型的系數和截距
weights, biases = model.linear.get_weights()
print(f"模型系數: {weights[0][0]}")
print(f"模型截距: {biases[0]}")
方案 4:函數式 API 構建模型
解釋:
- 使用函數式 API 構建模型,先定義輸入層,再定義?
Dense
?層,最后使用?Model
?類將輸入和輸出連接起來形成模型。 - 編譯、訓練、評估和參數輸出的步驟和前面方案相同。注意這里通過?
model.layers[1]
?獲取?Dense
?層的權重和偏置,因為第一層是輸入層。
import tensorflow as tf
import numpy as np
from sklearn.metrics import mean_squared_error, r2_score# 自定義數據集
X = np.random.rand(100, 1).astype(np.float32)
y = 2 * X + 1 + 0.3 * np.random.randn(100, 1).astype(np.float32)# 定義函數構建模型
def linear():input = tf.keras.layers.Input(shape=(1,), dtype=tf.float32)y = tf.keras.layers.Dense(1)(input)model = tf.keras.models.Model(inputs=input, outputs=y)return model# 構建模型
model = linear()# 編譯模型
model.compile(optimizer=tf.keras.optimizers.SGD(learning_rate=0.01),loss='mean_squared_error')# 訓練模型
history = model.fit(X, y, epochs=1000, verbose=0)# 模型評估
y_pred = model.predict(X)
mse = mean_squared_error(y, y_pred)
r2 = r2_score(y, y_pred)
print(f"均方誤差 (MSE): {mse}")
print(f"決定系數 (R2): {r2}")# 輸出模型的系數和截距
weights, biases = model.layers[1].get_weights()
print(f"模型系數: {weights[0][0]}")
print(f"模型截距: {biases[0]}")
3. 訓練和評估部分:
- 使用?
fit
?方法對模型進行訓練,verbose=0
?表示不顯示訓練過程中的詳細信息,訓練過程中的損失信息會存儲在?history
?對象中。 - 通過多個 epoch 進行訓練,每個 epoch 包含前向傳播、損失計算、反向傳播和參數更新。
- 使用?
predict
?方法進行預測,計算均方誤差和決定系數評估模型性能,通過?model.linear.get_weights()
?獲取模型的系數和截距。
四、paddlepaddle框架線性回歸
1. 數據部分:
- 首先自定義了一個簡單的數據集,特征?
X
?是 100 個隨機樣本,每個樣本一個特征,目標值?y
?基于線性關系并添加了噪聲。 - 將?
numpy
?數轉換為Paddlepaddle張量,方便后續在模型中使用。
2. 模型定義部分:
方案 1:使用?nn.Sequential
?組網
代碼解釋
① 數據生成與轉換:
- 生成自定義的特征矩陣?
X
?和目標值向量?y
,并添加高斯噪聲模擬真實數據。 - 使用?
paddle.to_tensor
?將?numpy
?數組轉換為 PaddlePaddle 張量。
② 模型組網:
- 使用?
nn.Sequential
?快速構建線性回歸模型,只包含一個?nn.Linear
?層。
③ 損失函數和優化器:
- 選擇均方誤差損失函數?
nn.MSELoss
?和隨機梯度下降優化器?paddle.optimizer.SGD
。
④ 模型訓練:
- 進行多個輪次的訓練,在每個輪次中進行前向傳播、損失計算、反向傳播和參數更新。
- 記錄每一輪的損失值,用于后續繪制損失曲線。
⑤ 損失曲線繪制:
- 使用?
matplotlib
?繪制訓練損失隨輪次的變化曲線,直觀展示模型的訓練過程。
⑥ 模型評估:
- 在無梯度計算的模式下進行預測,計算預測結果的均方誤差和決定系數。
⑦ 輸出模型參數:
- 獲取模型的系數和截距并輸出。
import paddle
import paddle.nn as nn
import numpy as np
from sklearn.metrics import mean_squared_error, r2_score
import matplotlib.pyplot as plt# 自定義數據集
# 生成 100 個樣本,每個樣本有 1 個特征
X = np.random.rand(100, 1).astype(np.float32)
# 根據特征生成目標值,添加一些噪聲
y = 2 * X + 1 + 0.3 * np.random.randn(100, 1).astype(np.float32)# 將 numpy 數組轉換為 PaddlePaddle 張量
X = paddle.to_tensor(X)
y = paddle.to_tensor(y)# 使用 nn.Sequential 組網
model = nn.Sequential(nn.Linear(1, 1)
)# 定義損失函數和優化器
criterion = nn.MSELoss()
optimizer = paddle.optimizer.SGD(learning_rate=0.01, parameters=model.parameters())# 訓練模型
num_epochs = 1000
losses = []
for epoch in range(num_epochs):# 前向傳播outputs = model(X)loss = criterion(outputs, y)losses.append(loss.numpy()[0])# 反向傳播和優化optimizer.clear_grad()loss.backward()optimizer.step()if (epoch + 1) % 100 == 0:print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.numpy()[0]:.4f}')# 繪制訓練損失曲線
plt.plot(range(num_epochs), losses)
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.title('Training Loss')
plt.show()# 模型評估
with paddle.no_grad():y_pred = model(X).numpy()mse = mean_squared_error(y.numpy(), y_pred)
r2 = r2_score(y.numpy(), y_pred)
print(f"均方誤差 (MSE): {mse}")
print(f"決定系數 (R2): {r2}")# 輸出模型的系數和截距
weights = model[0].weight.numpy()[0][0]
bias = model[0].bias.numpy()[0]
print(f"模型系數: {weights}")
print(f"模型截距: {bias}")
方案 2:單獨定義,使用類的方式?class nn.Layer
?組網
代碼解釋
此方案與方案 1 的主要區別在于模型的組網方式,具體如下:
模型組網:
① 定義一個繼承自?nn.Layer
?的自定義模型類?LinearRegression
。
② 在?__init__
?方法中初始化?nn.Linear
?層。
③ 在?forward
?方法中定義前向傳播邏輯。
后續步驟:
損失函數、優化器的選擇,模型訓練、評估以及參數輸出等步驟與方案 1 基本相同。
import paddle
import paddle.nn as nn
import numpy as np
from sklearn.metrics import mean_squared_error, r2_score
import matplotlib.pyplot as plt# 自定義數據集
# 生成 100 個樣本,每個樣本有 1 個特征
X = np.random.rand(100, 1).astype(np.float32)
# 根據特征生成目標值,添加一些噪聲
y = 2 * X + 1 + 0.3 * np.random.randn(100, 1).astype(np.float32)# 將 numpy 數組轉換為 PaddlePaddle 張量
X = paddle.to_tensor(X)
y = paddle.to_tensor(y)# 自定義模型類,繼承自 nn.Layer
class LinearRegression(nn.Layer):def __init__(self):super(LinearRegression, self).__init__()self.linear = nn.Linear(1, 1)def forward(self, x):return self.linear(x)# 創建模型實例
model = LinearRegression()# 定義損失函數和優化器
criterion = nn.MSELoss()
optimizer = paddle.optimizer.SGD(learning_rate=0.01, parameters=model.parameters())# 訓練模型
num_epochs = 1000
losses = []
for epoch in range(num_epochs):# 前向傳播outputs = model(X)loss = criterion(outputs, y)losses.append(loss.numpy()[0])# 反向傳播和優化optimizer.clear_grad()loss.backward()optimizer.step()if (epoch + 1) % 100 == 0:print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.numpy()[0]:.4f}')# 繪制訓練損失曲線
plt.plot(range(num_epochs), losses)
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.title('Training Loss')
plt.show()# 模型評估
with paddle.no_grad():y_pred = model(X).numpy()mse = mean_squared_error(y.numpy(), y_pred)
r2 = r2_score(y.numpy(), y_pred)
print(f"均方誤差 (MSE): {mse}")
print(f"決定系數 (R2): {r2}")# 輸出模型的系數和截距
weights = model.linear.weight.numpy()[0][0]
bias = model.linear.bias.numpy()[0]
print(f"模型系數: {weights}")
print(f"模型截距: {bias}")
3. 訓練和評估部分:
- 使用?
train_losses
?列表記錄每一輪訓練的損失值,方便后續繪制訓練損失曲線,直觀觀察模型的訓練過程。 - 將數據集按 80:20 的比例劃分為訓練集和測試集,以更準確地評估模型的泛化能力。
- 使用?
scikit-learn
?中的?mean_squared_error
?和?r2_score
?計算測試集的均方誤差和決定系數。