今さらながら自然言語分類を試してみる②(実践)

はじめに

文章を固定長のベクトルで表現することにチャレンジ
前回準備したデータを使用
touch-sp.hatenablog.com

モデルの作成

GRUを使用する
「gru.py」として保存

import mxnet as mx
from mxnet.gluon import Block, nn, rnn

ctx = mx.gpu()
#cpu = mx.cup()

class Model(Block):
    def __init__(self, word_num, hidden_size, **kwargs):
        super(Model, self).__init__(**kwargs)
        self.word_num = word_num
        self.hidden_size = hidden_size
        
        with self.name_scope():
            self.embed = nn.Embedding(word_num, hidden_size)
            self.rnn = rnn.GRU(hidden_size, num_layers=1)
            self.dense = nn.Dense(word_num, flatten=False)

    def forward(self, x): 
        batch_size = x.shape[0]
        x = self.embed(x)
        x = mx.nd.swapaxes(x, 0, 1)
        h = mx.nd.random.uniform(shape=(1, batch_size, self.hidden_size),ctx=ctx)
        x, h = self.rnn(x, h)
        x = mx.nd.swapaxes(x, 0, 1)
        x = self.dense(x)
        return x, h

実行

import pandas as pd
import numpy as np

#データの読みこみ
df = pd.read_csv('train.csv', header=None)

#2番目以降の列が文章、最初の列がカテゴリー
words = df.iloc[:,1:].values

#逆順の文
X = [np.flip(x, axis=0) for x in words]

import mxnet as mx

ctx = mx.gpu()
#ctx = mx.cpu()

X = mx.nd.array(X)
Y = mx.nd.array(words)

from mxnet import autograd
from mxnet.gluon import Trainer
from mxnet.gluon.loss import SoftmaxCrossEntropyLoss
import gru

#モデルの作成
word_num = np.amax(words)
model = gru.Model(word_num, 128)
model.initialize(ctx=ctx)

#学習アルゴリズムの設定
trainer = Trainer(model.collect_params(), 'adam')
loss_func = SoftmaxCrossEntropyLoss()

#データの準備
train_data = mx.io.NDArrayIter(X, Y, batch_size=15, shuffle=True)

#学習の開始
print('start training...')

epochs = 30
loss_n = []

for i in range(1, epochs+1):
    train_data.reset()
    for batch in train_data:
        data = batch.data[0].as_in_context(ctx)
        label = batch.label[0].as_in_context(ctx)
        with autograd.record():
            output, status = model(data)
            loss = loss_func(output, label)
            loss_n.append(np.mean(loss.asnumpy()))
            loss.backward()
        trainer.step(batch.data[0].shape[0])

    ll = np.mean(loss_n)
    print('%d epoch  loss = %f'%(i, ll))
    loss_n = []

model.save_parameters('rnn_model.params')

結果の確認

import pandas as pd
import numpy as np

#データの読みこみ
df = pd.read_csv('train.csv', header=None)

#2番目以降の列が文章、最初の列がカテゴリー
words = df.iloc[:,1:].values
category = df.iloc[:,0].values

#カテゴリーを文字列からIDにする
category_dict = {t:i+1 for i,t in enumerate(np.unique(category))}
category =  [category_dict[c] for c in category]

#逆順の文
X = [np.flip(x, axis=0) for x in words]

import mxnet as mx

ctx = mx.gpu()
#ctx = mx.cpu()

X = mx.nd.array(X).as_in_context(ctx)

#モデルのインポート
import gru
word_num = np.amax(words)
model = gru.Model(word_num, 128)
model.load_parameters('rnn_model.params', ctx=ctx)

#モデルの実行
output, status = model(X)

#ステータスの取得
doc_vec = status[0].asnumpy()[0]

#t-SNEで2次元に
from sklearn.manifold import TSNE
result = TSNE(n_components=2, random_state=0).fit_transform(doc_vec)

#結果を散布図にして表示
import matplotlib.pyplot as plt
df_plot = pd.DataFrame({'x':result[:,0], 'y':result[:,1], 'c':category})
df_plot.plot(kind='scatter', x='x', y='y', c=category, colormap='gnuplot')
plt.show()

f:id:touch-sp:20190709022134p:plain

参考文献

MXNetで作る データ分析AIプログラミング入門

MXNetで作る データ分析AIプログラミング入門