title: Custom Mean Directional Accuracy loss function in Keras
body: <p>I am trying to define <a href="https://www.wikiwand.com/en/Mean_Directional_Accuracy_(MDA)" rel="nofollow noreferrer">MDA</a> as loss function in Keras:</p>
  
  <p><a href="https://i.stack.imgur.com/mdYid.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/mdYid.png" alt="enter image description here"></a></p>
  
  <p>I have an example in TensorFlow which seems to work:</p>
  
  <pre><code>import numpy as np
  import tensorflow as tf
  import matplotlib.pyplot as plt
  
  
  def mda(y, y_hat):
      c = tf.equal(tf.sign(y[1:] - y[:-1]), tf.sign(y_hat[1:] - y_hat[:-1]))
      return tf.reduce_mean(tf.cast(c, tf.float32))
  
  y = np.array([0, 1, 2, 1, 0, 1])
  y_hat = np.array([0, 1, 0, 1, 0, 1])
  plt.plot(y)
  plt.plot(y_hat, alpha=.6)
  plt.show()
  
  sess = tf.Session()
  print(sess.run(mda(tf.constant(y), tf.constant(y_hat))))
  </code></pre>
  
  <p>The corresponding plot:</p>
  
  <p><a href="https://i.stack.imgur.com/JXS2R.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/JXS2R.png" alt="enter image description here"></a></p>
  
  <p>And the <code>mda</code> result: 0.6 which is 3/5 and makes sense in this case since 3 out of 5 directions were predicted correctly.</p>
  
  <p>However if I try to implement this code in Keras:</p>
  
  <pre><code>def mda(y_true, y_pred):
      """Compute Mean Directional Accuracy.
  
      https://en.wikipedia.org/wiki/Mean_Directional_Accuracy_(MDA)
  
      Parameters
      ----------
      y_true : tensor
      y_pred : tensor
  
      Returns
      -------
      mda : tensor
      """
      s = K.equal(K.sign(y_true[1:] - y_true[:-1]),
                   K.sign(y_pred[1:] - y_pred[:-1]))
      return K.mean(K.cast(s, K.floatx()))
  </code></pre>
  
  <p>I get a <code>ValueError: None values not supported.</code> which I can't resolve. </p>
  
  <p>Logs:</p>
  
  <pre><code>ValueError                                Traceback (most recent call last)
  &lt;ipython-input-101-b8bdd1fcaea1&gt; in &lt;module&gt;()
       67                         callbacks=[reduce_lr],
       68                         validation_data=(teX, teY),
  ---&gt; 69                         verbose=1)
       70     print("Runtime:", time.time() - start)
       71 
  
  /anaconda/lib/python3.6/site-packages/keras/models.py in fit(self, x, y, batch_size, epochs, verbose, callbacks, validation_split, validation_data, shuffle, class_weight, sample_weight, initial_epoch, **kwargs)
      861                               class_weight=class_weight,
      862                               sample_weight=sample_weight,
  --&gt; 863                               initial_epoch=initial_epoch)
      864 
      865     def evaluate(self, x, y, batch_size=32, verbose=1,
  
  /anaconda/lib/python3.6/site-packages/keras/engine/training.py in fit(self, x, y, batch_size, epochs, verbose, callbacks, validation_split, validation_data, shuffle, class_weight, sample_weight, initial_epoch, **kwargs)
     1411         else:
     1412             ins = x + y + sample_weights
  -&gt; 1413         self._make_train_function()
     1414         f = self.train_function
     1415 
  
  /anaconda/lib/python3.6/site-packages/keras/engine/training.py in _make_train_function(self)
      935                 self._collected_trainable_weights,
      936                 self.constraints,
  --&gt; 937                 self.total_loss)
      938             updates = self.updates + training_updates
      939             # Gets loss and metrics. Updates weights at each call.
  
  /anaconda/lib/python3.6/site-packages/keras/optimizers.py in get_updates(self, params, constraints, loss)
      231         for p, g, a in zip(params, grads, accumulators):
      232             # update accumulator
  --&gt; 233             new_a = self.rho * a + (1. - self.rho) * K.square(g)
      234             self.updates.append(K.update(a, new_a))
      235             new_p = p - lr * g / (K.sqrt(new_a) + self.epsilon)
  
  /anaconda/lib/python3.6/site-packages/keras/backend/tensorflow_backend.py in square(x)
     1369         A tensor.
     1370     """
  -&gt; 1371     return tf.square(x)
     1372 
     1373 
  
  /anaconda/lib/python3.6/site-packages/tensorflow/python/ops/math_ops.py in square(x, name)
      472           indices=x.indices, values=x_square, dense_shape=x.dense_shape)
      473     else:
  --&gt; 474       return gen_math_ops.square(x, name=name)
      475 
      476 
  
  /anaconda/lib/python3.6/site-packages/tensorflow/python/ops/gen_math_ops.py in square(x, name)
     2731     A `Tensor`. Has the same type as `x`.
     2732   """
  -&gt; 2733   result = _op_def_lib.apply_op("Square", x=x, name=name)
     2734   return result
     2735 
  
  /anaconda/lib/python3.6/site-packages/tensorflow/python/framework/op_def_library.py in apply_op(self, op_type_name, name, **keywords)
      502             # What type does convert_to_tensor think it has?
      503             observed = ops.internal_convert_to_tensor(
  --&gt; 504                 values, as_ref=input_arg.is_ref).dtype.name
      505             prefix = ("Input '%s' of '%s' Op has type %s that does not match" %
      506                       (input_name, op_type_name, observed))
  
  /anaconda/lib/python3.6/site-packages/tensorflow/python/framework/ops.py in internal_convert_to_tensor(value, dtype, name, as_ref, preferred_dtype)
      714 
      715         if ret is None:
  --&gt; 716           ret = conversion_func(value, dtype=dtype, name=name, as_ref=as_ref)
      717 
      718         if ret is NotImplemented:
  
  /anaconda/lib/python3.6/site-packages/tensorflow/python/framework/constant_op.py in _constant_tensor_conversion_function(v, dtype, name, as_ref)
      174                                          as_ref=False):
      175   _ = as_ref
  --&gt; 176   return constant(v, dtype=dtype, name=name)
      177 
      178 
  
  /anaconda/lib/python3.6/site-packages/tensorflow/python/framework/constant_op.py in constant(value, dtype, shape, name, verify_shape)
      163   tensor_value = attr_value_pb2.AttrValue()
      164   tensor_value.tensor.CopyFrom(
  --&gt; 165       tensor_util.make_tensor_proto(value, dtype=dtype, shape=shape, verify_shape=verify_shape))
      166   dtype_value = attr_value_pb2.AttrValue(type=tensor_value.tensor.dtype)
      167   const_tensor = g.create_op(
  
  /anaconda/lib/python3.6/site-packages/tensorflow/python/framework/tensor_util.py in make_tensor_proto(values, dtype, shape, verify_shape)
      358   else:
      359     if values is None:
  --&gt; 360       raise ValueError("None values not supported.")
      361     # if dtype is provided, forces numpy array to be the type
      362     # provided if possible.
  
  ValueError: None values not supported.
  </code></pre>
  
  <p>I also can't reproduce this error with TensorFlow, e.g. I tried to replace one of the <code>y_hat</code> values with <code>None</code> but that throws a different error. </p>
  
  <p>I'm not sure if that <code>ValueError</code> means that somehow <code>None</code> values are being generated during runtime or if I messed up the Keras implementation. I really appreciate any help.</p>