TensorFlow 加载模型进行预测

1. 保存模型

model_path = "./saves/"
model_name = "fasttext"
saver = tf.train.Saver(max_to_keep=10)
saver.save(sess, model_path + model_name, global_step=train_steps)

保存模型时会在model_path路径下得到3个名为model_name的文件和一个checkpoint文件,如下所示:

.data-00000-of-00001和.index保存了所有的weights、biases、gradients等变量。
.meta保存了图结构。
checkpoint文件是个文本文件,里面记录了保存的最新的checkpoint文件以及其它checkpoint文件列表。

 

2. 加载模型

# 1. 加载graph 
self.graph = tf.Graph()
self.saver = tf.train.import_meta_graph(self.meta_path, graph=self.graph)
self.sess = tf.Session(graph = self.graph)
ckpt = tf.train.latest_checkpoint(self.model_path) # 找到存储变量值的位置
self.saver.restore(self.sess, ckpt)

# 2. graph.get_operation_by_name获取需要feed的placeholder
# 注意: 这些tensor的名字需要跟模型创建的时候对应
self.input_x = self.graph.get_operation_by_name('input_x').outputs[0]
self.keep_prob = self.graph.get_operation_by_name('keep_prob').outputs[0]

feed_dict = {
self.input_x:input_x,
self.keep_prob: 1
}

# 3. 获取运算变量
pre = self.graph.get_operation_by_name('pred').outputs[0]


# 4. sess.run获得模型的预测输出
prediction = self.sess.run([pre], feed_dict=feed_dict)


注:这里self.meta_path = "./saves/fasttext-12000.meta", self.model_path = "./saves/"

关于get_operation_by_name和get_tensor_by_name的区别可见https://www.codenong.com/cs105854164/,这里简单说一下,get_operation_by_name获取的是operation,传入name即可,get_tensor_by_name获取的是tensor,传入name:0,我们在运行时将op打印出来,在使用名字后面加上:0我们就能得到OP运算的结果的tensor,注意这两者的区别。

注:如果模型中断了,想要加载之前的训练结果继续训练,可参考https://blog.csdn.net/weixin_40546602/article/details/81410251

 

3. 模型固化

# -*-coding:utf-8 -*-
import os
import tensorflow as tf
from tensorflow.python.framework import graph_util

class FrozenDiy(object):
    """
    自定义一个类来加载训练好的模型并进行固化
    """
    def __init__(self, meta_path, model_path):
        """
        读取配置
        """
        self.meta_path = meta_path
        self.model_path = model_path
        if not os.path.exists(meta_path) or not os.path.exists(model_path):
            raise RuntimeError("模型文件不存在!")
        self.load_model()

    def load_model(self):
        """
        加载graph
        """
        self.graph = tf.Graph()
        self.saver = tf.train.import_meta_graph(self.meta_path, graph=self.graph)
        self.sess = tf.Session(graph = self.graph)
        ckpt = tf.train.latest_checkpoint(self.model_path)# 找到存储变量值的位置
        self.saver.restore(self.sess, ckpt)

    def frozen(self, frozen_graph_path):
        """
        固化模型
        """
        logits = self.graph.get_operation_by_name('Softmax').outputs[0]
        pred = self.graph.get_operation_by_name('pred').outputs[0]

        '''开始固化'''
        input_graph_def = self.graph.as_graph_def()
        out_graph_def = graph_util.convert_variables_to_constants(self.sess, input_graph_def, 
                                                ["pred", "Softmax"])
        with tf.gfile.GFile(frozen_graph_path, "wb") as f:
            f.write(out_graph_def.SerializeToString())
        '''固化结束'''

注:

1. 如果想获取概率logits要看其tensor name为哪一个,通过查看tensor发现其name为关键字Softmax,其scope应该和pred保持一致。

2. 获取所有tensor(每个op的输出张量)的name

 for tensor_name in tf.contrib.graph_editor.get_tensors(tf.get_default_graph()):
    print(tensor_name)

3. 如果想获取获取tf.layers.dense的输出, 需要单独使用 tf.identity:返回一个与输入具有相同形状和内容的张量。直接命名是对dense这一层进行命名(包含bias和weights)。具体可参考:https://blog.csdn.net/qq_32565543/article/details/94722706

self.logits = tf.layers.dense(h_drop, self.num_classes) 
self.logits  = tf.identify(self.logits , name="fc2")

 

4. 采用固化后的模型进行预测

# -*-coding:utf-8 -*-
import os
import tensorflow as tf

