動手學(xué)深度學(xué)習筆記(一)

一、使用NDArray來處理數(shù)據(jù)

首先從 MXNet 導(dǎo)入ndarray模塊吁脱。ndndarray的縮寫形式涯保。
from mxnet import ndarray as nd

然后創(chuàng)建3行4列的2d數(shù)組
nd.zeros((3,4))

創(chuàng)建隨機數(shù)組一死,元素服從均值0,方差1的正態(tài)分布羡微。
y=nd.random_normal(0,1,shape=(3,4))

數(shù)組的形狀
y.shape

數(shù)組的大小
y.size

操作符

加法:x + y
乘法:x * y
指數(shù)運算:nd.exp(y)
轉(zhuǎn)秩矩陣然后計算矩陣乘法:nd.dot(x,y.T)

廣播

當二元操作符左右兩邊ndarray形狀不一樣時谷饿,系統(tǒng)會嘗試將其復(fù)制到一個共同的形狀。例如a的第0維是3妈倔,b的第0維是1博投,那么a+b時將b沿著第0維復(fù)制3遍:

a = nd.arrange(3).reshape((3,1))
b = nd.arrange(2).reshape((1,2))

print('a:',a)
print('b:',b)
print('a+b',a+b)

與Numpy的轉(zhuǎn)換

ndarray可以很方便同numpy進行轉(zhuǎn)換

import numpy as np

X = np.ones((2,3))
Y = nd.array(X) #numpy->mxnet
Z = y.asnumpy(Y) #mxnet->bumpy

替換操作

y = x + y,會將y從現(xiàn)在指向的實例轉(zhuǎn)到新建的實例上去:

x = nd.ones((3,4))
y = nd.ones((3,4))

before = id(y)
y = y + x

id(y) == before

也可以把結(jié)果通過[:]寫到一個之前開好的數(shù)組里:

z = nd.zeros_like(x)
before = id(z)
z[:] = x + y

id(z) == before

這里為x + y創(chuàng)建了臨時空間盯蝴,然后復(fù)制到z毅哗,更簡便的做法是使用操作符的全名版本中的out參數(shù):

nd.elemwise_add(x, y,out=z)

id(z) == before

總結(jié)

  • NDArray 是 MXNet 中存儲和變換數(shù)據(jù)的主要工具。
  • 我們可以輕松地對 NDArray 創(chuàng)建捧挺、運算虑绵、指定索引,并與 NumPy 之間相互變換闽烙。
  • ndarray模塊提供一系列多維數(shù)組操作函數(shù)翅睛。所有函數(shù)列表可以參見NDArrayAPI文檔。

使用autograd來自動求導(dǎo)

MXnet提供autograd包來自動化求導(dǎo)過程

import mxnet.adarray as nd
import mxnet.autograd as ag

為變量賦上梯度

對函數(shù)f = 2 * (x**2)求關(guān)于x的導(dǎo)數(shù)鸣峭;

創(chuàng)建變量x宏所,并賦初值酥艳。

x = nd.array([[1, 2],[3, 4]])

當進行求導(dǎo)時摊溶,需要一個空間來存放x的導(dǎo)數(shù),這個可以通過attach_grad()來要求系統(tǒng)申請對應(yīng)的空間充石。

x.attch_grad()

下面定義f莫换;默認條件下,MXNet不會自動記錄和構(gòu)建用于求導(dǎo)的計算圖骤铃,我們需要使用autograd里的record()函數(shù)來現(xiàn)實要求MXNet記錄我們需要求導(dǎo)的程序拉岁。

with at.record():
    y = x * 2
    z = y * x

使用z.backward()來進行求導(dǎo);如果z不是一個標量惰爬,那么z.backward()等價于nd.sum(z).backward()

z.backward()

驗證

x.grad == 4 * x

對控制流求導(dǎo)

可以對python的控制流進行求導(dǎo)喊暖。

def f(a):
    b = a * 2
    while nd.norm(b).asscalar() > 0:
        b = b * 2
    if nd.sum(b).asscalar()>0:
        c = b
    else:
        c = 100 * b
    return c

依舊可以用record記錄和backward求導(dǎo)。

a = nd.random_normal(shape=3)
a.attach_grad()

with ag.record():
    c = f(a)

c.backward()
a.grad == c/a

小結(jié)

  • MXNet 提供autograd包來自動化求導(dǎo)過程撕瞧。
  • MXNet 的autograd包可以對一般的命令式程序進行求導(dǎo)陵叽。

線性回歸

創(chuàng)建數(shù)據(jù)集

