MxNet新前端Gluon模型轉(zhuǎn)換到Symbol

1. 導(dǎo)入各種包

from mxnet import gluon
from mxnet.gluon import nn
import matplotlib.pyplot as plt
from mxnet import autograd as autograd
from mxnet import nd
import mxnet as mx
from collections import namedtuple
import random

2. 準(zhǔn)備數(shù)據(jù)

使用和mnist很像的FashionMNIST數(shù)據(jù)集,使用Gluon下載

def transform(data,label):
    return data.astype('float32')/255,label.astype('float32')
fashion_train = gluon.data.vision.FashionMNIST(root='./',train=True,transform=transform)
fashion_test = gluon.data.vision.FashionMNIST(root='./',train=True, transform=transform)
batch_size = 256
train_data = gluon.data.DataLoader(fashion_train,batch_size,shuffle=True)
test_data = gluon.data.DataLoader(fashion_test,batch_size,shuffle=True)

用于顯示圖像和標(biāo)簽

def show_images(images):
    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]

看下數(shù)據(jù)集長(zhǎng)啥樣

data,label = fashion_train[5:19]
show_images(data)
print(get_text_labels(label))
內(nèi)容示例
['coat', 'coat', 'sandal', 'coat', 'bag', 't-shirt', 'bag', 'ankle boot', 't-shirt', 'pullover', 'pullover', 'ankle boot', 'dress,', 'dress,']

3. 精度計(jì)算函數(shù)

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

def evaluate_accuracy(data_iterator, net):
    acc = 0.
    for data, label in data_iterator:
        output = net(nd.transpose(data,(0,3,1,2)))
        acc += accuracy(output, label)
    return acc / len(data_iterator)

4. 定義網(wǎng)絡(luò)

4.1 自己定義的層

Gluon模型轉(zhuǎn)到Symbol下只能用HybridSequential模式,HybridSequential是靜態(tài)圖,會(huì)對(duì)計(jì)算有優(yōu)化,不過HybridSequentialSequential可以很方便的轉(zhuǎn)換,確切的就是一行代碼的事。同樣自定義的網(wǎng)絡(luò),要使用HybridBlock,和Block沒有多大區(qū)別

class MyDense(nn.HybridBlock):
    def __init__(self,**kwargs):
        super(MyDense,self).__init__(**kwargs)
        with self.name_scope():
            self.dense0 = nn.Dense(256)
            self.dense1 = nn.Dense(10)
    def hybrid_forward(self,F,x):   #  這里要使用hybrid_forward而不是forward,并且多了個(gè)參數(shù)F
        return self.dense1(F.relu(self.dense0(x)))    #  F的作用就是替代 nd,如果是靜態(tài)圖,就是用 sym,否則使用 nd

4.2 使用自定義的層和自帶的層組成完整的網(wǎng)絡(luò)

網(wǎng)絡(luò)定義和動(dòng)態(tài)圖一樣,只不過把Sequential替換成了HybridSequential,在最后使用hybridize()會(huì)對(duì)靜態(tài)圖進(jìn)行優(yōu)化

net = nn.HybridSequential()
with net.name_scope():
    net.add(gluon.nn.Conv2D(channels=20, kernel_size=5, activation='relu'))
    net.add(gluon.nn.MaxPool2D(pool_size=2, strides=2))
    net.add(gluon.nn.Conv2D(channels=50, kernel_size=3, activation='relu'))
    net.add(gluon.nn.MaxPool2D(pool_size=2, strides=2))
    net.add(gluon.nn.Flatten())
    net.add(MyDense())
net.initialize(init=mx.init.Xavier())
net.hybridize()
net
HybridSequential(
  (0): Conv2D(20, kernel_size=(5, 5), stride=(1, 1))
  (1): MaxPool2D(size=(2, 2), stride=(2, 2), padding=(0, 0), ceil_mode=False)
  (2): Conv2D(50, kernel_size=(3, 3), stride=(1, 1))
  (3): MaxPool2D(size=(2, 2), stride=(2, 2), padding=(0, 0), ceil_mode=False)
  (4): Flatten
  (5): MyDense(
    (dense0): Dense(256, linear)
    (dense1): Dense(10, linear)
  )
)

5. 訓(xùn)練

使用Adam優(yōu)化算法,訓(xùn)練的速度會(huì)快點(diǎn)

softmax_cross_entropy = gluon.loss.SoftmaxCrossEntropyLoss()
trainer = gluon.Trainer(net.collect_params(), 'Adam', {'learning_rate': 0.008})
for epoch in range(5):
    train_loss = 0.
    train_acc = 0.
    test_acc = 0.
    for data, label in train_data:
        data = nd.transpose(data,(0,3,1,2))
        with autograd.record():
            output = net(data)
            loss = softmax_cross_entropy(output, label)
        loss.backward()
        trainer.step(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, Train acc %f, Test acc %f" % (
            epoch, train_loss/len(train_data), train_acc/len(train_data), test_acc))
Epoch 0. Loss: 0.498041, Train acc 0.817226, Test acc 0.865459
Epoch 1. Loss: 0.312128, Train acc 0.884813, Test acc 0.894265
Epoch 2. Loss: 0.274009, Train acc 0.898454, Test acc 0.898604
Epoch 3. Loss: 0.247741, Train acc 0.906521, Test acc 0.914910
Epoch 4. Loss: 0.226967, Train acc 0.913736, Test acc 0.914334

6. 保存成Symbol格式的網(wǎng)絡(luò)和參數(shù)(重點(diǎn))

要注意保存網(wǎng)絡(luò)參數(shù)的時(shí)候,需要net.collect_params().save()這樣保存,而不是net.save_params()保存
最新版的mxnet已經(jīng)有可以導(dǎo)出到symbol格式下的接口了。需要mxnet版本在20171015以上
下面示例代碼也已經(jīng)改成新版的保存,加載方式

#新版本的保存方式
net.export('Gluon_FashionMNIST')

7. 使用Symbol加載網(wǎng)絡(luò)并綁定

symnet = mx.symbol.load('Gluon_FashionMNIST-symbol.json')
mod = mx.mod.Module(symbol=symnet, context=mx.cpu())
mod.bind(data_shapes=[('data', (1, 1, 28, 28))])
mod.load_params('Gluon_FashionMNIST-0000.params')
Batch = namedtuple('Batch', ['data'])

8. 預(yù)測(cè)試試看效果

img,label = fashion_test[random.randint(0, 60000)]
data = img.transpose([2,0,1])
data = data.reshape([1,1,28,28])
mod.forward(Batch([data]))
out = mod.get_outputs()
prob = out[0]
predicted_labels = prob.argmax(axis=1)

plt.imshow(img.reshape((28, 28)).asnumpy())
plt.axis('off')
plt.show()
print('predicted labels:',get_text_labels(predicted_labels.asnumpy()))

print('true labels:',get_text_labels([label]))
預(yù)測(cè)內(nèi)容
predicted labels: ['pullover']
true labels: ['pullover']
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容