hellkite 日記と雑記とメモ。

Shiki Kazamaの駄文と音楽と、時々技術な感じ

Chainerで画像カテゴリ分類(CIFAR-10を使った学習)

ミスがあったので更新しました。 2016/10/25

すでにやりつくされている感がありますが、意外と学習から任意画像での評価までやっているサイトがなかったのでまとめておきます。学習させて用意されているテストデータを食べさせて何%の精度だったかより、ソリューション開発側としては、アプリに組み込んで動くかどうかの方が重要なので。

CIFAR-10データの準備と学習

というわけで、まずは、ChainerでCIFAR-10を学習してみます。基本は以下のサイトを参考にしました。
ai-programming.hatenablog.jp

ほぼそのままですが、少し修正して試してみます。

データの準備

まず、CIFAR-10を読み込みます。こちらは上のサイトと同じコードになりますが、読み込んだデータを画像として取り出してみました。画像として取り出すための処理は以下を参考にしました。
qiita.com

コードは以下の通りです。

import sklearn.datasets
import matplotlib
import matplotlib.pyplot as plt

import sys
import pickle
import os.path

def unpickle(file):
    fp = open(file, 'rb')
    data = pickle.load(fp, encoding='latin-1')
    fp.close()
    
    return data

X_train = None
y_train = []

for i in range(1,6):
    data_dic = unpickle(os.getcwd()+"\\data\\cifar-10\\data_batch_{0}".format(i))
    if i == 1:
        X_train = data_dic['data']
    else:
        X_train = np.vstack((X_train, data_dic['data']))
    y_train += data_dic['labels']
    
test_data_dic = unpickle(os.getcwd()+"\\data\\cifar-10\\test_batch")

# 評価用データ
X_test = test_data_dic['data']
X_test = X_test.reshape(len(X_test), 3, 32, 32)
y_test = np.array(test_data_dic['labels'])
X_train = X_train.reshape(len(X_train), 3, 32, 32)
y_train = np.array(y_train)

# ラベル名
batch_meta = unpickle(os.getcwd()+"\\data\\cifar-10\\batches.meta")
label_names = batch_meta['label_names']
label_names

# indexに入っている画像を描画(3×32×32のデータを32×32×3に変更)
index = 220
img = np.rollaxis(test_data_dic['data'][index].reshape((3,32,32)), 0, 3)
plt.title(label_names[y_test[index]])
plt.imshow(img, interpolation='none')

画像の出力結果はこんな感じ。

f:id:deis:20160923123641p:plain

学習

モデルと学習のコードは以下の通りです。ちょっとだけ修正しています。
話が逸れますがtqdmってライブラリがあるんですね。進捗が分かるようになっていたので感動しました。

import chainer
from chainer import cuda, Function, FunctionSet,gradient_check, Variable, optimizers, serializers, utils
from chainer import Link, Chain, ChainList
import chainer.functions as F
import chainer.links as L
import time

plt.style.use('ggplot')

# ニューラルネットワークの順伝播を記述
class Model(Chain):
    def __init__(self):
        super(Model, self).__init__(
            conv1=F.Convolution2D(3, 32, 3, pad=1),
            conv2=F.Convolution2D(32, 32, 3, pad=1),
            conv3=F.Convolution2D(32, 32, 3, pad=1),
            conv4=F.Convolution2D(32, 32, 3, pad=1),
            conv5=F.Convolution2D(32, 32, 3, pad=1),
            conv6=F.Convolution2D(32, 32, 3, pad=1),
            l1=F.Linear(512, 512),
            l2=F.Linear(512, 10)
        )
    def __call__(self, x):
        #x = chainer.Variable(x_data)
        h1 = F.relu(self.conv1(x))
        h2 = F.max_pooling_2d(F.relu(self.conv2(h1)), 2)
        h3 = F.relu(self.conv3(h2))
        h4 = F.max_pooling_2d(F.relu(self.conv4(h3)), 2)
        h5 = F.relu(self.conv5(h4))
        h6 = F.max_pooling_2d(F.relu(self.conv6(h5)), 2)
        h7 = F.dropout(F.relu(self.l1(h6)))
        y = self.l2(h7)
        return y

# Classifier Chain
model = L.Classifier(Model())

# Optimizer
optimizer = optimizers.Adam()
optimizer.setup(model)

## 学習
from tqdm import tqdm

train_loss = []
train_acc = []
test_loss = []
test_acc = []

batchsize = 100

N = len(X_train)
N_test = len(X_test)

