1. 概要
このラボでは、最新の畳み込みアーキテクチャについて学び、その知識を駆使して「squeezenet」というシンプルながら効果的な Convnet を実装します。
このコースには、畳み込みニューラル ネットワークに関して必要な理論的な説明が含まれており、ディープ ラーニングについて学習する出発点として適しています。
このラボは「TPU 上の Keras」のパート 4 です。シリーズとして提供されますこれらは次の順序で実行することも、個別に実行することもできます。
- TPU スピードのデータ パイプライン: tf.data.Dataset と TFRecords
- 転移学習を使用した最初の Keras モデル
- Keras と TPU を使用した畳み込みニューラル ネットワーク
- [このラボ] Keras と TPU による最新の convnets、squeezenet、Xception
学習内容
- Keras の関数スタイルをマスターする
- squeezenet アーキテクチャを使用してモデルを構築する
- アーキテクチャの迅速なトレーニングとイテレーションのために TPU を使用する
- tf.data.dataset によるデータの拡張を実装する
- TPU で事前トレーニング済みの大規模モデル(Xception)をファインチューニングする
フィードバック
この Codelab で何か問題がありましたらお知らせください。フィードバックは、GitHub の問題 [フィードバック リンク] からお送りいただけます。
2. Google Colaboratory クイック スタート
このラボでは Google Collaboratory を使用します。ユーザー側で設定を行う必要はありません。Colaboratory は、教育を目的としたオンライン ノートブック プラットフォームです。CPU、GPU、TPU を無料でトレーニングできます。
このサンプル ノートブックを開いていくつかのセルを実行し、Colaboratory についてよく理解してください。
TPU バックエンドを選択する
Colab のメニューで [ランタイム] >ランタイム タイプを変更し、[TPU] を選択します。この Codelab では、ハードウェア アクセラレーションによるトレーニングをサポートする強力な TPU(Tensor Processing Unit)を使用します。ランタイムへの接続は初回実行時に自動的に行われますが、[接続] オプションを使用してボタンをタップします。
ノートブックの実行
セルを 1 つずつ実行するには、セルをクリックして Shift+Enter キーを押します。[ランタイム >すべて実行
目次
すべてのノートブックには目次があります。左側にある黒い矢印をクリックすると開きます。
非表示のセル
一部のセルにはタイトルのみが表示されます。これは Colab 固有のノートブック機能です。それらをダブルクリックすると内部のコードを確認できますが、通常はあまり興味を引かないものです。通常はサポート関数または可視化関数です。内部の関数を定義するには、これらのセルを実行する必要があります。
認証
承認済みアカウントで認証すれば、Colab が限定公開の Google Cloud Storage バケットにアクセスできます。上記のコード スニペットによって認証プロセスがトリガーされます。
3. [情報] Tensor Processing Unit(TPU)とは
概要
Keras の TPU でモデルをトレーニングする(TPU が使用できない場合は GPU または CPU にフォールバックする)コード:
try: # detect TPUs
tpu = tf.distribute.cluster_resolver.TPUClusterResolver.connect()
strategy = tf.distribute.TPUStrategy(tpu)
except ValueError: # detect GPUs
strategy = tf.distribute.MirroredStrategy() # for CPU/GPU or multi-GPU machines
# use TPUStrategy scope to define model
with strategy.scope():
model = tf.keras.Sequential( ... )
model.compile( ... )
# train model normally on a tf.data.Dataset
model.fit(training_dataset, epochs=EPOCHS, steps_per_epoch=...)
本日は TPU を使用して、インタラクティブな速度(トレーニング実行あたり数分)で花の分類器を構築し、最適化します。
TPU を選ぶ理由
最新の GPU は、プログラム可能な「コア」を中心に構成されています。コアは、3D レンダリング、ディープ ラーニング、物理シミュレーションなどのさまざまなタスクを処理できる非常に柔軟なアーキテクチャです。一方、TPU は従来のベクトル プロセッサと専用の行列乗算ユニットをペアにして、ニューラル ネットワークなど、大規模な行列乗算が主体となるあらゆるタスクに優れています。
イラスト: 行列乗算としての高密度ニューラル ネットワーク レイヤ。ニューラル ネットワークによって一度に処理された 8 つの画像のバッチを示しています。1 行 x 列の乗算を実行して、画像のすべてのピクセル値の加重合計が実際に行われていることを確認してください。畳み込みレイヤも行列の乗算として表すことができますが、やや複雑です( 説明はセクション 1)。
ハードウェア
MXU と VPU
TPU v2 コアは、行列の乗算を実行する行列乗算ユニット(MXU)と、活性化やソフトマックスなどの他のタスクのためのベクトル処理ユニット(VPU)で構成されます。VPU は、float32 と int32 の計算を処理します。一方、MXU は、混合精度の 16 ~ 32 ビット浮動小数点形式で動作します。
混合精度の浮動小数点数と bfloat16
MXU は、bfloat16 入力と float32 出力を使用して行列乗算を計算します。中間の累積は float32 精度で行われます。
通常、ニューラル ネットワーク トレーニングでは浮動小数点精度の低下によるノイズに耐えられます。ノイズがオプティマイザーの収束に役立つ場合もあります。従来、計算を高速化するために 16 ビットの浮動小数点精度が使用されてきましたが、float16 形式と float32 形式では範囲が大きく異なります。精度を float32 から float16 に下げると、通常、オーバーフローとアンダーフローが発生します。ソリューションは存在しますが、通常、float16 を機能させるには追加の作業が必要です。
そのため、Google は TPU に bfloat16 形式を導入しました。bfloat16 は、float32 とまったく同じ指数ビットと範囲を持つ切り捨て型 float32 です。これは、TPU が bfloat16 入力と float32 出力の混合精度で行列乗算を計算するという事実に加え、通常はコードを変更しなくても精度が下がるというパフォーマンス向上のメリットを享受できることを意味します。
シストリック配列
MXU は、いわゆる「シストリックアレイ」を使用して、ハードウェアで行列乗算を実装します。データ要素が一連のハードウェア計算ユニットを通過するアーキテクチャ。(医学用語では、「最高血圧」は心臓の収縮と血流を意味し、ここではデータの流れを指します)。
行列の乗算の基本要素は、一方の行列と他方の行の直線との間のドット積です(このセクションの冒頭にある図を参照)。行列の乗算 Y=X*W の場合、結果の 1 つの要素は次のようになります。
Y[2,0] = X[2,0]*W[0,0] + X[2,1]*W[1,0] + X[2,2]*W[2,0] + ... + X[2,n]*W[n,0]
GPU では、このドット積を GPU「コア」にプログラムします。必要な数の「コア」で実行できるからです。結果の行列のすべての値を一度に計算しようと試みます。結果として得られるマトリクスのサイズが 128x128 の場合、128x128=16K「コア」が必要になります。通常は実現できません最大の GPU は約 4,000 コアです。一方、TPU は、MXU のコンピューティング単位に最小限のハードウェア(bfloat16 x bfloat16 => float32
乗アキュムレータ、それ以外は何も使用しません)を使用します。これらは非常に小さいため、TPU は 128x128 MXU で 16K を実装し、この行列の乗算を一度に処理できます。
イラスト: MXU シストリック アレイ。コンピューティング要素は乗算アキュムレータです。1 つの行列の値が配列に読み込まれます(赤いドット)。もう一方の行列の値は、配列(グレーのドット)を通過します。縦線により値が上に移動します。水平線は部分合計を表します。配列の中をデータが流れるときに、行列乗算の結果が右側から出力されることを確認するのは、ユーザーの演習として行います。
それに加えて、ドット積が MXU で計算されている間、中間合計は単に隣接する計算ユニット間で流れます。メモリやレジスタ ファイルへの格納や取得も不要です。最終的に、TPU シストリック アレイ アーキテクチャは、行列の乗算の計算において、密度と電力の大幅な利点があるだけでなく、GPU よりも無視できないほどの速度の点で優れています。
Cloud TPU
「Cloud TPU v2 インチGoogle Cloud Platform では、PCI 接続 TPU ボードを備えた仮想マシン(VM)を利用できます。TPU ボードには、デュアルコア TPU チップが 4 つあります。各 TPU コアは、VPU(ベクトル プロセッシング ユニット)と 128x128 MXU(MatriX 乗算ユニット)を備えています。この「Cloud TPU」は通常はネットワーク経由で要求元の VM に接続されます。全体像は次のようになります。
図: ネットワークに接続された「Cloud TPU」を持つ VM提供しています「Cloud TPU」それ自体は、4 つのデュアルコア TPU チップを搭載した PCI 接続 TPU ボードを備えた VM で構成されています。
TPU Pod
Google のデータセンターでは、TPU がハイ パフォーマンス コンピューティング(HPC)相互接続に接続されているため、1 つの非常に大規模なアクセラレータのように見えます。Google ではこれを Pod と呼び、最大 512 個の TPU v2 コアまたは 2,048 個の TPU v3 コアを含めることができます。
イラスト: TPU v3 Pod。HPC Interconnect で接続された TPU ボードとラック。
トレーニング中に、TPU コア間で勾配が all-reduce アルゴリズムを使用して交換されます(all-reduce についてはこちらの説明をご覧ください)。トレーニング対象のモデルは、大規模なバッチサイズでトレーニングすることでハードウェアを利用できます。
イラスト: Google TPU の 2D トロイダル メッシュ HPC ネットワークで all-reduce アルゴリズムを使用したトレーニング中の勾配の同期。
ソフトウェア
大規模なバッチサイズのトレーニング
TPU の理想的なバッチサイズは TPU コアあたり 128 個のデータアイテムですが、ハードウェアではすでに TPU コアあたり 8 個のデータアイテムから良好な利用率を示しています。1 つの Cloud TPU には 8 つのコアがあることを思い出してください。
この Codelab では、Keras API を使用します。Keras で指定するバッチは、TPU 全体のグローバル バッチサイズです。バッチは自動的に 8 に分割され、TPU の 8 コアで実行されます。
パフォーマンスに関するその他のヒントについては、TPU パフォーマンス ガイドをご覧ください。非常に大きなバッチサイズの場合、一部のモデルでは特別な注意が必要です。詳細については、LARSOptimizer をご覧ください。
仕組み: XLA
TensorFlow プログラムは計算グラフを定義します。TPU は Python コードを直接実行するのではなく、TensorFlow プログラムで定義された計算グラフを実行します。内部では、XLA(アクセラレータ線形代数コンパイラ)と呼ばれるコンパイラが、計算ノードの Tensorflow グラフを TPU マシンコードに変換します。このコンパイラは、コードとメモリ レイアウトに対して多くの高度な最適化も行います。処理が TPU に送信されると、コンパイルが自動的に行われます。ビルドチェーンに XLA を明示的に含める必要はありません。
図: TPU で実行するには、TensorFlow プログラムで定義された計算グラフがまず XLA(高速線形代数コンパイラ)表現に変換され、その後 XLA によって TPU マシンコードにコンパイルされます。
Keras での TPU の使用
TPU は、Tensorflow 2.1 以降の Keras API を通じてサポートされています。Keras のサポートは TPU と TPU Pod で動作します。TPU、GPU、CPU で動作する例を次に示します。
try: # detect TPUs
tpu = tf.distribute.cluster_resolver.TPUClusterResolver.connect()
strategy = tf.distribute.TPUStrategy(tpu)
except ValueError: # detect GPUs
strategy = tf.distribute.MirroredStrategy() # for CPU/GPU or multi-GPU machines
# use TPUStrategy scope to define model
with strategy.scope():
model = tf.keras.Sequential( ... )
model.compile( ... )
# train model normally on a tf.data.Dataset
model.fit(training_dataset, epochs=EPOCHS, steps_per_epoch=...)
このコード スニペットは次のようになります。
TPUClusterResolver().connect()
は、ネットワーク上の TPU を検索します。ほとんどの Google Cloud システム(AI Platform ジョブ、Colaboratory、Kubeflow、「ctpu up」ユーティリティで作成されたディープ ラーニング VM)で、パラメータなしで機能します。これらのシステムは、TPU_NAME 環境変数のおかげで TPU の場所を把握しています。TPU を手動で作成する場合は、TPU_NAME 環境を設定します。変数使用している VM に対して実行するか、明示的なパラメータでTPUClusterResolver
を呼び出します(TPUClusterResolver(tp_uname, zone, project)
)。TPUStrategy
は、分布と「all-reduce」を実装する部分です。勾配同期アルゴリズムで行われます- 戦略はスコープを通じて適用されます。モデルは、戦略 scope() 内で定義する必要があります。
tpu_model.fit
関数は、TPU トレーニングの入力として tf.data.Dataset オブジェクトを想定しています。
TPU 移行の一般的なタスク
- TensorFlow モデルにデータを読み込む方法は数多くありますが、TPU では
tf.data.Dataset
API を使用する必要があります。 - TPU は非常に高速であり、実行時にデータの取り込みがボトルネックになることがよくあります。TPU パフォーマンス ガイドには、データのボトルネックを検出するためのツールや、パフォーマンスに関するその他のヒントが記載されています。
- int8 または int16 の数値は int32 として扱われます。TPU には、32 ビット未満で動作する整数ハードウェアはありません。
- 一部の TensorFlow オペレーションはサポートされていません。こちらのリストをご覧ください。幸いなことに、この制限はトレーニング コード、つまりモデルのフォワード パスとバックワード パスにのみ適用されます。Tensorflow のオペレーションはすべて CPU で実行されるため、データ入力パイプラインでも使用できます。
tf.py_func
は TPU でサポートされていません。
4. [情報] ニューラル ネットワーク分類器 101
概要
次の段落で太字で示されている用語をすべて理解している場合は、次の演習に進みましょう。ディープ ラーニングを始めたばかりの方は、ぜひ本をお読みください。
一連のレイヤとして構築されたモデルの場合、Keras では Sequential API を使用できます。たとえば、3 つの Dense レイヤを使用する画像分類器は、Keras で次のように記述できます。
model = tf.keras.Sequential([
tf.keras.layers.Flatten(input_shape=[192, 192, 3]),
tf.keras.layers.Dense(500, activation="relu"),
tf.keras.layers.Dense(50, activation="relu"),
tf.keras.layers.Dense(5, activation='softmax') # classifying into 5 classes
])
# this configures the training of the model. Keras calls it "compiling" the model.
model.compile(
optimizer='adam',
loss= 'categorical_crossentropy',
metrics=['accuracy']) # % of correct answers
# train the model
model.fit(dataset, ... )
高密度ニューラル ネットワーク
これは、画像を分類するための最もシンプルなニューラル ネットワークです。「ニューロン」でできています。レイヤに配置されます。第 1 レイヤは入力データを処理し、その出力を他のレイヤにフィードします。「高密度」と呼ばれる各ニューロンが前のレイヤのすべてのニューロンと接続されているからです。
このようなネットワークに画像をフィードするには、すべてのピクセルの RGB 値を長いベクトルにフラット化し、入力として使用します。これは画像認識に最適な手法ではありませんが、後で改善します。
Neurons、Activations、RELU
「ニューロン」すべての入力の加重合計を計算し、「bias」と呼ばれる値を加算します。いわゆる「活性化関数」を通じて結果をフィードします重みとバイアスは、最初は未知です。これらはランダムに初期化され、「学習」されるニューラル ネットワークをトレーニングします。
最も一般的な活性化関数は、正規化線形ユニットの RELU です。上のグラフからわかるように、これは非常にシンプルな関数です。
ソフトマックスの有効化
花を 5 つのカテゴリ(バラ、チューリップ、タンポポ、ヒマワリ、ヒマワリ)に分類しているため、上記のネットワークは 5 個のニューロン層で終わります。中間層のニューロンは、従来の RELU 活性化関数を使用して活性化されます。最後のレイヤでは、この花がバラやチューリップなどになる確率を表す 0 ~ 1 の数値を計算します。そのために、「softmax」という活性化関数を使用します。
ベクトルにソフトマックスを適用するには、各要素の指数を受け取り、通常は L1 ノルム(絶対値の合計)を使用してベクトルを正規化します。これにより、値の和が 1 になり、確率として解釈できるようになります。
交差エントロピー損失
ニューラル ネットワークが入力画像から予測を生成するようになったので、予測の精度、すなわちネットワークが教える情報と正解(しばしば「ラベル」と呼ばれる)の間の距離を測定する必要があります。データセット内のすべての画像に正しいラベルが付けられていることを思い出してください。
どのような距離でもかまいませんが、分類問題では、いわゆる「交差エントロピー距離」を使用して最も効果的な方法です。これをエラーまたは「損失」と呼ぶことにします。関数:
勾配降下法
トレーニングニューラル ネットワークとは、交差エントロピー損失関数が最小になるように、トレーニング用の画像とラベルを使って重みとバイアスを調整することを意味します。仕組みは次のとおりです。
交差エントロピーは、トレーニング画像の重み、バイアス、ピクセル、および既知のクラスの関数です。
すべての重みとすべてのバイアスに対して交差エントロピーの偏導関数を計算すると、与えられた画像、ラベル、重みとバイアスの現在値に対して計算される「勾配」が得られます。何百万もの重みとバイアスが存在する可能性があるため、勾配の計算は大変な作業に思えます。幸いなことに、TensorFlow がそれを自動でやってくれます。勾配の数学的特性は、「上」を指すことです。交差エントロピーが低いところに目的のため、逆方向に移動します。重みとバイアスは、勾配のごく一部で更新されます。その後、トレーニング ループ内で、次のトレーニング画像とラベルのバッチを使用して、同じことを何度も繰り返します。うまくいけば、交差エントロピーが最小になるところに収束することが期待されます。ただし、この最小値が一意であるという保証はありません。
ミニバッチ処理とモメンタム
1 つのサンプル画像についてグラデーションを計算し、重みとバイアスをすぐに更新することもできますが、たとえば 128 枚の画像でバッチにすることで、異なるサンプル画像による制約をより適切に表現するグラデーションが得られるため、より速く解に収束する可能性が高くなります。ミニバッチのサイズは調整可能なパラメータです。
この手法は「確率的勾配降下法」とも呼ばれます。には、より現実的な利点がもう一つあります。バッチで作業することは、より大きな行列で作業することも意味し、通常は GPU や TPU での最適化が容易になります。
ただし、収束はやや混沌としたものになり、勾配ベクトルがすべてゼロになると収束が停止することさえあります。最小値を見つけたということでしょうか?必ずしも違反警告を受けるとは限りません。勾配コンポーネントは、最小値または最大値で 0 にできます。何百万もの要素を含む勾配ベクトルで、それらがすべてゼロの場合、すべてのゼロが最小値に対応し、どのゼロでも最大ポイントに対応する確率はかなり小さくなります。さまざまな次元の空間では、サドルポイントは非常に一般的なものなので、それだけでは不十分です。
イラスト: サドルポイント。勾配は 0 ですが、すべての方向で最小値ではありません。(画像の帰属: Wikimedia: 執筆者: Nicoguaro - 自著、CC BY 3.0)
解決策は、最適化アルゴリズムに勢いをつけて、止まることなく踏切を乗り越えることです。
用語集
バッチまたはミニバッチ: トレーニングは常に、トレーニング データとラベルのバッチに対して実行されます。これにより、アルゴリズムが収束しやすくなります。「バッチ」ディメンションは通常、データテンソルの 1 次元目です。たとえば、形状 [100, 192, 192, 3] のテンソルには、1 ピクセルあたり 3 つの値(RGB)を持つ 192x192 ピクセルの画像が 100 個含まれています。
交差エントロピー損失: 分類器でよく使用される特別な損失関数。
dense レイヤ: ニューロンの層。各ニューロンが前のレイヤのすべてのニューロンに接続されています。
特徴: ニューラル ネットワークの入力は「特徴」と呼ばれることもあります。適切な予測を得るために、データセットのどの部分(または複数の部分の組み合わせ)をニューラル ネットワークに入力すべきかを考える技術は「特徴量エンジニアリング」と呼ばれます。
labels: 「classes」の別の名前教師あり分類問題での正解や正解の
学習率: トレーニング ループの反復処理ごとに重みとバイアスが更新される勾配の割合。
ロジット: 活性化関数が適用される前のニューロン層の出力は「ロジット」と呼ばれます。この用語は「ロジスティック関数」に由来します。別名「シグモイド関数」活性化関数として最も広く利用されていました。「ロジスティック関数の前のニューロン出力」「Logits」に短縮されます。
loss: ニューラル ネットワークの出力と正解を比較する誤差関数
neuron: 入力の加重合計を計算し、バイアスを加えて、その結果を活性化関数に渡します。
ワンホット エンコーディング: クラス 5 のうち、クラス 3 が 5 つの要素のベクトルとしてエンコードされます。3 番目の要素である 1 を除き、すべてゼロになります。
relu: 正規化線形ユニット。ニューロンによく使用される活性化関数です。
シグモイド: 以前は一般的になっていたもう一つの活性化関数で、特殊なケースでも有用です。
ソフトマックス: ベクトルに対して作用する特別な活性化関数。最大の成分と他のすべての成分の差を増加させ、確率のベクトルとして解釈できるようにベクトルを合計 1 に正規化します。分類器の最後のステップとして使用されます。
tensor: 「テンソル」行列に似ていますが、次元数は任意です。1 次元テンソルはベクトルです。2 次元のテンソルは行列です。テンソルは 3 次元、4 次元、5 次元以上にすることができます。
5. [情報] 畳み込みニューラル ネットワーク
概要
次の段落で太字で示されている用語をすべて理解している場合は、次の演習に進みましょう。畳み込みニューラル ネットワークをこれから始める場合は、この後をお読みください。
イラスト: 4x4x3=48 の学習可能な重みから成る 2 つの連続したフィルタで画像をフィルタしています。
Keras での単純な畳み込みニューラル ネットワークは次のようになります。
model = tf.keras.Sequential([
# input: images of size 192x192x3 pixels (the three stands for RGB channels)
tf.keras.layers.Conv2D(kernel_size=3, filters=24, padding='same', activation='relu', input_shape=[192, 192, 3]),
tf.keras.layers.Conv2D(kernel_size=3, filters=24, padding='same', activation='relu'),
tf.keras.layers.MaxPooling2D(pool_size=2),
tf.keras.layers.Conv2D(kernel_size=3, filters=12, padding='same', activation='relu'),
tf.keras.layers.MaxPooling2D(pool_size=2),
tf.keras.layers.Conv2D(kernel_size=3, filters=6, padding='same', activation='relu'),
tf.keras.layers.Flatten(),
# classifying into 5 categories
tf.keras.layers.Dense(5, activation='softmax')
])
model.compile(
optimizer='adam',
loss= 'categorical_crossentropy',
metrics=['accuracy'])
畳み込みニューラル ネットワーク 101
畳み込みネットワークの層には、1 つの「ニューロン」がは、画像の小さな領域に対してのみ、そのすぐ上にあるピクセルの加重合計を行います。通常の密レイヤのニューロンと同様に、バイアスを加え、活性化関数を通じて合計をフィードします。この処理は、同じ重みを使用して画像全体で繰り返されます。密な層では、各ニューロンに独自の重みがあったことを思い出してください。ここでは、単一の「パッチ」がの重みが画像上を両方向にスライドする(「畳み込み」)。出力には、画像内のピクセルと同じ数の値が含まれます(ただし、端にはパディングが必要です)。これは、4×4×3=48 の重みのフィルタを使用するフィルタリング演算です。
ただし、48 個の重みでは不十分です。自由度をさらに広げるには、新しい重みのセットで同じ操作を繰り返します。これにより、新しいフィルタ出力のセットが生成されます。ここでは「チャンネル」とします。出力の 1 対 1 です。
2 組(または複数)の重みのセットは、新しい次元を追加することで 1 つのテンソルとして合計できます。これにより、畳み込みレイヤの重みテンソルの一般的な形状がわかります。入力チャンネルと出力チャンネルの数はパラメータであるため、畳み込みレイヤのスタックとチェーンを開始できます。
イラスト: 畳み込みニューラル ネットワークが「立方体」を変換する他の「キューブ」に分割できます。可視化できます
ストライド畳み込み、最大プーリング
2 または 3 のストライドで畳み込みを実行すると、結果として得られるデータキューブを水平方向に縮小することもできます。一般的な方法は次の 2 つです。
- ストライド畳み込み: 上記のスライディング フィルタで、ストライドが 1 より大きい
- 最大プーリング: MAX 演算を適用するスライディング ウィンドウ(通常は 2x2 パッチで、2 ピクセルごとに繰り返される)
イラスト: 計算ウィンドウを 3 ピクセル分スライドすると、出力値が少なくなります。ストライド畳み込みまたは最大プーリング(2 ストライドでスライドする 2x2 ウィンドウの最大)は、データキューブを水平方向に縮小する方法です。
畳み込み分類器
最後に、最後のデータキューブをフラット化し、密集したソフトマックス活性化層に通すことで分類ヘッドを接続します。一般的な畳み込み分類器は次のようになります。
イラスト: 畳み込みレイヤとソフトマックス レイヤを使用した画像分類器。3x3 と 1x1 のフィルタを使用しています。maxpool レイヤは、2x2 データポイントのグループの最大値を取ります。分類ヘッドは、ソフトマックス活性化を伴う密レイヤで実装されています。
Keras の場合
上記の畳み込みスタックは、Keras で次のように記述できます。
model = tf.keras.Sequential([
# input: images of size 192x192x3 pixels (the three stands for RGB channels)
tf.keras.layers.Conv2D(kernel_size=3, filters=32, padding='same', activation='relu', input_shape=[192, 192, 3]),
tf.keras.layers.Conv2D(kernel_size=1, filters=32, padding='same', activation='relu'),
tf.keras.layers.MaxPooling2D(pool_size=2),
tf.keras.layers.Conv2D(kernel_size=3, filters=32, padding='same', activation='relu'),
tf.keras.layers.Conv2D(kernel_size=1, filters=32, padding='same', activation='relu'),
tf.keras.layers.MaxPooling2D(pool_size=2),
tf.keras.layers.Conv2D(kernel_size=3, filters=32, padding='same', activation='relu'),
tf.keras.layers.Conv2D(kernel_size=1, filters=32, padding='same', activation='relu'),
tf.keras.layers.MaxPooling2D(pool_size=2),
tf.keras.layers.Conv2D(kernel_size=3, filters=32, padding='same', activation='relu'),
tf.keras.layers.Conv2D(kernel_size=1, filters=32, padding='same', activation='relu'),
tf.keras.layers.MaxPooling2D(pool_size=2),
tf.keras.layers.Conv2D(kernel_size=3, filters=16, padding='same', activation='relu'),
tf.keras.layers.Conv2D(kernel_size=1, filters=8, padding='same', activation='relu'),
tf.keras.layers.Flatten(),
# classifying into 5 categories
tf.keras.layers.Dense(5, activation='softmax')
])
model.compile(
optimizer='adam',
loss= 'categorical_crossentropy',
metrics=['accuracy'])
6. [最新情報] 最新の畳み込みアーキテクチャ
概要
イラスト: 畳み込み「モジュール」。現時点で最適なことは?max-pool レイヤの後に 1x1 の畳み込みレイヤが続くのか、それともレイヤの別の組み合わせなのか?すべて試し、結果を連結してネットワークに決定を任せる。画面右側の "inception」をご覧ください。畳み込みアーキテクチャを構築できます
Keras でデータフローを分岐させるモデルを作成するには、モデルスタイル。以下に例を示します。
l = tf.keras.layers # syntax shortcut
y = l.Conv2D(filters=32, kernel_size=3, padding='same',
activation='relu', input_shape=[192, 192, 3])(x) # x=input image
# module start: branch out
y1 = l.Conv2D(filters=32, kernel_size=1, padding='same', activation='relu')(y)
y3 = l.Conv2D(filters=32, kernel_size=3, padding='same', activation='relu')(y)
y = l.concatenate([y1, y3]) # output now has 64 channels
# module end: concatenation
# many more layers ...
# Create the model by specifying the input and output tensors.
# Keras layers track their connections automatically so that's all that's needed.
z = l.Dense(5, activation='softmax')(y)
model = tf.keras.Model(x, z)
その他の格安コツ
小さな 3x3 フィルタ
この図では、2 つの連続する 3x3 フィルタの結果が表示されています。結果に寄与したデータポイントをトレースしてみましょう。これら 2 つの連続する 3x3 フィルタは、5x5 領域のなんらかの組み合わせを計算します。5×5 フィルターとまったく同じ組み合わせではありませんが、2 つの連続した 3×3 フィルターは単一の 5×5 フィルターよりも安価であるため、試してみる価値があります。
1 行 1 の畳み込み?
数学的に「1×1」は畳み込みは定数の乗算なので、あまり有用な概念ではありません。ただし、畳み込みニューラル ネットワークでは、フィルタは 2D 画像だけでなくデータキューブにも適用されることを覚えておいてください。したがって、「1x1」はfilter は 1 行 1 列のデータの加重合計を計算し(図を参照)、データにわたってスライドしていくと、入力の各チャネルの線形結合が得られます。これは実に便利です。チャネルを個々のフィルタリング処理の結果として考える場合、たとえば「尖った耳」に対する別のフィルタや「ひげ」のフィルタなどが考えられます。3 つ目は「目がスリット」です次に「1x1」畳み込みレイヤは、これらの特徴の可能な線形組み合わせを複数計算します。これは「猫」を探すのに便利です。さらに、1x1 レイヤでは使用する重みが少なくなります。
7. スクイーズネット
これらのアイデアをまとめる簡単な方法は、「Squeezenet」ホワイトペーパーをご覧ください。著者は、1x1 と 3x3 の畳み込み層のみを使用する、非常にシンプルな畳み込みモジュール設計を提案しています。
イラスト: 「ファイア モジュール」に基づくスクイーズネット アーキテクチャ。1×1 の層を「押しつぶす」ように配置されています。垂直次元の受信データの後に「拡張」する 2 つの並列 1x1 および 3x3 畳み込み層必要があります。
ハンズオン
前のノートブックで、スクイーズネットにヒントを得た畳み込みニューラル ネットワークを構築します。モデルのコードを Keras の「関数型スタイル」に変更する必要があります。
Keras_Flowers_TPU (playground).ipynb
その他の情報
この演習では、squeezenet モジュールのヘルパー関数を定義すると便利です。
def fire(x, squeeze, expand):
y = l.Conv2D(filters=squeeze, kernel_size=1, padding='same', activation='relu')(x)
y1 = l.Conv2D(filters=expand//2, kernel_size=1, padding='same', activation='relu')(y)
y3 = l.Conv2D(filters=expand//2, kernel_size=3, padding='same', activation='relu')(y)
return tf.keras.layers.concatenate([y1, y3])
# this is to make it behave similarly to other Keras layers
def fire_module(squeeze, expand):
return lambda x: fire(x, squeeze, expand)
# usage:
x = l.Input(shape=[192, 192, 3])
y = fire_module(squeeze=24, expand=48)(x) # typically, squeeze is less than expand
y = fire_module(squeeze=32, expand=64)(y)
...
model = tf.keras.Model(x, y)
今度の目標は 80% の精度を達成することです。
次の方法をお試しください
1 つの畳み込みレイヤから始めて、その後に「fire_modules
」と MaxPooling2D(pool_size=2)
レイヤを交互に記述します。ネットワーク内の最大プーリング レイヤを 2 ~ 4 層、最大プーリング レイヤ間に連続する 1、2、または 3 つのファイア モジュールを接続してテストできます。
ファイア モジュールでは、「スクイーズ」というパラメータは通常、「expand」パラメータパラメータを指定します。これらのパラメータは実際にはフィルタの数です。通常は 8 ~ 196 の範囲になります。ネットワークを通じてフィルタの数が徐々に増えるアーキテクチャや、すべての Fire モジュールに同じ数のフィルタを使用する単純なアーキテクチャを試すことができます。
以下に例を示します。
x = tf.keras.layers.Input(shape=[*IMAGE_SIZE, 3]) # input is 192x192 pixels RGB
y = tf.keras.layers.Conv2D(kernel_size=3, filters=32, padding='same', activation='relu')(x)
y = fire_module(24, 48)(y)
y = tf.keras.layers.MaxPooling2D(pool_size=2)(y)
y = fire_module(24, 48)(y)
y = tf.keras.layers.MaxPooling2D(pool_size=2)(y)
y = fire_module(24, 48)(y)
y = tf.keras.layers.GlobalAveragePooling2D()(y)
y = tf.keras.layers.Dense(5, activation='softmax')(y)
model = tf.keras.Model(x, y)
この時点で、テストがあまりうまくいかず、精度を 80% という目標では難しいようだということに気付くかもしれません。もっと手ごろな価格のコツを試してみましょう。
バッチ正規化
バッチノルムは、発生している収束の問題に対処するのに役立ちます。この手法については、次のワークショップで詳しく説明します。今のところは、これをブラック ボックスの「魔法」として使ってください。以下のように、ネットワーク内のすべての畳み込みレイヤ(fire_module 関数内のレイヤを含む)の後に次の行を追加します。
y = tf.keras.layers.BatchNormalization(momentum=0.9)(y)
# please adapt the input and output "y"s to whatever is appropriate in your context
今回はデータセットが小さいため、モメンタム パラメータをデフォルト値の 0.99 から 0.9 に小さくする必要があります。今のところ、この詳細は気にしないでください。
データの拡張
彩度を左右に反転させるなどの簡単な変換でデータを拡張することで、さらにパーセンテージ ポイントが得られます。
tf.data.Dataset API を使用して Tensorflow でこれを行うのはとても簡単です。データに新しい変換関数を定義します。
def data_augment(image, label):
image = tf.image.random_flip_left_right(image)
image = tf.image.random_saturation(image, lower=0, upper=2)
return image, label
次に、そのデータセットを最終的なデータ変換に使用します(セル「トレーニングと検証のデータセット」、関数「get_batched_dataset」)。
dataset = dataset.repeat() # existing line
# insert this
if augment_data:
dataset = dataset.map(data_augment, num_parallel_calls=AUTO)
dataset = dataset.shuffle(2048) # existing line
データの拡張をオプションにして、トレーニング データセットのみが拡張されるように必要なコードを追加することを忘れないでください。検証用データセットを拡張しても意味がありません。
35 エポックで 80% の精度は達成できるレベルに達しているはずです。
ソリューション
こちらがソリューション ノートブックです。行き詰まった場合に使用できます。
Keras_Flowers_TPU_squeezenet.ipynb
学習した内容
- 🤔? Keras の「関数型」モデル
- 🤓? Squeezenet アーキテクチャ
- 🤓? tf.data.datset によるデータの拡張
このチェックリストをぜひチェックしてみてください。
8. Xception ファインチューニング
分離可能な畳み込み
最近では、深度分離可能な畳み込み積み重ねという、畳み込みレイヤを実装する別の方法の人気が高まっています。一口で言いますが、コンセプトはとてもシンプルです。Tensorflow と Keras で tf.keras.layers.SeparableConv2D
として実装されます。
分離可能な畳み込みも画像に対してフィルタを実行しますが、入力画像の各チャネルに対して異なる重みのセットを使用します。その後に「1x1 畳み込み」があります。これは一連のドット積で、フィルタされたチャネルの加重合計となります。毎回、新しい重みを使用して、チャネルの重み付き再結合が必要な回数だけ計算されます。
イラスト: 分離可能な畳み込み。フェーズ 1: チャンネルごとに個別のフィルタを使用した畳み込みフェーズ 2: チャネルの線形再結合。目的の出力チャンネル数に達するまで、新しい重みのセットでこれを繰り返します。フェーズ 1 は、毎回新しい重みで繰り返すこともできますが、実際にはめったにありません。
分離可能な畳み込みは、最近の畳み込みネットワーク アーキテクチャ(MobileNetV2、Xception、EfficientNet)で使用されています。なお、MobileNetV2 は以前に転移学習に使用していたものです。
この方法は通常の畳み込み積みよりも低コストで、実際には同じように効果的であることがわかっています。上記の例の重み数は次のとおりです。
畳み込み層: 4 x 4 x 3 x 5 = 240
分離可能な畳み込み層: 4 x 4 x 3 + 3 x 5 = 48 + 15 = 63
各スタイルの畳み込みレイヤ スケールを同様の方法で適用するために必要な乗算回数を計算することは、演習として残しておきます。分離可能な畳み込みは、より小規模で計算効率が大幅に向上します。
ハンズオン
「転移学習」からやり直す今回は Xception を事前トレーニング済みモデルとして選択します。Xception では分離可能な畳み込みのみを使用します。すべての重みをトレーニング可能な状態にしておきます。トレーニング済みのレイヤをそのまま使うのではなく、データに対してトレーニング済みの重みを微調整します。
Keras Flowers transfer learning (playground).ipynb
目標: 精度 >95%(可能性は低い)
これが最後の演習であるため、もう少しコードとデータ サイエンスの作業が必要です。
ファインチューニングに関する詳細情報
Xception は、tf.keras.application の標準の事前トレーニング済みモデルで利用できます*。今回は、すべての重みをトレーニング可能のままにすることを忘れないでください。
pretrained_model = tf.keras.applications.Xception(input_shape=[*IMAGE_SIZE, 3],
include_top=False)
pretrained_model.trainable = True
モデルをファインチューニングするときに適切な結果を得るには、学習率に注意を払い、立ち上げ期間を設定した学習率のスケジュールを使用する必要があります。この場合、次のように指定します。
標準の学習率から始めると、事前にトレーニングされたモデルの重みが中断されます。開始すると、モデルが適切な方法でデータを変更できるようになるまで、データが徐々に保持されます。立ち上げ後は、学習率を一定または指数関数的に減衰させながら学習を継続できます。
Keras では、学習率はコールバックによって指定され、エポックごとに適切な学習率を計算できます。Keras は、エポックごとに正しい学習率をオプティマイザーに渡します。
def lr_fn(epoch):
lr = ...
return lr
lr_callback = tf.keras.callbacks.LearningRateScheduler(lr_fn, verbose=True)
model.fit(..., callbacks=[lr_callback])
ソリューション
こちらがソリューション ノートブックです。行き詰まった場合に使用できます。
07_Keras_Flowers_TPU_xception_fine_tuned_best.ipynb
学習した内容
- 🤔? 深度分離可能な畳み込み
- 🤓? 学習率のスケジュール
- Roku 事前トレーニング済みモデルのファインチューニング。
このチェックリストをぜひチェックしてみてください。
9. 完了
最新の畳み込みニューラル ネットワークを初めて構築し、90% 以上の精度までトレーニングしました。TPU のおかげで、わずか数分で連続的なトレーニングのイテレーションを実行できました。これで 4 つの「TPU 上の Keras の Codelab」は終了です。
- TPU スピードのデータ パイプライン: tf.data.Dataset と TFRecords
- 転移学習を使用した最初の Keras モデル
- Keras と TPU を使用した畳み込みニューラル ネットワーク
- [このラボ] Keras と TPU による最新の convnets、squeezenet、Xception
TPU の実践
TPU と GPU は Cloud AI Platform で利用できます。
ぜひフィードバックをお寄せください。このラボで問題が見つかった場合や、改善が必要だと思われる点がありましたら、お知らせください。フィードバックは、GitHub の問題 [フィードバック リンク] からお送りいただけます。
|