Получение Keras / Tensorflow для вывода OneHotCategorical, но в операции есть None для градиента - PullRequest
1 голос
/ 10 октября 2019

Описание проблемы

У меня есть входные данные x, которые являются переменными индикатора, и выходные данные y, где каждая строка представляет собой случайный вектор с одним горячим током, который зависит от значений x (выборка данныхпоказано ниже).

Я хочу обучить модель, которая по существу изучает вероятностные отношения между x и y в форме весов для каждого столбца. Модель должна «выбрать» один и только один индикатор для вывода. Мой текущий подход заключается в выборке категориальной случайной величины и получении горячего вектора в качестве прогноза.

Проблема в том, что я получаю ошибку ValueError: An operation has `None` for gradient, когда пытаюсь обучить свою модель Keras.

Я нахожу эту ошибку странной, потому что я обучил смешанные сети, используя Keras и Tensorflow, которые используют tf.contrib.distributions.Categorical, и я не сталкивался с какими-либо проблемами, связанными с градиентом.

Код

Эксперимент

import tensorflow as tf
import tensorflow.contrib.distributions as tfd
import numpy as np
from keras import backend as K
from keras.layers import Layer
from keras.models import Sequential
from keras.utils import to_categorical


def 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]])

    # generate data and drop zeros for now
    x = rng.choice(2, (size, cols))
    is_zeros = x.sum(axis=1) == 0
    x = x[~is_zeros]

    # use weights to create probabilities for determining 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])

    # add zeros back and shuffle
    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, y


class 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)

        # weight indicators so that more probability is assigned to more likely columns
        weighted_x = x * self.kernel

        # fill zeros with -inf so that zero probability is assigned to that column
        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))

        # fill gate with zeros where input was originally zero
        zeros_fill = tf.fill(x_shape, 0.0)
        masked_gate = tf.where(zero_cond, zeros_fill, onehot_gate)
        return masked_gate


def 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.]])

>>> y
array([[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.

1 Ответ

1 голос
/ 10 октября 2019

Проблема заключается в том, что в OneHotCategorical выполняется прерывистая выборка - что приводит к сбою вычисления градиента. Чтобы заменить эту прерывистую выборку непрерывной ( расслабленной ) версией, можно попробовать использовать RelaxedOneHotCategorical (которая основана на интересной методике Gumbel Softmax ).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...