tensorflow - 为什么我的自定义损失(分类交叉熵)不起作用?
问题描述
我正在为自己构建基于 Tensorflow 和 Keras 的某种框架。作为开始,我只编写了框架的核心并实现了第一个玩具示例。这个玩具示例只是一个经典的前馈网络求解 XOR。
可能没有必要解释它周围的一切,但我实现了这样的损失函数:
class MeanSquaredError(Modality):
def loss(self, y_true, y_pred, sample_weight=None):
y_true = tf.cast(y_true, dtype=y_pred.dtype)
loss = tf.keras.losses.MeanSquaredError(reduction=tf.keras.losses.Reduction.NONE)(y_true, y_pred)
return tf.reduce_sum(loss) / self.model_hparams.model.batch_size
这将在实际模型类中使用,如下所示:
class Model(keras.Model):
def loss(self, y_true, y_pred, weights=None):
target_modality = self.modalities['targets'](self.problem.hparams, self.hparams)
return target_modality.loss(y_true, y_pred)
现在,在训练方面,我可以像这样训练模型:
model.compile(
optimizer=keras.optimizers.Adam(0.001),
loss=model.loss, # Simply setting 'mse' works as well here
metrics=['accuracy']
)
或者我可以设置loss=mse
. 两种情况都按预期工作,没有任何问题。
但是,我有另一个Modality
类用于序列到序列(例如翻译)任务。它看起来像这样:
class CategoricalCrossentropy(Modality):
"""Simple SymbolModality with one hot as embeddings."""
def loss(self, y_true, y_pred, sample_weight=None):
labels = tf.reshape(y_true, shape=(tf.shape(y_true)[0], tf.reduce_prod(tf.shape(y_true)[1:])))
y_pred = tf.reshape(y_pred, shape=(tf.shape(y_pred)[0], tf.reduce_prod(tf.shape(y_pred)[1:])))
loss = tf.keras.losses.CategoricalCrossentropy(reduction=tf.keras.losses.Reduction.NONE, from_logits=True)(labels, y_pred)
return tf.reduce_mean(loss) / self.model_hparams.model.batch_size
这样做只是将y_true
和y_pred
张量重塑[batch_size, seq_len, embedding_size]
为[seq_len * batch_size, embedding_size]
- 有效地堆叠所有示例。由此,计算并归一化分类交叉熵。
现在,我使用的模型是一个非常简单的 LSTM——不过这并不重要。当我像这样训练模型时:
model.compile(
optimizer=keras.optimizers.Adam(0.001),
loss='categorical_crossentropy', # <-- Setting the loss via string argument (works)
metrics=['accuracy']
)
该模型确实按预期学习了任务。但是,如果我使用CategoricalCrossentropy
上面的 -modality 设置loss=model.loss
,模型根本不会收敛。损失随机振荡但不收敛。
这就是我挠头的地方。由于简单的 XOR 示例在两种方式中都有效,并且由于设置categorical_crossentropy
也有效,我不太明白为什么使用所述模态不起作用。
我在做一些明显错误的事情吗?
很抱歉我不能在这里提供一个小例子,但这不可能,因为框架已经包含一些代码行。从经验上讲,一切都应该起作用。
任何想法我可以如何追踪问题或可能导致此问题的原因?
解决方案
您正在为形状创建一个张量元组。那可能行不通。
为什么不只是这个?
labels = tf.keras.backend.batch_flatten(y_true)
y_pred = tf.keras.backend.batch_flatten(y_pred)
标准'categorical_crossentropy'
损失不执行任何类型的展平,并将最后一个轴视为类。
您确定要展平数据吗?如果扁平化,就会将类数乘以步数,这似乎没有多大意义。
此外,标准'categorical_crossentropy'
损失使用from_logits=False
!
标准损失期望来自"softmax"
激活的输出,而from_logits=True
期望没有激活的输出。
推荐阅读
- flutter - 使连续的按钮在颤动中具有相同的宽度
- ios - 如何设置按钮以根据星期几显示不同的视图控制器?
- javascript - 显示图片时禁用提交按钮
- ios - 如何将tableView单元格行数据保存和编辑到coredata和设备联系人?
- javascript - React Ace 编辑器标记突出显示整行,甚至定义为限制列的 startCol 和 endCol
- swift - NavigationItem TitleView 约束不起作用
- c++ - C++循环只读取第一行
- python - 根据另一个列表中的元素查找列表中的元素
- azure - 容器化应用服务上的 azure webjob
- ruby-on-rails - 一个类被传递给 `:class_name` 但我们期待一个字符串