Пользовательские функции активации и производные для Keras и / или TFLearn
Я хотел бы поэкспериментировать с некоторыми функциями активации, которые не имеют классической производной (т. Е. Производная содержит импульсы Дирака, что не очень полезно для обучения типа градиентного спуска). Поэтому мне нужно определить и добавить в набор функции активации для Keras и / или TFLearn. И не только новая функция активации, но и ее определенная мной производная. Создание "поддельной" производной уже использовалось в бинаризованных нейронных сетях. Итак, я нашел это и попугаял это, чтобы определить свое собственное:
import numpy as np
import tensorflow as tf
from tensorflow.python.framework import ops
def nsign(x):
if x<0.0:
return -1.0
else:
return 1.0
np_nsign = np.vectorize(nsign)
def d_nsign(x):
if x>-1.0 and x<1.0:
return 1.0
else:
return 0.0
np_d_nsign = np.vectorize(d_nsign)
np_d_nsign_32 = lambda x: np_d_nsign(x).astype(np.float32)
def tf_d_nsign(x,name=None):
with ops.op_scope([x], name, "d_nsign") as name:
y = tf.py_func(np_d_nsign_32,
[x],
[tf.float32],
name=name,
stateful=False)
return y[0]
def py_func(func, inp, Tout, stateful=True, name=None, grad=None):
# Need to generate a unique name to avoid duplicates:
rnd_name = 'PyFuncGrad' + str(np.random.randint(0, 1E+8))
tf.RegisterGradient(rnd_name)(grad) # see _MySquareGrad for grad example
g = tf.get_default_graph()
with g.gradient_override_map({"PyFunc": rnd_name}):
return tf.py_func(func, inp, Tout, stateful=stateful, name=name)
def nsigngrad(op, grad):
x = op.inputs[0]
n_gr = tf_d_nsign(x)
return grad * n_gr
np_nsign_32 = lambda x: np_nsign(x).astype(np.float32)
def tf_nsign(x, name=None):
with ops.op_scope([x], name, "nsign") as name:
y = py_func(np_nsign_32,
[x],
[tf.float32],
name=name,
grad=nsigngrad) # <-- here's the call to the gradient
return y[0]
with tf.Session() as sess:
x = tf.constant([-0.2,0.7,1.2,-1.7])
y = tf_nsign(x)
tf.initialize_all_variables().run()
print(x.eval(), y.eval(), tf.gradients(y, [x])[0].eval())
Это сработало, кроме TF бормотания о том, что tf.op_scope устарел. Следующим шагом было перенести приведенный выше код в Keras для чего-то простого, такого как демонстрационный код cifar10, и изменить все результаты на n_sign, например так:
model.add(Activation(n_sign))
К сожалению, это привело к следующей ошибке:
Traceback (most recent call last):
File "cifar10_bin_tf.py", line 96, in <module>
model.add(Convolution2D(32, 3, 3))
File "/home/enzo/anaconda2/envs/neural/lib/python2.7/site-packages/keras/models.py", line 324, in add
output_tensor = layer(self.outputs[0])
File "/home/enzo/anaconda2/envs/neural/lib/python2.7/site-packages/keras/engine/topology.py", line 474, in __call__
self.assert_input_compatibility(x)
File "/home/enzo/anaconda2/envs/neural/lib/python2.7/site-packages/keras/engine/topology.py", line 415, in assert_input_compatibility
str(K.ndim(x)))
Exception: Input 0 is incompatible with layer convolution2d_2: expected ndim=4, found ndim=None
ndim звучит как "число измерений", что необъяснимо для того, что должно быть скалярной функцией. Нашел этот другой трюк для TH, но после адаптации он вызывает очень похожую ошибку (снова жалоба на ndim).
Вопросы: 1) Можете ли вы предложить исправление для вышеупомянутого?
2) Можете ли вы предложить другой простой способ сделать то, что я хочу, на таком высоком уровне, как Keras или TFLearn?
3) Будет ли приведенный выше код работать в TFLearn?
4) Сработает ли приведенный выше код, если я конвертирую cifar10 напрямую в TF и использую его там?
Очевидно, что я хотел бы избежать 4), поскольку это означает больше борьбы и конверсий.
Заранее большое спасибо.