使用Keras/Tensorflow输出OneHotCategorical,但操作的梯度为None

问题描述

我的输入是x,它们是指示变量,输出是y,其中每一行是一个依赖于x值的随机独热向量(下面展示了数据样本)。

我想训练一个模型,该模型本质上学习xy之间的概率关系,形式为每列的权重。模型必须“选择”一个,且仅一个指示变量作为输出。我当前的方法是抽样一个分类随机变量并生成一个独热向量作为预测。

问题是我在尝试训练我的Keras模型时遇到了错误ValueError: An operation has `None` for gradient

我觉得这个错误很奇怪,因为我之前使用Keras和Tensorflow训练过混合网络,它们使用tf.contrib.distributions.Categorical,我没有遇到任何与梯度相关的问题。

代码

实验

import tensorflow as tfimport tensorflow.contrib.distributions as tfdimport numpy as npfrom keras import backend as Kfrom keras.layers import Layerfrom keras.models import Sequentialfrom keras.utils import to_categoricaldef make_xy_prob(rng, size=10000):    rng = np.random.RandomState(rng) if isinstance(rng, int) else rng    cols = 3    weights = np.array([[1, 2, 3]])    # 生成数据并暂时删除零值    x = rng.choice(2, (size, cols))    is_zeros = x.sum(axis=1) == 0    x = x[~is_zeros]    # 使用权重创建概率以确定y    weighted_x = x * weights    prob_x = weighted_x / weighted_x.sum(axis=1, keepdims=True)    y = np.row_stack([to_categorical(rng.choice(cols, p=p), cols) for p in prob_x])    # 重新添加零值并打乱顺序    zeros = np.zeros(((size - len(x), cols)))    x = np.row_stack([x, zeros])    y = np.row_stack([y, zeros])    shuffle_idx = rng.permutation(size)    x = x[shuffle_idx]    y = y[shuffle_idx]    return x, yclass OneHotGate(Layer):    def build(self, input_shape):        self.kernel = self.add_weight(name='kernel', shape=(1, input_shape[1]), initializer='ones')    def call(self, x):        zero_cond = x < 1        x_shape = tf.shape(x)        # 加权指示变量,以便为更可能的列分配更多概率        weighted_x = x * self.kernel        # 用-inf填充零值,以便为该列分配零概率        ninf_fill = tf.fill(x_shape, -np.inf)        masked_x = tf.where(zero_cond, ninf_fill, weighted_x)        onehot_gate = tf.squeeze(tfd.OneHotCategorical(logits=masked_x, dtype=x.dtype).sample(1))        # 在输入原本为零的地方用零填充门        zeros_fill = tf.fill(x_shape, 0.0)        masked_gate = tf.where(zero_cond, zeros_fill, onehot_gate)        return masked_gatedef experiment(epochs=10):    K.clear_session()    rng = np.random.RandomState(2)    X, y = make_xy_prob(rng)    input_shape = (X.shape[1], )    model = Sequential()    gate_layer = OneHotGate(input_shape=input_shape)    model.add(gate_layer)    model.compile('adam', 'categorical_crossentropy')    model.fit(X, y, 64, epochs, verbose=1)

数据样本

>>> x array([[1., 1., 1.],       [0., 1., 0.],       [1., 0., 1.],       ...,       [1., 1., 1.],       [1., 1., 1.],       [1., 1., 0.]])>>> yarray([[0., 0., 1.],       [0., 1., 0.],       [1., 0., 0.],       ...,       [0., 0., 1.],       [1., 0., 0.],       [1., 0., 0.]])

错误

ValueError: An operation has `None` for gradient. Please make sure that all of your ops have a gradient defined (i.e. are differentiable). Common ops without gradient: K.argmax, K.round, K.eval.

回答:

问题在于OneHotCategorical执行的是不连续的抽样,这导致梯度计算失败。为了用连续的(松弛的)版本替换这种不连续的抽样,可以尝试使用RelaxedOneHotCategorical(它基于有趣的Gumbel Softmax技术)。

Related Posts

使用LSTM在Python中预测未来值

这段代码可以预测指定股票的当前日期之前的值,但不能预测…

如何在gensim的word2vec模型中查找双词组的相似性

我有一个word2vec模型,假设我使用的是googl…

dask_xgboost.predict 可以工作但无法显示 – 数据必须是一维的

我试图使用 XGBoost 创建模型。 看起来我成功地…

ML Tuning – Cross Validation in Spark

我在https://spark.apache.org/…

如何在React JS中使用fetch从REST API获取预测

我正在开发一个应用程序,其中Flask REST AP…

如何分析ML.NET中多类分类预测得分数组?

我在ML.NET中创建了一个多类分类项目。该项目可以对…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注