web-dev-qa-db-ja.com

クラスの不均衡への取り組み:損失とSGDへの寄与のスケーリング

(この質問に対する更新が追加されました。)

私はベルギーのゲント大学の大学院生です。私の研究は、深い畳み込みニューラルネットワークによる感情認識に関するものです。 Caffe フレームワークを使用してCNNを実装しています。

最近、クラスの不均衡に関する問題に遭遇しました。約9216のトレーニングサンプルを使用しています。 5%は正のラベルが付けられ(1)、残りのサンプルは負のラベルが付けられます(0)。

SigmoidCrossEntropyLoss レイヤーを使用して損失を計算しています。トレーニングすると、損失が減少し、数エポック後でも精度が非常に高くなります。これは不均衡が原因です。ネットワークは常に負(0)を予測するだけです。 (精度と再現率はどちらもゼロであり、この主張を裏付けています)

この問題を解決するために、私は予測-真の組み合わせに応じて損失への寄与をスケーリングする(偽陰性を厳しく罰する)にします。メンター/コーチはバックプロパゲーション時にスケール係数を使用するようにアドバイスしました確率的勾配降下法(sgd)を使用:係数はバッチ内の不均衡に相関します。負のサンプルのみを含むバッチは、重みをまったく更新しません。

Caffeにカスタムレイヤーを1つだけ追加しました:精度や再現率などの他のメトリックを報告します。 Caffeコードの使用経験は限られていますが、C++コードの記述には多くの専門知識があります。


SigmoidCrossEntropyLoss および Sigmoid レイヤーを調整して次の変更に対応する方法について、誰かが私を助けたり正しい方向に向けたりできますか:

  1. 予測と真の組み合わせ(真陽性、偽陽性、真陰性、偽陰性)に応じて、サンプルの合計損失への寄与を調整します。
  2. バッチの不均衡に応じて、確率的勾配降下法によって実行される重みの更新をスケーリングします(負と正)。

前もって感謝します!


更新

InfogainLossLayerShaiで推奨されているように組み込んでいます。また、infogainマトリックスHを構築する別のカスタムレイヤーを追加しました現在のバッチの不均衡に基づいています。

現在、マトリックスは次のように構成されています。

H(i, j) = 0          if i != j
H(i, j) = 1 - f(i)   if i == j (with f(i) = the frequency of class i in the batch)

私は将来、マトリックスのさまざまな構成を試すことを計画しています。

私はこれを10:1の不均衡でテストしました。結果は、ネットワークが現在有用なことを学習していることを示しています:(30エポック後の結果)

  • 精度は約です。 〜70%(〜97%から減少);
  • 精度は約です。 〜20%(0%から増加);
  • リコールは約です。 〜60%(0%から増加)。

これらの数値は約20エポックで到達し、その後は大幅に変化しませんでした。

!!上記の結果は単なる概念実証であり、10:1の不均衡データセットで単純なネットワークをトレーニングすることで得られたものです。 !!

32
Maarten Bamelis

InfogainLoss レイヤーを使用して、トレーニングセットの不均衡を補正しませんか?

Infogainの損失は、重み行列H(この場合は2行2列)を使用して定義されます。そのエントリの意味は次のとおりです。

[cost of predicting 1 when gt is 0,    cost of predicting 0 when gt is 0
 cost of predicting 1 when gt is 1,    cost of predicting 0 when gt is 1]

したがって、Hのエントリを設定して、0または1の予測におけるエラー間の違いを反映できます。

this thread でcaffeの行列Hを定義する方法を見つけることができます。

サンプルの重みに関して、あなたは この投稿 を見つけるかもしれません:サンプルの重みを考慮に入れるためにSoftmaxWithLossレイヤーを変更する方法を示しています。


最近、クロスエントロピー損失の修正が提案されました Tsung-Yi Lin、Priya Goyal、Ross Girshick、Kaiming He、PiotrDollár高密度オブジェクト検出の焦点損失、(ICCV 2017)
フォーカルロスの背後にある考え方は、この例を予測することの相対的な難しさに基づいて(むしろクラスサイズなどに基づいて)各例に異なる重みを割り当てることです。この損失を試してみた短い時間から、クラスサイズの重みを持つ"InfogainLoss"よりも優れていると感じています。

20
Shai

また、分類タスクでこのクラスの不均衡の問題に遭遇しました。現在私はCrossEntropyLossを重み付きで使用しています(ドキュメント here )が正常に機能します。アイデアは、画像の数が少ないクラスのサンプルにより多くの損失を与えることです。

重量の計算

各クラスの重みは、このクラスの画像番号に反比例します。以下は、numpyを使用してすべてのクラスの重みを計算するスニペットです。

cls_num = []
# train_labels is a list of class labels for all training samples
# the labels are in range [0, n-1] (n classes in total)
train_labels = np.asarray(train_labels)
num_cls = np.unique(train_labels).size

for i in range(num_cls):
    cls_num.append(len(np.where(train_labels==i)[0]))

cls_num = np.array(cls_num)

cls_num = cls_num.max()/cls_num
x = 1.0/np.sum(cls_num)

# the weight is an array which contains weight to use in CrossEntropyLoss
# for each class.
weight = x*cls_num
0
jdhao