我试图用keras(作为诊断工具)计算相对于神经网络的权重的梯度范数.最后,我想为此创建一个回调,但在那里,我一直在努力创建一个可以计算渐变的函数,并以numpy数组/标量值的形式返回实际值(而不仅仅是张量流张量).代码如下:
import numpy as np
import keras.backend as K
from keras.layers import Dense
from keras.models import Sequential
def get_gradient_norm_func(model):
grads = K.gradients(model.total_loss, model.trainable_weights)
summed_squares = [K.sum(K.square(g)) for g in grads]
norm = K.sqrt(sum(summed_squares))
func = K.function([model.input], [norm])
return func
def main():
x = np.random.random((128,)).reshape((-1, 1))
y = 2 * x
model = Sequential(layers=[Dense(2, input_shape=(1,)),
Dense(1)])
model.compile(loss='mse', optimizer='RMSprop')
get_gradient = get_gradient_norm_func(model)
history = model.fit(x, y, epochs=1)
print(get_gradient([x]))
if __name__ == '__main__':
main()
代码在调用get_gradient()时失败.追溯是漫长的,涉及很多形状,但很少有关于什么是正确形状的信息.我怎么能纠正这个?
理想情况下,我想要一个与后端无关的解决方案,但基于张量流的解决方案也是一种选择.
2017-08-15 15:39:14.914388: W tensorflow/core/framework/op_kernel.cc:1148] Invalid argument: Shape [-1,-1] has negative dimensions
2017-08-15 15:39:14.914414: E tensorflow/core/common_runtime/executor.cc:644] Executor Failed to create kernel. Invalid argument: Shape [-1,-1] has negative dimensions
[[Node: dense_2_target = Placeholder[dtype=DT_FLOAT, shape=[?,?], _device="/job:localhost/replica:0/task:0/cpu:0"]()]]
2017-08-15 15:39:14.915026: W tensorflow/core/framework/op_kernel.cc:1148] Invalid argument: Shape [-1,-1] has negative dimensions
2017-08-15 15:39:14.915038: E tensorflow/core/common_runtime/executor.cc:644] Executor Failed to create kernel. Invalid argument: Shape [-1,-1] has negative dimensions
[[Node: dense_2_target = Placeholder[dtype=DT_FLOAT, shape=[?,?], _device="/job:localhost/replica:0/task:0/cpu:0"]()]]
2017-08-15 15:39:14.915310: W tensorflow/core/framework/op_kernel.cc:1148] Invalid argument: Shape [-1] has negative dimensions
2017-08-15 15:39:14.915321: E tensorflow/core/common_runtime/executor.cc:644] Executor Failed to create kernel. Invalid argument: Shape [-1] has negative dimensions
[[Node: dense_2_sample_weights = Placeholder[dtype=DT_FLOAT, shape=[?], _device="/job:localhost/replica:0/task:0/cpu:0"]()]]
Traceback (most recent call last):
File "/home/josteb/.local/opt/anaconda3/envs/timeseries/lib/python3.6/site-packages/tensorflow/python/client/session.py", line 1139, in _do_call
return fn(*args)
File "/home/josteb/.local/opt/anaconda3/envs/timeseries/lib/python3.6/site-packages/tensorflow/python/client/session.py", line 1121, in _run_fn
status, run_Metadata)
File "/home/josteb/.local/opt/anaconda3/envs/timeseries/lib/python3.6/contextlib.py", line 89, in __exit__
next(self.gen)
File "/home/josteb/.local/opt/anaconda3/envs/timeseries/lib/python3.6/site-packages/tensorflow/python/framework/errors_impl.py", line 466, in raise_exception_on_not_ok_status
pywrap_tensorflow.TF_GetCode(status))
tensorflow.python.framework.errors_impl.InvalidArgumentError: Shape [-1] has negative dimensions
[[Node: dense_2_sample_weights = Placeholder[dtype=DT_FLOAT, shape=[?], _device="/job:localhost/replica:0/task:0/cpu:0"]()]]
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "gradientlog.py", line 45, in <module>
main()
File "gradientlog.py", line 42, in main
print(get_gradient([x]))
File "/home/josteb/sandBox/keras/keras/backend/tensorflow_backend.py", line 2251, in __call__
**self.session_kwargs)
File "/home/josteb/.local/opt/anaconda3/envs/timeseries/lib/python3.6/site-packages/tensorflow/python/client/session.py", line 789, in run
run_Metadata_ptr)
File "/home/josteb/.local/opt/anaconda3/envs/timeseries/lib/python3.6/site-packages/tensorflow/python/client/session.py", line 997, in _run
Feed_dict_string, options, run_Metadata)
File "/home/josteb/.local/opt/anaconda3/envs/timeseries/lib/python3.6/site-packages/tensorflow/python/client/session.py", line 1132, in _do_run
target_list, options, run_Metadata)
File "/home/josteb/.local/opt/anaconda3/envs/timeseries/lib/python3.6/site-packages/tensorflow/python/client/session.py", line 1152, in _do_call
raise type(e)(node_def, op, message)
tensorflow.python.framework.errors_impl.InvalidArgumentError: Shape [-1] has negative dimensions
[[Node: dense_2_sample_weights = Placeholder[dtype=DT_FLOAT, shape=[?], _device="/job:localhost/replica:0/task:0/cpu:0"]()]]
Caused by op 'dense_2_sample_weights', defined at:
File "gradientlog.py", line 45, in <module>
main()
File "gradientlog.py", line 39, in main
model.compile(loss='mse', optimizer='RMSprop')
File "/home/josteb/sandBox/keras/keras/models.py", line 783, in compile
**kwargs)
File "/home/josteb/sandBox/keras/keras/engine/training.py", line 799, in compile
name=name + '_sample_weights'))
File "/home/josteb/sandBox/keras/keras/backend/tensorflow_backend.py", line 435, in placeholder
x = tf.placeholder(dtype, shape=shape, name=name)
File "/home/josteb/.local/opt/anaconda3/envs/timeseries/lib/python3.6/site-packages/tensorflow/python/ops/array_ops.py", line 1530, in placeholder
return gen_array_ops._placeholder(dtype=dtype, shape=shape, name=name)
File "/home/josteb/.local/opt/anaconda3/envs/timeseries/lib/python3.6/site-packages/tensorflow/python/ops/gen_array_ops.py", line 1954, in _placeholder
name=name)
File "/home/josteb/.local/opt/anaconda3/envs/timeseries/lib/python3.6/site-packages/tensorflow/python/framework/op_def_library.py", line 767, in apply_op
op_def=op_def)
File "/home/josteb/.local/opt/anaconda3/envs/timeseries/lib/python3.6/site-packages/tensorflow/python/framework/ops.py", line 2506, in create_op
original_op=self._default_original_op, op_def=op_def)
File "/home/josteb/.local/opt/anaconda3/envs/timeseries/lib/python3.6/site-packages/tensorflow/python/framework/ops.py", line 1269, in __init__
self._traceback = _extract_stack()
InvalidArgumentError (see above for traceback): Shape [-1] has negative dimensions
[[Node: dense_2_sample_weights = Placeholder[dtype=DT_FLOAT, shape=[?], _device="/job:localhost/replica:0/task:0/cpu:0"]()]]
解决方法:
在Keras中有几个与梯度计算过程相关的占位符:
>输入x
>目标y
>样本权重:即使你没有在model.fit()中提供它,Keras仍会为样本权重生成一个占位符,并提供np.ones((y.shape [0],),dtype = K.floatx( ))在训练期间进入图表.
>学习阶段:只有在使用任何层(例如Dropout)时,此占位符才会连接到渐变张量.
因此,在您提供的示例中,为了计算渐变,您需要将x,y和sample_weights输入到图形中.这是错误的根本原因.
在Model._make_train_function()里面有the following lines,显示了在这种情况下如何构造K.function()的必要输入:
inputs = self._Feed_inputs + self._Feed_targets + self._Feed_sample_weights
if self.uses_learning_phase and not isinstance(K.learning_phase(), int):
inputs += [K.learning_phase()]
with K.name_scope('training'):
...
self.train_function = K.function(inputs,
[self.total_loss] + self.metrics_tensors,
updates=updates,
name='train_function',
**self._function_kwargs)
通过模仿此函数,您应该能够获得标准值:
def get_gradient_norm_func(model):
grads = K.gradients(model.total_loss, model.trainable_weights)
summed_squares = [K.sum(K.square(g)) for g in grads]
norm = K.sqrt(sum(summed_squares))
inputs = model.model._Feed_inputs + model.model._Feed_targets + model.model._Feed_sample_weights
func = K.function(inputs, [norm])
return func
def main():
x = np.random.random((128,)).reshape((-1, 1))
y = 2 * x
model = Sequential(layers=[Dense(2, input_shape=(1,)),
Dense(1)])
model.compile(loss='mse', optimizer='rmsprop')
get_gradient = get_gradient_norm_func(model)
history = model.fit(x, y, epochs=1)
print(get_gradient([x, y, np.ones(len(y))]))
执行输出:
Epoch 1/1
128/128 [==============================] - 0s - loss: 2.0073
[4.4091368]
请注意,由于您使用的是Sequential而不是Model,因此需要model.model._Feed_ *而不是model._Feed_ *.