Transfer ラーニングを使用して独自の画像分類子を構築する
目次
まとめ
上記の画像は、このチュートリアルの 2 番目の部分で使用されるテスト イメージです。 このタスクでは、既存の分類子モデルである基本モデルを変更することで、さまざまなカテゴリの画像 (この例ではヒツジとオオカミ) を区別できる分類子をトレーニングします。 ここでは、ImageNet コーパスでトレーニングされたResNet_18 モデルを使用します。 クラスあたりわずか 15 個の画像を数秒でトレーニングし、10 個のテスト 画像すべてを正しく予測します ( 塩の数粒に注意してください)。
転送学習チュートリアルの主なリソースを次に示します。
レシピ | TransferLearning.py と TransferLearning_Extended.py ( 例/Image/TransferLearning を参照)。 |
事前トレーニング済みモデル | 転送学習の基本モデルとして、 事前トレーニング済みのResNet_18 モデルを使用します。 |
Data | 102 カテゴリの花データセットと羊とオオカミの画像の例 (セットアップを参照)。 |
実行方法 | 以下の説明に従います。 |
セットアップ
この例のコードを実行するには、CNTK Python 環境が必要です (セットアップのヘルプについては、こちらを参照してください)。
必要なデータと事前トレーニング済みモデルをダウンロードするには、 Examples/Image/TransferLearning フォルダーから次のコマンドを実行します。
python install_data_and_model.py
例を実行する
このセクションでは、Flowers データ セットの分類子を作成します。 データセットは、画像分類タスクのためにオックスフォード大学の Visual Geometry グループによって作成されました。 これは、英国に共通の花の102の異なるカテゴリで構成され、1回6000と2回1000の画像の3セットに分割された約8000の画像が含まれています。 詳細については、 VGG ホームページを参照してください。
Flowers データ セットの実行で転送学習モデルをトレーニングおよび評価するには
python TransferLearning.py
このモデルは、20 エポックのトレーニング後に Flowers データ セットの 93% の精度を実現します。
転移学習の基本概念
転移学習に基本モデルを使用する場合、基本的には、基本モデルのトレーニング中に学習された特徴と概念に基づいて構築されます。 このケースでResNet_18畳み込み DNN の場合、これは、元の基本モデルのクラス ラベルを予測する最終的な高密度レイヤーを 切断 し、新しいタスクのクラス ラベルを予測する新しい高密度レイヤーに置き換えることを意味します。 古い予測レイヤーと新しい予測レイヤーへの入力は同じです。トレーニング済みの特徴を再利用するだけです。 次に、この変更されたネットワークをトレーニングします。新しい予測レイヤーの新しい重み、またはネットワーク全体のすべての重み。
次の TransferLearning.py
コードは、基本モデルから新しいモデルを作成する部分です。
# Load the pretrained classification net and find nodes
base_model = load_model(base_model_file)
feature_node = find_by_name(base_model, feature_node_name)
last_node = find_by_name(base_model, last_hidden_node_name)
# Clone the desired layers with fixed weights
cloned_layers = combine([last_node.owner]).clone(
CloneMethod.freeze if freeze else CloneMethod.clone,
{feature_node: Placeholder(name='features')})
# Add new dense layer for class prediction
feat_norm = input_features - Constant(114)
cloned_out = cloned_layers(feat_norm)
z = Dense(num_classes, activation=None, name=new_output_node_name) (cloned_out)
独自のカスタム画像分類子を構築する
前のセクションでは、トレーニングに約 6,000 個の画像を使用して、102 種類の花のカテゴリを区別する分類子をトレーニングしました。 このセクションでは、カテゴリごとに 15 個の画像のみを使用して、羊からオオカミを見分けることができる分類器を構築します。 転移学習にも同じ ResNet_18
基本モデルを使用します。 モデルの実行をトレーニングして評価するには
python TransferLearning_Extended.py
このモデルは、それぞれ羊とオオカミの 5 つの画像でテストされ、すべてのラベルが正しく予測されます。 出力ファイルには、予測結果の JSON 表現が行ごとに含まれています。
[{"class": "Sheep", "predictions": {"Sheep":1.000, "Wolf":0.000}, "image": "..."}]
[{"class": "Sheep", "predictions": {"Sheep":1.000, "Wolf":0.000}, "image": "..."}]
[{"class": "Sheep", "predictions": {"Sheep":1.000, "Wolf":0.000}, "image": "..."}]
[{"class": "Sheep", "predictions": {"Sheep":0.997, "Wolf":0.003}, "image": "..."}]
[{"class": "Sheep", "predictions": {"Sheep":1.000, "Wolf":0.000}, "image": "..."}]
[{"class": "Wolf", "predictions": {"Wolf":1.000, "Sheep":0.000}, "image": "..."}]
[{"class": "Wolf", "predictions": {"Wolf":1.000, "Sheep":0.000}, "image": "..."}]
[{"class": "Wolf", "predictions": {"Wolf":1.000, "Sheep":0.000}, "image": "..."}]
[{"class": "Wolf", "predictions": {"Wolf":1.000, "Sheep":0.000}, "image": "..."}]
[{"class": "Wolf", "predictions": {"Wolf":1.000, "Sheep":0.000}, "image": "..."}]
[{"class": "unknown", "predictions": {"Sheep":0.994, "Wolf":0.006}, "image": "..."}]
[{"class": "unknown", "predictions": {"Sheep":0.614, "Wolf":0.386}, "image": "..."}]
[{"class": "unknown", "predictions": {"Wolf":0.980, "Sheep":0.020}, "image": "..."}]
最後の 3 つの画像にはグラウンド トゥルース クラスが割り当てられていないことに注意してください。これはもちろん、Web サービスで見えない画像をスコア付けする場合など、有効なシナリオです。 実際の画像は、次に示す 3 つの鳥の画像です。 JSON 出力のこれらのグランド トゥルース クラスは 、次のように unknown
設定されます。 分類子がトレーニングされた概念の予測は、トレーニング画像が少ないにもかかわらず、かなり良いことに注意してください。 これは、事前トレーニング済みの基本モデルが原因で大きな部分に含まれています。 見 えない概念(鳥の画像など)の予測は、分類子が羊とオオカミのみを知っているので、もちろんあまり意味がありません。 これについては後で詳 しく説明します。
カスタム イメージ セットのフォルダー構造
スクリプトは、独自の TransferLearning_Extended.py
イメージで使用できます。 必要なものは次のとおりです。
class_mapping
- カテゴリの名前を含む配列 (例:['wolf', 'sheep']
train_map_file
- 1 行ごとに最初に画像の URL とタブを含むテキスト ファイル 。たとえば、オオカミや1
羊の場合など0
、対応するカテゴリ インデックスが区切られています。test_map_file
- テスト 画像を対応するカテゴリにマップするテキスト ファイル。 テスト 画像の不明なカテゴリの場合は、カテゴリ インデックスとして使用-1
します。
次の方法でイメージを構造化すると、スクリプトは上記の 3 つの項目すべてを自動的に生成できます。
<image root folder>
Train
Sheep
Wolf
Test
Sheep
Wolf
<optional: image files with unknown label directly here>
例として参照してください <cntk root>/Examples/Image/DataSets/Animals/
。 フォルダー内の Train
各サブフォルダーは、1 つのカテゴリと見なされます (単一レベルのみ、再帰なし)。 ルート フォルダー内の個々のイメージの Train
トレーニングでは、カテゴリが割り当てされていないため、無視されます。 フォルダー内に Test
存在しないフォルダー内の追加の Train
サブフォルダーは無視されます。 個々の 分類されていない 画像をテストするには、スコアリングにも使用されます。つまり、この例の 3 つの鳥の画像のように、フォルダーに Test
直接格納されている画像も使用されます。
カスタム イメージ フォルダーを使用するには、スクリプトの上部に設定train_image_folder
test_image_folder
するTransferLearning_Extended.py
必要があります。
# define data location and characteristics
train_image_folder = "<your_image_root_folder>/Train"
test_image_folder = "<your_image_root_folder>/Test"
その後、単に実行 python TransferLearning_Extended.py
します. 別の基本モデルを使用する方法については 、以下で説明します。
スコア付けには、1 つの画像を test_map_file
1 つずつスコア付けする場合など、使用する必要はありません。 トレーニング済みの転移学習モデルを 1 回読み込み、新しい画像の予測を取得するたびに呼び出 eval_single_image
すだけです。
# once:
# load the trained transfer learning model
trained_model = load_model(new_model_file)
# for every new image:
# get predictions for a single image
probs = eval_single_image(trained_model, img_file, image_width, image_height)
塩のいくつかの粒
トレーニング画像は、後でスコア付けするシナリオを十分にカバーする必要があります。 分類子が完全に新しい概念やコンテキストを見ると、パフォーマンスが低下する可能性があります。 いくつかの例を次に示します。
- 制約環境 (屋内など) からの画像のみをトレーニングし、別の環境 (屋外) から画像をスコア付けしようとします。
- あなたは特定のメイクの画像でのみトレーニングし、他の人を得点しようとします。
- テスト画像は、照明、背景、色、サイズ、位置などに関して、大きく異なる特性を持ちます。
- テスト イメージには、まったく新しい概念が含まれています。
キャッチオール カテゴリを追加することをお勧めしますが、そのカテゴリのトレーニング データに、スコアリング時に予想される画像と再び十分に似た画像が含まれている場合にのみ有効です。 上の例のように、羊とオオカミの画像を使用して分類器をトレーニングし、それを使用して鳥の画像をスコア付けした場合、分類子は他のカテゴリを知らないので、羊またはオオカミのラベルのみを割り当てることができます。 キャッチオール カテゴリを追加し、それに鳥のトレーニング画像を追加した場合、分類子は鳥の画像に対してクラスを正しく予測する可能性があります。 しかし、車の画像など、それを提示すると、羊、オオカミ、鳥(キャッチオールと呼ばれる)しか知らないので、以前と同じ問題に直面します。 そのため、トレーニング データは、キャッチオールについても、スコアリング時に後で想定される概念と画像を十分にカバーする必要があります。
留意すべきもう 1 つの側面は、特定の基本モデルが、一部の転移学習タスクに対して非常に適切に機能し、他のタスクには適していない場合があるということです。 たとえば、上記 ResNet_18
のモデルは、動物、人、車、その他の多くの 毎日のオブジェクトの多くの画像を含む ImageNet コーパスで事前トレーニングされました。 転送学習でこの基本モデルを使用して、同様の 毎日のオブジェクト の分類子を構築すると、うまく機能します。 基本モデルと同じモデルを使用して、微生物または鉛筆図面の画像の分類子を構築すると、平らな結果のみが得られる場合があります。
別の基本モデルの使用
基本モデルとして別のモデルを使用するには、次のパラメーターを (同じ) で TransferLearning.py
調整する TransferLearning_Extended.py
必要があります。
# define base model location and characteristics
_base_model_file = os.path.join(base_folder, "..", "..", "..", "PretrainedModels", "ResNet_18.model")
_feature_node_name = "features"
_last_hidden_node_name = "z.x"
_image_height = 224
_image_width = 224
_num_channels = 3
モデル内のノード名と、次の行を使用してすべてのノード名とノード図形を印刷できるように、どのノード名を選択last_hidden_node
するかを調べるには、次のTransferLearning.py
方法を参照してください__main__
。
# You can use the following to inspect the base model and determine the desired node names
node_outputs = get_node_outputs(load_model(_base_model_file))
for out in node_outputs: print("{0} {1}".format(out.name, out.shape))