1 線性回歸
線性回歸是一種基本的預測模型,用于根據輸入特征預測連續的輸出值。它是機器學習和深度學習中最簡單的模型之一,但卻是理解更復雜模型的基礎。
1.1 線性回歸的基本元素
概念理解:
線性回歸假設輸入特征和輸出之間存在線性關系。具體來說,假設有一個輸入特征向量 x x x 和一個目標值 y y y,線性回歸模型的目標是找到一個線性函數 f ( x ) f(x) f(x) ,使得 f ( x ) f(x) f(x)盡可能接近 y y y。
線性回歸模型的基本形式為:
y ^ = X w + b \hat{y} = Xw + b y^?=Xw+b
其中:
- X X X是輸入特征矩陣,每一行表示一個樣本,每一列表示一個特征。
- w w w 是權重向量,表示每個特征的權重。
- b b b是偏置項,是一個標量,用于調整模型的整體偏移。
- y ^ \hat{y} y^? 是預測值,是一個向量,表示每個樣本的預測結果。
代碼示例:
假設我們有一個簡單的線性回歸問題,輸入特征是一個一維向量 X X X,目標值是一個標量 y y y。
import numpy as np
import matplotlib.pyplot as plt# 生成數據
np.random.seed(42)
X = 2 * np.random.rand(100, 1)
y = 4 + 3 * X + np.random.randn(100, 1)# 繪制數據
plt.scatter(X, y)
plt.xlabel('X')
plt.ylabel('y')
plt.title('Generated Data')
plt.show()
1.2 向量化加速
概念理解:
向量化是一種利用矩陣和數組操作來替換顯式循環的技術。它可以顯著提高代碼的執行效率,尤其是在現代硬件(如GPU)上。在深度學習中,向量化操作是構建高效模型的關鍵。
代碼示例:
在上述數據生成代碼中,我們使用了 NumPy 的向量化操作來生成數據。這種操作比使用循環生成數據要快得多。
1.3 正態分布與平方損失
概念理解:
線性回歸通常假設誤差項(即真實值與預測值之間的差異)服從正態分布。因此,線性回歸常用的損失函數是均方誤差(MSE),它衡量了預測值與真實值之間的平方誤差。
均方誤差的公式為:
[ \text{MSE} = \frac{1}{n} \sum_{i=1}^{n} (y_i - \hat{y}_i)^2 ]
其中:
- ( y_i ) 是第 ( i ) 個樣本的真實值。
- ( \hat{y}_i ) 是第 ( i ) 個樣本的預測值。
- ( n ) 是樣本總數。
代碼示例:
定義均方誤差損失函數。
def mean_squared_error(y_true, y_pred):return ((y_true - y_pred) ** 2).mean()# 測試損失函數
y_true = np.array([3, 2, 4, 5])
y_pred = np.array([2.5, 2, 4, 5.5])
mse = mean_squared_error(y_true, y_pred)
print(f'Mean Squared Error: {mse}')
1.4 從線性回歸到深度網絡
概念理解:
線性回歸是深度學習的一個特例,其中網絡僅包含一個線性層。深度學習模型通過堆疊多個線性層和非線性激活函數來處理更復雜的數據。這些非線性激活函數(如 ReLU、Sigmoid)使得模型能夠學習數據中的非線性關系。
代碼示例:
構建一個簡單的深度神經網絡模型(包含一個隱藏層)。
import torch
import torch.nn as nn# 定義模型
class SimpleNN(nn.Module):def __init__(self):super(SimpleNN, self).__init__()self.linear1 = nn.Linear(1, 10) # 輸入特征維度為1,隱藏層維度為10self.relu = nn.ReLU()self.linear2 = nn.Linear(10, 1) # 輸出維度為1def forward(self, x):x = self.linear1(x)x = self.relu(x)x = self.linear2(x)return x# 實例化模型
model = SimpleNN()# 打印模型結構
print(model)
1.5 訓練線性回歸模型
概念理解:
訓練線性回歸模型的目標是找到最優的權重 w w w和偏置 b b b,使得損失函數(如均方誤差)最小。這通常通過優化算法(如梯度下降法)來實現。
代碼示例:
訓練一個簡單的線性回歸模型。
import torch.optim as optim# 轉換數據為張量
X_tensor = torch.from_numpy(X).float()
y_tensor = torch.from_numpy(y).float()# 定義模型
model = nn.Linear(1, 1)# 定義損失函數和優化器
criterion = nn.MSELoss()
optimizer = optim.SGD(model.parameters(), lr=0.01)# 訓練模型
num_epochs = 1000
for epoch in range(num_epochs):# 前向傳播y_pred = model(X_tensor)loss = criterion(y_pred, y_tensor)# 反向傳播optimizer.zero_grad()loss.backward()optimizer.step()if (epoch + 1) % 100 == 0:print(f'Epoch {epoch + 1}, Loss: {loss.item():.4f}')# 打印訓練后的參數
print(f'Estimated weight: {model.weight.item():.2f}, Estimated bias: {model.bias.item():.2f}')
1.6 模型評估
概念理解:
評估線性回歸模型的性能通常使用均方誤差(MSE)或其他回歸指標(如均方根誤差 RMSE、平均絕對誤差 MAE)。
代碼示例:
評估訓練后的模型性能。
# 使用訓練后的模型進行預測
y_pred = model(X_tensor).detach().numpy()# 計算均方誤差
mse = mean_squared_error(y, y_pred)
print(f'Mean Squared Error: {mse:.4f}')# 繪制真實值和預測值
plt.scatter(X, y, color='blue', label='True data')
plt.plot(X, y_pred, color='red', linewidth=2, label='Fitted line')
plt.xlabel('X')
plt.ylabel('y')
plt.title('Linear Regression')
plt.legend()
plt.show()
通過上述步驟,你可以從理論和實踐兩個方面理解線性回歸模型。線性回歸是深度學習的基礎,掌握它有助于你更好地理解和構建更復雜的神經網絡模型。
2 線性回歸的從零開始實現
2.1 生成數據集
首先生成一個簡單的模擬數據集用于訓練和測試我們的線性回歸模型。我們假設真實模型是 y = 4 + 3 X y= 4 + 3X y=4+3X + 噪聲 ,其中噪聲服從正態分布。
import numpy as np# 設置隨機種子以確保結果可復現
np.random.seed(42)# 生成訓練數據
X_train = 2 * np.random.rand(100, 1) # 特征
y_train = 4 + 3 * X_train + np.random.randn(100, 1) # 目標值,包含噪聲# 生成測試數據
X_test = 2 * np.random.rand(20, 1)
y_test = 4 + 3 * X_test + np.random.randn(20, 1)
2.2 數據預處理
在訓練模型之前,通常需要對數據進行預處理。在這里,我們將數據轉換為適合進行矩陣運算的形式。
# 數據預處理:將數據轉換為矩陣形式
X_train = np.hstack((np.ones((X_train.shape[0], 1)), X_train)) # 添加偏置項
X_test = np.hstack((np.ones((X_test.shape[0], 1)), X_test))
2.3 初始化模型參數
初始化線性回歸模型的權重向量。在我們這個簡單例子中,權重向量包含偏置項和特征的系數。
# 初始化權重向量(包括偏置項)
theta = np.random.randn(2, 1) # 2行1列,對應偏置和一個特征的權重
2.4 定義模型
定義線性回歸模型的正向傳播過程。這一步就是根據當前的權重向量計算預測值。
# 定義線性回歸模型
def linear_regression(X, theta):return X.dot(theta)
2.5 定義損失函數
選擇均方誤差(MSE)作為損失函數,它衡量了預測值與真實值之間的差異。
# 定義均方誤差損失函數
def mean_squared_error(y_true, y_pred):return np.mean((y_true - y_pred) ** 2)
2.6 定義優化算法
使用小批量隨機梯度下降法(Mini-batch Gradient Descent)來優化模型參數。我們手動計算梯度并更新參數。
# 定義小批量隨機梯度下降法
def minibatch_gradient_descent(X, y, theta, learning_rate, epochs, batch_size):m = len(y)for epoch in range(epochs):# 打亂數據indices = np.arange(m)np.random.shuffle(indices)X_shuffled = X[indices]y_shuffled = y[indices]# 分成小批次for i in range(0, m, batch_size):X_batch = X_shuffled[i:i+batch_size]y_batch = y_shuffled[i:i+batch_size]# 正向傳播y_pred = linear_regression(X_batch, theta)# 計算梯度gradient = (2 / batch_size) * X_batch.T.dot(y_pred - y_batch)# 更新參數theta -= learning_rate * gradient# 每隔一定迭代次數打印損失if epoch % 100 == 0:y_pred = linear_regression(X, theta)loss = mean_squared_error(y, y_pred)print(f'Epoch {epoch}, Loss: {loss}')return theta
2.7 訓練模型
現在開始訓練模型,使用我們剛才定義的梯度下降法來優化模型參數。
# 設置超參數
learning_rate = 0.01
epochs = 1000
batch_size = 10# 訓練模型
theta = minibatch_gradient_descent(X_train, y_train, theta, learning_rate, epochs, batch_size)# 輸出最終的模型參數
print(f'Estimated parameters: {theta.flatten()}')
2.8 模型評估
訓練完成后,我們對模型進行評估,看看它在測試集上的表現。
# 在測試集上進行預測
y_test_pred = linear_regression(X_test, theta)# 計算測試集上的損失
test_loss = mean_squared_error(y_test, y_test_pred)
print(f'Test Loss: {test_loss}')# 可視化結果
import matplotlib.pyplot as plt# 繪制訓練數據和測試數據
plt.scatter(X_train[:, 1], y_train, label='Training Data')
plt.scatter(X_test[:, 1], y_test, label='Test Data')# 繪制預測線
X_plot = np.linspace(0, 2, 100).reshape(-1, 1)
X_plot = np.hstack((np.ones((X_plot.shape[0], 1)), X_plot))
y_plot_pred = linear_regression(X_plot, theta)
plt.plot(X_plot[:, 1], y_plot_pred, color='red', label='Fitted Line')plt.xlabel('X')
plt.ylabel('y')
plt.title('Linear Regression from Scratch')
plt.legend()
plt.show()
3 線性回歸的簡潔實現
將使用PyTorch的高級API來實現線性回歸模型。這種方法更加簡潔,利用了PyTorch的內置功能,減少了代碼量并提高了開發效率。
3.1 生成數據集
我們繼續使用之前生成的數據,但如果需要重新生成,可以使用以下代碼:
import numpy as np
import torch
from torch.utils.data import TensorDataset, DataLoader# 生成數據集
np.random.seed(42)
X = 2 * np.random.rand(100, 1) # 100個樣本,每個樣本1個特征
y = 4 + 3 * X + np.random.randn(100, 1) # 真實模型 y = 3x + 4 加上一些噪聲# 轉換為張量
X_tensor = torch.from_numpy(X).float()
y_tensor = torch.from_numpy(y).float()# 創建數據集和數據加載器
dataset = TensorDataset(X_tensor, y_tensor)
data_loader = DataLoader(dataset, batch_size=10, shuffle=True)
3.2 定義模型
使用PyTorch的 nn.Linear
來定義線性回歸模型:
import torch.nn as nn# 定義模型
model = nn.Linear(1, 1) # 輸入特征維度為1,輸出維度為1
3.3 初始化模型參數
初始化模型的權重和偏置:
# 初始化參數
nn.init.normal_(model.weight, mean=0, std=0.01)
nn.init.zeros_(model.bias)
3.4 定義損失函數
使用PyTorch內置的均方誤差損失函數:
# 定義損失函數
loss_fn = nn.MSELoss()
3.5 定義優化算法
使用PyTorch的 torch.optim
模塊來定義優化器:
# 定義優化算法
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)
3.6 訓練模型
訓練模型并評估性能:
# 訓練模型
num_epochs = 100
for epoch in range(num_epochs):for X_batch, y_batch in data_loader:# 前向傳播y_pred = model(X_batch)loss = loss_fn(y_pred, y_batch)# 反向傳播optimizer.zero_grad()loss.backward()optimizer.step()if (epoch + 1) % 10 == 0:print(f'Epoch {epoch + 1}, Loss: {loss.item():.4f}')print(f'Estimated weight: {model.weight.item():.2f}, Estimated bias: {model.bias.item():.2f}')
3.7 模型評估
評估訓練后的模型性能,并繪制預測結果:
import matplotlib.pyplot as plt# 使用訓練后的模型進行預測
X_new = torch.tensor([[0], [2]]).float()
y_predict = model(X_new).detach().numpy()# 繪制數據和預測結果
plt.scatter(X, y, color='blue', label='True data')
plt.plot(X_new.numpy(), y_predict, color='red', linewidth=2, label='Fitted line')
plt.xlabel('X')
plt.ylabel('y')
plt.title('Linear Regression')
plt.legend()
plt.show()
3.8 完整代碼
將上述代碼整合在一起,可以直接運行以下代碼來實現線性回歸模型的簡潔版:
import numpy as np
import torch
import torch.nn as nn
from torch.utils.data import TensorDataset, DataLoader
import matplotlib.pyplot as plt# 生成數據集
np.random.seed(42)
X = 2 * np.random.rand(100, 1) # 100個樣本,每個樣本1個特征
y = 4 + 3 * X + np.random.randn(100, 1) # 真實模型 y = 3x + 4 加上一些噪聲# 轉換為張量
X_tensor = torch.from_numpy(X).float()
y_tensor = torch.from_numpy(y).float()# 創建數據集和數據加載器
dataset = TensorDataset(X_tensor, y_tensor)
data_loader = DataLoader(dataset, batch_size=10, shuffle=True)# 定義模型
model = nn.Linear(1, 1) # 輸入特征維度為1,輸出維度為1# 初始化參數
nn.init.normal_(model.weight, mean=0, std=0.01)
nn.init.zeros_(model.bias)# 定義損失函數
loss_fn = nn.MSELoss()# 定義優化算法
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)# 訓練模型
num_epochs = 100
for epoch in range(num_epochs):for X_batch, y_batch in data_loader:# 前向傳播y_pred = model(X_batch)loss = loss_fn(y_pred, y_batch)# 反向傳播optimizer.zero_grad()loss.backward()optimizer.step()if (epoch + 1) % 10 == 0:print(f'Epoch {epoch + 1}, Loss: {loss.item():.4f}')print(f'Estimated weight: {model.weight.item():.2f}, Estimated bias: {model.bias.item():.2f}')# 使用訓練后的模型進行預測
X_new = torch.tensor([[0], [2]]).float()
y_predict = model(X_new).detach().numpy()# 繪制數據和預測結果
plt.scatter(X, y, color='blue', label='True data')
plt.plot(X_new.numpy(), y_predict, color='red', linewidth=2, label='Fitted line')
plt.xlabel('X')
plt.ylabel('y')
plt.title('Linear Regression')
plt.legend()
plt.show()
概念理解
- 簡潔實現:使用PyTorch的高級API(如
nn.Linear
、torch.optim
)可以大大減少代碼量,提高開發效率。 - 模型定義:
nn.Linear
是PyTorch中定義線性層的模塊,自動管理權重和偏置。 - 損失函數:使用PyTorch內置的
MSELoss
,無需手動定義。 - 優化器:使用PyTorch的
torch.optim
模塊中的優化器(如SGD),自動更新模型參數。 - 訓練過程:通過循環調用
DataLoader
,自動處理數據的分批和隨機打亂。
通過這種簡潔實現,你可以更高效地構建和訓練線性回歸模型,同時利用PyTorch的強大功能來處理復雜的任務。
4 softmax回歸
Softmax回歸是用于多分類問題的線性模型。它通過Softmax函數將線性回歸的輸出轉換為概率分布,從而實現多類分類。
4.1 Softmax回歸的基本概念
概念理解:
Softmax回歸適用于多分類問題,其中目標值是離散的類別。模型通過學習輸入特征和類別之間的關系,預測每個類別的概率。
Softmax回歸的模型形式為:
y ^ \hat{y} y^?= s o f t m a x softmax softmax( X W + b XW + \mathbf{b} XW+b)
其中:
- X X X 是輸入特征矩陣。
- W W W 是權重矩陣,每一列對應一個類別的權重向量。
- b \mathbf{b} b 是偏置向量,每個元素對應一個類別的偏置。
- y ^ \hat{y} y^? 是預測的類別概率分布。
Softmax函數的定義為:
softmax ( z ) i \text{softmax}(\mathbf{z})_i softmax(z)i? = exp ? ( z i ) ∑ j = 1 K exp ? ( z j ) \frac{\exp(z_i)}{\sum_{j = 1}^{K} \exp(z_j)} ∑j=1K?exp(zj?)exp(zi?)?
其中:
- z z z 是線性回歸的輸出。
- K K K 是類別的總數。
- softmax ( z ) i ) \text{softmax}(\mathbf{z})_i) softmax(z)i?) 是第 i i i 個類別的概率。
4.2 Softmax回歸的從零開始實現
4.2.1 生成數據集
為了演示,我們生成一個簡單的多分類數據集,假設是一個三分類問題。
import numpy as np
import matplotlib.pyplot as plt# 生成數據集
np.random.seed(42)
X = np.random.rand(300, 2)
y = np.random.randint(0, 3, 300)# 繪制數據
plt.scatter(X[y == 0][:, 0], X[y == 0][:, 1], color='red', label='Class 0')
plt.scatter(X[y == 1][:, 0], X[y == 1][:, 1], color='blue', label='Class 1')
plt.scatter(X[y == 2][:, 0], X[y == 2][:, 1], color='green', label='Class 2')
plt.xlabel('X1')
plt.ylabel('X2')
plt.title('Generated Data')
plt.legend()
plt.show()
4.2.2 定義Softmax函數
Softmax函數將線性回歸的輸出轉換為概率分布。
def softmax(z):exp_z = np.exp(z - np.max(z, axis=1, keepdims=True)) # 防止數值溢出return exp_z / np.sum(exp_z, axis=1, keepdims=True)
4.2.3 定義模型
Softmax回歸模型的前向傳播。
def model(X, W, b):return softmax(X @ W + b)
4.2.4 定義損失函數
Softmax回歸使用交叉熵損失函數。
def cross_entropy_loss(y_pred, y_true):return -np.mean(np.log(y_pred[np.arange(len(y_true)), y_true]))
4.2.5 定義優化算法
使用隨機梯度下降法更新模型參數。
def gradient_descent(X, y, W, b, learning_rate):y_pred = model(X, W, b)loss = cross_entropy_loss(y_pred, y)# 計算梯度m = len(X)y_one_hot = np.eye(3)[y] # 將標簽轉換為one-hot編碼dW = X.T @ (y_pred - y_one_hot) / mdb = np.sum(y_pred - y_one_hot, axis=0) / m# 更新參數W -= learning_rate * dWb -= learning_rate * dbreturn loss
4.2.6 訓練模型
訓練Softmax回歸模型。
# 初始化參數
W = np.random.randn(2, 3)
b = np.zeros(3)# 訓練參數
learning_rate = 0.1
num_epochs = 100# 訓練過程
losses = []
for epoch in range(num_epochs):loss = gradient_descent(X, y, W, b, learning_rate)losses.append(loss)if (epoch + 1) % 10 == 0:print(f'Epoch {epoch + 1}, Loss: {loss:.4f}')# 繪制損失曲線
plt.plot(losses)
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.title('Loss Curve')
plt.show()
4.3 Softmax回歸的簡潔實現
使用PyTorch的高級API來實現Softmax回歸,更加簡潔高效。
4.3.1 定義模型
使用PyTorch的 nn.Linear
和 nn.Softmax
定義模型。
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import TensorDataset, DataLoader# 轉換為張量
X_tensor = torch.tensor(X, dtype=torch.float32)
y_tensor = torch.tensor(y, dtype=torch.long)# 創建數據集和數據加載器
dataset = TensorDataset(X_tensor, y_tensor)
data_loader = DataLoader(dataset, batch_size=32, shuffle=True)# 定義模型
model = nn.Sequential(nn.Linear(2, 3), # 輸入特征維度為2,輸出類別數為3nn.Softmax(dim=1) # 對輸出應用Softmax函數
)# 定義損失函數和優化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.1)
4.3.2 訓練模型
訓練Softmax回歸模型。
# 訓練模型
num_epochs = 100
losses = []for epoch in range(num_epochs):for X_batch, y_batch in data_loader:# 前向傳播y_pred = model(X_batch)loss = criterion(y_pred, y_batch)# 反向傳播optimizer.zero_grad()loss.backward()optimizer.step()losses.append(loss.item())if (epoch + 1) % 10 == 0:print(f'Epoch {epoch + 1}, Loss: {loss.item():.4f}')# 繪制損失曲線
plt.plot(losses)
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.title('Loss Curve')
plt.show()
4.4 模型評估
評估訓練后的模型性能,計算準確率。
# 計算準確率
model.eval() # 設置為評估模式
with torch.no_grad():y_pred = model(X_tensor)_, predicted = torch.max(y_pred, 1)accuracy = (predicted == y_tensor).sum().item() / len(y_tensor)print(f'Accuracy: {accuracy * 100:.2f}%')
4.5 完整代碼
將上述代碼整合在一起,可以直接運行以下代碼來實現Softmax回歸模型的簡潔版:
import numpy as np
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import TensorDataset, DataLoader
import matplotlib.pyplot as plt### 生成數據集
np.random.seed(42)
X = np.random.rand(300, 2)
y = np.random.randint(0, 3, 300)### 轉換為張量
X_tensor = torch.tensor(X, dtype=torch.float32)
y_tensor = torch.tensor(y, dtype=torch.long)### 創建數據集和數據加載器
dataset = TensorDataset(X_tensor, y_tensor)
data_loader = DataLoader(dataset, batch_size=32, shuffle=True)### 定義模型
model = nn.Sequential(nn.Linear(2, 3), # 輸入特征維度為2,輸出類別數為3nn.Softmax(dim=1) # 對輸出應用Softmax函數
)### 定義損失函數和優化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.1)### 訓練模型
num_epochs = 100
losses = []for epoch in range(num_epochs):for X_batch, y_batch in data_loader:# 前向傳播y_pred = model(X_batch)loss = criterion(y_pred, y_batch)# 反向傳播optimizer.zero_grad()loss.backward()optimizer.step()losses.append(loss.item())if (epoch + 1) % 10 == 0:print(f'Epoch {epoch + 1}, Loss: {loss.item():.4f}')### 繪制損失曲線
plt.plot(losses)
plt