python - 用 Keras 计数
问题描述
我正在尝试做的事情
我目前正在使用带有轻微扭曲的 Keras 制作一个非常简单的序列到序列 LSTM,序列中的早期预测应该比后来的预测少计入损失。我试图做到这一点的方法是计算序列号并乘以该计数的平方根。(我想这样做是因为这个值代表了泊松过程中基于收集的样本数量的不确定性的相对比率。我的网络正在收集数据并尝试根据迄今为止收集的数据估计一个不变的值。)
我是如何做到的
我已经实现了自定义损失函数和自定义层。
损失函数:
def loss_function(y_true, y_pred):
# extract_output essentially concatenates the first three regression outputs of y
# into a list representing an [x, y, z] vector, and returns it along with the rest as a tuple
r, e, n = extract_output(y_true)
r_h, e_h, n_h = extract_output(y_pred)
# Hyperperameters
dir_loss_weight = 10
dist_loss_weight = 1
energy_loss_weight = 3
norm_r = sqrt(dot(r, r))
norm_r_h = sqrt(dot(r_h, r_h))
dir_loss = mean_squared_error(r/norm_r, r_h/norm_r_h)
dist_loss = mean_squared_error(norm_r, norm_r_h)
energy_loss = mean_squared_error(e, e_h)
return sqrt(n) * (dir_loss_weight * dir_loss + dist_lost_weight * dist_loss + energy_loss_weight * energy_loss)
自定义层:
class CounterLayer(Layer):
def __init__(self, **kwargs):
super(CounterLayer, self).__init__(**kwargs)
def build(self, input_shape):
self.sequence_number = 0
pass
def call(self, x):
self.sequence_number += 1
return [self.sequence_number]
def compute_output_shape(self, input_shape):
return (1,)
然后我将输入作为连接添加到常规输出中:
seq_num = CounterLayer()(inputs)
outputs = concatenate([out, seq_num])
出了什么问题
我的错误是:
Traceback (most recent call last):
File "lstm.py", line 119, in <module>
main()
File "lstm.py", line 115, in main
model = create_model()
File "lstm.py", line 74, in create_model
seq_num = CounterLayer()(inputs)
File "/usr/lib/python3.7/site-packages/keras/engine/base_layer.py", line 497, in __call__
arguments=user_kwargs)
File "/usr/lib/python3.7/site-packages/keras/engine/base_layer.py", line 565, in _add_inbound_node
output_tensors[i]._keras_shape = output_shapes[i]
AttributeError: 'int' object has no attribute '_keras_shape'
我假设我的形状错误。但是我不知道怎么做。有谁知道我是否以错误的方式处理这个问题?我应该怎么做才能做到这一点?
进一步的冒险
根据@Mohammad Jafar Mashhadi 的评论,我的call
回报需要用keras.backend.variable
; 但是,根据他的链接答案,我的方法不起作用,因为call
没有像我最初假设的那样多次调用。
如何获得 RNN 的计数器?
为清楚起见,如果给定输入 xi 的 RNN 输出 yi,我试图将 i 作为输出的一部分。
x1 -> RNN -> (y1, 1)
h1 |
v
x2 -> RNN -> (y2, 2)
h2 |
v
x3 -> RNN -> (y3, 3)
h3 |
v
x4 -> RNN -> (y4, 4)
解决方案
错误是说,inputs
在行seq_num = CounterLayer()(inputs)
中,是一个整数。
您不能将整数作为输入传递给图层。您必须通过 keras 张量,并且只能通过 keras 张量。
其次,这不起作用,因为 Keras 以静态图形样式工作。层中的Acall
不计算事物,它只构建空张量的图。当您将数据传递给张量时,只有张量会得到更新,整数值不会。当你说它self.sequence_number += 1
时,它只会在构建模型时被调用,它不会被一遍又一遍地调用。
我们需要细节
如果您不向我们提供足够的信息,我们将无法真正了解发生了什么,例如:
- 该模型
- 摘要
- 您的输入数据形状
- 目标数据形状
- 自定义函数
- 等等
如果下面的解释是正确的,那么了解模型在摘要中的输出形状和传递给 fit 时的目标数据形状是绝对重要的。
建议的解决方案
如果我理解您所描述的内容,您希望拥有一个递增整数的序列以及序列的时间步长,因此这些数字将用于您的损失函数。
如果这个解释是正确的,你不需要不断更新数字,你只需要创建一个范围张量就可以了。
所以,在你的损失中(除非你向我们提供自定义函数,否则我不明白)你应该创建这个张量:
def custom_loss(y_true, y_pred):
#use this if you defined your model with static sequence length - input_shape =(length, features)
length = K.int_shape(y_pred)[1]
#use this if you defined your model with dynamic sequence length - input_shape = (None, features)
length = K.shape(y_pred)[1]
#this is the sequence vector:
seq = tf.range(1, length+1)
#you can get the root with
sec = K.sqrt(seq)
#you reshape to match the shape of the loss, which is probably (batch, length)
sec = K.reshape(sec, (1,-1)) #shape (1, lenght)
#compute your loss normally, taking care to reduce the last axis and keep the two first
loss = ..... #shape (batch, length)
#multiply the weights by the loss
return loss * sec
您必须将所有内容作为一个整体张量来处理!您不能将其解释为逐步进行。您必须尽一切努力保持损失中的第一和第二维度。
推荐阅读
- c# - ASP.NET MVC & C#:将视图模型传递给控制器
- ruby-on-rails - 如何确保他们在一台机器上的 rails 环境与另一台机器相同?
- javascript - 使用 JSX 导入 React 组件
- python - 如何在 Django 中找出 NoReverseMatch
- utf-8 - openssl req utf8 字符串
- ruby-on-rails - 为什么 GC stat minor_gc_count 会减少?
- python - 重新索引数据框的问题(处理分类数据)
- dynamics-crm - 如何通过 Web API 检索属性的显示名称?
- r - 绘制不同变量的点大小和颜色的问题(ggplot、geom_dot)
- java - Apache Camel Chronicle 组件 [已弃用]