使用如下方法來生成數(shù)據(jù)
y[i] = 2*X[i][0] - 3.4 * X[i][1] + 4.2 + noise
噪音服從均值0和方差0.1的正態(tài)分布。

from mxnet import ndarray as nd
from mxnet import autograd

num_inputs = 2
num_examples = 1000
true_w = [2, -3.4]
true_b = 4.2

X = nd.random_normal(shape=(num_examples, num_inputs))
y = true_w[0] * X[:,0] + true_w[1] * X[:,1] + true_b
y += .01 * nd.random_normal(shape=y.shape)

print(X[0], y[0])

數(shù)據(jù)讀取

當我們開始訓(xùn)練神經(jīng)網(wǎng)絡(luò)的時候丛版,我們需要不斷讀取數(shù)據(jù)塊巩掺。這里我們定義一個函數(shù)它每次返回batch_size個隨機的樣本和對應(yīng)的目標。我們通過python的yield來構(gòu)造一個迭代器页畦。

import random

batch_size = 10
def data_iter():
    #產(chǎn)生一個隨機索引
    idx = list(range(num_examples))
    random.shuffle(idx)

    for i in range(0, num_examples, baych_size):
        j = nd.array(idx[i:min(i+batch_size,num_examples)])
        yield nd.take(X, j), nd.take(y, j)

下面代碼讀取第一個隨機數(shù)據(jù)塊

for data, label in data_iter():
    print(data, label)
    break

初始化模型參數(shù)

下面我們隨機初始化模型參數(shù)

w = nd.random_normal(shape=(num_inputs, 1))
b = nd.zeros((1,))
params = [w, b]

之后訓(xùn)練時我們需要對這些參數(shù)求導(dǎo)來更新它們的值胖替,因此我們需要創(chuàng)建它們的梯度。

for param in params:
    param.attach_grad()

定義模型

線性模型就是將輸入和模型做乘法再加上偏移:

def net(X):
    return nd.dot(X, w)  + b

損失函數(shù)

我們使用常見的平方誤差來衡量預(yù)測目標和真實目標之間的差距

def square_loss(yhat, y):
    #注意這里我們把y變形成yhat的形狀來避免自動廣播
    return (yhat - y.reshape(yhat.shape)) ** 2

優(yōu)化

這里通過隨機梯度下降來求解:

def SGD(params, lr):
    for param in params:
        param[:] = param - lr * param.grad

訓(xùn)練

訓(xùn)練通常需要迭代數(shù)據(jù)數(shù)次,一次迭代里独令,我們每次隨機讀取固定數(shù)個數(shù)據(jù)點端朵,計算梯度并更新模型參數(shù)。

epochs = 5
learning_rate = .001

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()
    print(“Epoch %d, average loss: %f” % (e, total_loss/num_examples))

訓(xùn)練完成后可以比較學(xué)到的參數(shù)和真實參數(shù):
true_w, w
true_b, b

小結(jié)
可以看出燃箭,僅使用 NDArray 和autograd就可以很容易地實現(xiàn)一個模型逸月。

使用Gluon的線性回歸

創(chuàng)建數(shù)據(jù)集

生成同樣的數(shù)據(jù)集

from mxnet import ndarray as nd
from mxnet import autograd
from mxnet import gluon

num_inputs = 2
num_examples = 1000

true_w = [2, -3.4]
true_b = 4.2

X = nd.random_normal(shape=(num_examples, num_inputs))
y = true_w[0] * X[:,0] + true_w[1] * X[:,1] + true_b
y += .01 * nd.random_normal(shape=y.shape)

print(X[0], y[0])

數(shù)據(jù)讀取

這里使用data模塊來讀取數(shù)據(jù)。

batch_size = 10
dataset = gluon.data.ArrayDataset(X,y)
data_iter = gluon.data.DataLoader(dataset, batch_size, shuffle=True)

讀取和前面一致:

for data, label in data_iter:
    print(data, label)
    break

定義模型

gluon提供大量的提前定制好的層遍膜,使得我們只需要主要關(guān)注使用哪些層來構(gòu)建模型碗硬。例如線性模型就是使用Dense層。

構(gòu)建模型最簡單的辦法是利用Sequential來所有層串起來瓢颅。首先我們定義一個空的模型:

net = gluon.nn.Sequential()

然后加入一個Dense層恩尾,唯一要定義的參數(shù)就是輸出節(jié)點的個數(shù),在線性模型里面是1.

net.add(gluon.nn.Dense(1))

(注意這里沒有定義這個層的輸入節(jié)點是多少挽懦,這個在之后真正給數(shù)據(jù)的時候系統(tǒng)會自動賦值翰意。之后會詳細解釋這個特性)

