人工知能に関する断創録

このブログでは人工知能のさまざまな分野について調査したことをまとめています(更新停止: 2019年12月31日)

2017年の目標

明けましておめでとうございます。

今年も目標を立てた。何が起こるか先が読めないご時世なので予定通りには行かないと思うけど(^^;;

Deep Learningの深耕

今年も一昨年(2014/1/4)、昨年(2015/1/11)に引き続いてDeep Learningに関連した技術を深耕していきたい。最も興味があるのは生成系強化学習で昨年も目標にあげてたんだけど手付かずだったので今年こそちゃんと取り上げたい。

Deep Learning (Adaptive Computation and Machine Learning series)

Deep Learning (Adaptive Computation and Machine Learning series)

このブログでは主にKeras関連の情報をちまちまとまとめていきたいなと思ってます。

人工知能関係のWeb APIの調査

人工知能に関連したWeb APIを調査していきたい。海外だと

日本だと

あたりかな。この手のサービスはいつ止まるかわからないのが難点だけど(笑)最近はテキストだけでなく、画像や音声もWeb API経由で扱えるようになってきたので、より高度なWeb開発技術もちゃんとおさえていきたい。

参考

その他

  • 自動車免許を取る
  • Web技術の基礎が学べるCode Schoolを卒業する
  • Electronを勉強する
  • データサイエンスプラットフォームのKaggleに挑戦する
  • オンライン英会話(?)未だに話すのは苦手なので・・・

Cross-platform Desktop Applications: With Node, Electron, and Nw.js

Cross-platform Desktop Applications: With Node, Electron, and Nw.js

2016年の振り返り

年末なので年始に立てた目標(2016/1/1)の振り返りでもしようかな。

  • Deep Learning Tutorialの読破とTheanoでの実装を続ける
  • パターン生成・コンテンツ生成(2015/12/30)に関する従来研究のサーベイ
  • × 深層強化学習(Deep Reinforcement Learning)の理解
  • × 1週間に1本は論文を熟読する
  • TensorFlowをさわってみる
  • C­omputer vision: models, learning and inference(2015/12/31)の読破
  • × 情報理論の勉強
  • 多様体学習(manifold learning)の勉強
  • × Sparse Codingの勉強
  • × 上記に関係する数学の習得
  • Python3への移行
  • MOT・イノベーション・マーケティング関係の本を月1冊以上読む
  • × 英語ライティングを鍛える

あれ(^^;; 今年はダメダメ。ちゃんと意識してやってたのはPython3への切り替えとビジネス書読むのくらい?目標未達が多いのは4月から本業がちょっと変わって必要な勉強を優先していたためなのだ。まあすっごく言い訳がましいんだけどさ(^^;;

今年やったことをちょっとまとめておこう。

MEANスタック

JavaScriptとMEAN(MongoDBExpressAngularJSNode.js)とBootstrapの勉強をしていた。Webアプリケーション開発はあまり経験がなかったんだけどやってみるとけっこう楽しくてのめり込んでいた。あとAtomエディタでも使われているElectronという技術も勉強していた。JavaScriptでローカルアプリ作れるなんてすごい時代だな!

ここ二ヶ月はCode Schoolを受講していた。月額29$で高いんだけど動画チュートリアルがよくできていてやっていて楽しい。お金を節約するために早く制覇したい。

今年は人工知能関係のWeb API(機械翻訳、物体認識、感情認識、音声認識、音声合成、対話など)が国内でも海外でもたくさん公開された年だった。来年はこういうAPIの使い方も紹介できたらいいな。アイデア次第で面白いことがいろいろできそう!

Keras

今年はTheanoではなく、Keras(2016/3/28)というライブラリでDeep Learningの勉強をちまちましていた。keras_examplesというGithubのレポジトリを作ってこの中でいろいろ実験している。TODOはIssuesにまとめている。ブログにまとめるのが追いつかないけど来年もちまちま続けていきたい。

EmacsからAtomへ

EmacsからAtomに完全に切り替えた。AWSなどで遠隔ログインする場合もAtomのRemoteFTPというパッケージを使うようにしている。最初はPyCharmを課金して使ってたんだけどPythonだけでなくC言語やJavaScriptも頻繁に書くようになったので最終的にAtomに決めた。今のところまったく不満がない。

その他

  • 沖縄の宮古島を旅行してきた。がっつりした旅行は8年ぶり(^^;; くらいかも。台風がぎりぎりそれたおかげで青い海と満点の星空が見られた。少し疲れたけどとても楽しかったな。

  • 10月から自動車教習所へ通い始めた。学生の頃はバイト代をパソコンと本につぎ込んでいたのでお金がなくて、就職したら時間がなくて今さら(^^;; 土日だけで通っているけどけっこう順調で仮免許まで取れた。こんなに運転が楽しいんだと完全無人運転は流行らないかもね(笑)

  • HuluでGame of Thronesっていう歴史ファンタジー系の海外ドラマにすごくはまっていた。ドラマがすごく面白かったので原作(七王国の玉座)もKindleで買って読み始めた。

  • SteamはWitcher 3、Fallout 4、Dark Souls 3、Hearts of Iron 4、Civilization 6あたりをプレイしていた。時間がないとブログをサボっている割には有名どころは一通り抑えているという(笑)

あれ?こう書くとけっこう楽しいことばっかりだったみたい。ただ実感としては心が折れそうなことばかり続いていた。来年は本当に折れそう(^^;; だけどなんとか前向きに生きていきたい。まあ折れそうだけどなかなか折れないものだなと思った一年だった。

Kerasによるデータ拡張

今回は、画像認識の精度向上に有効な データ拡張(Data Augmentation) を実験してみた。データ拡張は、訓練データの画像に対して移動、回転、拡大・縮小など人工的な操作を加えることでデータ数を水増しするテクニック。画像の移動、回転、拡大・縮小に対してロバストになるため認識精度が向上するようだ。

音声認識でも訓練音声に人工的なノイズを上乗せしてデータを拡張するテクニックがあるらしいのでそれの画像版みたいなものだろう。

ソースコード

ImageDataGenerator

Kerasには画像データの拡張を簡単に行うImageDataGeneratorというクラスが用意されている。今回は、この使い方をまとめておきたい。ドキュメントを調べるとこのクラスにはパラメータが大量にあって目が回る。一気に理解するのは難しいので一つずつ検証しよう。

keras.preprocessing.image.ImageDataGenerator(featurewise_center=False,
    samplewise_center=False,
    featurewise_std_normalization=False,
    samplewise_std_normalization=False,
    zca_whitening=False,
    rotation_range=0.,
    width_shift_range=0.,
    height_shift_range=0.,
    shear_range=0.,
    zoom_range=0.,
    channel_shift_range=0.,
    fill_mode='nearest',
    cval=0.,
    horizontal_flip=False,
    vertical_flip=False,
    rescale=None,
    dim_ordering=K.image_dim_ordering())

まずは、適当な画像を1枚だけ入力し、各パラメータを1つだけ指定してどのような画像が生成されるか確認してみた。

if __name__ == '__main__':
    # 画像をロード(PIL形式画像)
    img = load_img(IMAGE_FILE)

    # numpy arrayに変換(row, col, channel)
    x = img_to_array(img)
    # print(x.shape)

    # 4次元テンソルに変換(sample, row, col, channel)
    x = np.expand_dims(x, axis=0)
    # print(x.shape)

    # パラメータを一つだけ指定して残りはデフォルト
    datagen = ImageDataGenerator(rotation_range=90)

    # 生成した画像をファイルに保存
    draw_images(datagen, x, "result_rotation.jpg")

draw_images()は、ジェネレータオブジェクト、画像の4次元テンソル、出力ファイル名を指定すると生成した画像をファイルに描画する自作関数。

def draw_images(datagen, x, result_images):
    # 出力先ディレクトリを作成
    temp_dir = "temp"
    os.mkdir(temp_dir)

    # generatorから9個の画像を生成
    # xは1サンプルのみなのでbatch_sizeは1で固定
    g = datagen.flow(x, batch_size=1, save_to_dir=temp_dir, save_prefix='img', save_format='jpg')
    for i in range(9):
        batch = g.next()

    # 生成した画像を3x3で描画
    images = glob.glob(os.path.join(temp_dir, "*.jpg"))
    fig = plt.figure()
    gs = gridspec.GridSpec(3, 3)
    gs.update(wspace=0.1, hspace=0.1)
    for i in range(9):
        img = load_img(images[i])
        plt.subplot(gs[i])
        plt.imshow(img, aspect='auto')
        plt.axis("off")
    plt.savefig(result_images)

    # 出力先ディレクトリを削除
    shutil.rmtree(temp_dir)

next()を呼び出すたびにbatch_size個の画像が生成される。今回は、入力画像が1枚の画像なのでbatch_sizeは1にしている。生成した9枚の画像は3x3のグリッドに配置し、ファイルに保存する。

早速やってみよう。入力画像はなんでもいいけど下のを入れた。ぞうさんかわいいね。

f:id:aidiary:20161212214844j:plain:w300

rotation_range

画像を指定角度の範囲でランダムに回転する。目が回るゾウ。

datagen = ImageDataGenerator(rotation_range=90)
draw_images(datagen, x, "result_rotation.jpg")

f:id:aidiary:20161212215418j:plain:w500

width_shift_range

画像を水平方向にランダムに移動する。

datagen = ImageDataGenerator(width_shift_range=0.2)
draw_images(datagen, x, "result_width_shift.jpg")

f:id:aidiary:20161212215510j:plain:w500

height_shift_range

画像垂直方向にランダムに移動する。

datagen = ImageDataGenerator(height_shift_range=0.2)
draw_images(datagen, x, "result_height_shift.jpg")

f:id:aidiary:20161212215528j:plain:w500

shear_range

シアー変換をかける。Wikipediaをざっと見たが斜めに引き延ばすような画像変換みたい。

datagen = ImageDataGenerator(shear_range=0.78)  # pi/4
draw_images(datagen, x, "result_shear.jpg")

f:id:aidiary:20161212215555j:plain:w500

zoom_range

画像をランダムにズームする。

datagen = ImageDataGenerator(zoom_range=0.5)
draw_images(datagen, x, "result_zoom.jpg")

f:id:aidiary:20161212215945j:plain:w500

channel_shift_range

画像のチャンネルをランダムに移動する。RGBの値をランダムに加えるのかな?要調査。

datagen = ImageDataGenerator(channel_shift_range=100)
draw_images(datagen, x, "result_channel_shift.jpg")

f:id:aidiary:20161212220056j:plain:w500

horizontal_flip

画像を水平方向にランダムに反転する。

datagen = ImageDataGenerator(horizontal_flip=True)
draw_images(datagen, x, "result_horizontal_flip.jpg")

f:id:aidiary:20161212220144j:plain:w500

vertical_flip

画像を垂直方向にランダムに反転する。

datagen = ImageDataGenerator(vertical_flip=True)
draw_images(datagen, x, "result_vertical_flip.jpg")

f:id:aidiary:20161212220200j:plain:w500

samplewise_center

サンプル平均を0にする。平均の正規化なんだろうけど平均0にしてimshow()しても大丈夫なのかな?imshow()でとりあえず画像出たけどあとで仕様を確認。

datagen = ImageDataGenerator(samplewise_center=True)
draw_images(datagen, x, "result_samplewise_center.jpg")

f:id:aidiary:20161212220405j:plain:w500

samplewise_std_normalization

サンプルを標準偏差で割る。画像はなんか真っ黒になっちゃった。上のと組み合わせると平均0、標準偏差1になる正規化をかけられるようだ。これもアルゴリズムを要確認。

datagen = ImageDataGenerator(samplewise_std_normalization=True)
draw_images(datagen, x, "result_samplewise_std_normalization.jpg")

f:id:aidiary:20161212220649j:plain:w500

ZCA白色化(ZCA whitening)

ZCA白色化の詳細はまだよくわかっていない。この変換は一枚の画像に対して適用するのではなく、画像集合に対して適用するようだ。なので入力は一枚の画像xではなく、X_trainなど画像集合を渡す必要がある。また、ZCA白色化を使うときはdatagen.fit()を使ってあらかじめ統計量を計算しておく必要があるので注意。試しにCIFAR-10の訓練データ画像に対してZCA白色化を適用し、適用後の画像がどうなるか調べた。

img_rows, img_cols, img_channels = 32, 32, 3
batch_size = 16
nb_classes = 10

# CIFAR-10データをロード
(X_train, y_train), (X_test, y_test) = cifar10.load_data()

# 画素値を0-1に変換
X_train = X_train.astype('float32')
X_train /= 255.0

draw(X_train[0:batch_size], 'zca_whitening_before.png')

# データ拡張
datagen = ImageDataGenerator(zca_whitening=True)

datagen.fit(X_train)
g = datagen.flow(X_train, y_train, batch_size, shuffle=False)
X_batch, y_batch = g.next()
print(X_batch.shape)
print(y_batch.shape)

draw(X_batch, 'zca_whitening_after.png')

適用前: f:id:aidiary:20161212220750p:plain:w500

適用後: f:id:aidiary:20161212220801p:plain:w500

訓練データに加えてこれらのデータ拡張で生成した画像を畳み込みニューラルネットに食わせると精度向上が期待できるようだ。長くなったので畳み込みニューラルネットワークとデータ拡張を組み合わせた実験は次回にまわそう。

参考