今日頭條石家莊重慶seo代理
文章目錄
- 1.線性回歸
- 1)介紹
- 2)加載自由泳冠軍數(shù)據(jù)集
- 3)從0開始實現(xiàn)線性回歸模型
- 4)使用自動求導訓練線性回歸模型
- 5)使用優(yōu)化器訓練線性回歸模型
- 2.使用torch.nn模塊構(gòu)建線性回歸模型
- 1)使用torch.nn.Linear訓練線性回歸模型
- 2)使用torch.nn.Sequential類訓練線性回歸模型
- 3)使用torch.nn.Module訓練線性回歸模型
- 3.邏輯回歸
- 1)介紹
- 2)從0開始實現(xiàn)邏輯回歸模型
- 3)使用Pytorch實現(xiàn)邏輯回歸模型
- 4.softmax回歸
- 1)介紹
- 2)從頭開始實現(xiàn)softmax回歸
- 3)使用Pytorch實現(xiàn)softmax回歸
- 5.神經(jīng)網(wǎng)絡
- 1)神經(jīng)元
- 2)激活函數(shù)
- 1.繪制Sigmoid激活函數(shù)
- 2.繪制雙曲正切Tanh激活函數(shù)
- 3.繪制ReLU激活函數(shù)
- 4.繪制LeakyReLU激活函數(shù)
- 5.softmax函數(shù)
- 6.選擇正確的激活函數(shù)
- 3)神經(jīng)網(wǎng)絡原理
- 4)Pytorch實現(xiàn)神經(jīng)網(wǎng)絡
- 5)神經(jīng)網(wǎng)絡應用示例一
- 6)神經(jīng)網(wǎng)絡應用示例二
- 7)兩層神經(jīng)網(wǎng)絡解決異或問題
- 8)Fizz Buzz神經(jīng)網(wǎng)絡實現(xiàn)
1.線性回歸
1)介紹
模型構(gòu)建步驟:
1.定義:找到目標函數(shù),將輸入屬性映射為輸出屬性。
2.模型假設:用一條直線擬合數(shù)據(jù)
3.模型評估:采用損失函數(shù)來評價預測值和真實值的接近程度。argmin是機器學習常用的函數(shù),用來尋找使損失函數(shù)最小時的參數(shù)取值。
4.梯度下降算法:也叫最速下降法。用來求代價函數(shù)(損失函數(shù)或者叫目標函數(shù))的最小值?;舅枷?#xff1a;隨機選擇一組參數(shù)初始值,計算損失或者代價,然后尋找能讓代價下降最多的另一組參數(shù),反復迭代直至達到一個局部最優(yōu)。
2)加載自由泳冠軍數(shù)據(jù)集
數(shù)據(jù)集為奧運會自由泳冠軍數(shù)據(jù),
創(chuàng)建文件display_olympics_freestyle100m.py
添加代碼如下:
import torch
from matplotlib import pyplot as plt
import pandas as pd
import matplotlib as mpl# 防止plt漢字亂碼
mpl.rcParams[u'font.sans-serif'] = ['SimHei']
mpl.rcParams['axes.unicode_minus'] = Falsedef main():# 加載奧運會數(shù)據(jù)file_path = "../datasets/Freestyle100m.csv"dataset = pd.read_csv(file_path)dataset_tensor = torch.tensor(dataset.values) # 轉(zhuǎn)換為tensorx = dataset_tensor[:, :-1]y = dataset_tensor[:, -1]# 繪圖plt.plot(x.numpy(), y.numpy(), 'o')plt.xlabel(u'奧運會年')plt.ylabel(u'取勝時間(秒)')plt.show()if __name__ == "__main__":main()
運行結(jié)果:
橫坐標為奧運舉辦年份,縱坐標為取勝時間
3)從0開始實現(xiàn)線性回歸模型
思路:
1.建立線性回歸模型;
2.損失函數(shù)及損失函數(shù)求導
3.利用損失函數(shù)求導,實現(xiàn)梯度函數(shù)
梯度下降的收斂可以通過設置最大迭代次數(shù)或者判斷參數(shù)不再改變來確定已經(jīng)收斂。更新參數(shù)使用全部樣本成為批量梯度下降法(BGD);使用一個樣本成為隨機梯度下降法(SGD);使用部分樣本叫小批量梯度下降法,兼顧前兩種優(yōu)缺點。
4.重復:計算預測值(前向傳播),然后計算損失和梯度;更新參數(shù);
創(chuàng)建文件linear_regression_from_scratch.py
實現(xiàn)代碼如下:
# -*- coding: utf-8 -*-
"""
從頭開始實現(xiàn)線性回歸模型
"""
import torch
from matplotlib import pyplot as plt
import pandas as pd
import matplotlib as mpl# 防止plt漢字亂碼
mpl.rcParams[u'font.sans-serif'] = ['SimHei']
mpl.rcParams['axes.unicode_minus'] = Falsedef model(x, w, b):""" 回歸模型 """return w * x + bdef loss_fn(y_pred, y):""" 損失函數(shù) """loss = (y_pred - y) ** 2return loss.mean()def grad_loss_fn(y_pred, y):""" 損失函數(shù)求導 """return 2 * (y_pred - y)def grad_fn(x, y, y_pred):""" 梯度函數(shù) """grad_w = grad_loss_fn(y_pred, y) * xgrad_b = grad_loss_fn(y_pred, y)return torch.stack([grad_w.mean(), grad_b.mean()])def model_training(x, y, n_epochs, learning_rate, params, print_params=True):""" 訓練 """for epoch in range(1, n_epochs + 1):w, b = params# 前向傳播y_pred = model(x, w, b)# 計算損失loss = loss_fn(y_pred, y)# 梯度grad = grad_fn(x, y, y_pred)# 更新參數(shù)params = params - learning_rate * gradif epoch == 1 or epoch % 500 == 1:print('輪次:%d,\t損失:%f' % (epoch, float(loss)))if print_params:print(f'參數(shù):{params.detach().numpy()}')print(f'梯度:{grad.detach().numpy()}')return paramsdef main():# 加載奧運會數(shù)據(jù)file_path = "../datasets/Freestyle100m.csv"dataset = pd.read_csv(file_path)dataset_tensor = torch.tensor(dataset.values) # 轉(zhuǎn)換為tensorxx = dataset_tensor[:, 0]y = dataset_tensor[:, -1]# 為方便數(shù)值運算,將原來的舉辦年減去第一屆奧運會年x = xx - xx[0]# 模型參數(shù)初始化w = torch.zeros(1)b = torch.zeros(1)# 直接用未優(yōu)化的模型來預測y_pred = model(x, w, b)print('未優(yōu)化的模型的預測結(jié)果:', y_pred.detach().numpy())loss = loss_fn(y_pred, y)print('未優(yōu)化的模型的損失:', loss.detach().numpy())params = model_training(x=x,y=y,n_epochs=50000,learning_rate=0.00017,params=torch.tensor([0.0, 0.0]))print('梯度下降找到的w和b:%f %f \n' % (params[0], params[1]))y_pred = model(x, *params)print(f'優(yōu)化后的模型的預測結(jié)果:{y_pred.detach().numpy()}\n')# 繪圖plt.plot(xx.numpy(), y_pred.detach().numpy(), label=u'模型')plt.plot(xx.numpy(), y.numpy(), 'o', label=u'數(shù)據(jù)')plt.xlabel(u'奧運會年')plt.ylabel(u'取勝時間(秒)')plt.legend()plt.show()if __name__ == "__main__":main()
運行結(jié)果:
4)使用自動求導訓練線性回歸模型
pytorch提供自動求導功能,計算梯度。只要提供前向表達式,就可以計算任意節(jié)點梯度。
只需要在張量的構(gòu)造中添加requires_grad=True參數(shù)即可。
detach().requires_grad_()表示將張量分離同時設置requires_grad=True。
創(chuàng)建文件linear_regression_autograd.py
完整實現(xiàn)代碼如下:
# -*- coding: utf-8 -*-
"""
使用自動求導訓練線性回歸模型
"""import torch
from matplotlib import pyplot as plt
import pandas as pd
import matplotlib as mpl# 防止plt漢字亂碼
mpl.rcParams[u'font.sans-serif'] = ['SimHei']
mpl.rcParams['axes.unicode_minus'] = Falsedef model(x, w, b):""" 回歸模型 """return w * x + bdef loss_fn(y_pred, y):""" 損失函數(shù) """loss = (y_pred - y) ** 2return loss.mean()def model_training(x, y, params, n_epochs, learning_rate):""" 訓練 """for epoch in range(1, n_epochs + 1):# 梯度清零if params.grad is not None:params.grad.zero_()# 前向傳播y_pred = model(x, *params)# 計算損失loss = loss_fn(y_pred, y)# 反向傳播loss.backward()# 更新參數(shù)params = (params - learning_rate * params.grad).detach().requires_grad_()if epoch == 1 or epoch % 500 == 0:print('輪次:%d,\t損失:%f' % (epoch, float(loss)))return paramsdef main():# 加載奧運會數(shù)據(jù)file_path = "../datasets/Freestyle100m.csv"dataset = pd.read_csv(file_path)dataset_tensor = torch.tensor(dataset.values) # 轉(zhuǎn)換為tensorxx = dataset_tensor[:, 0]y = dataset_tensor[:, -1]# 為方便數(shù)值運算,將原來的舉辦年減去第一屆奧運會年x = xx - xx[0]# 初始化模型參數(shù)params = torch.tensor([0.0, 0.0], requires_grad=True)print('params.grad is None: ', params.grad is None)loss = loss_fn(model(x, *params), y)loss.backward()print(params.grad)if params.grad is not None:params.grad.zero_()params = model_training(x=x,y=y,params=torch.tensor([0.0, 0.0], requires_grad=True),n_epochs=50000,learning_rate=0.00017)print('梯度下降找到的w和b:%f %f \n' % (params[0], params[1]))y_pred = model(x, *params)print(f'優(yōu)化后的模型的預測結(jié)果:{y_pred.detach().numpy()}\n')# 繪圖plt.plot(xx.numpy(), y_pred.detach().numpy(), label=u'模型')plt.plot(xx.numpy(), y.numpy(), 'o', label=u'數(shù)據(jù)')plt.xlabel(u'奧運會年')plt.ylabel(u'取勝時間(秒)')plt.legend()plt.show()if __name__ == "__main__":main()
5)使用優(yōu)化器訓練線性回歸模型
優(yōu)化器(optimizer)用來優(yōu)化梯度計算。包括SGD 優(yōu)化,Adam。
創(chuàng)建文件linear_regression_optimizers.py
完整實現(xiàn)代碼如下:
# -*- coding: utf-8 -*-
"""
使用優(yōu)化器訓練線性回歸模型
"""import torch
import torch.optim as optim
import pandas as pd
from matplotlib import pyplot as plt
import matplotlib as mpl# 防止plt漢字亂碼
mpl.rcParams[u'font.sans-serif'] = ['SimHei']
mpl.rcParams['axes.unicode_minus'] = Falsedef model(x, w, b):""" 回歸模型 """return w * x + bdef loss_fn(y_pred, y):""" 損失函數(shù) """loss = (y_pred - y) ** 2return loss.mean()def model_training(x, y, params, n_epochs, optimizer):""" 訓練 """for epoch in range(1, n_epochs + 1):# 前向傳播p_pred = model(x, *params)# 計算損失loss = loss_fn(p_pred, y)# 梯度清零optimizer.zero_grad()# 反向傳播loss.backward()# 更新參數(shù)optimizer.step()if epoch == 1 or epoch % 500 == 0:print('輪次:%d,\t損失:%f' % (epoch, float(loss)))return paramsdef main():# 加載奧運會數(shù)據(jù)file_path = "../datasets/Freestyle100m.csv"dataset = pd.read_csv(file_path)dataset_tensor = torch.tensor(dataset.values) # 轉(zhuǎn)換為tensorxx = dataset_tensor[:, 0]y = dataset_tensor[:, -1]# 為方便數(shù)值運算,將原來的舉辦年減去第一屆奧運會年x = xx - xx[0]# 參數(shù)params = torch.tensor([0.0, 0.0], requires_grad=True)learning_rate = 0.00017# 使用optim模塊中的現(xiàn)成優(yōu)化器optimizer = optim.SGD([params], lr=learning_rate)# 手工做一次優(yōu)化y_pred = model(x, *params)loss = loss_fn(y_pred, y)# 梯度清零optimizer.zero_grad()# 優(yōu)化loss.backward()optimizer.step()# 打印一次優(yōu)化后的參數(shù)print('一次優(yōu)化后的參數(shù):', params)# 手工再做一次優(yōu)化params = torch.tensor([0.0, 0.0], requires_grad=True)optimizer = optim.SGD([params], lr=learning_rate)y_pred = model(x, *params)loss = loss_fn(y_pred, y)# 梯度清零optimizer.zero_grad()# 優(yōu)化loss.backward()optimizer.step()# 打印再一次優(yōu)化后的參數(shù)print('再一次優(yōu)化后的參數(shù):', params)print('\n使用SGD訓練模型')params = torch.tensor([0.0, 0.0], requires_grad=True)optimizer = optim.SGD([params], lr=learning_rate)params = model_training(x=x,y=y,params=params,n_epochs=50000,optimizer=optimizer)print('SGD優(yōu)化器找到的w和b:%f %f \n' % (params[0], params[1]))print('\n使用Adam再訓練一次模型')# 注意學習率和訓練輪次都不同于SGD,說明Adam是高級優(yōu)化函數(shù)params = torch.tensor([0.0, 0.0], requires_grad=True)learning_rate = 1e-1optimizer = optim.Adam([params], lr=learning_rate)params = model_training(x=x,y=y,params=params,n_epochs=2000,optimizer=optimizer)print('Adam優(yōu)化器找到的w和b:%f %f \n' % (params[0], params[1]))# 再做一次預測y_pred = model(x, *params)# 繪圖plt.plot(xx.numpy(), y_pred.detach().numpy(), label=u'模型')plt.plot(xx.numpy(), y.numpy(), 'o', label=u'數(shù)據(jù)')plt.xlabel(u'奧運會年')plt.ylabel(u'取勝時間(秒)')plt.legend()plt.show()if __name__ == "__main__":main()
2.使用torch.nn模塊構(gòu)建線性回歸模型
pytorch提供nn模塊,包含有Lineaar、Sequential、Model和各種損失函數(shù)。
1)使用torch.nn.Linear訓練線性回歸模型
步驟:
1.加載數(shù)據(jù)集,劃分劃分訓練集驗證集
2.定義線性模型
3.設置優(yōu)化器
4.分別使用自定義的損失函數(shù)和nn模塊使用開箱即用的損失函數(shù)
# -*- coding: utf-8 -*-
"""
使用torch.nn.Linear訓練線性回歸模型
"""import torch
import torch.optim as optim
import torch.nn as nn
from matplotlib import pyplot as plt
import pandas as pd
import matplotlib as mpl# 防止plt漢字亂碼
mpl.rcParams[u'font.sans-serif'] = ['SimHei']
mpl.rcParams['axes.unicode_minus'] = Falsedef loss_fn(y_pred, y):""" 損失函數(shù) """loss = (y_pred - y) ** 2return loss.mean()def model_training(x_train, y_train, x_val, y_val, n_epochs, optimizer, model, loss_fn):""" 訓練 """for epoch in range(1, n_epochs + 1):# 前向傳播y_pred_train = model(x_train)loss_train = loss_fn(y_pred_train, y_train)with torch.no_grad():y_pred_val = model(x_val)loss_val = loss_fn(y_pred_val, y_val)# 梯度清零optimizer.zero_grad()# 反向傳播loss_train.backward()# 更新參數(shù)optimizer.step()if epoch == 1 or epoch % 100 == 0:print(f'輪次:{epoch},\t訓練損失:{float(loss_train)},\t驗證損失:{float(loss_val)}')def main():# 加載奧運會數(shù)據(jù)file_path = "../datasets/Freestyle100m.csv"dataset = pd.read_csv(file_path)dataset_tensor = torch.tensor(dataset.values) # 轉(zhuǎn)換為tensorxx = dataset_tensor[:, 0]y = dataset_tensor[:, -1]# 為方便數(shù)值運算,將原來的舉辦年減去第一屆奧運會年x = xx - xx[0]# 擴充一維,變?yōu)閚n可以接受的shape和數(shù)據(jù)類型x = x.unsqueeze(1).float()y = y.unsqueeze(1).float()# 劃分訓練集驗證集n_samples = x.shape[0]n_train = int(0.7 * n_samples)# 隨機置亂shuffled_idx = torch.randperm(n_samples)train_idx = shuffled_idx[:n_train]val_idx = shuffled_idx[n_train:]x_train = x[train_idx]y_train = y[train_idx]x_val = x[val_idx]y_val = y[val_idx]# 定義模型linear_model = nn.Linear(1, 1)# 使用optim模塊中的現(xiàn)成優(yōu)化器learning_rate = 1e-1epochs = 3000optimizer = optim.Adam(linear_model.parameters(), lr=learning_rate)# 使用自定義的損失函數(shù)model_training(x_train=x_train,y_train=y_train,x_val=x_val,y_val=y_val,n_epochs=epochs,optimizer=optimizer,model=linear_model,loss_fn=loss_fn)print()print(linear_model.weight)print(linear_model.bias)linear_model = nn.Linear(1, 1)optimizer = optim.Adam(linear_model.parameters(), lr=learning_rate)# 使用開箱即用的損失函數(shù)model_training(x_train=x_train,y_train=y_train,x_val=x_val,y_val=y_val,n_epochs=epochs,optimizer=optimizer,model=linear_model,loss_fn=nn.MSELoss())print('優(yōu)化后的模型參數(shù)')print(linear_model.weight)print(linear_model.bias)# 繪圖plt.plot(xx.numpy(), y.numpy(), 'go', label=u'數(shù)據(jù)')x_range = torch.arange(min(xx), max(xx)).unsqueeze(1)plt.plot(x_range.numpy(), linear_model(x_range - xx[0]).detach().numpy(), 'r-', label=u'模型')plt.plot(xx.numpy(), linear_model(x).detach().numpy(), 'bx', label=u'預測')plt.xlabel(u'奧運會年')plt.ylabel(u'取勝時間(秒)')plt.legend()plt.show()if __name__ == "__main__":main()
2)使用torch.nn.Sequential類訓練線性回歸模型
Sequential是一種容器,添加并連接模塊,最終形成一個網(wǎng)絡模型。
創(chuàng)建文件linear_regression_nn_sequential.py
添加代碼如下:
# -*- coding: utf-8 -*-
"""
使用torch.nn.Sequential類訓練線性回歸模型"""import torch
import torch.optim as optim
import torch.nn as nn
from matplotlib import pyplot as plt
import pandas as pd
import matplotlib as mpl# 防止plt漢字亂碼
mpl.rcParams[u'font.sans-serif'] = ['SimHei']
mpl.rcParams['axes.unicode_minus'] = Falsedef model_training(x_train, y_train, x_val, y_val, n_epochs, optimizer, model, loss_fn):""" 訓練 """for epoch in range(1, n_epochs + 1):# 前向傳播y_pred_train = model(x_train)loss_train = loss_fn(y_pred_train, y_train)y_pred_val = model(x_val)loss_val = loss_fn(y_pred_val, y_val)# 梯度清零optimizer.zero_grad()# 反向傳播loss_train.backward()# 更新參數(shù)optimizer.step()if epoch == 1 or epoch % 100 == 0:print(f'輪次:{epoch},\t訓練損失:{float(loss_train)},\t驗證損失:{float(loss_val)}')def main():learning_rate = 1e-1# 設置隨機數(shù)種子seed = 1torch.manual_seed(seed)torch.cuda.manual_seed_all(seed)# 加載奧運會數(shù)據(jù)file_path = "../datasets/Freestyle100m.csv"dataset = pd.read_csv(file_path)dataset_tensor = torch.tensor(dataset.values) # 轉(zhuǎn)換為tensorxx = dataset_tensor[:, 0]y = dataset_tensor[:, -1]# 為方便數(shù)值運算,將原來的舉辦年減去第一屆奧運會年x = xx - xx[0]# 擴充一維,變?yōu)閚n可以接受的shape和數(shù)據(jù)類型x = x.unsqueeze(1).float()y = y.unsqueeze(1).float()# 劃分訓練集驗證集n_samples = x.shape[0]n_trin = int(0.7 * n_samples)# 隨機置亂shuffled_idx = torch.randperm(n_samples)train_idx = shuffled_idx[:n_trin]val_idx = shuffled_idx[n_trin:]x_train = x[train_idx]y_train = y[train_idx]x_val = x[val_idx]y_val = y[val_idx]# 定義模型# 讀者可嘗試使用兩種模型定義中的一種,看看有什么區(qū)別# 第一種定義# seq_model = nn.Sequential(# nn.Linear(1, 10),# nn.LogSigmoid(),# nn.Linear(10, 1)# )# 第二種定義from collections import OrderedDictseq_model = nn.Sequential(OrderedDict([('hidden_linear', nn.Linear(1, 10)),('hidden_activation', nn.LogSigmoid()),('output_linear', nn.Linear(10, 1))]))# 打印模型信息print(seq_model)for name, param in seq_model.named_parameters():print("{:21} {:19} {}".format(name, str(param.shape), param.numel()))optimizer = optim.Adam(seq_model.parameters(), lr=learning_rate)# 使用開箱即用的損失函數(shù)model_training(x_train=x_train,y_train=y_train,x_val=x_val,y_val=y_val,n_epochs=3000,optimizer=optimizer,model=seq_model,loss_fn=nn.MSELoss())print('優(yōu)化后的模型參數(shù)')for name, param in seq_model.named_parameters():print(name, param)# 繪圖plt.plot(xx.numpy(), y.numpy(), 'go', label=u'數(shù)據(jù)')x_range = torch.arange(min(xx), max(xx)).unsqueeze(1)plt.plot(x_range.numpy(), seq_model(x_range - xx[0]).detach().numpy(), 'r-', label=u'模型')plt.plot(xx.numpy(), seq_model(x).detach().numpy(), 'bx', label=u'預測')plt.xlabel(u'奧運會年')plt.ylabel(u'取勝時間(秒)')plt.legend()plt.show()if __name__ == "__main__":main()
3)使用torch.nn.Module訓練線性回歸模型
使用nn.Module實現(xiàn)自定義線性模型。
創(chuàng)建文件linear_regression_nn_module.py
添加代碼如下:
# -*- coding: utf-8 -*-
"""
使用torch.nn.Module訓練線性回歸模型
"""import torch
import torch.optim as optim
import torch.nn as nn
from matplotlib import pyplot as plt
import pandas as pd
import matplotlib as mpl# 防止plt漢字亂碼
mpl.rcParams[u'font.sans-serif'] = ['SimHei']
mpl.rcParams['axes.unicode_minus'] = Falseclass LinearModel(nn.Module):""" 自定義模型 """def __init__(self):super().__init__()self.hidden_linear = nn.Linear(1, 10)self.activation = nn.LogSigmoid()self.output_linear = nn.Linear(10, 1)def forward(self, input):output = self.hidden_linear(input)output = self.activation(output)output = self.output_linear(output)return outputdef model_training(x_train, y_train, x_val, y_val, n_epochs, optimizer, model, loss_fn):""" 訓練 """for epoch in range(1, n_epochs + 1):# 前向傳播y_pred_train = model(x_train)loss_train = loss_fn(y_pred_train, y_train)y_pred_val = model(x_val)loss_val = loss_fn(y_pred_val, y_val)# 梯度清零optimizer.zero_grad()# 反向傳播loss_train.backward()# 更新參數(shù)optimizer.step()if epoch == 1 or epoch % 100 == 0:print(f'輪次:{epoch},\t訓練損失:{float(loss_train)},\t驗證損失:{float(loss_val)}')def main():learning_rate = 1e-1# 設置隨機數(shù)種子seed = 1torch.manual_seed(seed)torch.cuda.manual_seed_all(seed)# 加載奧運會數(shù)據(jù)file_path = "../datasets/Freestyle100m.csv"dataset = pd.read_csv(file_path)dataset_tensor = torch.tensor(dataset.values) # 轉(zhuǎn)換為tensorxx = dataset_tensor[:, 0]y = dataset_tensor[:, -1]# 為方便數(shù)值運算,將原來的舉辦年減去第一屆奧運會年x = xx - xx[0]# 擴充一維,變?yōu)閚n可以接受的shape和數(shù)據(jù)類型x = x.unsqueeze(1).float()y = y.unsqueeze(1).float()# 劃分訓練集驗證集n_samples = x.shape[0]n_trin = int(0.7 * n_samples)# 隨機置亂shuffled_idx = torch.randperm(n_samples)train_idx = shuffled_idx[:n_trin]val_idx = shuffled_idx[n_trin:]x_train = x[train_idx]y_train = y[train_idx]x_val = x[val_idx]y_val = y[val_idx]# 定義模型linear_model = LinearModel()# 打印模型信息print(linear_model)for name, param in linear_model.named_parameters():print("{:21} {:19} {}".format(name, str(param.shape), param.numel()))optimizer = optim.Adam(linear_model.parameters(), lr=learning_rate)# 使用開箱即用的損失函數(shù)model_training(x_train=x_train,y_train=y_train,x_val=x_val,y_val=y_val,n_epochs=3000,optimizer=optimizer,model=linear_model,loss_fn=nn.MSELoss())print('優(yōu)化后的模型參數(shù)')for name, param in linear_model.named_parameters():print(name, param)# 繪圖plt.plot(xx.numpy(), y.numpy(), 'go', label=u'數(shù)據(jù)')x_range = torch.arange(min(xx), max(xx)).unsqueeze(1)plt.plot(x_range.numpy(), linear_model(x_range - xx[0]).detach().numpy(), 'r-', label=u'模型')plt.plot(xx.numpy(), linear_model(x).detach().numpy(), 'bx', label=u'預測')plt.xlabel(u'奧運會年')plt.ylabel(u'取勝時間(秒)')plt.legend()plt.show()if __name__ == "__main__":main()
3.邏輯回歸
線性回歸解決回歸問題;邏輯回歸主要解決分類問題。區(qū)別在于前者目標值連續(xù);后者是離散的。
可以將邏輯回歸視為神經(jīng)網(wǎng)絡的一個神經(jīng)元
1)介紹
思路:
1.假設函數(shù):使用激活函數(shù)求輸出。Sigmoid函數(shù)很好模擬了階躍函數(shù)
2.代價函數(shù):求代價使用負對數(shù)似然代價函數(shù)表示。
3.邏輯回歸梯度下降算法
2)從0開始實現(xiàn)邏輯回歸模型
創(chuàng)建文件logistic_regression_from_scratch.py
添加代碼如下:
# -*- coding: utf-8 -*-
"""
從頭開始實現(xiàn)邏輯回歸模型
"""import torch
import numpy as np
from matplotlib import pyplot as plt
import matplotlib as mpl# 防止plt漢字亂碼
mpl.rcParams[u'font.sans-serif'] = ['SimHei']
mpl.rcParams['axes.unicode_minus'] = Falsedef sigmoid(z):""" S型激活函數(shù) """g = 1 / (1 + torch.exp(-z))return gdef model(x, w, b):""" 邏輯回歸模型 """return sigmoid(x.mv(w) + b)def loss_fn(y_pred, y):""" 損失函數(shù) """loss = - y.mul(y_pred.view_as(y)) - (1 - y).mul(1 - y_pred.view_as(y))return loss.mean()def grad_loss_fn(y_pred, y):""" 損失函數(shù)求導 """return y_pred.view_as(y) - ydef grad_fn(x, y, y_pred):""" 梯度函數(shù) """grad_w = grad_loss_fn(y_pred, y) * xgrad_b = grad_loss_fn(y_pred, y)return torch.cat((grad_w.mean(dim=0), grad_b.mean().unsqueeze(0)), 0)def model_training(x, y, n_epochs, learning_rate, params, print_params=True):""" 訓練 """for epoch in range(1, n_epochs + 1):w, b = params[: -1], params[-1]# 前向傳播y_pred = model(x, w, b)# 計算損失loss = loss_fn(y_pred, y)# 梯度grad = grad_fn(x, y, y_pred)# 更新參數(shù)params -= learning_rate * gradif epoch == 1 or epoch % 10 == 1:print('輪次:%d,\t損失:%f' % (epoch, float(loss)))if print_params:print(f'參數(shù):{params.detach().numpy()}')print(f'梯度:{grad.detach().numpy()}')return paramsdef generate_data():""" 隨機生成數(shù)據(jù) """np.random.seed(0)# 使用二個高斯分布來生成隨機數(shù)據(jù)phi = 0.6means = [[0.0, -3.2], [1.0, 3.5]]covs = np.zeros((2, 2, 2))covs[0] = [[0.58, -0.05], [-0.05, 1.55]]covs[1] = [[0.65, -0.15], [-0.15, 1.12]]priors = [1 - phi, phi]n = 100x = np.zeros((n, 2))y = np.zeros((n, 1))# 選擇一個高斯,并隨機抽樣數(shù)據(jù)for i in range(n):comp = np.random.choice(2, p=priors)x[i] = np.random.multivariate_normal(means[comp], covs[comp], 1)y[i] = compreturn torch.from_numpy(x).float(), torch.from_numpy(y).float()def plot_decision_boundary(x, y, theta):"""繪制二元分類問題的決策邊界輸入?yún)?shù)x:輸入,y:輸出,theta:參數(shù)輸出參數(shù)無"""plt.figure()neg_x = x[np.where(y[:, 0] == 0)]pos_x = x[np.where(y[:, 0] == 1)]neg = plt.scatter(neg_x[:, 0], neg_x[:, 1], c='b', marker='o')pos = plt.scatter(pos_x[:, 0], pos_x[:, 1], c='r', marker='+')# 繪制決策邊界# 只需要兩點便可以定義一條直線,選擇兩個端點plot_x = np.array([min(x[:, 0]), max(x[:, 0])])# 計算決策邊界線,theta0 + theta1*x + theta2*y = 0# 已知x,可計算yplot_y = np.dot(np.divide(-1, theta[1]), (theta[2] + np.dot(theta[0], plot_x)))lr, = plt.plot(plot_x, plot_y, 'g') # 繪制擬合直線# 坐標plt.xlabel('x1')plt.ylabel('x2')# 圖例plt.legend([neg, pos, lr], ['負例', '正例', u'決策邊界'], loc='lower right')plt.show()def main():# 隨機生成數(shù)據(jù)x, y = generate_data()# 模型參數(shù)初始化w = torch.zeros(2)b = torch.zeros(1)# 直接用未優(yōu)化的模型來預測y_pred = model(x, w, b)print('未優(yōu)化的模型的預測結(jié)果:', y_pred.detach().numpy())loss = loss_fn(y_pred, y)print('未優(yōu)化的模型的損失:', loss.detach().numpy())params = model_training(x=x,y=y,n_epochs=500,learning_rate=0.1,params=torch.tensor([0.0, 0.0, 0.0]))print(f'梯度下降找到的w和b:{params.numpy()} \n')y_pred = model(x, params[: -1], params[-1])print(f'優(yōu)化后的模型的預測結(jié)果:{y_pred.detach().numpy()}\n')# 繪制決策邊界plot_decision_boundary(x, y, params)if __name__ == "__main__":main()
運行結(jié)果:
3)使用Pytorch實現(xiàn)邏輯回歸模型
使用nn.Sequential定義模型;nn.Sigmoid定義激活函數(shù)。
創(chuàng)建文件logistic_regression_concise.py
添加代碼如下:
# -*- coding: utf-8 -*-
"""
簡潔實現(xiàn)邏輯回歸模型
"""
import torch
import torch.optim as optim
import torch.nn as nn
import numpy as np
from matplotlib import pyplot as plt
import matplotlib as mpl# 防止plt漢字亂碼
mpl.rcParams[u'font.sans-serif'] = ['SimHei']
mpl.rcParams['axes.unicode_minus'] = False
def model_training(x, y, n_epochs, optimizer, model, loss_fn):""" 訓練 """for epoch in range(1, n_epochs + 1):# 前向傳播y_pred = model(x)# 計算損失loss = loss_fn(y_pred, y)# 梯度清零optimizer.zero_grad()# 反向傳播loss.backward()# 更新參數(shù)optimizer.step()if epoch == 1 or epoch % 10 == 1:print('輪次:%d,\t損失:%f' % (epoch, float(loss)))def generate_data():""" 隨機生成數(shù)據(jù) """np.random.seed(0)# 使用二個高斯分布來生成隨機數(shù)據(jù)phi = 0.6means = [[0.0, -3.2], [1.0, 3.5]]covs = np.zeros((2, 2, 2))covs[0] = [[0.58, -0.05], [-0.05, 1.55]]covs[1] = [[0.65, -0.15], [-0.15, 1.12]]priors = [1 - phi, phi]n = 100x = np.zeros((n, 2))y = np.zeros((n, 1))# 選擇一個高斯,并隨機抽樣數(shù)據(jù)for i in range(n):comp = np.random.choice(2, p=priors)x[i] = np.random.multivariate_normal(means[comp], covs[comp], 1)y[i] = compreturn torch.from_numpy(x).float(), torch.from_numpy(y).float()def plot_decision_boundary(x, y, model):"""繪制二元分類問題的決策邊界輸入?yún)?shù)x:輸入,y:輸出,model:模型輸出參數(shù)無"""plt.figure()neg_x = x[np.where(y[:, 0] == 0)]pos_x = x[np.where(y[:, 0] == 1)]neg = plt.scatter(neg_x[:, 0], neg_x[:, 1], c='b', marker='o')pos = plt.scatter(pos_x[:, 0], pos_x[:, 1], c='r', marker='+')# 繪制決策邊界# 網(wǎng)格范圍u = np.linspace(min(x[:, 0]), max(x[:, 0]), 150)v = np.linspace(min(x[:, 1]), max(x[:, 1]), 150)uu, vv = np.meshgrid(u, v) # 生成網(wǎng)格數(shù)據(jù)z = model(torch.cat((torch.from_numpy(uu.ravel()).float().unsqueeze(1),torch.from_numpy(vv.ravel()).float().unsqueeze(1)), 1))# 保持維度一致z = z.detach().numpy().reshape(uu.shape)# 畫圖plt.contour(uu, vv, z, 0)# 坐標plt.xlabel('x1')plt.ylabel('x2')# 圖例plt.legend([neg, pos], ['負例', '正例'], loc='lower right')plt.show()def main():# 隨機生成數(shù)據(jù)x, y = generate_data()# 定義模型seq_model = nn.Sequential(nn.Linear(2, 1),nn.Sigmoid())# 打印模型信息print(seq_model)# 模型參數(shù)初始化print('\n使用SGD訓練模型')learning_rate = 0.1# 使用optim模塊中的現(xiàn)成優(yōu)化器optimizer = optim.SGD(seq_model.parameters(), lr=learning_rate)model_training(x=x,y=y,n_epochs=500,optimizer=optimizer,model=seq_model,loss_fn=nn.BCELoss())print('優(yōu)化后的模型參數(shù)')for name, param in seq_model.named_parameters():print(name, param)y_pred = seq_model(x)print(f'優(yōu)化后的模型的預測結(jié)果:{y_pred.detach().numpy()}\n')# 繪制決策邊界plot_decision_boundary(x, y, seq_model)if __name__ == "__main__":main()
4.softmax回歸
解決多元分類問題可以使用softmax回歸。softmax回歸的輸出單元數(shù)k>2,對應k個類別的預測概率分布。訓練好模型后,選擇概率最大的類別作為預測類別。
1)介紹
思想:
1.假設函數(shù),概率分布歸一化
2.代價函數(shù)使用交叉熵
2)從頭開始實現(xiàn)softmax回歸
創(chuàng)建文件softmax_regression_from_scratch.py
添加代碼如下:
# -*- coding: utf-8 -*-
"""
從頭開始實現(xiàn)softmax回歸
"""import torch
import torchvision
import torchvision.transforms as transforms
from torch.utils import data
import numpy as np# 超參數(shù)
num_inputs = 784
num_outputs = 10def softmax(z):"""實現(xiàn)Softmax激活函數(shù)。每一個Z減去一個max值是為了避免數(shù)值溢出輸入?yún)?shù):z:二維Tensor數(shù)組返回:a:softmax(z)輸出,與z的shape一致"""z_rescale = z - torch.max(z, dim=1, keepdim=True)[0]a = torch.exp(z_rescale) / torch.sum(torch.exp(z_rescale), dim=1, keepdim=True)assert (a.shape == z.shape)return adef model(x, w, b):""" 定義Softmax模型 """return softmax(torch.mm(x.view((-1, num_inputs)), w) + b)def cross_entropy(y_hat, y):""" 計算交叉熵 """return - torch.log(y_hat.gather(1, y.view(-1, 1)))def grad_loss_fn(y_pred, y):""" 損失函數(shù)求導 """return y_pred - torch.nn.functional.one_hot(y, num_classes=10)def grad_fn(x, y, y_pred):""" 梯度函數(shù) """grad_w = torch.mm(x.view((-1, num_inputs)).T, grad_loss_fn(y_pred, y))grad_b = grad_loss_fn(y_pred, y)return [grad_w, grad_b.mean(dim=0)]def accuracy(y_hat, y):""" 計算分類準確率 """_, pred_y = torch.max(y_hat, 1)return (pred_y == y).mean().item()def evaluate_accuracy(data_iter, net, w, b):""" 計算準確率 """correct_acc, n = 0.0, 0for x, y in data_iter:_, pred_y = torch.max(net(x, w, b).data, 1)correct_acc += (pred_y == y).sum().item()n += y.shape[0]return correct_acc / ndef train(net, train_iter, test_iter, loss, num_epochs, params, lr):""" 模型訓練 """w, b = paramsfor epoch in range(num_epochs):train_loss_sum, train_acc_sum, n = 0.0, 0.0, 0for x, y in train_iter:# 前向傳播y_pred = net(x, w, b)# 計算損失loss_mini_batch = loss(y_pred, y).sum()# 梯度grad = grad_fn(x, y, y_pred)# 更新參數(shù)for i in range(len(params)):params[i] -= lr * grad[i]# 統(tǒng)計train_loss_sum += loss_mini_batch.item()train_acc_sum += (y_pred.argmax(dim=1) == y).sum().item()n += y.shape[0]# 測試準確率test_acc = evaluate_accuracy(test_iter, net, w, b)print('輪次:%d,損失%.4f,訓練準確率:%.3f,測試準確率:%.3f'% (epoch + 1, train_loss_sum / n, train_acc_sum / n, test_acc))def get_labels_by_indices(labels):""" 返回目標索引對應的標簽字符串 """text_labels = ['t-shirt', 'trouser', 'pullover', 'dress', 'coat', 'sandal', 'shirt', 'sneaker', 'bag', 'ankle boot']return [text_labels[int(i)] for i in labels]def main():# 超參數(shù)num_epochs, learning_rate, batch_size = 5, 0.001, 32# 加載數(shù)據(jù)集mnist_train = torchvision.datasets.FashionMNIST(root='../datasets/FashionMNIST', train=True, download=False,transform=transforms.ToTensor())train_iter = data.DataLoader(mnist_train, batch_size=batch_size, shuffle=True)mnist_test = torchvision.datasets.FashionMNIST(root='../datasets/FashionMNIST', train=False, download=False,transform=transforms.ToTensor())test_iter = data.DataLoader(mnist_test, batch_size=batch_size, shuffle=False)# 參數(shù)w = torch.tensor(np.random.normal(0, 0.01, (num_inputs, num_outputs)), dtype=torch.float, requires_grad=False)b = torch.zeros(num_outputs, dtype=torch.float, requires_grad=False)# 訓練模型train(model, train_iter, test_iter, cross_entropy, num_epochs, [w, b], learning_rate)# 顯示部分測試數(shù)據(jù)的真實標簽和預測標簽x, y = next(iter(test_iter))true_labels = get_labels_by_indices(y.numpy())pred_labels = get_labels_by_indices(model(x, w, b).argmax(dim=1).numpy())for true_label, pred_label in zip(true_labels, pred_labels):print(f"真實標簽:{true_label}\t預測標簽:{pred_label}")if __name__ == '__main__':main()
3)使用Pytorch實現(xiàn)softmax回歸
使用Pytorch的自動求導功能。
創(chuàng)建文件softmax_regression.py
添加代碼如下:
# -*- coding: utf-8 -*-
"""
softmax回歸實現(xiàn)
"""import torch
import torchvision
import torchvision.transforms as transforms
from torch import nn
from torch.utils import data
import torch.nn.functional as Fclass Net(nn.Module):""" 定義Softmax模型 """def __init__(self):super(Net, self).__init__()self.fc1 = nn.Linear(784, 10)def forward(self, x):# 展平數(shù)據(jù) (n, 1, 28, 28) --> (n, 784)x = x.view(-1, 784)return F.softmax(self.fc1(x), dim=1)def train(epochs, train_loader, model, optimizer, loss_fn, print_every):""" 迭代訓練模型 """for epoch in range(epochs):# 每次輸入batch_idx個數(shù)據(jù)loss_acc = 0.0 # 累計損失for batch_idx, (data, target) in enumerate(train_loader):# 梯度清零optimizer.zero_grad()# 前向傳播output = model(data)# 損失loss = loss_fn(output, target)# 反向傳播loss.backward()# 更新參數(shù)optimizer.step()loss_acc += loss.item()if batch_idx % print_every == print_every - 1:print('[%d, %5d] 損失: %.3f' % (epoch + 1, batch_idx + 1, loss_acc / print_every))loss_acc = 0.0print('完成訓練!')def test(model, test_loader):""" 測試 """correct = 0total = 0# 預測不需要梯度來修改參數(shù)with torch.no_grad():for data in test_loader:images, labels = dataoutputs = model(images)_, predicted = torch.max(outputs.data, 1)total += labels.size(0)correct += (predicted == labels).sum().item()print('在測試集中的預測準確率: {:.2%}'.format(correct / total))def main():# 超參數(shù)num_epochs = 5batch_size = 16print_every = 200learning_rate = 0.001# 加載數(shù)據(jù)集mnist_train = torchvision.datasets.FashionMNIST(root='../datasets/FashionMNIST', train=True, download=False,transform=transforms.ToTensor())train_loader = data.DataLoader(mnist_train, batch_size=batch_size, shuffle=True)mnist_test = torchvision.datasets.FashionMNIST(root='../datasets/FashionMNIST', train=False, download=False,transform=transforms.ToTensor())test_loader = data.DataLoader(mnist_test, batch_size=batch_size, shuffle=False)model = Net()# 交叉熵損失函數(shù)loss_fn = nn.CrossEntropyLoss()# 優(yōu)化算法optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)train(num_epochs, train_loader, model, optimizer, loss_fn, print_every)test(model, test_loader)if __name__ == '__main__':main()
運行結(jié)果:
輪次:1,損失0.6634,訓練準確率:0.782,測試準確率:0.805
輪次:2,損失0.5175,訓練準確率:0.826,測試準確率:0.817
輪次:3,損失0.4881,訓練準確率:0.835,測試準確率:0.827
輪次:4,損失0.4720,訓練準確率:0.840,測試準確率:0.830
輪次:5,損失0.4616,訓練準確率:0.844,測試準確率:0.830
真實標簽:ankle boot 預測標簽:ankle boot
真實標簽:pullover 預測標簽:pullover
真實標簽:trouser 預測標簽:trouser
真實標簽:trouser 預測標簽:trouser
真實標簽:shirt 預測標簽:shirt
真實標簽:trouser 預測標簽:trouser
真實標簽:coat 預測標簽:coat
真實標簽:shirt 預測標簽:shirt
真實標簽:sandal 預測標簽:sandal
真實標簽:sneaker 預測標簽:sneaker
真實標簽:coat 預測標簽:coat
真實標簽:sandal 預測標簽:sandal
真實標簽:sneaker 預測標簽:sandal
真實標簽:dress 預測標簽:dress
真實標簽:coat 預測標簽:coat
真實標簽:trouser 預測標簽:trouser
真實標簽:pullover 預測標簽:pullover
真實標簽:coat 預測標簽:pullover
真實標簽:bag 預測標簽:bag
真實標簽:t-shirt 預測標簽:t-shirt
真實標簽:pullover 預測標簽:pullover
真實標簽:sandal 預測標簽:sneaker
真實標簽:sneaker 預測標簽:sneaker
真實標簽:ankle boot 預測標簽:sneaker
真實標簽:trouser 預測標簽:trouser
真實標簽:coat 預測標簽:pullover
真實標簽:shirt 預測標簽:shirt
真實標簽:t-shirt 預測標簽:t-shirt
真實標簽:ankle boot 預測標簽:ankle boot
真實標簽:dress 預測標簽:dress
真實標簽:bag 預測標簽:bag
真實標簽:bag 預測標簽:bag
5.神經(jīng)網(wǎng)絡
1)神經(jīng)元
線性回歸實際上就是一個線性神經(jīng)元。多變量線性回歸實現(xiàn)了加權求和計算。增加了激活函數(shù)的神經(jīng)元直接稱為神經(jīng)元。
2)激活函數(shù)
1.繪制Sigmoid激活函數(shù)
創(chuàng)建文件plot_sigmoid.py
添加代碼如下:
# -*- coding: utf-8 -*-
"""
繪制Sigmoid激活函數(shù)"""import matplotlib.pyplot as plt
import numpy as np
import torch# x取值,start到stop范圍內(nèi)間隔均勻的100個數(shù)
x_vals = np.linspace(start=-10., stop=10., num=100)activation = torch.nn.Sigmoid()# Sigmoid激活函數(shù)
print(activation(torch.Tensor([-1., 0., 1.])))
y_vals = activation(torch.Tensor(x_vals))# 繪制Sigmoid激活函數(shù)圖像
plt.plot(x_vals, y_vals, "r--", label="Sigmoid", linewidth=1.5)
plt.ylim([-0.5, 1.5])
plt.legend(loc="upper left")
plt.grid(axis="y")
plt.show()
運行結(jié)果:
2.繪制雙曲正切Tanh激活函數(shù)
它是Sigmoid函數(shù)的變體,放大并平移
# -*- coding: utf-8 -*-
"""
繪制雙曲正切Tanh激活函數(shù)
"""import matplotlib.pyplot as plt
import numpy as np
import torch# x取值,start到stop范圍內(nèi)間隔均勻的100個數(shù)
x_vals = np.linspace(start=-10., stop=10., num=100)activation = torch.nn.Tanh()# 雙曲正切激活函數(shù)
print(activation(torch.Tensor([-1., 0., 1.])))
y_vals = activation(torch.Tensor(x_vals))# 繪制Tanh激活函數(shù)圖像
plt.plot(x_vals, y_vals, "r--", label="Tanh", linewidth=1.5)
plt.ylim([-1.5, 1.5])
plt.legend(loc="upper left")
plt.grid(axis="y")
plt.show()
運行結(jié)果:
3.繪制ReLU激活函數(shù)
創(chuàng)建文件display_olympics_freestyle100m.py
添加代碼如下:
# -*- coding: utf-8 -*-
"""
繪制ReLU激活函數(shù)
"""import matplotlib.pyplot as plt
import numpy as np
import torch# x取值,start到stop范圍內(nèi)間隔均勻的100個數(shù)
x_vals = np.linspace(start=-10., stop=10., num=100)relu = torch.nn.ReLU()
relu6 = torch.nn.ReLU6()# ReLU激活函數(shù)
print("ReLU: ", relu(torch.Tensor([-5., 5., 10.])))
y_relu = relu(torch.Tensor(x_vals))# ReLU-6激活函數(shù)
print("ReLU-6: ", relu6(torch.Tensor([-5., 5., 10.])))
y_relu6 = relu6(torch.Tensor(x_vals))# 繪制ReLU激活函數(shù)圖像
plt.plot(x_vals, y_relu, "r:", label="ReLU", linewidth=1.5)
plt.plot(x_vals, y_relu6, "b-.", label="ReLU6", linewidth=1.5)
plt.ylim([-1, 8])
plt.legend(loc="upper left")
plt.grid(axis="y")
plt.show()
運行結(jié)果:
4.繪制LeakyReLU激活函數(shù)
創(chuàng)建文件display_olympics_freestyle100m.py
添加代碼如下:
# -*- coding: utf-8 -*-
"""
繪制LeakyReLU激活函數(shù)
"""import matplotlib.pyplot as plt
import numpy as np
import torch# x取值,start到stop范圍內(nèi)間隔均勻的100個數(shù)
x_vals = np.linspace(start=-10., stop=10., num=100)leaky_relu = torch.nn.LeakyReLU()
elu = torch.nn.ELU()# ReLU激活函數(shù)
print("Leaky ReLU: ", leaky_relu(torch.Tensor([-5., 5., 10.])))
y_leaky_relu = leaky_relu(torch.Tensor(x_vals))# ELU激活函數(shù)
print("ELU: ", elu(torch.Tensor([-5., 5., 10.])))
y_elu = elu(torch.Tensor(x_vals))# 繪制ReLU激活函數(shù)圖像
plt.plot(x_vals, y_leaky_relu, "r:", label="Leaky ReLU", linewidth=1.5)
plt.plot(x_vals, y_elu, "b-.", label="ELU", linewidth=1.5)
plt.ylim([-1, 8])
plt.legend(loc="upper left")
plt.grid(axis="y")
plt.show()
運行結(jié)果:
5.softmax函數(shù)
主要用于神經(jīng)網(wǎng)絡最后一層,解決多元分類問題
6.選擇正確的激活函數(shù)
中間層選ReLU;二元分類選Sigmoid;多元分類選Softmax函數(shù);深層網(wǎng)絡一般避免Tanh函數(shù)和Sigmoid函數(shù);如果出現(xiàn)較多死亡神經(jīng)元,用Leaky ReLU和ELU函數(shù)代替
3)神經(jīng)網(wǎng)絡原理
主要思想:
1.神經(jīng)網(wǎng)絡表示和結(jié)構(gòu);
2.前向傳播;
3.代價函數(shù):訓練權重和偏置。一般采用交叉熵代價函數(shù)
4.BP算法:即反向傳播算法。用于優(yōu)化神經(jīng)網(wǎng)絡參數(shù)算法,推薦使用Pytorch的自動求導解決方案。
4)Pytorch實現(xiàn)神經(jīng)網(wǎng)絡
nn.Sequential定義一個簡單的神經(jīng)網(wǎng)絡模型;
另一種方式是使用nn.Module定義神經(jīng)網(wǎng)絡。
兩種方式實現(xiàn)如下,
創(chuàng)建文件neural_networks_initialization.py
添加代碼如下:
# -*- coding: utf-8 -*-
"""
PyTorch定義神經(jīng)網(wǎng)絡及參數(shù)初始化
"""import torch
from torch import nn
from torch.nn import initnum_inputs, num_hiddens, num_outputs = 4, 5, 3# nn.Sequential定義一個簡單的神經(jīng)網(wǎng)絡模型
seq_model = nn.Sequential(nn.Linear(num_inputs, num_hiddens),nn.ReLU(),nn.Linear(num_hiddens, num_hiddens),nn.ReLU(),nn.Linear(num_hiddens, num_outputs),nn.Softmax(dim=1),
)class Net(nn.Module):""" 定義一個簡單的神經(jīng)網(wǎng)絡模型 """def __init__(self):super().__init__()self.fc1 = nn.Linear(num_inputs, num_hiddens)self.act1 = nn.ReLU()self.fc2 = nn.Linear(num_hiddens, num_hiddens)self.act2 = nn.ReLU()self.fc3 = nn.Linear(num_hiddens, num_outputs)self.act3 = nn.Softmax(dim=1)def forward(self, x):x = self.act1(self.fc1(x))x = self.act2(self.fc2(x))return self.act3(self.fc3(x))def weights_init(m):""" 初始化網(wǎng)絡權重 """if isinstance(m, nn.Conv2d):init.normal_(m.weight.data)# init.xavier_normal_(m.weight.data)# init.kaiming_normal_(m.weight.data) # 卷積層參數(shù)初始化m.bias.data.fill_(0)elif isinstance(m, nn.Linear):m.weight.data.normal_() # 全連接層參數(shù)初始化def main():# 初始化for params in seq_model.parameters():init.normal_(params, mean=0, std=0.01)print("nn.Sequential定義的網(wǎng)絡:")print(seq_model)for name, param in seq_model.named_parameters():print(name, param.shape)# 隨機初始化輸入xx = torch.randn(10, 4)y_hat = seq_model(x)print(y_hat)model = Net()# 網(wǎng)絡參數(shù)初始化model.apply(weights_init) # apply函數(shù)會遞歸搜索網(wǎng)絡中的子模塊并應用初始化print("nnn.Module定義的網(wǎng)絡:")print(model)y_hat = model(x)print(y_hat)if __name__ == "__main__":main()
5)神經(jīng)網(wǎng)絡應用示例一
需求:FashionMNIST分類問題。
創(chuàng)建文件neural_networks_demo1.py
添加代碼如下:
# -*- coding: utf-8 -*-
"""
PyTorch實現(xiàn)神經(jīng)網(wǎng)絡示例一
"""import torch
import torchvision
import torchvision.transforms as transforms
from torch import nn
from torch.utils import data
from torch.nn import initnum_inputs, num_hiddens, num_outputs = 784, 256, 10# nn.Sequential模型
net = nn.Sequential(nn.Linear(num_inputs, num_hiddens),nn.ReLU(),nn.Linear(num_hiddens, num_outputs),
)for params in net.parameters():init.normal_(params, mean=0, std=0.01)def train(epochs, train_loader, model, optimizer, loss_fn, print_every):""" 迭代訓練模型 """for epoch in range(epochs):loss_acc = 0.0 # 累計損失# 每次輸入第batch_idx批數(shù)據(jù)for batch_idx, (data, target) in enumerate(train_loader):# 梯度清零optimizer.zero_grad()# 前向傳播output = model(data.view(data.shape[0], -1))# 損失loss = loss_fn(output, target)# 反向傳播loss.backward()# 更新參數(shù)optimizer.step()loss_acc += loss.item()if batch_idx % print_every == print_every - 1:print('[%d, %5d] 損失: %.3f' % (epoch + 1, batch_idx + 1, loss_acc / print_every))loss_acc = 0.0print('完成訓練!')def test(model, test_loader):""" 模型測試 """correct = 0total = 0# 預測不需要梯度來修改參數(shù)with torch.no_grad():for data in test_loader:images, labels = dataoutputs = model(images.view(images.shape[0], -1))_, predicted = torch.max(outputs.data, 1)total += labels.size(0)correct += (predicted == labels).sum().item()print('在測試集中的預測準確率: {:.2%}'.format(correct / total))def main():# 超參數(shù)num_epochs = 5batch_size = 16print_every = 200learning_rate = 0.001# 加載數(shù)據(jù)集mnist_train = torchvision.datasets.FashionMNIST(root='../datasets/FashionMNIST', train=True, download=False,transform=transforms.ToTensor())train_loader = data.DataLoader(mnist_train, batch_size=batch_size, shuffle=True)mnist_test = torchvision.datasets.FashionMNIST(root='../datasets/FashionMNIST', train=False, download=False,transform=transforms.ToTensor())test_loader = data.DataLoader(mnist_test, batch_size=batch_size, shuffle=False)# 交叉熵損失函數(shù)loss_fn = nn.CrossEntropyLoss()# 優(yōu)化算法optimizer = torch.optim.Adam(net.parameters(), lr=learning_rate)# 訓練與評估train(num_epochs, train_loader, net, optimizer, loss_fn, print_every)test(net, test_loader)if __name__ == '__main__':main()
6)神經(jīng)網(wǎng)絡應用示例二
示例二使用nn.Module定義網(wǎng)絡模型
創(chuàng)建文件neural_networks_demo2.py
添加代碼如下:
# -*- coding: utf-8 -*-
"""
PyTorch實現(xiàn)神經(jīng)網(wǎng)絡示例二
"""import torch
import torchvision
import torchvision.transforms as transforms
from torch import nn
from torch.utils import data
import torch.nn.functional as Fnum_inputs, num_hiddens, num_outputs = 784, 256, 10class Net(nn.Module):""" nn.Module定義網(wǎng)絡模型 """def __init__(self):super(Net, self).__init__()self.fc1 = nn.Linear(num_inputs, num_hiddens)self.fc2 = nn.Linear(num_hiddens, num_outputs)def forward(self, x):# 展平數(shù)據(jù) (n, 1, 28, 28) --> (n, 784)x = x.view(x.shape[0], -1)x = F.relu(self.fc1(x))return F.log_softmax(self.fc2(x), dim=1)def train(epochs, train_loader, model, optimizer, loss_fn, print_every):""" 迭代訓練模型 """for epoch in range(epochs):loss_acc = 0.0 # 累計損失# 每次輸入第batch_idx批數(shù)據(jù)for batch_idx, (data, target) in enumerate(train_loader):# 梯度清零optimizer.zero_grad()# 前向傳播output = model(data)# 損失loss = loss_fn(output, target)# 反向傳播loss.backward()# 更新參數(shù)optimizer.step()loss_acc += loss.item()if batch_idx % print_every == print_every - 1:print('[%d, %5d] 損失: %.3f' % (epoch + 1, batch_idx + 1, loss_acc / print_every))loss_acc = 0.0print('完成訓練!')def test(model, test_loader):""" 模型測試 """correct = 0total = 0# 預測不需要梯度來修改參數(shù)with torch.no_grad():for data in test_loader:images, labels = dataoutputs = model(images)_, predicted = torch.max(outputs.data, 1)total += labels.size(0)correct += (predicted == labels).sum().item()print('在測試集中的預測準確率: {:.2%}'.format(correct / total))def main():# 超參數(shù)num_epochs = 5batch_size = 16print_every = 200learning_rate = 0.001# 加載數(shù)據(jù)集mnist_train = torchvision.datasets.FashionMNIST(root='../datasets/FashionMNIST', train=True, download=False,transform=transforms.ToTensor())train_loader = data.DataLoader(mnist_train, batch_size=batch_size, shuffle=True)mnist_test = torchvision.datasets.FashionMNIST(root='../datasets/FashionMNIST', train=False, download=False,transform=transforms.ToTensor())test_loader = data.DataLoader(mnist_test, batch_size=batch_size, shuffle=False)model = Net()# 負對數(shù)似然損失函數(shù)loss_fn = nn.NLLLoss()# 優(yōu)化算法optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)# 訓練與評估train(num_epochs, train_loader, model, optimizer, loss_fn, print_every)test(model, test_loader)if __name__ == '__main__':main()
7)兩層神經(jīng)網(wǎng)絡解決異或問題
# -*- coding: utf-8 -*-
"""
兩層神經(jīng)網(wǎng)絡解決異或問題
"""import torch
from torch import nndef main():# 設置隨機數(shù)種子seed = 1torch.manual_seed(seed)torch.cuda.manual_seed_all(seed)# 定義輸入單元數(shù)、隱藏層單元數(shù)、輸出層單元數(shù)n_in, n_h, n_out = 2, 2, 1# 創(chuàng)建XOR數(shù)據(jù)集x = torch.tensor([[0.0, 0.0], [0.0, 1.0], [1.0, 0.0], [1.0, 1.0]])y = torch.tensor([[0.0], [1.0], [1.0], [0.0]])# 創(chuàng)建模型model = nn.Sequential(nn.Linear(n_in, n_h),nn.Sigmoid(),nn.Linear(n_h, n_out),nn.Sigmoid())# 損失函數(shù)criterion = nn.MSELoss()# 優(yōu)化器optimizer = torch.optim.Adam(model.parameters(), lr=0.01)# 梯度下降for epoch in range(1, 1001):# 前向傳播y_pred = model(x)# 計算損失loss = criterion(y_pred, y)if epoch == 1 or epoch % 100 == 0:print(f'輪次:{epoch},\t損失:{loss.item()}')# 梯度置零optimizer.zero_grad()# 反向傳播loss.backward()# 更新參數(shù)optimizer.step()# 預測y_pred = model(x)print("輸入為:\n{}".format(x))print('輸出為:\n{}'.format(y_pred))if __name__ == "__main__":main()
8)Fizz Buzz神經(jīng)網(wǎng)絡實現(xiàn)
# -*- coding: utf-8 -*-
"""
Fizz Buzz神經(jīng)網(wǎng)絡實現(xiàn)
"""import numpy as np
import torchdef binary_encode(i, num_digits):""" 將輸入的十進制i轉(zhuǎn)換為位數(shù)是num_digits的二進制 """return np.array([i >> d & 1 for d in range(num_digits)])def fizz_buzz_encode(i):""" 將輸入數(shù)字編碼為標簽 """if i % 3 == 0 and i % 5 == 0:return 3elif i % 5 == 0:return 2elif i % 3 == 0:return 1else:return 0def fizz_buzz_decode(i, encode):""" 解碼為人類可讀的輸出 """return [str(i), "Fizz", "Buzz", "FizzBuzz"][encode]# 超參數(shù)
learning_rate = 0.05
epochs = 3000
batch_size = 128
num_digits = 10
num_hidden = 100# 構(gòu)建訓練集。使用101~1024作為訓練數(shù)據(jù)
train_x = torch.tensor([binary_encode(i, num_digits) for i in range(101, 2 ** num_digits)]).float()
train_y = torch.tensor([fizz_buzz_encode(i) for i in range(101, 2 ** num_digits)]).long()
# 隨機置亂
torch.manual_seed(123)
rand_idx = torch.randperm(len(train_y))
train_x = train_x[rand_idx, :]
train_y = train_y[rand_idx]# 定義網(wǎng)絡模型
model = torch.nn.Sequential(torch.nn.Linear(num_digits, num_hidden),torch.nn.ReLU(),torch.nn.Linear(num_hidden, 4)
)# 定義損失函數(shù)和優(yōu)化器
criterion = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)# 模型訓練
model.train()
for epoch in range(epochs):for start in range(0, len(train_x), batch_size):end = start + batch_sizebatch_x = train_x[start:end]batch_y = train_y[start:end]y_hat = model(batch_x)loss = criterion(y_hat, batch_y)optimizer.zero_grad()loss.backward()optimizer.step()# 計算訓練損失loss = criterion(model(train_x), train_y).item()print(f'Epoch:{epoch}\tLoss:{loss}')# 預測1~100
model.eval()
test_x = torch.tensor([binary_encode(i, num_digits) for i in range(1, 101)]).float()
test_y = torch.tensor([fizz_buzz_encode(i) for i in range(1, 101)]).long()
with torch.no_grad():pred_y = model(test_x)
predictions = zip(range(1, 101), list(pred_y.max(1)[1].data.tolist()))print("預測:", [fizz_buzz_decode(i, x) for (i, x) in predictions])
acc = np.sum(pred_y.max(1)[1].numpy() == np.array(test_y)) / len(test_y)
print("準確率:{:.2%}".format(acc))