最近、CV コンテストに参加したところ、画像認識モデルをトレーニングするときによく使用するヒントを参加者が共有しているのを見たので、今後の学習を容易にするためにそれらを記録して整理しました。たくさんのことを整理しました。毎回役立つとは限りませんが、将来特定のタスクで役割を果たす可能性があることを覚えておいてください。
主に次の9つの側面からです。
画像補正
より良いモデル
学習率とスケジューラ
オプティマイザ
正則化手段
ラベルのスムージング
知識の蒸留
疑似ラベル
エラー分析
1. 画像補正
以下に挙げる強化方法は数多くありますが、中にはまだ見たこともない強化方法もありますが、すべての強化方法が有益であるわけではなく、タスクや実験に応じて適切な強化方法を選択する必要があります。
色の強調
カラースキュー:
この強化では、各チャネルにランダムに選択された係数を乗算することで、画像の色相、彩度、明るさをランダムに調整します。結果の画像が過度に歪まないように、係数は [0:6;1:4] の範囲から選択されます。
def color_skew(image):
h, s, v = cv2.split(image)
h = h * np.random.uniform(low=0, high=6)
s = s * np.random.uniform(low=1, high=4)
v = v * np.random.uniform(low=0, high=6)
return cv2.merge((h, s, v))
RGB ノルム:
この拡張では、各チャネルの値から平均値を減算し、チャネルの標準偏差で割ることにより、画像の RGB チャネルを正規化します。これは画像内の値を正規化するのに役立ち、モデルのパフォーマンスを向上させることができます。
def rgb_norm(image):
r, g, b = cv2.split(image)
r = (r - np.mean(r)) / np.std(r)
g = (g - np.mean(g)) / np.std(g)
b = (b - np.mean(b)) / np.std(b)
return cv2.merge((r, g, b))
黒と白:
この拡張機能では、画像をグレースケール色空間に変換することにより、画像を白黒に変換します。
defblack_and_white(image):
return cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
ベン・グラハム: グレースケール + ガウスぼかし:
この拡張機能では、画像をグレースケールに変換し、ガウスぼかしを適用して画像内のノイズやディテールを滑らかにします。
def ben_graham(image):
image = cv2.cvtColor(image, cv2.COLOR_RGB2HSV)
image = cv2.GaussianBlur(image, (5, 5), 0)
return image
色相、彩度、明度:
この拡張により、画像が HLS 色空間に変換され、画像が色相、彩度、明度のチャネルに分割されます。
def hsb(image):
return cv2.cvtColor(image, cv2.COLOR_RGB2HLS)
LUV 色空間:
この機能強化により、画像が LUV 色空間に変換されます。LUV 色空間は、知覚的に一貫性があり、より正確な色の比較ができるように設計されています。
def luv(image):
return cv2.cvtColor(image, cv2.COLOR_RGB2LUV)
アルファチャンネル:
この機能強化により、画像にアルファ チャネルが追加され、透明度を高めるために使用できます。
def alpha_channel(image):
return cv2.cvtColor(image, cv2.COLOR_RGB2RGBA)
YZ色空間:
この機能強化により、画像が XYZ カラー スペースに変換されます。XYZ カラー スペースは、より正確なカラー表現を可能にするデバイスに依存しないカラー スペースです。
def xyz(image):
return cv2.cvtColor(image, cv2.COLOR_RGB2XYZ)
ルマクロマ:
この拡張機能により、画像が YCrCb 色空間に変換され、画像がルマ (明るさ) チャネルとクロマ (色) チャネルに分離されます。
def luma_chroma(image):
return cv2.cvtColor(image, cv2.COLOR_RGB2YCrCb)
CIEラボ:
この機能強化により、画像が知覚的に均一になるように設計された CIE Lab 色空間に変換され、より正確な色比較が可能になります。
def cie_lab(image):
return cv2.cvtColor(image, cv2.COLOR_RGB2Lab)
YUV色空間:
この拡張機能により、画像が YUV 色空間に変換され、画像がルマ (明るさ) チャネルとクロマ (色) チャネルに分離されます。
def yuv(image):
return cv2.cvtColor(image, cv2.COLOR_RGB2YUV)
センタークロップ:
この拡張機能は、アスペクト比 [3/4,4/3] の長方形領域をランダムにトリミングし、次に [8%,100%] の間の係数でトリミングをランダムに拡大縮小し、最後にトリミングを img_{size} * に調整します。 img_ {size} img_{size} * img_{size} の正方形。これはバッチごとにランダムに行われます。
transforms.CenterCrop((100, 100))
フリッピング:
この拡張により、画像がランダムに水平方向に反転される可能性が高まります。たとえば、確率が 0.5 の場合、画像が水平方向に反転する確率は 50% です。
def flippings(image):
if np.random.uniform() < 0.5:
image = cv2.flip(image, 1)
return image
ランダムクロップ:
この拡張により、画像から長方形の領域がランダムに切り取られます。
transforms.RandomCrop((100, 100))
ランダムにサイズ変更されたクロップ:
この拡張により、画像の長方形領域がランダムにサイズ変更され、トリミングされます。
transforms.RandomResizedCrop((100, 100))
カラージッター:
この強化により、画像の明るさ、コントラスト、彩度、色相がランダムに調整されます。
transforms.ColorJitter(brightness=0.5, contrast=0.5, saturation=0.5, hue=0.5)
ランダムアフィン:
この拡張により、回転、スケーリング、せん断などのアフィン変換が画像にランダムに適用されます。
transforms.RandomAffine(degrees=45,translate=(0.1,0.1),scale=(0.5,2.0),shear=45)
ランダムな水平反転:
確率 0.5 でランダムに画像を水平方向に反転します。
transforms.RandomHorizontalFlip()
ランダムな垂直反転:
この拡張により、画像が 0.5 の確率でランダムに垂直方向に反転されます。
transforms.RandomVerticalFlip()
ランダムな視点:
この拡張により、画像に透視変換がランダムに適用されます。
transforms.RandomPerspective()
ランダムな回転:
この拡張により、画像が指定された角度範囲でランダムに回転されます。
transforms.RandomRotation(degrees=45)
ランダム反転:
この強化により、画像の色がランダムに反転されます。
transforms.RandomInvert()
ランダムなポスタリゼーション:
この増強により、各ピクセル値を表すために使用されるビット数がランダムに削減され、色分離効果が生まれます。
transforms.RandomPosterize(bits=4)
ランダムソラリゼーション:
この強化により、画像に露出効果がランダムに適用され、特定の強度しきい値を超えるピクセルが反転されます。
transforms.RandomSolarize(threshold=128)
ランダムオートコントラスト:
この拡張機能は、利用可能な範囲全体にわたって強度値を拡張することにより、画像のコントラストをランダムに調整します。
transforms.RandomAutocontrast()
ランダムイコライズ:
この拡張により、画像のヒストグラムがランダムに均等化され、コントラストが増加します。
transforms.RandomEqualize()
より高度な機能強化
上記の基本的な強化方法に加えて、より高度な強化方法がいくつかあります。
自動拡張:
自動拡張は、強化学習を使用して特定のデータセットに最適な拡張戦略を検索する拡張方法です。画像分類モデルのパフォーマンスが向上することが示されています。
from autoaugment import AutoAugment
auto_augment = AutoAugment()
image = auto_augment(image)
高速自動拡張:
高速自動拡張は、自動拡張メソッドのより高速な実装です。ニューラル ネットワークを使用して、特定のデータセットに対する最適な拡張戦略を予測します。
from fast_autoaugment import FastAutoAugment
fast_auto_augment = FastAutoAugment()
image = fast_auto_augment(image)
オーミックス:
Augmix は、複数の拡張画像を組み合わせて、より多様でリアルな単一の画像を作成する拡張方法です。画像分類モデルの堅牢性と一般化が向上することが示されています。
from augmix import AugMix
aug_mix = AugMix()
image = aug_mix(image)
ミックスアップ/カットアウト:
ミックスアップは、ピクセル値を線形補間して 2 つの画像を結合する拡張手法です。カットアウトは、画像から長方形の領域をランダムに削除する拡張方法です。これらの方法は、画像分類モデルの堅牢性と一般化を向上させることが示されています。
"You take a picture of a cat and add some "transparent dog" on top of it. The amount of transparency is a hyperparam."
x=lambda*x1+(1-lambda)x2,
y=lambda*x1+(1-lambda)y2
テスト時間拡張(TTA)
画像拡張は、トレーニング中だけでなくテスト中にも役立ちます。テスト フェーズの場合は、TTA と呼ばれます。テスト セットの画像を複数の拡張機能で取得し、それを予測に適用し、結果を平均するだけです。この方法では予測の堅牢性を高めることができますが、それに応じて時間も増加します。テスト セットを強化する場合、画像スケールの変更、別の場所のトリミング、反転などの高度すぎる強化方法には適していません。
個人的には、このアプローチは競技会でのみ使用されるべきだと思います〜
2. より良いモデル
以下のモデルは現在から数年離れていますが、その卓越したパフォーマンスにより、依然として競争の最前列を占めています。近年、より優れたモデルが生産されていますが、多くのモデルはオープンソースではなく、大きすぎるため、まだ開発されていません。利用可能になり、より広く使用されるようになります。
tf_efficientnetv1,v2系列
seresnext
試してみたいアイデアやモデルもいくつかあります。
Swin Transformer
BeIT Transformer
ViT Transformers
バックボーンの背後にさらに隠れたレイヤーを追加します
レイヤーを追加すると、より高度な機能を学習できるため有益ですが、大規模な事前トレーニング済みモデルの微調整が容易になり、モデルのパフォーマンスが低下する可能性もあります。
層ごとに解凍します
小さな改善をもたらす簡単なトリックは、トレーニングの進行に応じて、事前トレーニングされたバックボーンのレイヤーをフリーズ解除することです。まずレイヤーを追加してバックボーンをフリーズし、次にバックボーンのパラメータをゆっくりとフリーズ解除してトレーニングに参加できるようにします。
## Weight freezing
for param in model.parameters():
param.requires_grad = False
## Weight unfreezing
for param in model.parameters():
param.requires_grad = True
TensorFlow でのウェイトの凍結と凍結解除
## Weight freezing
layer.trainable = False
## Weight unfreezing
layer.trainable = True
3. 学習率とスケジューラ
学習率と学習率スケジューラは、モデルのトレーニング パフォーマンスに影響を与えます。学習率を変更すると、パフォーマンスとトレーニングの収束に大きな影響を与える可能性があります。
学習率スケジューラ
最近、1 サイクル コサイン スケジュールが複数のタスクでより良い結果をもたらすことが示されており、次のように使用できます。
PyTorch での 1 サイクル コサイン スケジューリング
from torch.optim.lr_scheduler import CosineAnnealingLR
optimizer = torch.optim.Adam(optimizer_grouped_parameters, lr=args.learning_rate, eps=args.adam_epsilon)
#这里使用
scheduler = CosineAnnealingLR(optimizer, T_max=num_train_optimization_steps)
num_training_steps = num_train_optimization_steps / args.gradient_accumulation_steps
# Update the scheduler
scheduler.step()
# step the learning rate scheduler here,
# you will want to step the learning rate scheduler only once per optimizer step nothing more nothing less.
# So in this case, it should be called before you expect the gradients to be applied.
テンソルフロー
## One Cycle Cosine scheduling in TensorFlow
optimizer = tf.keras.optimizers.Adam(learning_rate)
scheduler = tf.keras.optimizers.schedules.CosineDecay(learning_rate, decay_steps=num_training_steps)
学習率スケジューラの使用に関するヒント
「三角法」または「ワンサイクリック」法を使用した学習率の調整は、微妙ではあるが大幅な改善をもたらす可能性があります。これらの学習率スケジューリングのインテリジェントな方法により、一部のバッチ サイズの問題を克服できます。
タスクと使用するモデルに最適な学習率スケジュール方法を調査することに時間を費やすことは、モデルがどのように収束するかに関して非常に重要です。
学習率のスケジューリング戦略を使用して、より低いバッチサイズまたは複数の学習率でモデルをトレーニングできます。
学習率が重要であることは誰もが知っているので、まず低い学習率を試して、学習率を上げることがモデルのパフォーマンスに役立つか悪影響を与えるかを確認してください。
トレーニングの後半で、学習率または複数の学習率、バッチサイズ、勾配累積、または学習率スケジュール戦略を増やすと、モデルの収束が向上する場合があります。これは、パフォーマンスに悪影響を与える場合があるため、高度なテクニックです。ただし、値が大きすぎる場合に限ります。覚えておいてください。それをテストするために。
損失スケーリングは、勾配累積、複数の学習率、または高いバッチ サイズを使用する場合に、損失の分散を削減し、勾配フローを改善するのに役立ちます。ただし、バッチ サイズを増やすことで問題を解決しようとしている場合は、学習率を上げてみると、より良い結果が得られる場合があります。パフォーマンス。
4. オプティマイザー
最近では、Adam または AdamW を使用する人がたくさんいます。Adam オプティマイザーから最高のパフォーマンスを引き出したい場合は、次のことを知っておく必要があります。
最適な重量減衰値を見つけるのは、多くの実験 (そして運) に依存するため、面倒な場合があります。
もう 1 つの重要なハイパーパラメータは、Adam オプティマイザーで使用される beta1 と beta2 で、最適な値の選択はタスクとデータによって異なります。多くの新しいミッションは、低いベータ 1 と高いベータ 2 から恩恵を受けますが、確立されたミッションではその逆になります。繰り返しになりますが、実験はあなたの親友になります。
Adam オプティマイザーの世界では、最初のルールは、オプティマイザーのイプシロン値の重要性を過小評価しないことです。最適な重み減衰ハイパーパラメータを見つけるのと同じ原則がここにも適用されます。
グラデーション クリッピング ノルムを使いすぎないでください。これは、グラデーションが爆発するときに役立つこともありますが、その逆も同様です。一部のタスクでは収束が妨げられる可能性があります。
勾配の累積には、依然としていくつかの微妙な利点が得られます。私は通常、約 2 ステップの勾配を累積しますが、GPU のメモリが不足していない場合は、最大 8 ステップの勾配の累積をプッシュできます。勾配累積は、混合精度を使用する場合にも役立ちます。
また、十分な時間をかけて SGD の運動量を調整すると、より良い結果が得られる可能性がありますが、これも多くの調整が必要です。
他にもいくつかの注目すべきオプティマイザーがあります。
AdamW: これは、外部モデルの重みの指数関数的な重み減衰を防ぎ、デフォルトの重みを下回るペナルティ付きのオーバーボリュームを奨励する Adam アルゴリズムの拡張機能です。
Adafactor: メモリ使用量が少なく、スケーラビリティが高いように設計されています。オプティマイザーは複数の GPU を使用して、オプティマイザーの優れたパフォーマンスを提供できます。
Novograd: 基本的には別の Adam のようなオプティマイザーですが、より優れた機能を備えています。これは、bert-large モデルのトレーニングに使用されるオプティマイザーの 1 つです。
Ranger: Ranger オプティマイザーは、パフォーマンス最適化ソリューションで優れた結果を達成している非常に興味深いオプティマイザーですが、あまり知られておらず、サポートされていません。
Lamb: GLUE および QQP コンテストの優勝者によって開発された、GPU に最適化された再利用可能な Adam オプティマイザー。
Lookahead: 他のオプティマイザーの上で使用できる人気のオプティマイザーで、パフォーマンスがある程度向上します。
5. 正則化手段
ドロップアウトを使おう!通常、レイヤー間にドロップアウトを追加すると、トレーニングの安定性が高まり、結果の信頼性が高まります。これを隠れレイヤーで使用します。ドロップアウトはパフォーマンスをわずかに改善するために使用することもできます。トレーニング前にレイヤーのドロップアウトを設定してみてください。タスクとモデル。
正則化:ニューラル ネットワークが過学習または過小学習している場合、正則化によりパフォーマンスが大幅に向上します。通常の機械学習モデルの場合は、L1 または L2 正則化で問題ありません。
アイデアをテストするには常に実験を使用してください。実験を使用してください。実験。モデルを実験して試してみましょう。
複数の検証:複数の検証を使用すると、過学習に対するモデルの堅牢性を向上させることができます。ただし、これには計算時間がかかります。
6. ラベルのスムージング
論文リンク:
ラベルのスムージングはどのような場合に役立ちますか?:
https://arxiv.org/pdf/1906.02629.pdf
核となる式は 1 行に要約されています。
通常はうまく機能し、多くのゲームで見られます。バイナリ分類タスクを例として、ラベル スムージングのサンプル コードを以下に示します。これは直接使用できます。
テンソルフロー:
loss = BinaryCrossentropy(label_smoothing = label_smoothing)
ピトーチ:
from torch.nn.modules.loss import _WeightedLoss
class SmoothBCEwLogits(_WeightedLoss):
def __init__(self, weight = None, reduction = 'mean', smoothing = 0.0, pos_weight = None):
super().__init__(weight=weight, reduction=reduction)
self.smoothing = smoothing
self.weight = weight
self.reduction = reduction
self.pos_weight = pos_weight
@staticmethod
def _smooth(targets, n_labels, smoothing = 0.0):
assert 0 <= smoothing < 1
with torch.no_grad(): targets = targets * (1.0 - smoothing) + 0.5 * smoothing
return targets
def forward(self, inputs, targets):
targets = SmoothBCEwLogits._smooth(targets, inputs.size(-1), self.smoothing)
loss = F.binary_cross_entropy_with_logits(inputs, targets,self.weight, pos_weight = self.pos_weight)
if self.reduction == 'sum': loss = loss.sum()
elif self.reduction == 'mean': loss = loss.mean()
return loss
7. 知識の蒸留
大規模な教師ネットワークを使用して、小規模なネットワークの学習を指導します。
ステップ:
大規模なモデルをトレーニングする: データに基づいて大規模なモデルをトレーニングします。
ソフト ラベルの計算: トレーニングされた大規模モデルを使用してソフト ラベルを計算します。つまり、大規模モデルが「ソフト化」された後のソフトマックスの出力
学生モデルのトレーニング: 大規模モデルに基づいて、追加のソフト ラベル損失関数としての教師の出力に基づいて学生モデルをトレーニングし、補間によって 2 つの損失関数の比率を調整します。
8. 疑似ラベル付け
モデルを使用してラベルのないデータ (テスト データなど) にラベルを付けた後、新しいラベルの付いたデータを使用してモデルを再トレーニングします。
ステップ:
教師モデルをトレーニングする: 持っているデータに基づいてモデルをトレーニングします。
擬似ラベルの計算: トレーニングされた大規模モデルを使用して、ラベルのないデータのソフト ラベルを計算します。
モデルによって「確実」なターゲットのみを使用する:エラーをできる限り回避するために、疑似ラベルとして最も信頼性の高い予測のみを使用します。(そうしないと機能しない可能性があります)
Studnet モデルのトレーニング: 新しいラベル付きデータを使用して学生モデルをトレーニングします。
9. エラー分析
研修の際、パラメータを調整するだけで分析の仕方が分からない人も多く、社内では分析の悪い事例という言葉をよく聞きます。それは同様に重要であり、時には追加のアイデアを提供することもあります。時間を大幅に節約できる重要な方法は、モデルを使用して、より困難なデータ サンプルや破損したデータ サンプルを見つけることです。画像は、小さなターゲット オブジェクト、異なる色、切り取られたターゲット、無効な注釈など、さまざまな理由によりモデルにとって「より困難」になる可能性があります。理由を考えてみてください。役立つかもしれません。
間違いは時には良い知らせになります!
これらは、トップリーダーと残りのプレーヤーを区別するサンプルです。モデルで何が起こっているのかを説明するのが難しい場合は、モデルが遭遇した検証サンプルを見てください。
モデルのエラーを見つけよう!
エラーを見つける最も簡単な方法は、検証サンプルをモデルの信頼スコアで並べ替えて、どのサンプルの予測信頼度が最も低いかを確認することです。
mistakes_idx = [img_idx for img_idx in range(len(train)) if int(pred[img_idx] > 0.5) != target[img_idx]]
mistakes_preds = pred[mistakes_idx]
sorted_idx = np.argsort(mistakes_preds)[:20]
# Show the images of the sorted idx here..
要約する
上記では、たくさんのことを整理しました。毎回役立つわけではないかもしれませんが、将来的には特定のタスクで役割を果たす可能性があることを覚えておいてください。