初始化模型參數(shù)

使用默認初始化方法

net.initialize()

損失函數(shù)

gluon提供了平方誤差函數(shù):

square_loss = gluon.loss.L2Loss()

優(yōu)化

創(chuàng)建一個Trainer的實例,并且將模型參數(shù)傳遞給它就行

trainer = gluon.Trainer(net.collect_params(), 'sgd', {'learning_rate': 0.1})

訓(xùn)練

不再調(diào)用SGD而是trainer.step來更新模型

epochs = 5
batch_size = 0

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()
      trainer.step(batch_size)
      total_loss += nd.sum(loss).asscalar()

    print("Epoch %d, average loss: %f"% (e, total_loss/num_examples))

先從net拿到需要的層信柿,然后訪問其權(quán)重和偏置冀偶。

dense = net[0]
true_w, dense.weight.data()
true_b, dense.bias.data()

小結(jié)
使用 Gluon 可以更簡潔地實現(xiàn)模型。
在 Gluon 中渔嚷,data模塊提供了有關(guān)數(shù)據(jù)處理的工具进鸠,nn模塊定義了大量神經(jīng)網(wǎng)絡(luò)的層,loss模塊定義了各種損失函數(shù)形病。
MXNet 的initializer模塊提供了模型參數(shù)初始化的各種方法客年。

從0開始的多類邏輯回歸

獲取數(shù)據(jù)

分類服飾

from mxnet import gluon
from mxnet import ndarray as nd

def transform(data, label):
    return data.astype('float32')/255, label.astype('float32')

mnist_train = gluon.data.vision.FashionMNIST(train=True, transform = transform)
mnist_test = gluon.data.vision.FashionMNIST(train=False, transform = transform)

打印樣本的形狀和標簽

data, label = mnist_train[0]
(‘example shape: ‘, data.shape, 'label:', label)

樣本圖片顯示

import matplotlib.pyplot as plt

def show_images(image):
    n = images.shape[0]
    _, figs = plt.subplots(1, n, figsize=(15, 15))

    for i in range(n):
        figs[i].imshow(images[i].reshape((28, 28)).asnumpy())
        figs[i].axes.get_xaxis().set_visible(False)
        figs[i].axes.get_yaxis().set_visible(False)

plt.show()

def get_text_labels(label):
    text_labels = [‘t-shirt', 'trouser', 'pullover', 'dress', ‘coat’,’sandal’, ’shirt’, ’sneaker’, bag', 'ankle boot']
    return [text_labels[int(i)] for i in label]

data, label = mnist_train[0:9]
show_images(data)
print(get_text_labels(label))

數(shù)據(jù)讀取

直接使用DataLoader函數(shù)

batch_size = 256
train_data = gluon.data.DataLoader(mnist_train, batch_size, shuffle=True)
test_data = gluon.data.DataLoader(mnist_test, batch_size, shuffle=True)

初始化模型參數(shù)

輸入向量的長度為2828,輸出向量長度為10漠吻,因此權(quán)重的大小為78410:

num_inputs = 784
num_outputs = 10

W = nd.random_normal(shape=(num_inputs, num_outputs))
b = nd.random_normal(shape=num_outputs)
params = [W, b]

為模型參數(shù)附上梯度:


for param in params:

param.attach_grad()

定義模型

這里使用softmax函數(shù)來將任意的輸入歸一成合法的概率值量瓜。

from mxnet import nd

def softmax(X):
    exp = nd.exp(X)
    # 假設(shè)exp是矩陣,這里對行進行求和途乃,并要求保留axis 1
    # 返回(nrows绍傲, 1)形狀的矩陣
    partition = exp.sum(axis=1, keepdims=True)
    return exp / partiton

測試:

X = nd.random_normal(shape=(2,5))
x_prob = softmax(X)

print(X)
print(X_prob)
print(X_prob.sum(axis=1))

定義模型:

def net(X):
    # -1 系統(tǒng)自己判斷
    return softmax(nd.dot(X.reshape((-1,num_inputs)), W) + b)

交叉熵損失函數(shù)

交叉熵損失函數(shù),將兩個概率分布的負交叉熵作為目標值耍共,最小化這個值等價于最大化這兩個概率的相似度烫饼。

def cross_entropy(yhat, y):
return - nd.pick(nd.log(yhat), y)

計算精度

給定一個概率輸出,我們將預(yù)測概率最高的那個類作為預(yù)測的類划提,然后通過筆記真實標號我們可以計算精度:

def accuracy(output, label):
return nd.mean(output.argmax(axis=1)==label).asscalar()

