筋トレ大学生によるアウトプット雑記

筋トレや読書のことをはじめとして、プログラミングその他日常生活における様々なことについて書いていきます。

Output Blog

主に筋トレ・プログラミングについて書きます

ニューラルネットワークによる教師あり機械学習の実装方法!【語義判別】

スポンサーリンク

f:id:daimori1005:20191011201005j:plain

こんにちは!
もうすぐ研究の中間発表が近づいて参りまして、時間に追われる日々です。
そんな中でもブログ更新します!

さて、本日はニューラルネットワーク。
以前にSVMでの語義曖昧性解消を紹介しました。
今回は、同様のプログラムをChainerを使ってニューラルネットワークで実装していきます。

今回も、基礎的なことを堅実にやっていきます。
難しい分類問題も、基礎の応用でしかありませんので、土台をうまく組み立てておくと研究も進めやすいです。

それではやっていきましょう!



f:id:daimori1005:20191011203059j:plain

スポンサーリンク



手順


データを準備 → データの前処理 → データセット構築 → ニューラルネットワーク構築 → 学習とテスト

前回と同じです。


データセット構築まで


www.i-like-output.work

こちらをご覧ください。
今回は便宜上、データセットは同じものを使います。


ニューラルネットワーク構築

ニューラルネットワークを構築していきます。
多層パーセプトロンを使っていきます。

中間層は1層、200個のユニット、活性化関数はSoftmax、損失関数は交差エントロピー、最適化はAdamを使用していきます。
以下順に解説します。

データの準備まで

import numpy as np
import chainer
import chainer.links as L
import chainer.functions as F
from chainer.datasets import TupleDataset
from chainer.datasets import split_dataset_random
from chainer import iterators
from chainer import optimizers
from chainer import training
from chainer.training import extensions

x = np.load(file="example-x.npy")
y = np.load(file="example-y.npy")
y = np.array(y,dtype=np.int32)
y = [z-1 for z in y]


batch = 1

dataset = TupleDataset(x,y)
train,test = split_dataset_random(dataset, 6,seed=0)
train_iter = iterators.SerialIterator(train,batch)
test_iter = iterators.SerialIterator(test,batch,False,False)

まずは必要なライブラリをインポートします。

次にnumpy形式で x と y それぞれに保存しておいた配列情報を読み込みます。
この時、yは文字列として保存されている場合があるので、 numpy.int32 形式に変更します。
また、SVMでは大丈夫でしたが、ニューラルネットワークはクラスの番号を0から始めないといけません。
なので、前回付与したラベル番号から -1 しています。

今回はデータが少ないので、バッチサイズは1にしてます。
そして今回も訓練データとテストデータは 6:4 に分割してます。

SerialIteratorは、データを順番にバッチサイズに応じた個数ずつ取り出してきて、Variableオブジェクトに変換します。
デフォルトでは、repeat(繰り返し取り出し)とshuffle(シャッフルして取り出し)が True になっています。
テストデータでは、これらをオフにしないと終わらないため、Falseにしています。

ネットワークの構築とトレーニングまで

class mlp(chainer.Chain):
    def __init__(self,mid_units):
        super().__init__()

        with self.init_scope():
            self.fc1 = L.Linear(None,mid_units)
            self.fc2 = L.Linear(mid_units,mid_units)
            self.fc3 = L.Linear(mid_units,2)

    def forward(self,x):
        h = F.softmax(self.fc1(x))
        h = F.softmax(self.fc2(h))
        h = F.softmax(self.fc3(h))
        return h

pred = mlp(200)
net = L.Classifier(pred)
optimizer = optimizers.Adam().setup(net)
updater = training.StandardUpdater(train_iter,optimizer,device = -1)
trainer = training.Trainer(updater,(30,'epoch'), out="a")

trainer.extend(extensions.LogReport(trigger=(1, 'epoch'), log_name='log'))
trainer.extend(extensions.PrintReport(['epoch', 'iteration', 'main/loss', 'main/accuracy', 'elapsed_time']))
trainer.extend(extensions.ProgressBar())
trainer.run()

ここもそう難しくはありません。
困ったらこれと同じような感じで書けばなんとかなります。笑

順序的には、

ネットワーク構築 → ネットワーククラスをインスタンス化 → 最適化手法書く → ネットワーク更新手法書く → トレーナー書く → エクステンション書く → トレーニング

という感じです。

テスト

2通りの方法を示します。

test_evaluator = extensions.Evaluator(test_iter, net, device=-1)
results = test_evaluator()
print('Test accuracy:', results['main/accuracy'])

こちらは、精度だけを見たい場合に使います。
エクステンションをモジュール化して使うことで、普通の関数として使えます。

for t in test:
    a,b = t
    y_pred = net.predictor(a[None, ...])
    print(y_pred.data[0],b)

こちらは、テストデータのうち1データずつの出力を得ることができます。
精度だけでなく、softmaxした結果も見たい方などはこの書き方のようなテストの仕方をすると良いと思います。

分類結果

f:id:daimori1005:20191011222213p:plain

損失は少しだけ下がってきていますね。
精度はデータが少ないので仕方ありません。

ちなみに、自然言語処理における分類問題では、SVMとニューラルネットワークを比べた場合、
SVMの方が良い結果が得られる傾向があります。
ニューラルネットワークはパラメータが多いためだと考えています。


まとめ

いかがでしたか?

今回は、前回に引き続きニューラルネットワークを使って分類問題を解くプログラムの実装方法を記事にしました。

今回も簡単に行える実装ですので、お時間あれば是非一度やってみてくださいね。

データさえ増やせば、それなりの研究もできます。
これを機に機械学習に興味を持ってくれる方が増えるとうれしいです。

それでは!

スポンサーリンク