【问题标题】:Slicing-based assignment in Keras / Tensorflow?Keras / Tensorflow 中基于切片的分配?
【发布时间】:2018-04-09 11:19:21
【问题描述】:

看我的 Keras 自定义损失函数:

def custom_loss(y_true, y_pred):
    sqerr = (y_true - y_pred)**2
    sqerr[:,4:-1:7] = sqerr[:,4:-1:7] * ((y_true[:,2:-1:7]-y_true[:,3:-1:7])/y_true[:,2:-1:7])**2
    return sqerr.mean()

但是 'sqerr' 不是一个 numpy 数组,所以这段代码会导致错误

TypeError: 'Tensor' 对象不支持项目分配

于是我阅读了"How to do slice assignment in Tensorflow" 的帖子,包括jdehesa's answerGitHub page on this discussion。所以这就是我现在所拥有的......

def custom_loss(y_true, y_pred):
    sqerr = K.square(y_true-y_pred)

    sqerr = tf.Variable(  sqerr , validate_shape=False )
    with tf.control_dependencies([sqerr[:,4:-1:7].assign( sqerr[:,4:-1:7] * ((y_true[:,2:-1:7]-y_true[:,3:-1:7])/y_true[:,2:-1:7])**2 )]):
        sqerr = tf.identity(sqerr)

    return K.mean(sqerr)

...但显然我在实际使用它时搞砸了:

Traceback(最近一次调用最后一次):文件“my_awesome_nn.py”,行 119,在 setup_model 中

model.compile(loss=custom_loss, optimizer=opt)  

文件“/opt/anaconda/envs/py35/lib/python3.5/site-packages/keras/engine/training.py”, 第 850 行,编译中

sample_weight, mask)   

文件“/opt/anaconda/envs/py35/lib/python3.5/site-packages/keras/engine/training.py”, 第 465 行,加权

score_array = K.mean(score_array, axis=list(range(weight_ndim, ndim))) 

TypeError: 'NoneType' 对象不能被解释为整数

发生的事情是,TF 切片只允许应用于变量,而不是一般张量,所以我正在转换为变量。但是当我转换为变量时,它想知道形状,但形状在那时是“动态定义的”(即第一个元素是“?”)。所以设置 validate_shape=False 让我实际上定义了一个变量,但这会破坏 Keras 以后想要的维度信息。观察:

def custom_loss(y_true, y_pred):  
        sqerr = K.square(y_true-y_pred)
        print("K.ndim(sqerr) #1 = ",K.ndim(sqerr))
        sqerr = tf.Variable(  sqerr , validate_shape=False )
        print("K.ndim(sqerr) #2 = ",K.ndim(sqerr))
        with tf.control_dependencies([sqerr[:,4:-1:7].assign( sqerr[:,4:-1:7] * ((y_true[:,2:-1:7]-y_true[:,3:-1:7])/y_true[:,2:-1:7])**2 )]):
            sqerr = tf.identity(sqerr)

        return K.mean(sqerr)

...输出结果

K.ndim(sqerr) #1 = 2

K.ndim(sqerr) #2 = 无

因此,稍后,当 Keras training.py 代码说“ndim = K.ndim(score_array)”时,它以 None 结束,因此出现 NoneType 错误。

任何人都可以阐明如何做我需要的事情吗?似乎我不能在不转换为变量的情况下进行切片,无法为动态形状的张量定义变量,以保留动态形状。

(如果我只是省略上面的“中间 3 行”并将我的自定义损失设为常规 MSE,这是一个完全有效的代码)

【问题讨论】:

  • 您可以尝试包含更多相关代码吗?你在哪里计算score_array?你能向我们展示更多关于你的模型的声明和编译的代码吗?
  • 我可以包含它,但它不是我的代码,因为 score_array 显示为在 Keras 发行版中进行评估,例如在github.com/fchollet/keras/blob/master/keras/engine/training.py。在组装损失时,甚至还没有构建模型。目前,问题似乎是作为变量的转换(切片需要),并且需要 validate_shape=False 因为张量形状在那时是“松散定义的”。但这会导致 K.dim(sqerr) = None。我将编辑帖子以反映这一点...

标签: python numpy tensorflow keras slice


【解决方案1】:

我认为这种自定义损失可以避免切片分配。如果你想调整sqerr[:, 4:-1:7]的损失值,你可以从总损失中减去原来的值,然后再加回调整后的损失值。

def custom_loss_keras(y_true, y_pred):
    # first sum up the squared error column-wise
    sqerr = K.square(y_true - y_pred)
    loss = K.sum(sqerr, axis=-1)

    # subtract the loss for the sliced part
    loss -= K.sum(sqerr[:, 4:-1:7], axis=-1)

    # add back the adjusted loss for the sliced part
    denominator = K.maximum(y_true[:, 2:-1:7], K.epsilon())  # handle zero-division
    numerator = y_true[:, 2:-1:7] - y_true[:, 3:-1:7]
    loss += K.sum(sqerr[:, 4:-1:7] * K.square(numerator / denominator), axis=-1)

    # take average
    ncols = K.int_shape(y_pred)[-1]
    loss /= ncols
    return K.mean(loss)

您可以通过将其与原始 numpy 版本进行比较来验证此功能:

def custom_loss_numpy(y_true, y_pred):
    sqerr = (y_true - y_pred)**2
    sqerr[:,4:-1:7] = sqerr[:,4:-1:7] * ((y_true[:,2:-1:7]-y_true[:,3:-1:7])/y_true[:,2:-1:7])**2
    return sqerr.mean()

y_true = np.random.rand(50, 1000)
y_pred = np.random.rand(50, 1000)

print(custom_loss_numpy(y_true, y_pred))
889.992075384

print(K.eval(custom_loss_keras(K.variable(y_true), K.variable(y_pred))))
889.992

【讨论】:

    猜你喜欢
    • 2016-03-04
    • 2019-10-21
    • 2019-11-10
    • 2017-01-02
    • 2020-03-14
    • 1970-01-01
    • 1970-01-01
    • 2020-09-17
    • 2019-05-15
    相关资源
    最近更新 更多