在Tensorflow中加载多个模型

15

我在Tensorflow中编写了以下卷积神经网络(CNN)类[为了清晰起见,我尝试省略了一些代码行。]

class CNN:
def __init__(self,
                num_filters=16,        # initial number of convolution filters
             num_layers=5,           # number of convolution layers
             num_input=2,           # number of channels in input
             num_output=5,          # number of channels in output
             learning_rate=1e-4,    # learning rate for the optimizer
             display_step = 5000,   # displays training results every display_step epochs
             num_epoch = 10000,     # number of epochs for training
             batch_size= 64,        # batch size for mini-batch processing
             restore_file=None,      # restore file (default: None)

            ):

                # define placeholders
                self.image = tf.placeholder(tf.float32, shape = (None, None, None,self.num_input))  
                self.groundtruth = tf.placeholder(tf.float32, shape = (None, None, None,self.num_output)) 

                # builds CNN and compute prediction
                self.pred = self._build()

                # I have already created a tensorflow session and saver objects
                self.sess = tf.Session()
                self.saver = tf.train.Saver()

                # also, I have defined the loss function and optimizer as
                self.loss = self._loss_function()
                self.optimizer = tf.train.AdamOptimizer(learning_rate).minimize(self.loss)

                if restore_file is not None:
                    print("model exists...loading from the model")
                    self.saver.restore(self.sess,restore_file)
                else:
                    print("model does not exist...initializing")
                    self.sess.run(tf.initialize_all_variables())

def _build(self):
    #builds CNN

def _loss_function(self):
    # computes loss


# 
def train(self, train_x, train_y, val_x, val_y):
    # uses mini batch to minimize the loss
    self.sess.run(self.optimizer, feed_dict = {self.image:sample, self.groundtruth:gt})


    # I save the session after n=10 epochs as:
    if epoch%n==0:
        self.saver.save(sess,'snapshot',global_step = epoch)

# finally my predict function is
def predict(self, X):
    return self.sess.run(self.pred, feed_dict={self.image:X})

我已经分别为两个独立的任务训练了两个CNN模型。每个模型都花费了大约一天的时间,分别保存在“snapshot-model1-10000”和“snapshot-model2-10000”(以及它们对应的元文件)中。我可以单独测试每个模型并计算其性能。

现在,我想在一个脚本中加载这两个模型。我自然会尝试以下操作:

cnn1 = CNN(..., restore_file='snapshot-model1-10000',..........) 
cnn2 = CNN(..., restore_file='snapshot-model2-10000',..........)

我遇到了错误[错误信息比较长,我只复制/粘贴了其中的一部分。]

NotFoundError: Tensor name "Variable_26/Adam_1" not found in checkpoint files /home/amitkrkc/codes/A549_models/snapshot-hela-95000
     [[Node: save_1/restore_slice_85 = RestoreSlice[dt=DT_FLOAT, preferred_shard=-1, _device="/job:localhost/replica:0/task:0/cpu:0"](_recv_save_1/Const_0, save_1/restore_slice_85/tensor_name, save_1/restore_slice_85/shape_and_slice)]]

有没有办法从这两个文件中加载两个独立的CNN?欢迎任何建议/评论/反馈。

谢谢!

5个回答

26

有的。使用单独的图表。

g1 = tf.Graph()
g2 = tf.Graph()

with g1.as_default():
    cnn1 = CNN(..., restore_file='snapshot-model1-10000',..........) 
with g2.as_default():
    cnn2 = CNN(..., restore_file='snapshot-model2-10000',..........)

编辑:

如果你想要将它们放到同一个图中,你需要重命名一些变量。一个想法是将每个 CNN 放在单独的作用域中,并让 saver 处理该作用域中的变量,例如:

saver = tf.train.Saver(tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES), scope='model1')

并在CNN中将所有构建物包裹在范围内:

with tf.variable_scope('model1'):
    ...

编辑2:

另一个想法是重命名变量,这些变量由saver管理(因为我假设您希望在不重新训练的情况下使用已保存的检查点)。保存允许在图形中使用不同的变量名称和检查点中使用不同的变量名称,请查看文档以进行初始化。


非常感谢。您的第一个建议对我的情况很有效。 - Amit

10

这应该是对最受欢迎的答案进行评论,但我没有足够的声望来这样做。

不管怎样,如果您(任何人搜索并到达此处)仍然对lpp提供的解决方案有困惑,并且您正在使用Keras,请检查来自GitHub的以下引用。

这是因为如果没有提供默认的TF会话,则Keras共享全局会话

当model1创建时,它在graph1上 当model1加载权重时,权重在与graph1关联的Keras全局会话中

当model2创建时,它在graph2上 当model2加载权重时,全局会话不知道graph2

下面的解决方案可能有所帮助,

graph1 = Graph()
with graph1.as_default():
    session1 = Session()
    with session1.as_default():
        with open('model1_arch.json') as arch_file:
            model1 = model_from_json(arch_file.read())
        model1.load_weights('model1_weights.h5')
        # K.get_session() is session1

# do the same for graph2, session2, model2

1
你需要创建2个会话并分别恢复2个模型。为了使其工作,您需要执行以下操作:
1a. 当保存模型时,您需要向变量名称添加范围。这样,您就会知道哪些变量属于哪个模型:
# The first model
tf.Variable(tf.zeros([self.batch_size]), name="model_1/Weights")
...

# The second model 
tf.Variable(tf.zeros([self.batch_size]), name="model_2/Weights")
...

1b. 或者,如果您已经保存了模型,可以通过添加范围并使用this script重命名变量。

2. 当您恢复不同的模型时,需要按变量名称进行过滤,如下所示:

# The first model
sess_1 = tf.Session()
sess_1.run(tf.initialize_all_variables())
saver_1 = tf.train.Saver([v for v in tf.all_variables() if 'model_1' in v.name])
saver_1.restore(sess_1, weights_1_file)
sess_1.run(pred, feed_dict={image: X})

# The second model
sess_2 = tf.Session()
sess_2.run(tf.initialize_all_variables())
saver_2 = tf.train.Saver([v for v in tf.all_variables() if 'model_2' in v.name])
saver_2.restore(sess_2, weights_2_file)
sess_2.run(pred, feed_dict={image: X})

-1

我遇到了同样的问题,而且在网上找到的任何解决方案都无法解决这个问题(不需要重新训练)。所以我在两个单独的线程中加载每个模型,这些线程与主线程通信。编写代码足够简单,只需在同步线程时小心即可。

在我的情况下,每个线程接收其问题的输入并将输出返回给主线程。它可以正常工作,没有任何可观察的开销。


你能提供一个你的解决方案的例子吗? - gab

-1

如果你想连续训练或加载多个模型,一种方法是清除你的会话。你可以轻松地使用以下方式完成:

from keras import backend as K 

# load and use model 1

K.clear_session()

# load and use  model 2

K.clear_session()`

K.clear_session()会销毁当前的TF图并创建一个新的图。 这对于避免旧模型/层的混乱非常有用。


2
这个方法适用于一个接一个地加载模型,但是如果你想要同时加载它们就不行了。此外,这是Keras的方法,Tensorflow的替代方法是tf.reset_default_graph() - tsveti_iko

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接