rstudio / tfestimators

R interface to TensorFlow Estimators
https://tensorflow.rstudio.com/tfestimators
57 stars 21 forks source link

Using custom prediction function in prediction #117

Open dfalbel opened 6 years ago

dfalbel commented 6 years ago

Suppose I need to do downsampling in each batch during training. Since I can't create all batches before start training I created an input function like this:

downsampling_input_fn <- function(dataset, batch_size) {
  function() {

    y_1 <- dataset %>%
      filter(y == 1) %>%
      sample_n(batch_size/2)

    y_0 <- dataset %>%
      filter(y == 0) %>%
      sample_n(batch_size/2)

    df <- bind_rows(y_1, y_0)

    reticulate::tuple(
      inputs = tf$constant(df$x, shape = c(batch_size, 1)),
      labels = tf$constant(df$y, shape = c(batch_size, 1))
    )
  }
}

And I was able to train the following model:

my_custom_fn <- function(inputs, labels, mode, params, config) {

  # Connect the first hidden layer to input layer
  logits <- tf$layers$dense(inputs, 1L)
  output_layer <- tf$nn$sigmoid(logits)

  # Reshape output layer to 1-dim Tensor to return predictions
  # TODO: This failed if it's c(-1L) - check in reticulate for single element vector conversion
  predictions <- tf$reshape(output_layer, list(-1L))
  predictions_list <- list(pred = predictions)

  # Calculate loss using mean squared error
  loss <- tf$losses$sigmoid_cross_entropy(labels, logits)

  optimizer <- tf$train$GradientDescentOptimizer(learning_rate = 0.01)
  train_op <- optimizer$minimize(loss = loss, global_step = tf$train$get_global_step())

  estimator_spec(
    mode = mode,
    predictions = predictions_list,
    loss = loss,
    train_op = train_op
  )
}

model <- estimator(my_custom_fn)

dataset <- data_frame(
  x = runif(10000),
  y = rbinom(10000, size = 1, prob = x)
)

train(model, input_fn = downsampling_input_fn(dataset, 16), steps = 1000)

Now, I want to create predictions, and I created an special input_fn for prediction like this:

prediction_input_fn <- function(df) {
  function(){
    reticulate::tuple(
      inputs = tf$constant(df$x, shape = c(nrow(df), 1))
    )
  }
}

predict(model, prediction_input_fn(dataset))

And It gives me the following error:

WARNING:tensorflow:Input graph does not contain a QueueRunner. That means predict yields forever. This is probably a mistake.
Error in py_iterate(it, f) : 
  RuntimeError: Evaluation error: ValueError: None values not supported.

Detailed traceback: 
  File "/home/dani/.virtualenvs/r-tensorflow/lib/python2.7/site-packages/tensorflow/python/ops/losses/losses_impl.py", line 580, in sigmoid_cross_entropy
    multi_class_labels = math_ops.cast(multi_class_labels, logits.dtype)
  File "/home/dani/.virtualenvs/r-tensorflow/lib/python2.7/site-packages/tensorflow/python/ops/math_ops.py", line 713, in cast
    x = ops.convert_to_tensor(x, name="x")
  File "/home/dani/.virtualenvs/r-tensorflow/lib/python2.7/site-packages/tensorflow/python/framework/ops.py", line 611, in convert_to_tensor
    as_ref=False)
  File "/home/dani/.virtualenvs/r-tensorflow/lib/python2.7/site-packages/tensorflow/python/framework/ops.py", line 676, in internal_convert_to_tensor
    ret = conversion_func(value, dtype=dtype, name=name, as_ref=as_ref)
  File "/home/dani/.virtualenvs/r-tensorflow/lib/python2.7/site-packages/tensorflow/python/framework/constant_op.py", l

I'm sure I'm doing something wrong, but what's the recommended approach to this problem? I think this will be a common thing to do, since negative sampling methods (like the one used in word2vec) are also very used!

I tried using the input_fn but had an error too. For example, I called:

prediction_input_fn <- input_fn(y ~ x, dataset)
predict(model, prediction_input_fn)

But got:

Error in py_iterate(it, f) : 
  RuntimeError: Evaluation error: ValueError: None values not supported.

Detailed traceback: 
  File "/home/dani/.virtualenvs/r-tensorflow/lib/python2.7/site-packages/tensorflow/python/ops/losses/losses_impl.py", line 580, in sigmoid_cross_entropy
    multi_class_labels = math_ops.cast(multi_class_labels, logits.dtype)
  File "/home/dani/.virtualenvs/r-tensorflow/lib/python2.7/site-packages/tensorflow/python/ops/math_ops.py", line 713, in cast
    x = ops.convert_to_tensor(x, name="x")
  File "/home/dani/.virtualenvs/r-tensorflow/lib/python2.7/site-packages/tensorflow/python/framework/ops.py", line 611, in convert_to_tensor
    as_ref=False)
  File "/home/dani/.virtualenvs/r-tensorflow/lib/python2.7/site-packages/tensorflow/python/framework/ops.py", line 676, in internal_convert_to_tensor
    ret = conversion_func(value, dtype=dtype, name=name, as_ref=as_ref)
  File "/home/dani/.virtualenvs/r-tensorflow/lib/python2.7/site-packages/tensorflow/python/framework/constant_op.py", l
terrytangyuan commented 6 years ago

I think your custom model function is defined problematically. The ValueError happens in sigmoid_cross_entropy(), which means you are passing None values to it. Try defining your model function more carefully using mode and calculate/return only the things that are valid for that particular mode.