公式ウェブサイトのカスタム損失関数:ここ
公式ウェブサイトではKeras
、カスタム損失を提供するために使用する2つの方法があることがわかります。
1.単純な平均二乗誤差
def custom_mean_squared_error(y_true, y_pred):
return tf.math.reduce_mean(tf.square(y_true - y_pred))
model.compile(optimizer=keras.optimizers.Adam(), loss=custom_mean_squared_error)
この場合、y_true
合計y_pred
値は自動的に損失関数に渡され、実際の出力と予測された出力のデフォルトパラメータは2つしかないため、この方法は単純な損失関数にのみ適しています。あなたがに加えて使用が必要な場合y_true
やy_pred
以外の他のパラメータの機能の喪失を、次のことができtf.keras.losses.Loss
サブクラスを入力します。
1.1単純なケース
ここでも例として虹彩分類を取り上げています。シーケンスモデルを使用して必要なモデルを定義し、そのcompile
中でカスタム損失関数を指定するだけです。シーケンスモデルで使用する損失関数はであるためsparse_categorical_crossentropy
、2つの違いの簡単な記録を次に示します。
1.1.1 sparse_categorical_crossentropy&categorical_crossentropy
- それはもし
y
あるone-hot encoding
形式(すなわち、ワンホット符号ベクトル形式)、使用sparse_categorical_crossentropy
。 - フォーマットでは
y
なく整数の場合は、;をone-hot encoding
使用しcategorical_crossentropy
ます。
アイリス分類のコードをコピーするだけです。
from sklearn.datasets import load_iris
x_data = load_iris().data # 特征,【花萼长度,花萼宽度,花瓣长度,花瓣宽度】
y_data = load_iris().target # 分类
import tensorflow as tf
model = tf.keras.Sequential()
model.add(tf.keras.layers.Dense(4, input_shape=(4,), activation='relu'))
model.add(tf.keras.layers.Dense(3, input_shape=(4,), activation='softmax'))
model.compile(
optimizer="adam",
loss="sparse_categorical_crossentropy", # 三分类的结果,已经需要使用独热码来表示。故而不能使用categorical_crossentropy
metrics=['accuracy']
)
model.fit(x_data, y_data, epochs=100)
アイリスは3つのカテゴリーに分類されるため、3つのカテゴリーの結果です。むしろ非より0
すなわち1
結果、したがって、使用される必要がありますsparse_categorical_crossentropy
。しかし、その本質はクロスエントロピーです。クロスエントロピーの式は次のように表すことができます
。H(p、q)= − ∑ iy(xi)log(y ^(xi))H(p、q)=-\ sum_i y(x_i)log (\ hat y(x_i))H (p 、q )=−私Σy (x私)l o g (Y^(x私))
y ^(xi)\ hat y(x_i)Y^(x私)を表しXI X_Iをバツ私予測分布、およびy(xi)y(x_i)y (x私)トレーニングデータ内のカテゴリの確率分布を表します。
あなたは、クロスエントロピーを使用する必要がある場合は、に、私は、最終的な指標値のカテゴリに、とのために取得する必要があるためy_true
、およびy_pred
これらの2は、tf.Tensor
オブジェクトの型が、その対応する値を取得する方法はありませんので、PROCLAIMに来ます失敗しました。代わりに、二乗損失関数を使用して以下を解決します。
from sklearn.datasets import load_iris
x_data = load_iris().data # 特征,【花萼长度,花萼宽度,花瓣长度,花瓣宽度】
y_data = load_iris().target # 分类
# 转化为独热编码
y_data_one_hot = tf.one_hot(y_data, depth=3) # 3分类
import tensorflow as tf
model = tf.keras.Sequential()
model.add(tf.keras.layers.Dense(4, input_shape=(4,), activation='relu'))
model.add(tf.keras.layers.Dense(3, input_shape=(4,), activation='softmax'))
def custom_mean_squared_error(y_true, y_pred):
return tf.math.reduce_mean(tf.square(y_true - y_pred))
model.compile(
optimizer="adam",
loss=custom_mean_squared_error,
metrics=['acc']
)
history = model.fit(x_data, y_data_one_hot, epochs=300)
for key in history.history.keys():
plt.plot(history.epoch, history.history[key])
もちろん、別の方法があります。それは、tensorflow
提供されたクロスエントロピー損失関数を直接呼び出すことです。
# 转化为独热编码
y_data_one_hot = tf.one_hot(y_data, depth=3) # 3分类
import tensorflow as tf
model = tf.keras.Sequential()
model.add(tf.keras.layers.Dense(4, input_shape=(4,), activation='relu'))
model.add(tf.keras.layers.Dense(3, input_shape=(4,), activation='softmax'))
def custom_mean_squared_error(y_true, y_pred):
return tf.losses.categorical_crossentropy(y_true, y_pred)
model.compile(
optimizer="adam",
loss=custom_mean_squared_error,
metrics=['acc']
)
history = model.fit(x_data, y_data_one_hot, epochs=300)
または
from sklearn.datasets import load_iris
x_data = load_iris().data # 特征,【花萼长度,花萼宽度,花瓣长度,花瓣宽度】
y_data = load_iris().target # 分类
# 转化为独热编码
#y_data_one_hot = tf.one_hot(y_data, depth=3) # 3分类
import tensorflow as tf
model = tf.keras.Sequential()
model.add(tf.keras.layers.Dense(4, input_shape=(4,), activation='relu'))
model.add(tf.keras.layers.Dense(3, input_shape=(4,), activation='softmax'))
def custom_mean_squared_error(y_true, y_pred):
return tf.losses.sparse_categorical_crossentropy(y_true, y_pred)
model.compile(
optimizer="adam",
loss=custom_mean_squared_error,
metrics=['acc']
)
history = model.fit(x_data, y_data, epochs=300)
for key in history.history.keys():
plt.plot(history.epoch, history.history[key])
2.Lossクラスをインスタンス化します
同様に、クラスはから継承する必要がありtf.keras.losses.Loss
、次に次の2つのメソッドを複製する必要があります。
__init__(self)
:損失関数の呼び出し中に渡されるパラメーターを受け入れます。call(self, y_true, y_pred)
:ターゲットy_true
と予測モデルy_pred
を使用して損失モデルを計算します。
たとえば、公式Webサイトの場合:mse, 存在一个会抑制预测值远离 0.5
class CustomMSE(keras.losses.Loss):
def __init__(self, regularization_factor=0.1, name="custom_mse"):
super().__init__(name=name)
self.regularization_factor = regularization_factor
def call(self, y_true, y_pred):
mse = tf.math.reduce_mean(tf.square(y_true - y_pred))
reg = tf.math.reduce_mean(tf.square(0.5 - y_pred))
return mse + reg * self.regularization_factor
model.compile(optimizer=keras.optimizers.Adam(), loss=CustomMSE())
比較的単純なため、虹彩分類の場合は設定されていません。しかし、上記の公式Webサイトの場合から、1つの問題も見られ
ます。損失関数を定義するためのここでの単純なインスタンス化サブクラスは、実際には、損失関数function
として直接定義する上記と同様です。call
パラメータまたは2つの値のみy_true
を渡したためy_pred
、上部で大騒ぎする必要がありますが、さらに困難になります。
次の記事では、損失関数をカスタマイズするためのより柔軟な方法について説明します。実際、前のブログで言及されていました。つまり、複雑さと学習率と損失関数は次のようになります。
import tensorflow as tf
x = tf.random.normal([20, 2], mean=2, stddev=1, dtype=tf.float32)
y = [item1 + 2 * item2 for item1, item2 in x]
w = tf.Variable(tf.random.normal([2, 1], mean=0, stddev=1))
epoch = 5000
lr = 0.002
for epoch in range(epoch):
with tf.GradientTape() as tape:
y_hat = tf.matmul(x, w)
loss = tf.reduce_mean(tf.where(tf.greater(y_hat, y), 3*(y_hat - y), y-y_hat))
w_grad = tape.gradient(loss, w)
w.assign_sub(lr * w_grad)
print(w.numpy().T) # [[0.73728406 0.83368826]]