class FrozenPredict(object):
    """
    读取固化模型进行预测
    """
    def __init__(self, frozen_graph_path):
        """
        读取配置
        """
        self.frozen_graph_path = frozen_graph_path
        if not os.path.exists(frozen_graph_path):
            raise RuntimeError("模型文件不存在!")
        self.load_model()

    def load_model(self):
        """
        加载模型
        """
        with open(frozen_graph_path, "rb") as f:
            graph_def = tf.GraphDef()
            graph_def.ParseFromString(f.read())
        
        # 导入计算图
        self.graph = tf.Graph()
        with self.graph.as_default():
            tf.import_graph_def(graph_def, name="")
        
        self.sess = tf.Session(graph=self.graph)

    def predict(self, input_x):
        """
        预测
        """
        self.input_x = self.graph.get_tensor_by_name('input_x:0')
        self.keep_prob = self.graph.get_tensor_by_name('keep_prob:0')
        logits = self.graph.get_operation_by_name('Softmax').outputs[0]
        pred = self.graph.get_tensor_by_name('pred:0')

        feed_dict = {
        self.input_x:input_x,
        self.keep_prob: 1
        }

        #sess.run获得模型的预测输出
        prediction, logits = self.sess.run([pred, logits], feed_dict=feed_dict)
        probs = np.max(logis, 1) # 取最大概率,结果为一维数组
        print(prediction, probs) 

注:如果tf.import_graph_def指定了name,则graph.get_tensor_by_name要加上name,如graph.get_tensor_by_name("name/input_x:0")

 

5. 实验

模型固化的主函数调用

if __name__ == "__main__":
    # 固化模型
    meta_path = "./saves/fasttext-12000.meta"
    model_path = "./saves/"
    frozen_graph_path = "./saves/fasttext/constant_model.pb"
    froze_diy = FrozenDiy(meta_path, model_path)
    froze_diy.frozen(frozen_graph_path)

    
    # 预测
    froze_predict = FrozenPredict(frozen_graph_path)

    val_file = "./val.txt"
    data_set_val = load_data(val_file) # 加载数据
    max_seq_len = 32
    word2id_dict = load_dict("./word2id_dict.txt")
    label2id_dict = load_dict("./label2id_dict.txt")
    num_classes = len(label2id_dict)
    data_set_val = data_set_val[:5]
    val_x, val_y = convert_corpus_to_id_with_padding(data_set_val, word2id_dict, label2id_dict, max_seq_len, num_classes) # 把数据转成需要的格式
    froze_predict.predict(val_x)

完整代码可见:https://download.csdn.net/download/jingyi130705008/12590809

