【发布时间】:2019-05-15 22:53:39
【问题描述】:
我正在 Tensorflow 中构建强化学习算法,我希望能够在一次调用 session.run() 后动态关闭 dropout,然后再打开。
基本原理:我需要 (1) 做一个没有 dropout 的前向传递来计算目标; (2) 对生成的目标进行训练。如果我在对session.run() 的不同调用中执行这两个步骤,则一切正常。但我想通过一次调用session.run()(使用tf.stop_gradients(targets))来做到这一点。
在尝试了几个没有成功的解决方案之后,我找到了一个解决方案,我将 Keras 使用的 learning_phase 占位符替换为一个变量(因为占位符是张量并且不允许赋值)并使用一个自定义层,根据需要将该变量设置为 True 或 False。该解决方案如下面的代码所示。分别获取m1 或m2 的值(例如,运行sess.run(m1, feed_dict={ph:np.ones((1,1))}) 按预期工作而不会出错。但是,获取m3 的值,或获取m1 和m2 的值同时,有时有效,有时无效(并且错误消息没有提供信息)。
你知道我做错了什么或更好的方法来做我想做的事吗?
编辑: 代码显示了一个玩具示例。实际上,我有一个模型,我需要运行两次向前传球(一次关闭 dropout,另一次打开 dropout)和一次向后传球。我想在不返回 python 的情况下完成这一切。
from tensorflow.keras.layers import Dropout, Dense, Input, Layer
from tensorflow.python.keras import backend as K
from tensorflow.keras import Model
import tensorflow as tf
import numpy as np
class DropoutSwitchLayer(Layer):
def __init__(self, stateful=True, **kwargs):
self.stateful = stateful
self.supports_masking = True
super(DropoutSwitchLayer, self).__init__(**kwargs)
def build(self, input_shape):
self.lph = tf.Variable(True, dtype=tf.bool, name="lph", trainable=False)
K._GRAPH_LEARNING_PHASES[tf.get_default_graph()] = self.lph
super(DropoutSwitchLayer, self).build(input_shape)
def call(self, inputs, mask=None):
data_input, training = inputs
op = self.lph.assign(training[0], use_locking=True)
# ugly trick here to make the layer work
data_input = data_input + tf.multiply(tf.cast(op, dtype=tf.float32), 0.0)
return data_input
def compute_output_shape(self, input_shape):
return input_shape[0]
dropout_on = np.array([True], dtype=np.bool)
dropout_off = np.array([False], dtype=np.bool)
input_ph = tf.placeholder(tf.float32, shape=(None, 1))
drop = Input(shape=(), dtype=tf.bool)
input = Input(shape=(1,))
h = DropoutSwitchLayer()([input, drop])
h = Dense(1)(h)
h = Dropout(0.5)(h)
o = Dense(1)(h)
m = Model(inputs=[input, drop], outputs=o)
m1 = m([input_ph, dropout_on])
m2 = m([input_ph, dropout_off])
m3 = m([m2, dropout_on])
sess = tf.Session()
K.set_session(sess)
sess.run(tf.global_variables_initializer())
编辑 2: Daniel Möller 下面的解决方案在使用 Dropout 层时有效,但如果在 LSTM 层内使用 dropout 会怎样?
input = Input(shape=(1,))
h = Dense(1)(input)
h = RepeatVector(2)(h)
h = LSTM(1, dropout=0.5, recurrent_dropout=0.5)(h)
o = Dense(1)(h)
【问题讨论】:
标签: python tensorflow keras keras-layer dropout