回答:
ネットワークが1つの出力のみを生成する通常のケースについて話している場合、仮定は正しいです。アルゴリズムがクラス1のすべてのインスタンスをクラス0の 50インスタンスとして処理するように強制するには、以下を行う必要があります。
ラベルとそれに関連する重みで辞書を定義する
class_weight = {0: 1.,
1: 50.,
2: 2.}
辞書をパラメーターとしてフィードします。
model.fit(X_train, Y_train, nb_epoch=5, batch_size=32, class_weight=class_weight)
編集:「クラス1のすべてのインスタンスをクラス0の 50インスタンスとして扱う」とは、損失関数でこれらのインスタンスにより高い値を割り当てることを意味します。したがって、損失は加重平均になります。各サンプルの重みは、class_weightとその対応するクラスによって指定されます。
Keras docsから:class_weight:クラスインデックス(整数)を重み(浮動)値にマッピングするオプションの辞書。損失関数の重み付けに使用します(トレーニング中のみ)。
単にclass_weight
fromを実装できますsklearn
:
最初にモジュールをインポートしましょう
from sklearn.utils import class_weight
クラスの重みを計算するには、次を実行します
class_weights = class_weight.compute_class_weight('balanced',
np.unique(y_train),
y_train)
第三に、最後にモデルのフィッティングに追加します
model.fit(X_train, y_train, class_weight=class_weights)
注意:私はこの記事を編集したから変数名を変更しclass_weightにclass_weight のインポートされたモジュールを上書きしないようにするために。コメントからコードをコピーするときは、それに応じて調整してください。
class_weight.compute_class_weight
は、配列を生成します。Kerasで作業するには、配列を辞書に変更する必要があります。より具体的には、ステップ2の後、次を使用しますclass_weight_dict = dict(enumerate(class_weight))
y_train
は、(300096, 3)
numpy配列です。したがって、class_weight=
行は私にTypeErrorを与えます:ハッシュできない型: 'numpy.ndarray'
y_ints = [y.argmax() for y in y_train]
。
私はこの種のルールをclass_weight
以下に使用します:
import numpy as np
import math
# labels_dict : {ind_label: count_label}
# mu : parameter to tune
def create_class_weight(labels_dict,mu=0.15):
total = np.sum(labels_dict.values())
keys = labels_dict.keys()
class_weight = dict()
for key in keys:
score = math.log(mu*total/float(labels_dict[key]))
class_weight[key] = score if score > 1.0 else 1.0
return class_weight
# random labels_dict
labels_dict = {0: 2813, 1: 78, 2: 2814, 3: 78, 4: 7914, 5: 248, 6: 7914, 7: 248}
create_class_weight(labels_dict)
math.log
非常に不均衡なクラスの重みを滑らかにします!これは返します:
{0: 1.0,
1: 3.749820767859636,
2: 1.0,
3: 3.749820767859636,
4: 1.0,
5: 2.5931008483842453,
6: 1.0,
7: 2.5931008483842453}
n_total_samples / n_class_samples
各クラスに使用しました。
注:コメントを参照してください。この答えは時代遅れです。
すべてのクラスを均等に重み付けするには、次のようにclass_weightを「auto」に設定するだけです。
model.fit(X_train, Y_train, nb_epoch=5, batch_size=32, class_weight = 'auto')
class_weight='auto'
Kerasのドキュメントにもソースコードにも参照が見つかりませんでした。これを見つけた場所を教えていただけますか?
class_weightは問題ありませんが、@ Aalokが述べたように、ワンホットエンコードマルチラベルクラスの場合、これは機能しません。この場合、sample_weightを使用します。
sample_weight:各サンプルのモデルの損失に適用する重みを含む、xと同じ長さのオプションの配列。時間データの場合、形状(サンプル、sequence_length)を含む2D配列を渡して、すべてのサンプルのすべてのタイムステップに異なる重みを適用できます。この場合、compile()でsample_weight_mode = "temporal"を指定する必要があります。
sample_weightsは、各トレーニングサンプルの重みを提供するために使用されます。つまり、トレーニングサンプルと同じ要素数の1D配列を渡す必要があります(これらの各サンプルの重みを示します)。
class_weightsは、各出力クラスの重みまたはバイアスを提供するために使用されます。つまり、分類しようとしている各クラスに重みを渡す必要があります。
sample_weightには、その形状が評価されるため、numpy配列を指定する必要があります。
この回答も参照してください:https : //stackoverflow.com/questions/48315094/using-sample-weight-in-keras-for-sequence-labelling
https://github.com/keras-team/keras/issues/2115でソリューションに追加します。偽陽性と偽陰性に対して異なるコストが必要なクラスの重み付け以上が必要な場合。新しいkerasバージョンでは、以下のようにそれぞれの損失関数をオーバーライドすることができます。weights
は正方行列であることに注意してください。
from tensorflow.python import keras
from itertools import product
import numpy as np
from tensorflow.python.keras.utils import losses_utils
class WeightedCategoricalCrossentropy(keras.losses.CategoricalCrossentropy):
def __init__(
self,
weights,
from_logits=False,
label_smoothing=0,
reduction=losses_utils.ReductionV2.SUM_OVER_BATCH_SIZE,
name='categorical_crossentropy',
):
super().__init__(
from_logits, label_smoothing, reduction, name=f"weighted_{name}"
)
self.weights = weights
def call(self, y_true, y_pred):
weights = self.weights
nb_cl = len(weights)
final_mask = keras.backend.zeros_like(y_pred[:, 0])
y_pred_max = keras.backend.max(y_pred, axis=1)
y_pred_max = keras.backend.reshape(
y_pred_max, (keras.backend.shape(y_pred)[0], 1))
y_pred_max_mat = keras.backend.cast(
keras.backend.equal(y_pred, y_pred_max), keras.backend.floatx())
for c_p, c_t in product(range(nb_cl), range(nb_cl)):
final_mask += (
weights[c_t, c_p] * y_pred_max_mat[:, c_p] * y_true[:, c_t])
return super().call(y_true, y_pred) * final_mask
ミニストデータセットを使用して損失関数でクラスの重みをコーディングする次の例を見つけました。こちらのリンクをご覧ください:https : //github.com/keras-team/keras/issues/2115
def w_categorical_crossentropy(y_true, y_pred, weights):
nb_cl = len(weights)
final_mask = K.zeros_like(y_pred[:, 0])
y_pred_max = K.max(y_pred, axis=1)
y_pred_max = K.reshape(y_pred_max, (K.shape(y_pred)[0], 1))
y_pred_max_mat = K.equal(y_pred, y_pred_max)
for c_p, c_t in product(range(nb_cl), range(nb_cl)):
final_mask += (weights[c_t, c_p] * y_pred_max_mat[:, c_p] * y_true[:, c_t])
return K.categorical_crossentropy(y_pred, y_true) * final_mask