ニートの言葉

元ニートがやってみたこと・その過程で学んだこと・考えたこと・技術メモあたりを主に書いています。情報革命が起きた後に訪れるであろう「一億総ニート時代」の生き方を考え中です。

【ディープラーニング】少ないデータで効率よく学習させる方法:準備編

こんにちは。あんどう(@t_andou)です。

ディープラーニングによる学習精度を上げるためには大量のデータが必要と言われていますが、学習済みのモデルを流用することで少ないデータから効率よく・高精度な学習をさせることが可能な場合があります。

それが Fine Tuning と言われるものです。

具体的なやり方については↓こちらの記事がとてもわかりやすかったので、著者のFrancois Cholletさんより許可を頂き、翻訳させていただきます。

Building powerful image classification models using very little data

注意:意訳しています。間違っているところも多々あると思いますので、ご指摘いただけると幸いです。 

 

本文が長いので3回程度に分けて投稿する予定です。

  1. データの準備・データの水増し
  2. 1から小さな畳み込みニューラルネットワークを作ってみる
  3. 学習済みネットワークを流用する(Finetuning)

少量のデータから高性能な画像のクラス分類器を作る

このチュートリアルでは高性能な画像の分類器を作る上で、単純な割に効果的な方法をお教えします。この方法を使えば、1クラスあたり数百枚というとても少ない画像数でも学習することができるようになります。

このチュートリアルは下記のように進めていきます

  1. 小さな畳み込みニューラルネットワークを0から構築し、学習させます。これが基礎になります。
  2. 学習済みのネットワークのボトルネック特徴量*1を利用します
  3. 学習済みのネットワークの一番上のレイヤーをファインチューニング(微調整)していきます

また、このチュートリアルを進めることでKerasの次のような機能を学んでいきます。

  1. fit_generator:Pythonのデータ生成機能を利用したKerasの学習用モデル
  2. ImageDataGenerator:学習用データの水増しをするためのもの
  3. レイヤーの固定やファインチューニング…などなど

準備:2000枚の画像(1カテゴリにつき1000枚)

まずは次の準備をしましょう。

  • Keras, Scipy, PILがインストールされたマシン。また、今回は少量の画像しか使わないので必ずしも必要というわけではありませんが、NVIDIA のGPU(とcuDNN)が使えると更に良いです。
    このチュートリアルで紹介する機能はver1.0.4のKerasで導入されたものになりますので、開始前にKerasのアップデートをしておいてください。
  • 学習(=train)用ディレクトリと検証(=validation)用ディレクトリを作成。更にそれぞれのディレクトリ内に各クラス名(ここではdogsとcats)のディレクトリを作り、pngかjpg形式の画像を入れておいてください。(画像の入手先については後述します。)
data/
    train/
        dogs/
            dog001.jpg
            dog002.jpg
            ...
        cats/
            cat001.jpg
            cat002.jpg
            ...
    validation/
        dogs/
            dog001.jpg
            dog002.jpg
            ...
        cats/
            cat001.jpg
            cat002.jpg
            ...

分類したいクラスの学習用画像を数百枚〜数千枚入手するために、Flickr APIを利用するという方法があります。このAPIを利用すると使いやすいライセンスで画像をダウンロードすることができます。

今回進めるチュートリアルでは、Kaggleから入手できる「犬」と「猫」の2クラスの画像データセットを使います。オリジナルのデータセットには犬・猫それぞれ12,500枚の画像が入っていますが、今回は学習用に1000枚ずつ、モデルの検証用に400枚ずつしか使いません。

1クラスにつき1000枚というのは「クラス分類」という複雑な問題を行うにはとても少ない数です。ですので、今回のチュートリアルは挑戦的で、また現実の問題に近くもあります。というのも、実際問題多くの場合ではほんの少しのデータだったとしても、非常に高価であったり、もしくは集めることが不可能に近かったりします。(例えば、医療関係の画像など)
ですので、ごく少量のデータを最大限活用できるようになることは有能なデータサイエンティストの必須スキルとなるでしょう。

