1. 程式人生 > >MXNet實戰之多層感知機

MXNet實戰之多層感知機

這是來自MXNet官網裡面的一個例子,利用module包[1]來構建一個多層感知機,並在UCI letter recognition[2]中進行訓練。利用module包來訓練網路,可以採用兩種介面:中層介面和高層介面。高層介面可以看做是對中層介面的一種封裝。 其基本步驟大致如下:載入資料、定義網路、建立module模組、呼叫介面進行訓練。

載入資料

載入資料的目的是將訓練集和驗證集載入到記憶體中。因為,我們訓練網路的資料集比較大,所以我們一般使用一個迭代器,這樣每次只用載入batch大小的資料。 下面是下載該資料集,並將資料集按照8:2的比例分為訓練集和測試集。

import logging
logging.getLogger().setLevel(logging.INFO)
import mxnet as mx
import numpy as np

mx.random.seed(1234)
fname = mx.test_utils.download('https://s3.us-east-2.amazonaws.com/mxnet-public/letter_recognition/letter-recognition.data')
data = np.genfromtxt(fname, delimiter=',)[:,1:]    #data.shape = (10000L, 16L)
label = np.array([ord(l.split(',')[0])-ord('A') for l in open(fname, 'r')])

batch_size = 32
ntrain = int(data.shape[0]*0.8)
train_iter = mx.io.NDArrayIter(data[:ntrain, :], label[:ntrain],batch_size, shuffle=True)
val_iter = mx.io.NDArrayIter(data[ntrain:, :], label[ntrain:],batch_size)

定義網路

利用symbol介面定義網路模型,包括網路的輸入和標籤。

net = mx.sym.Variable("data")
net = mx.sym.FullyConnected(net, name="fc1", num_hidden=64)
net = mx.sym.Activation(net, name="relu1", act_type="relu")
net = mx.sym.FullyConnected(net, name="fc2", num_hidden=26)
net = mx.sym.SoftmaxOutput(net, name="softmax")
mx.viz.plot_network(net)        # 顯示網路模型 

建立module模組

mod = mx.mod.Module(symbol=net, context=mx.cpu(),     #  context指定cpu或是gpu
                    data_names=['data'],
                    label_names=['softmax_label'])

中層介面

採用中層介面的好處是便於debug。因為,中層介面需要明確寫出forward和backward。如下程式碼:

mod.bind(data_shapes=train_iter.provide_data, label_shapes=train_iter.provide_label)
mod.init_params(initializer=mx.init.Uniform(scale=.1))
mod.init_optimizer(optimizer='sgd',optimizer_params=(('learning_rate',0.1),))
metric=mx.metric.create('acc')

for epoch in range(5):
    train_iter.reset()
    metric.reset()
    for batch in train_iter:
        mod.forward(batch, is_train=True)
        mod.update_metric(metric, batch.label)
        mod.backward()
        mod.update()
    print('Epoch %d, Training %s' % (epoch, metric.get()))

採用高層介面

train_iter.reset()
mod = mx.mod.Module(symbol=net, context=mx.cpu(),
                    data_names=['data'], label_name=['softmax_label'])

mod.fit(train_iter, eval_data=val_iter, 
        optimizer='sgd', optimizer_params={'learning_rate':0.1},
        eval_metric='acc', num_epoch=60)

可以看出,module為了方便,將訓練、預測和評價等操作都進行了封裝。與中層介面不同,需要一步一步來操作,module包直接呼叫了fit函式介面就完成相同的操作。

預測和指標評價

可以採用兩種方式:

# 方式一:直接獲得預測結果
y = mod.predict(val_iter) 

# 方式二:直接獲得指標結果
score = mod.score(val_iter, ['acc'])
print("Accuracy score is %f" % (score[0][1]))

使用第二種方式,我們可以直接獲得指標結果,而指標我們也可以根據實際情況進行替換。如top_k_acc,F1,RMSE等等。

儲存和載入模型

使用checkpoint callback來控制每一輪迭代後是否需要自動儲存模型,如下:

model_prefix = "mx_mlp"
checkpoint = mx.callback.do_checkpoint(model_prefix)

mod = mx.mod.Module(symbol=net)
mod.fit(train_iter, num_epoch=5, epoch_end_callback=checkpoint)

為了載入模型,我們需要呼叫load_checkpoint函式。這個函式載入symbol以及對應的引數,然後我們將這些模型和引數來初始化module。如下:

sym, arg_params, aux_params = mx.model.load_checkpoint(model_prefix, 3)
assert sym.tojson()==net.tojson()

mod.set_params(arg_params, aux_params)

如果我們想從某個節點訓練模型,那麼我們可以直接呼叫fit函式。在fit函式中,我們可以直接載入這些引數,而不是初始化。另外,我們可以設定begin_epoch引數,讓模型知道我們是從之前某個節點開始訓練。

mod=mx.mod.Module(symbol=sym)
mod.fit(train_iter, num_epoch=21,
        arg_params=arg_params,
        aux_params=aux_params,
        begin_epoch=3)

參考