# 学習ループ
n_epoch = 30
for epoch in range(1, n_epoch+1):
    print("eopch", epoch)
    
    # training
    perm = np.random.permutation(N)
    sum_accuracy = 0
    sum_loss = 0
    # 0~Nまでのデータをバッチサイズごとに使って学習
    for i in tqdm(range(0, N, batchsize)):
        x = Variable(X_train[perm[i:i + batchsize]])
        t = Variable(y_train[perm[i:i + batchsize]])
        
        optimizer.update(model, x, t)
        
        sum_loss += float(model.loss.data) * len(t.data)
        sum_accuracy += float(model.accuracy.data) * len(t.data)

        train_loss.append(float(model.loss.data) * len(t.data))
        train_acc.append(float(model.accuracy.data) * len(t.data))
        
    # 訓練データの誤差と正解精度を表示
    print("train mean loss={0}, accuracy={1}".format(sum_loss / N, sum_accuracy / N))
    
    # 評価
    # テストデータの誤差と正解精度を算出し、汎化性能を確認
    sum_accuracy = 0
    sum_loss = 0
    for i in tqdm(range(0, N_test, batchsize)):
        x_batch = Variable(X_test[i:i+batchsize])
        y_batch = Variable(y_test[i:i+batchsize])

        loss = model(x, t)
        
        sum_loss += float(loss.data) * len(t.data)
        sum_accuracy += float(model.accuracy.data) * len(t.data)

        train_loss.append(float(loss.data) * len(t.data))
        train_acc.append(float(model.accuracy.data) * len(t.data))

    # テストデータでの誤差と正解精度を表示
    print("test mean loss={0}, accuracy={1}".format(sum_loss / N_test, sum_accuracy / N_test))

ちなみに、Trainerという機能を使った場合は、以下のコードになります。開発元のPFNの方が、Trainerを使ってください、とカンファレンスで言っていたので、できるだけこちらを利用した方がいいはず。ただ、残念ながら、私の環境では進捗がうまく表示されませんでしたが・・・コードのせいなのかな・・・。

from chainer import report, training, datasets, iterators
from chainer.training import extensions
from chainer.datasets import tuple_dataset

# データセットの準備
train = tuple_dataset.TupleDataset(X_train, y_train)
test = tuple_dataset.TupleDataset(X_test, y_test)

train_iter = iterators.SerialIterator(train, batch_size=100)
test_iter = iterators.SerialIterator(test, batch_size=100, repeat=False, shuffle=False)

updater = training.StandardUpdater(train_iter, optimizer)
trainer = training.Trainer(updater, (30, 'epoch'), out='result')

# trainerを設定
trainer.extend(extensions.Evaluator(test_iter, model))
trainer.extend(extensions.LogReport())
trainer.extend(extensions.PrintReport(['epoch', 'main/accuracy', 'validation/main/accuracy']))
trainer.extend(extensions.ProgressBar())

trainer.run()

学習時のエポック数は30にしました。学習結果は精度が90%程度でした。元サイトの精度グラフの30あたりを確認すると90%となっているので、妥当な値になっているようです。
ちなみに学習時間はCPU利用で6時間程度。このレベルならまだCPUでがんばれます。。

学習ファイルの保存(2016/10/25更新)

以下のコードで学習したモデルを保存します。次からは、この学習データを使って評価することができます。

# 学習データの保存

# 古いやり方らしく、うまく動作しない
# model.to_cpu()
# with open('model.pkl', 'wb') as o:
#     pickle.dump(model, o)

serializers.save_npz('model_cifar10.model', model)
serializers.save_npz('model_cifar10.state', optimizer)

その他

ちなみに学習の最中にMemoryErrorが発生することが何度かありました。そのため、Jupyterを利用して検証しながらやっていましたが、最終的にはコマンドプロンプトで実行しました。それでも発生することがありましたが、エラーの頻度は減ったようです。原因はよくわかりませんが、PCを再起動するとでなくなったりします。

次は、学習ファイルを読み込んで任意の画像ファイルが認識できるか確認してみます。
↓更新しました。
hellkite.hatenablog.com

機械学習のトレンドはマルチモーダル、応用で生活が変わる

今年もPrometech Simulation Conferenceに行ってきました。
www.prometech.co.jp
シミュレーション技術がメインのカンファレンスですが、Deep Learningのセッションも多く大学の研究内容を話してくれるので、情報を得るには有益でした。

最近のDeepLearningの1つのトレンドは、画像認識の分野において、CNNの多層化が顕著だということ。1つ1つの層のフィルタを小さめに、階層を深くすることで、より少ないパラメータでより複雑な非線形性を持たせることができるらしい。
一般画像認識の分野は、CNNがかなりいい成績を出しているので、今後大きな進展はないかも?正答率97%くらいらしいですし。