最近在跑deeplabv1,在测试代码的时候,跑通了训练程序,但是用训练好的模型进行与测试却发现相同的图片预测的结果不一样??请问有大神知道怎么回事吗? 用的是saver.restore()方法载入模型。代码如下: ``` def main(): """Create the model and start the inference process.""" args = get_arguments() # Prepare image. img = tf.image.decode_jpeg(tf.read_file(args.img_path), channels=3) # Convert RGB to BGR. img_r, img_g, img_b = tf.split(value=img, num_or_size_splits=3, axis=2) img = tf.cast(tf.concat(axis=2, values=[img_b, img_g, img_r]), dtype=tf.float32) # Extract mean. img -= IMG_MEAN # Create network. net = DeepLabLFOVModel() # Which variables to load. trainable = tf.trainable_variables() # Predictions. pred = net.preds(tf.expand_dims(img, dim=0)) # Set up TF session and initialize variables. config = tf.ConfigProto() config.gpu_options.allow_growth = True sess = tf.Session(config=config) #init = tf.global_variables_initializer() sess.run(tf.global_variables_initializer()) # Load weights. saver = tf.train.Saver(var_list=trainable) load(saver, sess, args.model_weights) # Perform inference. preds = sess.run([pred]) print(preds) if not os.path.exists(args.save_dir): os.makedirs(args.save_dir) msk = decode_labels(np.array(preds)[0, 0, :, :, 0]) im = Image.fromarray(msk) im.save(args.save_dir + 'mask1.png') print('The output file has been saved to {}'.format( args.save_dir + 'mask.png')) if __name__ == '__main__': main() ``` 其中load是 ``` def load(saver, sess, ckpt_path): '''Load trained weights. Args: saver: TensorFlow saver object. sess: TensorFlow session. ckpt_path: path to checkpoint file with parameters. ''' ckpt = tf.train.get_checkpoint_state(ckpt_path) if ckpt and ckpt.model_checkpoint_path: saver.restore(sess, ckpt.model_checkpoint_path) print("Restored model parameters from {}".format(ckpt_path)) ``` DeepLabLFOVMode类如下: ``` class DeepLabLFOVModel(object): """DeepLab-LargeFOV model with atrous convolution and bilinear upsampling. This class implements a multi-layer convolutional neural network for semantic image segmentation task. This is the same as the model described in this paper: https://arxiv.org/abs/1412.7062 - please look there for details. """ def __init__(self, weights_path=None): """Create the model. Args: weights_path: the path to the cpkt file with dictionary of weights from .caffemodel. """ self.variables = self._create_variables(weights_path) def _create_variables(self, weights_path): """Create all variables used by the network. This allows to share them between multiple calls to the loss function. Args: weights_path: the path to the ckpt file with dictionary of weights from .caffemodel. If none, initialise all variables randomly. Returns: A dictionary with all variables. """ var = list() index = 0 if weights_path is not None: with open(weights_path, "rb") as f: weights = cPickle.load(f) # Load pre-trained weights. for name, shape in net_skeleton: var.append(tf.Variable(weights[name], name=name)) del weights else: # Initialise all weights randomly with the Xavier scheme, # and # all biases to 0's. for name, shape in net_skeleton: if "/w" in name: # Weight filter. w = create_variable(name, list(shape)) var.append(w) else: b = create_bias_variable(name, list(shape)) var.append(b) return var def _create_network(self, input_batch, keep_prob): """Construct DeepLab-LargeFOV network. Args: input_batch: batch of pre-processed images. keep_prob: probability of keeping neurons intact. Returns: A downsampled segmentation mask. """ current = input_batch v_idx = 0 # Index variable. # Last block is the classification layer. for b_idx in xrange(len(dilations) - 1): for l_idx, dilation in enumerate(dilations[b_idx]): w = self.variables[v_idx * 2] b = self.variables[v_idx * 2 + 1] if dilation == 1: conv = tf.nn.conv2d(current, w, strides=[ 1, 1, 1, 1], padding='SAME') else: conv = tf.nn.atrous_conv2d( current, w, dilation, padding='SAME') current = tf.nn.relu(tf.nn.bias_add(conv, b)) v_idx += 1 # Optional pooling and dropout after each block. if b_idx < 3: current = tf.nn.max_pool(current, ksize=[1, ks, ks, 1], strides=[1, 2, 2, 1], padding='SAME') elif b_idx == 3: current = tf.nn.max_pool(current, ksize=[1, ks, ks, 1], strides=[1, 1, 1, 1], padding='SAME') elif b_idx == 4: current = tf.nn.max_pool(current, ksize=[1, ks, ks, 1], strides=[1, 1, 1, 1], padding='SAME') current = tf.nn.avg_pool(current, ksize=[1, ks, ks, 1], strides=[1, 1, 1, 1], padding='SAME') elif b_idx <= 6: current = tf.nn.dropout(current, keep_prob=keep_prob) # Classification layer; no ReLU. # w = self.variables[v_idx * 2] w = create_variable(name='w', shape=[1, 1, 1024, n_classes]) # b = self.variables[v_idx * 2 + 1] b = create_bias_variable(name='b', shape=[n_classes]) conv = tf.nn.conv2d(current, w, strides=[1, 1, 1, 1], padding='SAME') current = tf.nn.bias_add(conv, b) return current def prepare_label(self, input_batch, new_size): """Resize masks and perform one-hot encoding. Args: input_batch: input tensor of shape [batch_size H W 1]. new_size: a tensor with new height and width. Returns: Outputs a tensor of shape [batch_size h w 18] with last dimension comprised of 0's and 1's only. """ with tf.name_scope('label_encode'): # As labels are integer numbers, need to use NN interp. input_batch = tf.image.resize_nearest_neighbor( input_batch, new_size) # Reducing the channel dimension. input_batch = tf.squeeze(input_batch, squeeze_dims=[3]) input_batch = tf.one_hot(input_batch, depth=n_classes) return input_batch def preds(self, input_batch): """Create the network and run inference on the input batch. Args: input_batch: batch of pre-processed images. Returns: Argmax over the predictions of the network of the same shape as the input. """ raw_output = self._create_network( tf.cast(input_batch, tf.float32), keep_prob=tf.constant(1.0)) raw_output = tf.image.resize_bilinear( raw_output, tf.shape(input_batch)[1:3, ]) raw_output = tf.argmax(raw_output, dimension=3) raw_output = tf.expand_dims(raw_output, dim=3) # Create 4D-tensor. return tf.cast(raw_output, tf.uint8) def loss(self, img_batch, label_batch): """Create the network, run inference on the input batch and compute loss. Args: input_batch: batch of pre-processed images. Returns: Pixel-wise softmax loss. """ raw_output = self._create_network( tf.cast(img_batch, tf.float32), keep_prob=tf.constant(0.5)) prediction = tf.reshape(raw_output, [-1, n_classes]) # Need to resize labels and convert using one-hot encoding. label_batch = self.prepare_label( label_batch, tf.stack(raw_output.get_shape()[1:3])) gt = tf.reshape(label_batch, [-1, n_classes]) # Pixel-wise softmax loss. loss = tf.nn.softmax_cross_entropy_with_logits(logits=prediction, labels=gt) reduced_loss = tf.reduce_mean(loss) return reduced_loss ``` 按理说载入模型应该没有问题,可是不知道为什么结果却不一样? 图片:![图片说明](https://img-ask.csdn.net/upload/201911/15/1573810836_83106.jpg) ![图片说明](https://img-ask.csdn.net/upload/201911/15/1573810850_924663.png) 预测的结果: ![图片说明](https://img-ask.csdn.net/upload/201911/15/1573810884_985680.png) ![图片说明](https://img-ask.csdn.net/upload/201911/15/1573810904_577649.png) 两次结果不一样,与保存的模型算出来的结果也不一样。 我用的是GitHub上这个人的代码: https://github.com/minar09/DeepLab-LFOV-TensorFlow 急急急,请问有大神知道吗???
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页