keras Tensorflow:在模型拟合期间确定自定义损失函数中的批量大小的问题(批量大小为“无”)

yvgpqqbh  于 2022-11-13  发布在  其他
关注(0)|答案(1)|浏览(195)

我正在尝试创建一个自定义的损失函数,在这个函数中,我必须对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进行了大量的切片,我在寻找一个通用的切片解决方案)。
我试着看了一下thisthis,我通读了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)
pengsaosao

pengsaosao1#

让我们一起完成这个任务。可能我们两个都需要来回编辑内容。
我将解决你问题的切片部分,因为这是最容易处理的信息。
让我们示例化一个形状为[3,3,3]的Tensor:

y = tf.constant([ [[1, 2, 3]   , [4, 5, 6   ], [7, 8, 9   ]],                                                                                                          
                  [[10, 11, 12], [13, 14, 15], [16, 17, 18]],                                                                                                 
                  [[19, 20, 21], [22, 23, 24], [25, 26, 27]] ])

注意,这是形状为[3,3,3]的1Tensor,让我们把它形象化:

[ins] In [50]: y[0]                                                                                                                                                         
Out[50]:                                                                                                                                                                    
<tf.Tensor: shape=(3, 3), dtype=int32, numpy=                                                                                                                               
array([[1, 2, 3],                                                                                                                                                           
       [4, 5, 6],                                                                                                                                                           
       [7, 8, 9]], dtype=int32)>                                                                                                                                            
                                                                                                                                                                            
[ins] In [51]: y[1]                                                                                                                                                         
Out[51]:                                                                                                                                                                    
<tf.Tensor: shape=(3, 3), dtype=int32, numpy=                                                                                                                               
array([[10, 11, 12],                                                                                                                                                        
       [13, 14, 15],                                                                                                                                                        
       [16, 17, 18]], dtype=int32)>                                                                                                                                         
                                                                                                                                                                            
[ins] In [52]: y[2]                                                                                                                                                         
Out[52]:                                                                                                                                                                    
<tf.Tensor: shape=(3, 3), dtype=int32, numpy=                                                                                                                               
array([[19, 20, 21],                                                                                                                                                        
       [22, 23, 24],                                                                                                                                                        
       [25, 26, 27]], dtype=int32)>

就坐标轴而言,我们可以想象最左边的坐标轴包含3个3x 3矩阵,上面我们用y[0]y[1]y[2]引用了这些矩阵。现在,让我们来画出这个数字立方体。

[nav] In [53]: tf.slice(y, begin=[0, 0, 0], size=[2, 2, 2])                                                                                                                 
Out[53]:                                                                                                                                                                    
<tf.Tensor: shape=(2, 2, 2), dtype=int32, numpy=                                                                                                                            
array([[[ 1,  2],                                                                                                                                                           
        [ 4,  5]],                                                                                                                                                          
                                                                                                                                                                            
       [[10, 11],                                                                                                                                                           
        [13, 14]]], dtype=int32)>

这里我们要从一个大的立方体中得到一个小的立方体,具体来说就是[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如下所示:

[ins] In [57]: tf.reshape(y, shape=(-1, 3, 3, 3))                                                                                                                           
Out[57]:                                                                                                                                                                    
<tf.Tensor: shape=(1, 3, 3, 3), dtype=int32, numpy=                                                                                                                         
array([[[[ 1,  2,  3],                                                                                                                                                      
         [ 4,  5,  6],                                                                                                                                                      
         [ 7,  8,  9]],                                                                                                                                                     
                                                                                                                                                                            
        [[10, 11, 12],                                                                                                                                                      
         [13, 14, 15],                                                                                                                                                      
         [16, 17, 18]],                                                                                                                                                     
                                                                                                                                                                            
        [[19, 20, 21],                                                                                                                                                      
         [22, 23, 24],                                                                                                                                                      
         [25, 26, 27]]]], dtype=int32)>                                                                                                                                     
                                                                                                                                                                            
[ins] In [58]: tf.reshape(y, shape=(-1, 3, 3, 3)).shape                                                                                                                     
Out[58]: TensorShape([1, 3, 3, 3])

上面所说的是重新调整我的数据,使我有一个3x 3x 3的立方体,但我还想在最左边的,也就是批处理,轴上有一些东西。它只是“加深”了维度。这可以通过在上面的输出中添加另一对[ ]来看出。它毕竟不能为我们制造数字,因为这些是我们的观察结果。您也可以使用tf.expand_dims,但我发现tf.reshape更直观。
现在我们有一批1号的,其中每个观察是[3, 3, 3]形状的立方体,如果你愿意,可以将其分配给y_pred。尝试通过你的函数运行批处理,看看它是如何工作的。我发现另一件对处理形状问题非常有用的事情是在ipython中使用ipdb和嵌入模式。你可以设置断点,进入违规的行,观察并修复。祝你好运!
解(没有任何基本的领域知识。显然Tensor是领域不可知的:))

pts_tensor = tf.constant(pts)                                                                                                                                               
dummy_in_tensor = tf.constant(tf.reshape(dummy_in, (-1,1)))                                                                                                                 
my_ds = tf.data.Dataset.from_tensor_slices((dummy_in_tensor, pts_tensor))                                                                                                   
model.fit(my_ds, verbose=1)

我认为问题出在批处理轴上。要做得更好,我需要了解域,但我还有一些研究要做:)

相关问题