一方で、画像と他のデータを組み合わせた研究が盛ん。こういういくつかの異なる情報を使うことをマルチモーダルと呼ぶらしいです。今回は文章からの画像生成や画像の説明文を生成したりといった事例やロボット制御の話題などがでました。それにしても、人工知能が画像を想起できる能力を得たことはスゴイことです。
分かり易くいうと「赤い魚」といったときに、こんな形かな?と人が連想する処理と全く同じことを今の人工知能ではできてしまうということ。
これを応用すると、こんな動作をすると、次にこんな画像が得られるはず、つまり、次に起こることを連想しながら行動したり出力を操作したりすることができるようになる。

まぁ、実際にこういったものを実現するためには、色々な論文を読んだりしないといけないんでしょうけど、そういったことができる未来がすぐそこにあると感じられたのは、よいきっかけだったかと思います。逆にちょっと焦りますね。そんな世界で技術者としてやっていけるのかと。。。
人との一番確実なコミュニケーションは自然言語。この分野も面白そうだなぁ。強化学習もやってみたいけど。。


まぁ、とりあえず、いまだに動かないCIFAR-10をなんとかします^^;
↓動きました。
hellkite.hatenablog.com
hellkite.hatenablog.com

Chainerが面白い。手書き文字認識MNISTをやってみた。

触り始めた機械学習ライブラリ、Chainer。
まず、ここでNNの用語、構成要素を整理した後で、サンプルをやってみました。
パラメータやネットワークの記述の仕方に関してはなんとなくつかめた気がします。
qiita.com


やっぱり機械学習に触れてみたら画像を扱ってみたい。というわけで、画像を使ったサンプルとしては有名な、MNISTをやってみました。

f:id:deis:20160908174204p:plain

おおーって感じ。精度は98%程度ですが、パッと見、間違いが見つかりません。というより300文字くらいは見ましたが見つけられませんでした^^;

Chainerはバージョンによってネットワーク記述のやり方が変わったり*1、学習部分を担当するクラスが増えたり*2と結構バージョンによって書き方が変わるようです。ネットで探していると記述の違うサンプルがいくつか出てきて混乱しました。

Chainerのサンプルはアチコチに転がっているので、特に書きませんが、以下のサイトを参考にしました。

qiita.com

次のステップとしては、CIFAR-10という10種類のカテゴリ別に画像を分類するデータセットを試したいと思います。
というより試しているのですが、うまく動いていないのでデバッグ中です・・・。これができたら少し応用的なものを考えたいと思ってます。

*1:FunctionSetのcollect_parametersを使う書き方は古いらしく警告が出る

*2:Trainerというクラスが便利みたい。

Chainerを試してみた

急に時間が空いたので前々から興味のあった機械学習ライブラリ、Chainerをいじってみました。といっても、機械学習に関してはド素人なので、以下のページをやってみただけですが。

qiita.com


機械学習のライブラリは色々と設定が大変という印象があったので時間がないとできないと思っていましたが、

pip install chainer

の一行だけで使えるようになっているのが素敵。
昔とはえらい違いですね。。
なお、numpy scipy scikit-learn等が必要です。これらをWindowsにインストールしておく必要があります。今回はすでにやっていたのであっという間です。
hellkite.hatenablog.com


サイトの通りにやったら、ちゃんとこんな感じの結果が得られました。
f:id:deis:20160830145839p:plain
学習のところで固まってしまったので、不安でしたが30秒程度で戻ってきました。このくらいでも固まるのか・・・。ちゃんとやるならやっぱりGPUが欲しくなるかも。

色々と試したいこと*1はありますが、まずは今回やったことを調べて消化してから次のステップにいかないと分けわからない状態になりそうです。。

*1:ライントレースロボットとか倒立振子とか・・・

オーディオインターフェイスにノイズが入った時の対策

症状

オーディオインターフェイスを使用中にこんな症状が出て困ってました。ちなみに

  • 音源を再生するとノイズが入る
  • 録音するとノイズが入る
  • PCを通さない場合は問題ない

インターフェイスを繋いでしばらくは平気だけど、時間が経つとこれらの症状が出ます。せっかく買ったのにもう壊れた?

f:id:deis:20140922004505j:plain

隙間時間にDTMしようとしてこんな症状が出るとやる気が損なわれますね…
でも、ちょっと調べてみたら、簡単な解決方法が見つかりました。

それは、PCを再起動する!