この問題はどのくらい難しいのでしょうか?(この段落の意味がよくわかりませんでした。原文はこちら->*2

犬・猫分類のコンペティション(合計25,000枚の画像が準備されていた)が始まった時、それはほんの2年くらい前のことですが、次のようなことが言われていました。

"何年も前の非公式な調査では、コンピュータービジョンのエキスパートは「最先端の研究を除くと、クラス分類において60%を超える精度を出すことは難しい」と話していました。参考までに、60%精度の分類器は12- image HIP の確率を1/4096から1/459まで改善しました。現在の文献では機械による分類は80%以上の精度が可能だと言われています。"

コンペティションの結果として、トップの成績は最近のディープラーニング技術を使うことによって98%以上の精度を出すことができました。我々のケースでは使うデータセットを8%に抑えるので、より難しい問題になるはずです。 

データの少なさとディープラーニングの関係

私がよく聞く言葉として、「ディープラーニングは大量のデータがある時にだけ使える」というものがあります。これは間違ってはいませんが、少し誤解を招く言い方です。
確かに、ディープラーニングでは一般的に大量のが使える時にだけデータから特徴を抽出できます。特に画像のようにとても高次元なものを入力とする問題の場合はそうです。

しかし畳み込みニューラルネットワーク(= Convolutional neural networks :略 CNN)というディープラーニングの中心になっているアルゴリズムは少量のデータからでも学習できるようにデザインされています。

少量のデータセットを使って0から構築されたCNNは、特徴量の選択などのカスタマイズをしなくても良い結果を出すでしょう。CNNはシンプルで良いものです。今回の問題には効果的なツールでしょう。

しかしさらに重要なことは、ディープラーニングのモデルは再利用可能だということです。このようにも言えます、大量のデータで学習された画像分類や音声認識のモデルは、全く別の問題にも適用することが可能です。コンピュータービジョンの例で具体的を挙げると、学習済みのモデル(一般的にはImageNetのデータセットを利用して学習されたもの)が公開されダウンロードして使えるようになっていますが、それを基礎として利用することで、ごく少量の画像からでも強力な画像分類器を作ることができます。 

データの前処理と水増し

少ない学習用データを最大限利用するために、画像をランダムに変形・加工することでデータ数を水増しします。そうすることで、全く同じ画像を二回見ることは無くなります。これは過学習を防ぎ、より一般的なモデルになる手助けとなります。

Kerasではkeras.preprocessing.image.ImageDataGeneratorクラスによって提供されています。これを使えば下記のようなことが可能です。

  • 学習途中に画像の変形や正規化を調整できます。
  • ここの訳がわかりませんでした。(instantiate generators of augmented image batches (and their labels) via .flow(data, labels) or .flow_from_directory(directory). These generators can then be used with the Keras model methods that accept data generators as inputs, fit_generator, evaluate_generator and predict_generator.)

早速、例を見てみましょう。

from keras.preprocessing.image import ImageDataGenerator

datagen = ImageDataGenerator(
        rotation_range=40,
        width_shift_range=0.2,
        height_shift_range=0.2,
        rescale=1./255,
        shear_range=0.2,
        zoom_range=0.2,
        horizontal_flip=True,
        fill_mode='nearest')

これらは使えるオプションのうちのほんの一部です。詳しくはドキュメントを参照ください。(これらのオプションに関しては日本語のドキュメントがあるので、こちらをご覧ください。)

  • rotation_range is a value in degrees (0-180), a range within which to randomly rotate pictures
  • width_shift and height_shift are ranges (as a fraction of total width or height) within which to randomly translate pictures vertically or horizontally
  • rescale is a value by which we will multiply the data before any other processing. Our original images consist in RGB coefficients in the 0-255, but such values would be too high for our models to process (given a typical learning rate), so we target values between 0 and 1 instead by scaling with a 1/255. factor.
  • shear_range is for randomly applying shearing transformations
  • zoom_range is for randomly zooming inside pictures
  • horizontal_flip is for randomly flipping half of the images horizontally --relevant when there are no assumptions of horizontal assymetry (e.g. real-world pictures).
  • fill_mode is the strategy used for filling in newly created pixels, which can appear after a rotation or a width/height shift.

日本語ドキュメント:画像の前処理 - Keras Documentation

 

さて、それでは実際にこのツールを使っていくつかの画像生成をして、一時フォルダへの保存してみましょう。そうすれば画像の水増しというものが何をしているかを理解できるかと思います。(ここでは画像の可視性を維持するためにリサイズは無効にしています)

from keras.preprocessing.image import ImageDataGenerator, array_to_img, img_to_array, load_img

datagen = ImageDataGenerator(
        rotation_range=40,
        width_shift_range=0.2,
        height_shift_range=0.2,
        shear_range=0.2,
        zoom_range=0.2,
        horizontal_flip=True,
        fill_mode='nearest')

img = load_img('data/train/cats/cat.0.jpg')  # this is a PIL image
x = img_to_array(img)  # this is a Numpy array with shape (3, 150, 150)
x = x.reshape((1,) + x.shape)  # this is a Numpy array with shape (1, 3, 150, 150)

# the .flow() command below generates batches of randomly transformed images
# and saves the results to the `preview/` directory
i = 0
for batch in datagen.flow(x, batch_size=1,
                          save_to_dir='preview', save_prefix='cat', save_format='jpeg'):
    i += 1
    if i > 20:
        break  # otherwise the generator would loop indefinitely

実行するとこんな感じになります。

 


ここまでで画像の準備と、画像の水増しについて学びました。

次回は実際にCNNを構築して、学習をさせていこうと思います。

ではでは。

 

次記事書きました

andoo.hatenablog.com

 

*1:よくわかっていません。学習済みの重みのこと?要調査

*2:"How difficult is this problem? When Kaggle started the cats vs. dogs competition (with 25,000 training images in total), a bit over two years ago, it came with the following statement:

"In an informal poll conducted many years ago, computer vision experts posited that a classifier with better than 60% accuracy would be difficult without a major advance in the state of the art. For reference, a 60% classifier improves the guessing probability of a 12-image HIP from 1/4096 to 1/459. The current literature suggests machine classifiers can score above 80% accuracy on this task [ref]."

In the resulting competition, top entrants were able to score over 98% accuracy by using modern deep learning techniques. In our case, because we restrict ourselves to only 8% of the dataset, the problem is much harder."