Seq2Seq 模型和损失函数(在 keras 中)
Seq2Seq models and loss functions( in keras)
我的 seq2seq 模型有问题
在某些情况下,它的工作很好,但在某些情况下,它的 return 结果只是结束标记。
例如:
For given vector :
[2, #start token
3,
123,
1548, #end token
1548,
1548,
1548,
1548,
1548,
1548]
The model predict :
[1548,
1548,
1548,
1548,
1548,
1548,
1548,
1548,
1548,
1548]
我尝试使用来自监控 "loss" 的 keras 的 SaveModel 回调,但它仍然给出相同的结果。
所以我想也许我应该使用我自己的损失函数。
keras 提供的简单损失函数:
def mean_absolute_error(y_true, y_pred):
return K.mean(K.abs(y_pred - y_true), axis=-1)
y_true 和 y_pred 都是张量流对象(我们只得到指向真实数组的指针)所以..为了创建一些逻辑,我们需要从 gpu 或将我自己的数组上传到 gpu..
我想要的损失函数
def mean_absolute_error(y_true, y_pred):
sum = 0
for y , _y in zip(y_true , y_pred):
if (y == _y) and (y == self.startToken or y == self.endToken):
continue
else:
sum += abs(y - _y)
return sum
我尝试使用 y_true.eval() 应该将数组作为 numpy 对象带到 cpu(无法使用 eval()
评估张量:未注册默认会话)
我没能找到如何将我自己的数组上传到 tensorflow 中。
如果您有解决方案或任何建议,我将非常乐意听到。
谢谢..
(不太重要但是...)
模型基于:https://blog.keras.io/a-ten-minute-introduction-to-sequence-to-sequence-learning-in-keras.html,但具有单热(两个暗淡 [Matrix])输出。
在损失函数中使用K.eval
或if
不是一个好主意。关于张量的所有想法都是它们有一个由 tensorflow/keras 管理的内部连接,通过它可以计算梯度和其他东西。
使用 eval
并处理 numpy 值会破坏这种联系并破坏模型。使用 eval
仅查看结果,不创建函数。
使用 if
s 将不起作用,因为张量的值不可用。但是还有keras的函数,比如K.switch
、K.greater
、K.less
等,都列在backend documentation.
您可以使用这些函数重新创建您的函数。
但老实说,我认为您应该改用“屏蔽”或“class 加权”。
屏蔽(解决方案 1)
如果您正在使用嵌入层,您可以有意为“结束后什么都没有”保留零值。
然后您可以在嵌入层中使用 mask_zero=True
并有 输入 像这样:
[2, #start token
3,
123,
1548, #end token
0, #nothing, value to be masked
0,
0,
0,
0,
0]
另一种选择是不使用“结束标记”,而是使用“零”。
Class加权(方案二)
由于这很可能会发生,因为您的结束标记比所需输出中的任何其他内容都多得多,因此您可以降低结束标记的相关性。
计算输出中出现的每个 class 次并计算结束标记的比率。一个例子:
- 计算所有其他 classes
出现的平均值
- 计算结束标记的出现次数
ratio = other_classes_mean / end_token_occurences
然后在fit
方法中,使用:
class_weight = {0:1, 1:1, 2:1, ...., 1548:ratio, 1549:1,1550:1,...}
通过以下方式轻松实现:
class_weight = {i:1. for i in range(totalTokens)}
class_weight[1548] = ratio
model.fit(...,...,....., class_weight = class_weight,...)
(在这种情况下确保你有可能的 0 class,或者将索引移动 1)
类似的损失函数(方案3)
请注意 y_pred
永远不会“等于”y_true
。
y_pred
是可变的、连续的、可微的
y_true
是精确且恒定的
为了进行比较,您应该使用“argmax”,它与 class 索引非常相似(如果不完全相同的话)。
def mean_absolute_error(y_true, y_pred):
#for comparing, let's take exact values
y_true_max = K.argmax(y_true)
y_pred_max = K.argmax(y_pred)
#compare with a proper tensor function
equal_mask = K.equal(y_true_max,y_pred_max)
is_start = K.equal(y_true_max, self.startTokenAsIndex)
is_end = K.equal(y_true_max, self.endTokenAsIndex)
#cast to float for multiplying and summing
equal_mask = K.cast(equal_mask, K.floatx())
is_start = K.cast(is_start, K.floatx())
is_end = K.cast(is_end, K.floatx())
#these are tensors with 0 (false) and 1 (true) as float
#entire condition as you wanted
condition = (is_start + is_end) * equal_mask
# sum = or ||| multiply = and
# we don't have to worry about the sum resulting in 2
# because you will never have startToken == endToken
#reverse condition:
condition = 1 - condition
#result
return condition * K.mean(K.abs(y_pred - y_true), axis=-1)
我的 seq2seq 模型有问题 在某些情况下,它的工作很好,但在某些情况下,它的 return 结果只是结束标记。
例如:
For given vector :
[2, #start token
3,
123,
1548, #end token
1548,
1548,
1548,
1548,
1548,
1548]
The model predict :
[1548,
1548,
1548,
1548,
1548,
1548,
1548,
1548,
1548,
1548]
我尝试使用来自监控 "loss" 的 keras 的 SaveModel 回调,但它仍然给出相同的结果。
所以我想也许我应该使用我自己的损失函数。
keras 提供的简单损失函数:
def mean_absolute_error(y_true, y_pred):
return K.mean(K.abs(y_pred - y_true), axis=-1)
y_true 和 y_pred 都是张量流对象(我们只得到指向真实数组的指针)所以..为了创建一些逻辑,我们需要从 gpu 或将我自己的数组上传到 gpu..
我想要的损失函数
def mean_absolute_error(y_true, y_pred):
sum = 0
for y , _y in zip(y_true , y_pred):
if (y == _y) and (y == self.startToken or y == self.endToken):
continue
else:
sum += abs(y - _y)
return sum
我尝试使用 y_true.eval() 应该将数组作为 numpy 对象带到 cpu(无法使用 eval()
评估张量:未注册默认会话)
我没能找到如何将我自己的数组上传到 tensorflow 中。
如果您有解决方案或任何建议,我将非常乐意听到。
谢谢..
(不太重要但是...)
模型基于:https://blog.keras.io/a-ten-minute-introduction-to-sequence-to-sequence-learning-in-keras.html,但具有单热(两个暗淡 [Matrix])输出。
在损失函数中使用K.eval
或if
不是一个好主意。关于张量的所有想法都是它们有一个由 tensorflow/keras 管理的内部连接,通过它可以计算梯度和其他东西。
使用 eval
并处理 numpy 值会破坏这种联系并破坏模型。使用 eval
仅查看结果,不创建函数。
使用 if
s 将不起作用,因为张量的值不可用。但是还有keras的函数,比如K.switch
、K.greater
、K.less
等,都列在backend documentation.
您可以使用这些函数重新创建您的函数。
但老实说,我认为您应该改用“屏蔽”或“class 加权”。
屏蔽(解决方案 1)
如果您正在使用嵌入层,您可以有意为“结束后什么都没有”保留零值。
然后您可以在嵌入层中使用 mask_zero=True
并有 输入 像这样:
[2, #start token
3,
123,
1548, #end token
0, #nothing, value to be masked
0,
0,
0,
0,
0]
另一种选择是不使用“结束标记”,而是使用“零”。
Class加权(方案二)
由于这很可能会发生,因为您的结束标记比所需输出中的任何其他内容都多得多,因此您可以降低结束标记的相关性。
计算输出中出现的每个 class 次并计算结束标记的比率。一个例子:
- 计算所有其他 classes 出现的平均值
- 计算结束标记的出现次数
ratio = other_classes_mean / end_token_occurences
然后在fit
方法中,使用:
class_weight = {0:1, 1:1, 2:1, ...., 1548:ratio, 1549:1,1550:1,...}
通过以下方式轻松实现:
class_weight = {i:1. for i in range(totalTokens)}
class_weight[1548] = ratio
model.fit(...,...,....., class_weight = class_weight,...)
(在这种情况下确保你有可能的 0 class,或者将索引移动 1)
类似的损失函数(方案3)
请注意 y_pred
永远不会“等于”y_true
。
y_pred
是可变的、连续的、可微的y_true
是精确且恒定的
为了进行比较,您应该使用“argmax”,它与 class 索引非常相似(如果不完全相同的话)。
def mean_absolute_error(y_true, y_pred):
#for comparing, let's take exact values
y_true_max = K.argmax(y_true)
y_pred_max = K.argmax(y_pred)
#compare with a proper tensor function
equal_mask = K.equal(y_true_max,y_pred_max)
is_start = K.equal(y_true_max, self.startTokenAsIndex)
is_end = K.equal(y_true_max, self.endTokenAsIndex)
#cast to float for multiplying and summing
equal_mask = K.cast(equal_mask, K.floatx())
is_start = K.cast(is_start, K.floatx())
is_end = K.cast(is_end, K.floatx())
#these are tensors with 0 (false) and 1 (true) as float
#entire condition as you wanted
condition = (is_start + is_end) * equal_mask
# sum = or ||| multiply = and
# we don't have to worry about the sum resulting in 2
# because you will never have startToken == endToken
#reverse condition:
condition = 1 - condition
#result
return condition * K.mean(K.abs(y_pred - y_true), axis=-1)