web-dev-qa-db-ja.com

Kerasのsample_weightを使用したシーケンスのラベル付け

不均衡なクラスでの順次ラベル付けの問題に取り組んでおり、_sample_weight_を使用して不均衡の問題を解決したいと思います。基本的に、モデルを約10エポックにわたってトレーニングすると、素晴らしい結果が得られます。より多くのエポックをトレーニングする場合、_val_loss_は低下し続けますが、より悪い結果が得られます。私は、モデルがより小さなクラスの不利益に対してより多くの支配的なクラスを検出するだけだと思います。

モデルには、Word埋め込みと文字埋め込みの2つの入力があり、入力は0から6までの7つの可能なクラスの1つです。

パディングを使用すると、Word埋め込みの入力レイヤーの形状は_(3000, 150)_になり、Word埋め込みの入力レイヤーは_(3000, 150, 15)_になります。データのテストとトレーニングに0.3分割を使用します。つまり、Word埋め込みの_X_train_は_(2000, 150)_であり、char埋め込みの_(2000, 150, 15)_です。 yには、7次元のワンホットベクトルでエンコードされた各Wordの正しいクラスが含まれているため、その形状は_(3000, 150, 7)_です。 yも同様にトレーニングセットとテストセットに分割されます。その後、各入力は双方向LSTMに送られます。

出力は、2000のトレーニングサンプルの各Wordに割り当てられた7つのカテゴリの1つを持つ行列なので、サイズは_(2000, 150, 7)_です。


最初は、単純に_sample_weight_を、各クラスの重みを含む長さ7の_np.array_として定義しようとしました:

_count = [list(array).index(1) for arrays in y for array in arrays]
count = dict(Counter(count))
count[0] = 0
total = sum([count[key] for key in count])
count = {k: count[key] / total for key in count}
category_weights = np.zeros(7)
for f in count:
    category_weights[f] = count[f]
_

しかし、次のエラーが発生しますValueError: Found a sample_weight array with shape (7,) for an input with shape (2000, 150, 7). sample_weight cannot be broadcast.

ドキュメントを見ると、代わりにa 2D array with shape (samples, sequence_length)を渡す必要があるようです。したがって、各シーケンスのすべてのWordの重みを連結した_(3000, 150)_配列を作成します。

_weights = []

for sample in y:
    current_weight = []
    for line in sample:
        current_weight.append(frequency[list(line).index(1)])
    weights.append(current_weight)

weights = np.array(weights)
_

compile()に_sample_weight_オプションを追加した後、それを_sample_weight_mode="temporal"_パラメーターを介してフィット関数に渡します。

最初に、ディメンションが間違っているというエラーが発生しましたが、トレーニングサンプルのみの重みを生成した後、モデルの適合に使用できる_(2000, 150)_配列が作成されます。


  • これはsample_weightsを定義する適切な方法ですか、それとも間違っていますか?重みを追加したことによる改善に気付いたとは言えないので、何かを見落としていたに違いありません。
8
user2969402

_sample_weights_と_class_weights_は紛らわしいと思います。 docs を確認すると、それらの違いが少しわかります。

_sample_weights_は、eachトレーニングサンプルの重みを提供するために使用されます。つまり、トレーニングサンプルと同じ数の要素を持つ1D配列を渡す必要があります(これらの各サンプルの重みを示します)。テンポラルデータを使用している場合は、代わりに2D配列を渡して、各サンプルの各タイムステップに重みを付けることができます。

_class_weights_は、each出力クラスの重みまたはバイアスを提供するために使用されます。つまり、分類しようとしているクラスごとに重みを渡す必要があります。さらに、このパラメーターは、辞書が渡されることを期待しています(配列ではないため、エラーが発生します)。たとえば、次の状況を考えます。

_class_weight = {0 : 1. , 1: 50.}
_

この場合(バイナリ分類の問題)、クラス_1_のサンプルに、クラス_0_と比較して50倍の重み(または「関連性」)を与えています。このようにして、不均衡なデータセットを補正できます。これは別の便利な post であり、不均衡なデータセットを処理するときに考慮するこのオプションや他のオプションについて詳しく説明しています。

より多くのエポックをトレーニングする場合、val_lossは低下し続けますが、より悪い結果が得られます。

おそらくあなたは過剰適合であり、あなたが正しく疑っていたように、それに貢献しているかもしれない何かはあなたのデータセットが持っている不均衡なクラスです。クラスの重みを補正することでこれを軽減できますが、この質問/回答の範囲を超える過剰適合を引き起こす可能性がある他の要因がまだある可能性があります(そのため、この質問を解決した後は注意してください)。


あなたの投稿から判断すると、トレーニングのためにデータセットのバランスを取るために_class_weight_を使用する必要があると私には思われます。これには、dictionaryを渡して、あなたの7つのクラス間の重量比。 eachサンプルに考慮のためにカスタムの重みを与える場合にのみ、_sample_weight_の使用を検討してください。

これら2つの間のより詳細な比較が必要な場合は、チェックを検討してください この回答 関連する質問に投稿しました。 スポイラー:_sample_weight_は_class_weight_をオーバーライドするため、どちらか一方を使用する必要がありますが、両方を使用する必要はありません。それらを混ぜません。


更新:この編集(2020年3月27日)の時点で、training_utils.standardize_weights()これで、both_class_weights_と_sample_weights_の両方がサポートされるようになりました。

すべてが単一のサンプル単位(またはタイムステップ単位)の重み配列に正規化されます。 _sample_weights_と_class_weights_の両方が指定されている場合、重みは一緒に乗算されます。

11
DarkCygnus