転移学習・ファインチューニングとは【Python】

AI基礎

畳み込みニューラルネットワーク(CNN)に代表される画像の分類、物体検出、セグメンテーションなどのモデルは学習する際に、多くのデータ数と時間を要します。そこで、転移学習やファインチューニングが役立ちます、というか必須と言っても過言ではないくらい使えます。

転移学習やファインチューニングを扱うのは難しそうなイメージあると思いますが、有名なCNNモデル(ResNet、VGGなど)はImageNetというデータで学習済の重みデータがweb上に公開されており誰でも活用することができるようになっています。今回はそのやり方を見ていきます。

以降、前の記事(ResNetの解説)を例に転移学習、ファインチューニングを説明していきます。

ResNetの解説についてはこちら↓

こんな人におすすめ
  • AI・機械学習を勉強したいけど、何からやればよいか分からない
  • 書籍が難しすぎて挫折した
  • これからデータサイエンティストを目指したい
  • CNNをやってみたい

転移学習・ファインチューニングとは?違いは?

  1. 転移学習
    • ImageNetで学習したモデルの最終ブロックに新たに何層か自分で付けたし(もしくはモデルを書換え)その層だけを学習する。
    • 逆に言えば付け足した層以外の元のモデルの重みは学習し直さない。
  2. ファインチューニング
    • ImageNetで学習したモデルへ付け足すまでは転移学習と一緒だが、付け足した部分以外にモデルの任意の部分を学習する。

言葉だけではわかりずらいので図で説明すると↓

ブロックは隠れ層(畳み込み層)をイメージしています。転移学習およびファインチューニングにおいて、出力を学習することで自分の好きな分類であったり、物体検出モデルをつくることが可能です。転移学習は最後の出力層へ付け足した部分だけ学習します。一方、ファインチューニングは元の重みをすべて利用するのではなく、途中から重みを学習していきます。

転移学習していいのか?

よくある質問として、「ImageNetで分類しているようなモノ※とは違うけど転移学習しても良いか?」があります。結論としては、転移学習した方がいいです。問題によってはファインチューニングをした方が良いものもありますが、いづれにせよやったほうがいいです。

理由としては、畳み込みの最初の層付近では、いわゆる画像というモノはどういうモノか?輪郭・境界を見ているといわれており、その画像の分類について核心を突く学習を実施しているわけではないためです。核心を突くような学習は最後の層付近に現れます。入力近くの層においてImageNetの膨大なデータで取得した重みを使うことで、学習が収束するスピードは段違いに良くなります。自前画像で学習を繰り返すより転移学習・ファインチューニングを用いた方がメリットは大きくなるということです。

転移学習・ファインチューニングの手法選択については、その画像を分類しやすければ転移学習を選択します。分類が難しい場合や、ImageNetで学習した内容と大きく異なる場合は、ファインチューニングを選ぶと良いかと思います。この辺は明確な回答がなく、私が実際にやってみた感覚であり持論です。

※ImageNetは1400万枚以上のカラーのイメージ画像に、その画像が何かをラベルを付与したデータセットです。中身はさまざまですが、犬やらトカゲ、機関車、ドライヤーなど1000クラスあります。

Pythonコードで説明

前の記事でResNetモデルに対しTensorFlowライブラリで転移学習する方法を実施しています。そのコードを使って説明します。

  • 転移学習の場合コードは↓になります。
from tensorflow.keras.applications.resnet50 import ResNet50
from tensorflow.keras.models import Sequential, Model
from tensorflow.keras.layers import Input, Flatten, Dense

input_tensor = tf.keras.Input(shape=(image_size, image_size, 3))
#ResNet50モデルの呼出し。転移学習をする場合はここでweights="imagenet"とします
#include_top=Falseとすることで最後の全結合層を含まないモデルの状態にします
ResNet50 = tf.keras.applications.ResNet50(include_top=False, weights="imagenet", 
                                          input_tensor=input_tensor,classes=2,)
#次に転移学習で学習する出力層をモデリングします。
top_model = Sequential()
top_model.add(Flatten(input_shape = ResNet50.output_shape[1:]))
top_model.add(Dense(2, activation = 'sigmoid'))
#最後にResNet50の重みを流用する部分と、転移学習する全結合層を1つのモデルにします
model = Model(inputs=ResNet50.inputs, outputs=top_model(ResNet50.outputs))
  1. tf.keras.applications.ResNet50()の引数:weights=”imagenet”とします
  2. tf.keras.applications.ResNet50()の引数:include_top=Falseとします
  3. 出力層のモデリングをします
  4. ResNet50の重みを流用する部分と、転移学習する全結合層を1つのモデルにします
  • ファインチューニングの場合コードは↑の転移学習のコードへ下記を追記するだけです。
for layer in model.layers[:168]:
    layer.trainable = False
#数値(168)は固定させる層の数によって変化させてください

# 重みがどの層で固定されているかの確認
for layer in model.layers:
    print(layer.name, layer.trainable )
  1. 転移学習1~4と同様の作業を実施します
  2. 固定させる層の数を指定します
  3. どの層が固定されてるか確認します

以上でつくったmodelを用い、学習をさせることで転移学習およびファインチューニングが実施できます。Lossの減り方がオリジナルと比較し速いと思われますので興味ある方は試してみると良いかと思います。

まとめ

  • 転移学習とは既に学習済のモデルに対し新たに何層か自分で付けたし(もしくはモデルを書換え)、その層だけを学習する。
  • ファインチューニングとは学習済のモデルに対し何層か付け足すまでは転移学習と一緒だが、付け足した部分以外にモデルの任意の部分を学習する。
  • 学習済みモデルで分類しているモノとは違う分類をしたい場合も、転移学習(場合によってはファインチューニング)した方が良い。

コメント

タイトルとURLをコピーしました