可以評估一個模型在這個數(shù)據(jù)上的精度枫弟。

def evaluate_accuracy(data_iterator, net):
    acc = 0.

    for data, label in data_iterator:
        output = net(data)
        acc += accuracy(output, label)
        return acc / len(data_iterator)

嘗試測試:

evaluate_accuracy(test_data, net)

訓(xùn)練

import sys
sys.path.append('..')
from utils import SGD
from mxnet import autograd

learning_rate = .1
for epoch in range(5):
    train_loss = 0.
    train_acc = 0.

for data, label in train_data:
    with autograd.record():
    output = net(data)
    loss = cross_entropy(output, label)
    loss.backward()
    #對梯度做平均。這樣學(xué)習率會對batch size不那么敏感
    SGD(params, learning_rate/batch_size)
    train_loss += nd.mean(loss).asscalar()
    train_acc += accuracy(output, label)
    test_acc = evaluate_accuracy(test_data, net)

    print(“Epoch %d. Loss: %f, Test acc %f” % (epoch, train_loss/len(train_data),                                     \train_acc/len(train_data),test_acc/len(test_acc))

預(yù)測

data, label = mnist_test[0:9]
show_images(data)
print(‘true labels’)
print(get_text_labels(label))

predicted_labels = net(data).argmax(axis=1)
print(‘predicted labels’)
print(get_text_labels(predicted_labels.asnumpy()))

小結(jié)
我們可以使用 Softmax 回歸做多類別分類鹏往。與訓(xùn)練線性回歸相比淡诗,你會發(fā)現(xiàn)訓(xùn)練 Softmax 回歸的步驟跟其非常相似:獲取并讀取數(shù)據(jù)骇塘、定義模型和損失函數(shù)并使用優(yōu)化算法訓(xùn)練模型。事實上韩容,絕大多數(shù)深度學(xué)習模型的訓(xùn)練都有著類似的步驟款违。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市群凶,隨后出現(xiàn)的幾起案子插爹,更是在濱河造成了極大的恐慌,老刑警劉巖请梢,帶你破解...
    沈念sama閱讀 221,576評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件赠尾,死亡現(xiàn)場離奇詭異,居然都是意外死亡毅弧,警方通過查閱死者的電腦和手機气嫁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,515評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來够坐,“玉大人寸宵,你說我怎么就攤上這事≡” “怎么了梯影?”我有些...
    開封第一講書人閱讀 168,017評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長庶香。 經(jīng)常有香客問我甲棍,道長,這世上最難降的妖魔是什么脉课? 我笑而不...
    開封第一講書人閱讀 59,626評論 1 296
  • 正文 為了忘掉前任救军,我火速辦了婚禮,結(jié)果婚禮上倘零,老公的妹妹穿的比我還像新娘。我一直安慰自己戳寸,他們只是感情好呈驶,可當我...
    茶點故事閱讀 68,625評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著疫鹊,像睡著了一般袖瞻。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上拆吆,一...
    開封第一講書人閱讀 52,255評論 1 308
  • 那天聋迎,我揣著相機與錄音,去河邊找鬼枣耀。 笑死霉晕,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播牺堰,決...
    沈念sama閱讀 40,825評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼拄轻,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了伟葫?” 一聲冷哼從身側(cè)響起恨搓,我...
    開封第一講書人閱讀 39,729評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎筏养,沒想到半個月后斧抱,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,271評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡渐溶,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,363評論 3 340
  • 正文 我和宋清朗相戀三年夺姑,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片掌猛。...
    茶點故事閱讀 40,498評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡盏浙,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出荔茬,到底是詐尸還是另有隱情废膘,我是刑警寧澤,帶...
    沈念sama閱讀 36,183評論 5 350
  • 正文 年R本政府宣布慕蔚,位于F島的核電站丐黄,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏孔飒。R本人自食惡果不足惜灌闺,卻給世界環(huán)境...
    茶點故事閱讀 41,867評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望坏瞄。 院中可真熱鬧桂对,春花似錦、人聲如沸鸠匀。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,338評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽缀棍。三九已至宅此,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間爬范,已是汗流浹背父腕。 一陣腳步聲響...
    開封第一講書人閱讀 33,458評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留青瀑,地道東北人璧亮。 一個月前我還...
    沈念sama閱讀 48,906評論 3 376
  • 正文 我出身青樓萧诫,卻偏偏與公主長得像,于是被迫代替她去往敵國和親杜顺。 傳聞我的和親對象是個殘疾皇子财搁,可洞房花燭夜當晚...
    茶點故事閱讀 45,507評論 2 359

推薦閱讀更多精彩內(nèi)容