PyTorchを使用した効率的な画像セグメンテーション:パート3
Efficient Image Segmentation with PyTorch Part 3.
Depthwise separable convolutions
この4部作では、PyTorchを使用して深層学習技術を使って画像セグメンテーションをゼロからスクラッチで実装します。このパートでは、デプロイメント可能なモバイルやその他のエッジデバイスでモデルを展開できるように、トレーニング可能なパラメータの数を減らすために深さ方向分離畳み込みを使用してCNNベースラインモデルを最適化することに焦点を当てます。
Naresh Singhと共同執筆
記事の概要
この記事では、以前に構築した畳み込みニューラルネットワーク(CNN)を改良して、ネットワーク内の学習可能なパラメータの数を減らすことで、モデルのサイズを最適化します。入力画像内のペットピクセル(犬、猫、ハムスターなどに属するピクセル)を特定するタスクは変わりません。ネットワークの選択肢はSegNetのままで、畳み込み層を深さ方向分離畳み込み(DSC)に置き換えるだけです。これを行う前に、深さ方向分離畳み込みの理論と実践について掘り下げ、その技術の背後にあるアイデアについて詳しく説明します。
この記事全体を通じて、モデルのトレーニングに関するコードと結果については、このノートブックを参照してください。深さ方向分離畳み込みについてのプライマーについては、このノートブックを参照してください。結果を再現する場合は、最初のノートブックが合理的な時間内に完了するように、GPUが必要です。2番目のノートブックは通常のCPUで実行できます。
このシリーズの記事
このシリーズは深層学習についての経験レベルを問わず、すべての読者を対象としています。深層学習とビジョンAIの実践について学び、堅実な理論と実践経験を積んでみたい場合は、正しい場所に来ました!これは以下の記事を含む4部作になる予定です。
- 概念とアイデア
- CNNベースのモデル
- 深さ方向分離畳み込み(この記事)
- ビジョントランスフォーマーベースのモデル
イントロダクション
モデルサイズと計算コストの観点から、畳み込みをより詳しく見てみましょう。トレーニング可能なパラメータの数は、モデルのサイズを示す良い指標であり、テンソル演算の数はモデルの複雑さまたは計算コストを反映します。サイズがm x h x wである入力を処理する畳み込み層があり、nフィルターがサイズdₖ x dₖである場合を考えてみましょう。ここで、mは入力チャンネルの数であり、hとwは高さおよび幅の寸法です。この場合、畳み込み層は図2に示すように、形状がn x h x wの出力を生成します。畳み込みにstride=1が使用されていると仮定しています。トレーニング可能なパラメータと計算コストについてこのセットアップを評価してみましょう。
トレーニング可能なパラメータの評価: n個のフィルターがあり、各フィルターにはm x dₖ x dₖのトレーニング可能なパラメータがあります。これにより、合計でn x m x dₖ x dₖのトレーニング可能なパラメータが得られます。バイアス項はこのディスカッションを単純化するために無視されます。以下のPyTorchコードを見て、理解を検証しましょう。
import torchfrom torch import nndef num_parameters(m):return sum([p.numel() for p in m.parameters()])dk, m, n = 3, 16, 32print(f"Expected number of parameters: {m * dk * dk * n}")conv1 = nn.Conv2d(in_channels=m, out_channels=n, kernel_size=dk, bias=False)print(f"Actual number of parameters: {num_parameters(conv1)}")
以下を印刷します。
期待されるパラメータ数:4608実際のパラメータ数:4608
さて、畳み込みの計算コストを評価しましょう。
計算コストの評価:形状がm x dₖ x dₖの単一の畳み込みフィルタを、ストライド=1かつパディング=dₖ-2で実行する場合、h x wサイズの入力に適用すると、dₖ x dₖのサイズを持つ各画像セクションに1回ずつ畳み込みフィルタが適用され、h x w回適用されます。これにより、フィルタまたは出力チャネルごとにm x dₖ x dₖ x h x wのコストが発生し、n個の出力チャネルを計算する必要があるため、合計コストはm x dₖ x dₖ x h x nになります。torchinfo PyTorchパッケージを使用してこれを検証しましょう。
from torchinfo import summaryh, w = 128, 128print(f"Expected total multiplies: {m * dk * dk * h * w * n}")summary(conv1, input_size=(1, m, h, w))
以下が表示されます。
期待される合計乗算回数:75497472==========================================================================================Layer (type:depth-idx) Output Shape Param #==========================================================================================Conv2d [1, 32, 128, 128] 4,608==========================================================================================Total params: 4,608Trainable params: 4,608Non-trainable params: 0Total mult-adds (M): 75.50==========================================================================================Input size (MB): 1.05Forward/backward pass size (MB): 4.19Params size (MB): 0.02Estimated Total Size (MB): 5.26==========================================================================================
畳み込み層の実装の詳細を一時的に無視すると、畳み込み層は高レベルでm x h x wの入力をn x h x wの出力に変換するだけであることに気付くでしょう。この変換は、入力を見るたびに特徴を徐々に学習するトレーニング可能なフィルタを使用して行われます。次の質問は、この変換を少ない学習可能なパラメーターで実現し、同時にレイヤーの学習能力を最小限に抑えることができるかどうかです。深い分離畳み込みは、この正確な質問に答えるために提案されました。それらが評価指標でどのように積み重なるかを理解し、詳細を学びましょう。
深さ方向分離畳み込み
深さ方向分離畳み込み(DSC)のコンセプトは、Laurent Sifreが彼らの博士論文「画像分類のための剛体運動散乱」で最初に提案しました。それ以来、XceptionNetやMobileNetなどのさまざまな人気のある深層畳み込みネットワークで成功裏に使用されています。
通常の畳み込みとDSCの主な違いは、DSCが以下の2つの畳み込みで構成されていることです。
- 深さ方向にグループ化された畳み込み:入力チャネルの数mが出力チャネルの数と等しく、各出力チャネルが1つの入力チャネルにのみ影響を与えるため、これは「グループ化」畳み込みと呼ばれます。PyTorchでは、これを「グループ化された」畳み込みと呼びます。PyTorchでグループ化された畳み込みについては、ここを読んでください。
- pointwise畳み込み(フィルターサイズ=1):n個のフィルタがあり、各フィルタはすべてのm入力チャネルで動作して1つの出力値を生成します。
通常の畳み込みと同様に、DSCについても、トレーニング可能なパラメーターと計算の数を計算してみましょう。
トレーニング可能なパラメータの評価:「グループ化された」畳み込みにはm個のフィルタがあり、各フィルタにはdₖ x dₖの学習可能なパラメーターがあり、m個の出力チャネルが生成されます。これにより、m x dₖ x dₖの学習可能なパラメーターが得られます。pointwise畳み込みには、n個のサイズm x 1 x 1のフィルタがあり、n x m x 1 x 1の学習可能なパラメーターがあります。以下は、PyTorchコードを見て、私たちの理解を検証する方法です。
class DepthwiseSeparableConv(nn.Sequential): def __init__(self, chin, chout, dk): super().__init__( # Depthwise convolution nn.Conv2d(chin, chin, kernel_size=dk, stride=1, padding=dk-2, bias=False, groups=chin), # Pointwise convolution nn.Conv2d(chin, chout, kernel_size=1, bias=False), )conv2 = DepthwiseSeparableConv(chin=m, chout=n, dk=dk)print(f"Expected number of parameters: {m * dk * dk + m * 1 * 1 * n}")print(f"Actual number of parameters: {num_parameters(conv2)}")
これは以下を出力します。
Expected number of parameters: 656Actual number of parameters: 656
DSCバージョンはパラメータ数がおよそ7倍少ないことがわかります。次に、DSCレイヤーの計算コストに注目しましょう。
計算コストの評価: 入力が空間次元m x h x wを持っていると仮定します。DSCのグループ畳み込みセグメントでは、dₖ x dₖのサイズを持つm個のフィルタがあります。フィルタは、対応する入力チャネルに適用され、セグメントコストはm x dₖ x dₖ x h x wになります。ポイントウィズ畳み込みでは、n個のサイズm x 1 x 1のフィルタを適用し、n個の出力チャネルを生成します。これにより、セグメントコストはn x m x 1 x 1 x h x wになります。グループとポイントウィズの操作のコストを合算して、総コストを計算する必要があります。torchinfo PyTorchパッケージを使用して、これを検証してみましょう。
print(f"Expected total multiplies: {m * dk * dk * h * w + m * 1 * 1 * h * w * n}")s2 = summary(conv2, input_size=(1, m, h, w))print(f"Actual multiplies: {s2.total_mult_adds}")print(s2)
これは以下を出力します。
Expected total multiplies: 10747904Actual multiplies: 10747904==========================================================================================Layer (type:depth-idx) Output Shape Param #==========================================================================================DepthwiseSeparableConv [1, 32, 128, 128] --├─Conv2d: 1-1 [1, 16, 128, 128] 144├─Conv2d: 1-2 [1, 32, 128, 128] 512==========================================================================================Total params: 656Trainable params: 656Non-trainable params: 0Total mult-adds (M): 10.75==========================================================================================Input size (MB): 1.05Forward/backward pass size (MB): 6.29Params size (MB): 0.00Estimated Total Size (MB): 7.34==========================================================================================
いくつかの例を比較して、両方の畳み込みのサイズとコストを比較してみましょう。
通常の畳み込みと深度方向分離畳み込みのサイズとコストの比較
通常の畳み込みと深度方向分離畳み込みのサイズとコストを比較するために、ネットワークへの入力サイズを128 x 128、カーネルサイズを3 x 3、および空間次元を半分にし、チャネル次元を2倍にするネットワークを仮定します。各ステップで単一の2D-convレイヤーを仮定しますが、実際にはそれ以上のレイヤーがある場合があります。
上記の構成に対して、DSCのサイズとコンピューテーションコストは、平均して通常の畳み込みのコストの約11%から12%になることがわかります。
畳み込みの種類とその相対的なコストについて理解を深めたところで、DSCを使用することにデメリットがあるかどうか気になるはずです。これまで見てきたすべてのことは、あらゆる点でDSCが優れているように思われます!しかし、モデルの精度に与える影響という重要な側面はまだ考慮していません。以下の実験を通じて探ってみましょう。
Depthwise Separable Convolutionsを使用したSegNet
このノートブックには、このセクションのすべてのコードが含まれています。
前の記事からSegNetモデルを適応し、すべての通常の畳み込み層をDSC層に置き換えます。これを行うと、ノートブックのパラメータ数が15.27Mから1.75Mのパラメータに減少し、88.5%の削減になります!これは、ネットワークの学習可能なパラメータの削減率が11%から12%であるという以前の見積もりと一致しています。
モデルのトレーニングと検証には前と同様の構成が使用されました。以下にその構成を示します。
- 過学習を防ぐために、ランダムな水平反転と色のジッターのデータ拡張をトレーニングセットに適用する
- 画像は、アスペクト比を維持しないリサイズ操作で128×128ピクセルにリサイズされる
- 画像に入力正規化は適用されない。代わりに、バッチ正規化層がモデルの最初の層として使用される
- モデルはAdamオプティマイザを使用して20エポックでトレーニングされ、LRは0.001で、LRスケジューラは使用されない
- ピクセルをペット、背景、またはペットの境界に属するものとして分類するため、クロスエントロピー損失関数が使用される
モデルは、20のトレーニングエポック後に検証精度86.96%を達成しました。これは、同じ数のトレーニングエポックを使用して通常の畳み込みを使用したモデルが達成した88.28%の精度よりも低いです。我々は実験的に、より多くのエポックでトレーニングすると両方のモデルの精度が向上することを確認しました。つまり、20エポックはトレーニングサイクルの終わりではないということです。今回の記事では、デモンストレーションの目的のために20エポックで終了します。
以下のgifは、検証セットの21の画像のセグメンテーションマスクを予測する方法を示しています。
モデルがトレーニングサイクルを通じてどのように進行しているかを見たので、通常の畳み込みとDSCを使用したモデルのトレーニングサイクルを比較してみましょう。
精度の比較
通常の畳み込みとDSCを使用したモデルのトレーニングサイクルを見ることが有益であることがわかりました。主な違いは、トレーニングの初期段階(エポック)で起こり、その後、両方のモデルがほぼ同じ予測フローに落ち着くことです。実際に、通常の畳み込みを使用したモデルと同じ数のエポックをトレーニングした後、DSCを使用したモデルの精度は通常の畳み込みを使用したモデルよりもわずかに低く、1%程度です。これは、20エポックのトレーニングからの観察結果と一致しています。
あなたは、両方のモデルが6つのトレーニングエポック後に予測をほぼ正しく行っていることに気付いたでしょう – つまり、モデルが何か有用なものを予測していることが視覚的にわかります。その後、モデルをトレーニングして、予測マスクの境界ができるだけタイトで、画像内の実際のペットにできるだけ近くなるようにすることが重要になります。つまり、後期トレーニングエポックでの精度の絶対的な向上は少ないと予想されますが、予測品質への影響ははるかに大きいです。私たちは、高い絶対精度値(89%から90%に移行する)での精度の向上が、予測の質的改善につながることに気付きました。
UNetモデルとの比較
私たちは多くのハイパーパラメータを変更し、全体的な精度を改善することに焦点を当てた実験を実施し、この設定が最適に近いかどうかを把握しました。以下はその実験の構成です。
- 画像サイズ:128 x 128 — 現在の実験と同じ
- トレーニングエポック:100 — 現在の実験は20エポックでトレーニングされています
- Augmentations:画像回転、チャネルドロップ、ランダムブロック削除など、より多くのAugmentations。torchvision transformsの代わりにAlbumentationsを使用しました。Albumentationsはセグメンテーションマスクを自動的に変換します
- LRスケジューラ:StepLRスケジューラを使用し、25回のトレーニングエポックごとに0.8xの減衰を行いました
- 損失関数:Cross Entropy、Focal、Dice、Weighted Cross Entropyの4つの損失関数を試しました。Diceが最も悪く、残りの3つはほぼ同等でした。実際、100エポック後の最高精度の差は、小数点以下の4桁目にありました(精度が0.0から1.0の間の数であると仮定した場合)
- 畳み込みタイプ:通常
- モデルタイプ:UNet — 現在の実験ではSegNetモデルを使用しました
上記の設定で最高の検証精度は91.3%を達成しました。画像サイズが最高の検証精度に大きな影響を与えることに気付きました。例えば、画像サイズを256 x 256に変更すると、最高の検証精度は93.0%に向上します。ただし、トレーニングにははるかに時間がかかり、より多くのメモリを使用するため、バッチサイズを減らさなければなりませんでした。
従来のものに比べて、予測がはるかにスムーズで鮮明であることがわかります。
結論
このシリーズのパート3では、モデルサイズとトレーニング/推論コストを大幅に削減するテクニックとして、深度分離畳み込み(DSC)について学びました。特定の設定における通常とDSCのサイズ/コストのトレードオフを理解することができました。
PyTorchでSegNetモデルをDSCに適応する方法を示しました。このテクニックは、どの深いCNNにも適用できます。実際、一部の畳み込み層をDSCで置き換えることができます。すなわち、すべてを置き換える必要はありません。モデルサイズ/ランタイムコストと予測精度のバランスをどのように取るかは、特定のユースケースと展開セットアップに依存します。
この記事では、20エポックのモデルをトレーニングしましたが、これはプロダクションワークロードには不十分であり、モデルをより多くのエポックでトレーニングした場合に何が期待できるかを示しました。さらに、モデルトレーニング中にチューニングできるハイパーパラメータのいくつかについて紹介しました。このリストは完全ではありませんが、プロダクションワークロードの画像セグメンテーションモデルをトレーニングするために必要な複雑さと意思決定を理解することができます。
このシリーズの次の部分では、Vision Transformersを紹介し、このモデルアーキテクチャを使用してpetsセグメンテーションタスクの画像セグメンテーションを行う方法を説明します。
参考文献と追加の読書
- Efficient Deep Learning Book Chapter 04 — Efficient Architectures
- A Basic Introduction to Separable Convolutions
We will continue to update VoAGI; if you have any questions or suggestions, please contact us!
Was this article helpful?
93 out of 132 found this helpful
Related articles