寫在前面
- 剛開始先從普通的尋優算法開始,熟悉一下學習訓練過程
- 下面將使用梯度下降法尋優,但這大概只能是局部最優,它并不是一個十分優秀的尋優算法
整體流程
- 生成訓練數據集(實際工程中,需要從實際對象身上采集數據)
- 確定模型及其參數(輸入輸出個數、階次,偏置等)
- 確定學習方式(損失函數、優化算法,學習率,訓練次數,終止條件等)
- 讀取數據集(不同的讀取方式會影響最終的訓練效果)
- 訓練模型
完整程序及注釋
from IPython import display
from matplotlib import pyplot as plt
from mxnet import autograd, nd
import random'''
獲取(生成)訓練集
'''
input_num = 2 # 輸入個數
examples_num = 1000 # 生成樣本個數
# 確定真實模型參數
real_W = [10.9, -8.7]
real_bias = 6.5 features = nd.random.normal(scale=1, shape=(examples_num, input_num)) # 標準差=1,均值缺省=0
labels = real_W[0]*features[:,0] + real_W[1]*features[:,1] + real_bias # 根據特征和參數生成對應標簽
labels_noise = labels + nd.random.normal(scale=0.1, shape=labels.shape) # 為標簽附加噪聲,模擬真實情況# 繪制標簽和特征的散點圖(矢量圖)
# def use_svg_display():
# display.set_matplotlib_formats('svg')# def set_figure_size(figsize=(3.5,2.5)):
# use_svg_display()
# plt.rcParams['figure.figsize'] = figsize# set_figure_size()
# plt.scatter(features[:,0].asnumpy(), labels_noise.asnumpy(), 1)
# plt.scatter(features[:,1].asnumpy(), labels_noise.asnumpy(), 1)
# plt.show()# 創建一個迭代器(確定從數據集獲取數據的方式)
def data_iter(batch_size, features, labels):num = len(features)indices = list(range(num)) # 生成索引數組random.shuffle(indices) # 打亂indices# 該遍歷方式同時確保了隨機采樣和無遺漏for i in range(0, num, batch_size):j = nd.array(indices[i: min(i+batch_size, num)]) # 對indices從i開始取,取batch_size個樣本,并轉換為列表yield features.take(j), labels.take(j) # take方法使用索引數組,從features和labels提取所需數據"""
訓練的基礎準備
"""
# 聲明訓練變量,并賦高斯隨機初始值
w = nd.random.normal(scale=0.01, shape=(input_num))
b = nd.zeros(shape=(1,))
# b = nd.zeros(1) # 不同寫法,等價于上面的
w.attach_grad() # 為需要迭代的參數申請求梯度空間
b.attach_grad()# 定義模型
def linreg(X, w, b):return nd.dot(X,w)+b# 定義損失函數
def squared_loss(y_hat, y):return (y_hat - y.reshape(y_hat.shape)) **2 /2# 定義尋優算法
def sgd(params, learning_rate, batch_size):for param in params:# 新參數 = 原參數 - 學習率*當前批量的參數梯度/當前批量的大小param[:] = param - learning_rate * param.grad / batch_size# 確定超參數和學習方式
lr = 0.03
num_iterations = 5
net = linreg # 目標模型
loss = squared_loss # 代價函數(損失函數)
batch_size = 10 # 每次隨機小批量的大小'''
開始訓練
'''
for iteration in range(num_iterations): # 確定迭代次數for x, y in data_iter(batch_size, features, labels):with autograd.record():l = loss(net(x,w,b), y) # 求當前小批量的總損失l.backward() # 求梯度sgd([w,b], lr, batch_size) # 梯度更新參數train_l = loss(net(features,w,b), labels)print("iteration %d, loss %f" % (iteration+1, train_l.mean().asnumpy()))
# 打印比較真實參數和訓練得到的參數
print("real_w " + str(real_W) + "\n train_w " + str(w))
print("real_w " + str(real_bias) + "\n train_b " + str(b))
具體程序解釋
param[:] = param - learning_rate * param.grad / batch_size
:
將batch_size與參數調整相關聯的原因,是為了使得每次更新的步長不受批次大小的影響
具體來說,當計算一批數據的損失函數的梯度時,實際上是將這批數據中每個樣本對損失函數的貢獻累加起來。這意味著如果批次較大,梯度的模也會相應增大
故更新權值時,使用的是數據集的平均梯度,而不是總和