我正在尝试创建一个自定义的损失函数,在这个函数中,我必须对Tensor进行多次切片。下面列出了一个例子:
# Since different nodes need different activations, I decided to just do it like this
def activations(y_true, y_pred):
n = y_true.shape[1]
means = tf.slice(y_pred, begin=[0,0], size=[y_pred.shape[0], n])
stdevs = tf.slice(y_pred, begin=[0,n], size=[y_pred.shape[0], n])
corrs = tf.slice(y_pred, begin=[0,2*n], size=[y_pred.shape[0], y_pred.shape[1]-2*n])
stdevs = keras.activations.softplus(stdevs)
corrs = keras.activations.tanh(corrs)
当在自制的Tensory_true和y_pred上手动测试时,这(以及整个损失函数)工作正常,但当在损失函数内使用它时,它将在模型拟合时给予错误(编译正常)。
File <filename>, line 105, in activations *
means = tf.slice(y_pred, begin=[0,0], size=[y_true.shape[0], n])
TypeError: Expected int32 passed to parameter 'size' of op 'Slice', got [None, 3] of type 'list' instead. Error: Expected int32, but got None of type 'NoneType'.
因此,很明显,在损失层内执行时,它无法确定批处理大小。
我该如何解决这个问题?
(note:我并不是在寻找一个只针对这段特定代码的解决方案,因为我对Tensor进行了大量的切片,我在寻找一个通用的切片解决方案)。
我试着看了一下this和this,我通读了this的帖子。编写一个自定义生成器来使批处理大小静态化真的是唯一的方法吗?
先谢了?
**EDIT:**这里是一个(非常)简化的代码版本,它触发了错误。
import numpy as np
import numpy.random as npr
import keras
from keras import layers
import tensorflow as tf
# Since different nodes need different activations, I decided to just do it like this
def dummy_loss_func(y_true, y_pred):
n = y_true.shape[1]
means = tf.slice(y_pred, begin=[0,0], size=[y_pred.shape[0], n])
stdevs = tf.slice(y_pred, begin=[0,n], size=[y_pred.shape[0], n]) #I'm assuming these are all (0, infty)
corrs = tf.slice(y_pred, begin=[0,2*n], size=[y_pred.shape[0], y_pred.shape[1]-2*n])
stdevs = keras.activations.softplus(stdevs)
corrs = keras.activations.tanh(corrs)
relErrors = tf.math.square(means - y_true)/stdevs
return tf.reduce_mean(tf.math.square(relErrors))
def dummy_model(dim):
model = keras.Sequential(
[
keras.Input(shape=(1)),
layers.Dense(2*dim + int(round(dim * (dim-1)/2)), kernel_initializer = tf.keras.initializers.GlorotUniform()),
]
)
model.summary()
model.compile(loss=dummy_loss_func, optimizer="adam")
return model
#Generating some fake data
n = 5000
dim = 3
pts = npr.uniform(size=[n, 2*dim + int(round(dim * (dim-1)/2))])
dummy_in = np.zeros(n)
print(dummy_in.size)
print(pts.size)
#Comping the model goes fine
model = dummy_model(dim)
# Model exucution will go fine
print(model.predict([0]))
# Just calling the loss function also works
print(dummy_loss_func(tf.constant([[3., 2., 1.],[1., 2., 3.]]), tf.constant([[2., 1., 1., 5., 3., 2., 3., 2., 1.], [2., 5., 1., 1., 3., 6., 3., 4., 1.]])))
# The error only comes here
model.fit(dummy_in, pts, verbose=1)
1条答案
按热度按时间pengsaosao1#
让我们一起完成这个任务。可能我们两个都需要来回编辑内容。
我将解决你问题的切片部分,因为这是最容易处理的信息。
让我们示例化一个形状为[3,3,3]的Tensor:
注意,这是形状为[3,3,3]的
1
Tensor,让我们把它形象化:就坐标轴而言,我们可以想象最左边的坐标轴包含3个3x 3矩阵,上面我们用
y[0]
、y[1]
和y[2]
引用了这些矩阵。现在,让我们来画出这个数字立方体。这里我们要从一个大的立方体中得到一个小的立方体,具体来说就是
[2, 2, 2]
的形状,我们要从[0, 0, 0]
点开始,我们要对这个大的立方体做三次切割:首先,我们将进入“计算机”轴的两个步骤,因此最深层中的任何内容都不会显示出来(形状为[3, 3]
的数字[19, 20, 21],[22, 23, 24],[25, 26, 27]
)。然后我们将进行水平剪切,这意味着[7, 8, 9],[16, 17, 18]
中的数字都没有出现,[25, 26, 27]
已在上次剪切中被切掉。最后,我们从原点开始两步处进行垂直剪切,确保[3, 6],[12,15]
不会出现。所以我们在第一个chop中丢失了9个数字,我们在第二个chop中丢失了9个数字,但是有3个数字与第一个chop重叠,所以我们只丢失了6个数字。第三个chop,我们丢失了9个数字,但是我们在第一个chop中丢失了3个数字,在第二个chop中丢失了2个(应该是三个,但一个与第一个重叠),这就剩下了四个在最后一次斩波中丢失。27 - (9 + 6 + 4) = 8
这是我们得到的。要解决的关键问题之一是提出以下问题:我这里有一个批次,还是我正在处理的批次中的一个观测。你怎么知道呢?最左边的轴是批次轴,通常表示为
None
,这意味着批次的数量是可变的。让我们用现有的Tensor创建一个批次,你可以用上面的Tensor如下所示:上面所说的是重新调整我的数据,使我有一个3x 3x 3的立方体,但我还想在最左边的,也就是批处理,轴上有一些东西。它只是“加深”了维度。这可以通过在上面的输出中添加另一对
[ ]
来看出。它毕竟不能为我们制造数字,因为这些是我们的观察结果。您也可以使用tf.expand_dims
,但我发现tf.reshape
更直观。现在我们有一批1号的,其中每个观察是
[3, 3, 3]
形状的立方体,如果你愿意,可以将其分配给y_pred
。尝试通过你的函数运行批处理,看看它是如何工作的。我发现另一件对处理形状问题非常有用的事情是在ipython
中使用ipdb
和嵌入模式。你可以设置断点,进入违规的行,观察并修复。祝你好运!解(没有任何基本的领域知识。显然Tensor是领域不可知的:))
我认为问题出在批处理轴上。要做得更好,我需要了解域,但我还有一些研究要做:)