在TensorFlow张量上调用Keras模型,但保留权重



在Keras作为TensorFlow的简化接口中:教程描述了如何在TensorFlow张量上调用Keras模型。

from keras.models import Sequential
model = Sequential()
model.add(Dense(32, activation='relu', input_dim=784))
model.add(Dense(10, activation='softmax'))
# this works! 
x = tf.placeholder(tf.float32, shape=(None, 784))
y = model(x)

他们还说:

注意:通过调用Keras模型,您可以重用其架构和权重。当您在张量上调用模型时,您在输入张量的顶部创建新的TF操作,这些操作重用模型中已经存在的TF变量实例。

我将其解释为模型的权重在y中与在模型中相同。然而,对我来说,结果Tensorflow节点中的权重似乎被重新初始化了。下面可以看到一个最小的例子:

import numpy as np
from keras.models import Sequential
from keras.layers import Dense
# Create model with weight initialized to 1
model = Sequential()
model.add(Dense(1, input_dim=1, kernel_initializer='ones',
bias_initializer='zeros'))
model.compile(loss='binary_crossentropy', optimizer='adam',
metrics=['accuracy'])
# Save the weights 
model.save_weights('file')
# Create another identical model except with weight initialized to 0
model2 = Sequential()
model2.add(Dense(1, input_dim=1, kernel_initializer='zeros',
bias_initializer='zeros'))
model2.compile(loss='binary_crossentropy', optimizer='adam',
metrics=['accuracy'])
# Load the weight from the first model
model2.load_weights('file')
# Call model with Tensorflow tensor
v = tf.Variable([[1, ], ], dtype=tf.float32)
node = model2(v)
sess = tf.Session()
init = tf.global_variables_initializer()
sess.run(init)
print(sess.run(node), model2.predict(np.array([[1, ], ])))
# Prints (array([[ 0.]], dtype=float32), array([[ 1.]], dtype=float32))

我为什么要这样做:

我想在另一个最小化方案中使用经过训练的网络,如果网络"惩罚"搜索空间中不允许的地方。因此,如果你有不涉及这种具体方法的想法,也非常感谢。

终于找到了答案。这个问题的例子有两个问题。

1:

第一个也是最明显的是,我调用了tf.global_variables_intializer()函数,它将重新初始化会话中的所有变量。相反,我应该调用tf.variables_initializer(var_list),其中var_list是要初始化的变量列表。

2:

第二个问题是Keras没有使用与原生Tensorflow对象相同的会话。这意味着,为了能够使用会话sess运行tensorflow对象model2(v),需要对其进行重新初始化。再次Keras作为tensorflow的简化界面:教程能够帮助

我们应该首先创建一个TensorFlow会话并将其注册到Keras。这意味着Keras将使用我们注册的会话来初始化它在内部创建的所有变量。

import tensorflow as tf
sess = tf.Session()
from keras import backend as K
K.set_session(sess)

如果我们将这些更改应用于我的问题中提供的示例,我们将得到以下代码,该代码完全符合预期

from keras import backend as K
from keras.models import Sequential
from keras.layers import Dense
sess = tf.Session()
# Register session with Keras
K.set_session(sess)
model = Sequential()
model.add(Dense(1, input_dim=1, kernel_initializer='ones',
bias_initializer='zeros'))
model.compile(loss='binary_crossentropy', optimizer='adam',
metrics=['accuracy'])
model.save_weights('test')
model2 = Sequential()
model2.add(Dense(1, input_dim=1, kernel_initializer='zeros',
bias_initializer='zeros'))
model2.compile(loss='binary_crossentropy', optimizer='adam',
metrics=['accuracy'])
model2.load_weights('test')
v = tf.Variable([[1, ], ], dtype=tf.float32)
node = model2(v)
init = tf.variables_initializer([v, ])
sess.run(init)
print(sess.run(node), model2.predict(np.array([[1, ], ])))
# prints: (array([[ 1.]], dtype=float32), array([[ 1.]], dtype=float32))

结论:

教训是,当混合Tensorflow和Keras时,请确保所有内容都使用相同的会话。

感谢您提出并回答这个问题,它帮助了我!除了在Keras后端设置相同的tf会话外,还需要注意的是,如果您想从文件加载Keras模型,则需要在加载模型之前运行全局变量初始值设定项操作。

sess = tf.Session()
# make sure keras has the same session as this code
tf.keras.backend.set_session(sess)
# Do this BEFORE loading a keras model
init_op = tf.global_variables_initializer()
sess.run(init_op)

model = models.load_model('path/to/your/model.h5')

最新更新