まぁ、うちの場合はMacなんですけどね。ずっと電源入れっぱなし、使わないときはスリープモードという使い方をしていました。オーディオインターフェイスDTMで使うときだけ付けたり外したりしていたのですが、これが良くなかったみたい。
オーディオインターフェイスを使うときは再起動して繋ぎ直してあげた方が良いみたいです。PCそのものの動作も安定しますしね。

ちなみにNative Instrumentsのサイトに対策が色々載っていて参考になりました。ケーブルなどに気が入っていて、PCの負荷を確認するのは盲点でした。例えば、Macの場合、TimeMachineが動作するとノイズが入ったりします。

オーディオ処理のためのWindows最適化 | ナレッジベース | サポート

ナレッジベースには他にも色々なケースの情報があるので覗いてみる価値はあります。
あまり理解できませんでしたが、ケーブルやグランドの引き回し方なども情報がありました。

トラックボールを買って、ディスプレイを買った

最近、何か買ったか何か壊れたかといったエントリばかり書いている気がします。。

さて、今月先月トラックボールとディスプレイを購入しました。
ディスプレイは、UnrealEngineを使って作業しているとどうしても画面1枚だと効率が悪いので購入を決断。買ったのはこれ。

初めは、50,000円くらいで解像度が2560×1600なディスプレイ*1にしようと考えていたけど、結局安価なFullHDにしました。画面が26インチを超えてくると疲れるのでは?というアドバイスをもらったので。。

もう少し安くて15,000円以下でも同じような大きさで買えたけど縦置きができるところが気に入りました。今後、UnrealEngine+VR用にPCを買ったとして、机に最大3枚縦置きできるサイズです!
まぁ、そこまでするかはおいといて設置に自由度があるのは正義。

もうひとつ買ったのはトラックボール
最近トラックボールの選択肢が増えてうれしい限りです。購入するのはマイクロソフトトラックボールをリリースしていたとき以来。少し大きめのトラックボールがちょうどいいですね。



実際に店頭で確認したところ、手のサイズからしてこれしかありませんでしたが。
会社で使っています。マウスでも困っていなかったのですが、肩こりがひどく作業環境を改善したいという気持ちがありました。実際使っているとあまり感じませんが、自宅でマウスを使うとしょっちゅうマウスを持ち上げる動作をしていることに気づきました。
それがなくなっただけでも負担は減ってくれているはず。

実際、ディスプレイを買ってこんな感じで横に広くなったので自宅もトラックボールにしたいところ・・・。

f:id:deis:20160731224847j:plain

トラックボールにしたら、次に気になるのはキーボード。体にやさしいものにしたいですね。肩幅より狭くなる通常のキーボードは猫背になりやすいそうです。肩幅で使えるセパレートタイプのキーボードがいいのですが、財布には厳しい・・・。

探せば意外とあるみたいですけどね。

*1:使用しているMacの外部出力最大解像度

Unreal Engineを動かし始めました

これまでゲームエンジンはUnityを使っていましたが、ライセンス形態が変わることをきっかけに、UE4を触り始めました。ライセンス以外にもUE4はムービー作成機能が充実しているので、自分の使い方だとUnityよりUnrealEngineの方があっているかなぁと・・・。インストール先のMacは推奨動作環境には届いていませんが、外部GPUを積んでるのでなんとかなるだろうとインストールして動かしてみました。

f:id:deis:20160708182042p:plain

エディタが重い!
FPSを確認してみたら13FPS・・・。スクリーンショットではEffect関係のサンプルを開いていますが、スタータコンテンツでもガクガク。これじゃ安めのノートパソコンじゃいじることすらできないのでは?
そう思い、手元にあるWindowsのモバイルPCにダメ元で入れてみたら・・・意外や意外、スタータコンテンツがエディタ上でそれなりに動く・・・。

ちなみに、入れたWindowsマシンのスペック。

調べてみたらMacだとWindowsよりも重くなるらしいです。DirectXOpenGLの違いみたい。Unreal Engine側もその辺は理解しているらしく、新しめバージョンではMetalに対応しているとのこと。

MetalってMac OSだとEl Capitanで導入されていますね。うちのMacはまだYosemiteで頑張っていたので、これを機会にバージョンアップすることにします*1。さすがに今の状態のままで触る気にはならないし、、それに、モバイルPCに快適さで劣るのは納得がいかないですしね!

El Captanにしてみました。
f:id:deis:20160708182043p:plain

あんまり変わらなかったです・・・。残念・・・。てか、ほとんどのMacで満足に動作しないのでは?
CG用途のためにはデスクトップのWindowsPCを用意した方がよさそうですね。。

*1:持っているCubaseが未対応だったのでアップデートを控えていました。