標籤:col 避免 演算法 puts 因此 fun amp 引入 backward
線性迴歸
給定一個資料點集合 X 和對應的目標值 y,線性模型的目標就是找到一條使用向量 w 和位移 b
描述的線,來儘可能地近似每個樣本X[i] 和 y[i]。
數學公式表示為\(\hat{y}=Xw+b\)
目標函數是最小化所有點的平方誤差 \(\sum_{i=1}^{n} (\hat{y_i}-y_i)^2\)
?個神經?絡就是?個由節點(神經元)和有向邊組成的集合。我們? 般把?些節點群組成層,每?層先從下??層的節點擷取輸?,然後輸出給上?的層使?。要計算? 個節點值,我們需要將輸?節點值做加權和(權數值即w),然後再加上?個啟用函數(activation function)。這裡的啟用函數是\(f(x)=x\)
建立資料集: \(y=2*x[0] - 3.4*x[1] + 4.2 +noise\)
# -*- coding: utf-8 -*-from mxnet import ndarray as ndfrom mxnet import autogradnum_inputs = 2num_examples = 1000true_w = [2, -3.4]true_b = 4.2X = nd.random_normal(shape=(num_examples, num_inputs))y = true_w[0] * X[:, 0] + true_w[1] * X[:, 1] + true_by += .01 * nd.random_normal(shape=y.shape)print 'dataset'import matplotlib.pyplot as pltplt.scatter(X[:, 1].asnumpy(),y.asnumpy())plt.show()
當我們開始訓練神經?絡的時候,我們需要不斷讀取資料區塊。這?我們定義?個函數它每次返回 batch_size 個隨機的樣本和對應的?標。
import randombatch_size = 10def data_iter(): # 產??個隨機索引 idx = list(range(num_examples)) random.shuffle(idx) for i in range(0, num_examples, batch_size): j = nd.array(idx[i:min(i+batch_size,num_examples)]) yield nd.take(X, j), nd.take(y, j)for data, label in data_iter(): print(data, label)
隨機初始化模型參數,之後訓練時我們需要對這些參數求導來更新它們的值,使損失盡量減小;因此我們需要建立它們的梯度。
w = nd.random_normal(shape=(num_inputs, 1))b = nd.zeros((1,))params = [w, b]for param in params: param.attach_grad()
定義網路
def net(X): return nd.dot(X, w) + b
定義損失函數
def square_loss(yhat, y): # 注意這?我們把 y 變形成 yhat 的形狀來避免矩陣形狀的?動轉換 return (yhat - y.reshape(yhat.shape)) ** 2
定義最佳化方案,我們這?通過隨機梯度下降來求解。每?步,我們將模型參數沿著梯度的反?向走特定距離,這個距離?般叫學習率(learning rate)lr。
def SGD(params, lr): for param in params: param[:] = param - lr * param.grad
現在我們可以開始訓練了。訓練通常需要迭代資料數次,在這?使? epochs表?迭代總次數; ?次迭代中,我們每次隨機讀取固定數個資料點,計算梯度並更新模型參數。
epochs = 5learning_rate = .001niter = 0moving_loss = 0smoothing_constant = .01# 訓練for e in range(epochs): total_loss = 0 for data, label in data_iter(): with autograd.record(): output = net(data) loss = square_loss(output, label) loss.backward() SGD(params, learning_rate) total_loss += nd.sum(loss).asscalar() # 記錄每讀取?個資料點後,損失的移動平均值的變化; niter +=1 curr_loss = nd.mean(loss).asscalar() moving_loss = (1 - smoothing_constant) * moving_loss + (smoothing_constant * curr_loss) if (niter + 1) % 100 == 0: print("Epoch %d, batch %d. Average loss: %f" % ( epochs, niter, moving_loss))print(params)# output[[ 1.99952257] [-3.39969802]]<NDArray 2x1 @cpu(0)>, [ 4.19949913]<NDArray 1 @cpu(0)>
線性迴歸-使用Gluon
這裡我們將使用MXNet提供的Gluon介面更方便地實現線性迴歸的訓練。
首先產生資料集
num_inputs = 2num_examples = 1000true_w = [2, -3.4]true_b = 4.2features = nd.random_normal(scale=1, shape=(num_examples, num_inputs))labels = true_w[0] * features[:, 0] + true_w[1] * features[:, 1] + true_blabels += nd.random_normal(scale=0.01, shape=labels.shape)
讀取資料,使用Gluon提供的data模組來讀取資料。在每一次迭代中,我們將隨機讀取包含10個資料樣本的小批量。
from mxnet.gluon import data as gdatabatch_size = 10dataset = gdata.ArrayDataset(features, labels)data_iter = gdata.DataLoader(dataset, batch_size, shuffle=True)
在前面我們需要定義模型參數,並使用它們一步步描述模型是怎樣計算的。當模型結構變得更複雜時,這些步驟將變得更加繁瑣。其實,Gluon提供了大量預定義的層,這使我們只需關注使用哪些層來構造模型。
首先,匯入nn模組。我們先定義一個模型變數net,它是一個Sequential執行個體。在Gluon中,Sequential執行個體可以看做是一個串聯各個層的容器。在構造模型時,我們在該容器中依次添加層。當給定輸入資料時,容器中的每一層將依次計算並將輸出作為下一層的輸入。
線性迴歸的輸出層又叫全串連層。在Gluon中,全串連層是一個Dense執行個體。我們定義該層輸出個數為1。
from mxnet.gluon import nnnet = nn.Sequential()net.add(nn.Dense(1))
值得一提的是,在Gluon中我們無需指定每一層輸入的形狀,例如線性迴歸的輸入個數。當模型看見資料時,例如後面執行net(X)時,模型將自動推斷出每一層的輸入個數。
初始化模型參數,從MXNet中匯入init模組,並通過init.Normal(sigma=0.01)指定權重參數每個元素將在初始化時隨機採樣於均值為0標準差為0.01的常態分佈。偏差參數全部元素初始化為零。
from mxnet import initnet.initialize(init.Normal(sigma=0.01))
定義損失函數,從gluon引入loss模組
from mxnet.gluon import loss as glossloss = gloss.L2Loss()
定義最佳化演算法,在匯入Gluon後,我們可以建立一個Trainer執行個體,並且將模型參數傳遞給它。
from mxnet.gluon import Trainertrainer = Trainer(net.collect_params(), 'sgd', {'learning_rate': 0.03})
訓練模型,我們通過調用step函數來迭代模型參數。由於變數l是batch_size維的NDArray,執行l.backward()等價於l.sum().backward()。按照小批量隨機梯度下降的定義,我們在step函數中提供batch_size,以確保小批量隨機梯度是該批量中每個樣本梯度的平均。
num_epochs = 3for epoch in range(1, num_epochs + 1): for X, y in data_iter: with autograd.record(): l = loss(net(X), y) l.backward() trainer.step(batch_size) print("epoch %d, loss: %f" % (epoch, loss(net(features), labels).asnumpy().mean()))dense = net[0]print true_w, dense.weight.data()print true_b, dense.bias.data()
可以從net獲得需要的層,並訪問其權重和位移。學到的和真實的參數很接近。
MXNET:監督學習