tensorflow 导入pb模型进行前向推导

tensorflow一般使用pb文件进行前向推导(在非部署环境使用ckpt也可以)载入pb文件到图的函数

def load_pb_to_graph(sess, pb_file):
with tf.gfile.FastGFile(pb_file, "rb") as f:
graph_def = tf.GraphDef()
graph_def.ParseFromString(f.read())
sess.graph.as_default()
tf.import_graph_def(graph_def,name="")

在会话中,调用该函数,并根据名称获取输入和输出的tensor,然后就可以sess.run进行前向推导

load_pb_to_graph(sess, "xxnet.pb")
inputs = tf.get_default_graph().get_tensor_by_name("xxnet/input:0")
outputs = tf.get_default_graph().get_tensor_by_name("xxnet/score:0")
scores = sess.run([outputs], feed_dict={inputs: input_data})

tensorflow 将ckpt文件导出为pb文件

tensorflow训练时将模型保存为ckpt文件,它包含了网络结构、网络权重、训练过程中间变量等等信息。而网络部署一般是使用pb文件,它将变量保存为常量,以及网络前向传播的所有必要结构。如何将ckpt文件导出为pb文件?

首先,使用tfrecord训练的ckpt一般包含读取训练tfrecord文件的结构,而这是pb文件所不需要的。pb文件通常使用placeholder接受输入。因此,要以placeholder为输入重新定义一遍网络结构(通常就是调用一次网络构建函数)。假设为
output = xxnet(input_placeholder)
要获取输出节点的名称
output_nd_name = output.op.name

然后,载入ckpt的权重
saver = tf.train.Saver()
saver.restore(sess, “xxnet.ckpt”)

然后,将其中的变量转化为常量,保存模型

out_graph_def = tf.graph_util.convert_variables_to_constants(
    sess=sess,
    input_graph_def=sess.graph_def,
    output_node_names=[output_nd_name]
)
with tf.gfile.GFile("xxnet.pb","wb") as f:
    f.write(out_graph_def.SerializeToString())

tensorflow 训练网络的一般步骤

本文不针对tensorflow2.0。首先要构建数据的输入,一般是将数据转化为pb格式

然后构建自己的网络,并构建损失函数的节点。构建网络有多种方式,可以用代码构建(利用slim、keras等高级api,或者基础的api,或者已有的代码),也可以从ckpt.meta中载入网络结构(断点继续训练等情况)tf.train.import_meta_graph(“xxx.ckpt.meta”)。这里要注意,一般训练时会同时进行网络在验证集上的测试,比如每训练n步后在训练集上进行测试。因此构建网络需要同时构建一个验证网络,共享训练网络的变量权重。构建验证网络时要在variable_scope中设置reuse=True。

定义优化器,如opt=tf.train.AdamOptimizer()
将优化器应用在损失节点上计算梯度。grads=opt.compute_gradients(L)
梯度下降优化节点 apply_grad_op = opt.apply_gradients(grads)

训练模型需要保存,定义一个saver
saver = tf.train.Saver(max_to_keep=10) 最多保留10个ckpt
在训练时,使用saver.save(sess, “xxx.ckpt”, global_step=step)保存ckpt文件

希望在训练时看到训练过程, 使用tf.summary.scalar 添加想要的变量到训练过程日志中。
如 tf.summary.scalar(“training loss”, L)添加训练损失到训练过程。然后定义summary_op = tf.summary.merge_all()
然后要定义一个summary_writer
summary_writer = tf.summary.FileWriter(logdir, sess.graph)
训练时,每隔n步,使用summary_writer.add_summary(sess.run(summary_op), step)保存训练过程日志
训练开始后,就可以使用tensorboard查看训练过程了

训练过程一般在一个for循环中进行,
sess.run([apply_grad_op])进行网络的训练
在这个循环中,还要进行上面所说的保存ckpt文件、训练日志

tensorflow 初始化新增变量,保持载入的预训练模型权重不变

我们经常会遇到这样一些问题,想要使用一些预训练好的模型,然后在其基础上进行一些增减,以适应新的任务。在开始训练之前,要对所有的新增变量进行初始化,但是要保持预训练模型中已有的权重不变,即只初始化新增变量。而如果使用tensorflow中提供的saver.restore(sess, ckpt_path),会报找不到新增节点的错误!记录一下这种情况要如何处理。

首先,在对预训练模型进行增减之前,先进行saver.restore(sess, ckpt_path)载入预训练权重,然后再进行对网络结构的增减(这里可以使用tf.get_default_graph().get_tensor_by_name(tensor_name)获取到原网络中的tensor,来进行新增节点)

在增加完新增节点之后,要初始化这些新增节点权重变量。接下来就是最关键的一步,获取网络中所有未初始化的权重变量。

def get_uninitialized_variables(sess):
global_vars = tf.global_variables()
is_not_initialized = sess.run([tf.is_variable_initialized(var) for var in global_vars])
not_initialized_vars = [v for (v, f) in zip(global_vars, is_not_initialized) if not f]
print([str(i.name) for i in not_initialized_vars])
return not_initialized_vars

然后在会话中,初始化这些变量

sess.run(tf.variables_initializer(get_uninitialized_variables(sess)))

接下来就可以愉快地进行训练了

Python中logging的使用

python中logging用于记录日志,记录一下该模块的用法

logging日志级别分为6种,从低到高分别为NOTSET、DEBUG、INFO、WARNING、ERROR、CRITICAL,logging执行时会输出大于等于设置级别的信息。默认的设置级别是WARNING。

首先import logging
然后logging.basicConfig(filename=”xxx.log”, filemode=”w”, format=”%(asctime)s %(name)s:%(levelname)s:%(message)s”, datefmt=”%d-%M-%Y %H:%M:%S”, level=logging.DEBUG)
然后就可以在需要输出日志信息的地方加入下面的语句
logging.debug(‘This is a debug message’)
logging.info(‘This is an info message’)
logging.warning(‘This is a warning message’)
logging.error(‘This is an error message’)
logging.critical(‘This is a critical message’)

其中,format中的内容格式如下

生成的日志文件xxx.log,内容如下:

19-11-18 21:10:32 root:DEBUG:This is a debug message
19-11-18 21:10:32 root:INFO:This is an info message
19-11-18 21:10:32 root:WARNING:This is a warning message
19-11-18 21:10:32 root:ERROR:This is an error message
19-11-18 21:10:32 root:CRITICAL:This is a critical message

摘抄自 https://cloud.tencent.com/developer/article/1354396

linux 解压、压缩

tar
-c:建立压缩档案
-x:解压
-t:查看内容
-r:向压缩归档文件末尾追加文件
-u:更新原压缩包中的文件
这五个是互斥的参数,必须用且仅能用其中一个,可以和其它参数连用。

-z: gzip相关
-j: bz2相关
-Z:compress相关
-v:显示所有过程
根据需要在压缩或者解压时选择

-f: 使用档案名字。该参数必须为最后一个参数。后面加上文件名

tar –xvf file.tar //解压 tar包
tar -xzvf file.tar.gz //解压tar.gz
tar -xjvf file.tar.bz2   //解压 tar.bz2
tar –xZvf file.tar.Z   //解压tar.Z
unrar e file.rar //解压rar
unzip file.zip //解压zip

tar -cvf xx.tar *.txt //将目录里所有txt文件打包成xx.tar
tar -czf xx.tar.gz *.txt //将目录里所有txt文件打包并用gzip压缩,得到xx.tar.gz
tar -cjf xx.tar.bz2 *.txt //将目录里所有txt文件打包并用bzip2压缩,得到xx.tar.bz2

Python2和Python3中 / 的差异

今天用python2的时候,发现a=19/25,a竟然为0!搜了一下才知道python2中,一个整数被另一个整数除,结果只保留整数部分。类似python3中//的操作。想得到预期中的小数形式,可以将参与运算的其中一个数字变为小数。

>>>1.0/2
0.5

如何在TensorFlow中添加自定义数据显示在tensorboard中

以在tensorboard中添加训练过程中网络的损失值为例。

在网络构建阶段,
L = xxnet.loss(output, label)
tf.summary.scalar("Training loss", L)
然后添加一个op
summary_op = tf.summary.merge_all()

在会话中,定义一个SummaryWriter
summary_writer = tf.summary.FileWriter(logdir, sess.graph)
在每一训练步骤中,
summary_str = sess.run(summary_op)
summary_writer.add_summary(summary_str, step)

然后当训练开始后,就可以在tensorboard中看到损失值了。不过,这种方式缺乏灵活性。更推荐使用下面的方式

summary_writer = tf.summary.FileWriter(logdir)
summary = tf.Summary(value=[
    tf.Summary.Value(tag="Training loss", simple_value=L),
    tf.Summary.Value(tag="Validation loss", simple_value=L_val)])
summary_writer.add_summary(summary, step)

或者:

summary_writer = tf.summary.FileWriter(logdir)
summary = tf.Summary()
summary.value.add(tag="Training loss", simple_value=L)
summary.value.add(tag="Validation loss", simple_value=L_val)
summary_writer.add_summary(summary, step)

C/C++中的mmset函数

void * memset(void *buffer, int c, int count)
将buffer所指位置后面的count个字节用c代替,并返回buffer。c实际值应该在0到255之间

在一段内存块中填充某个给定的值,是对较大的结构体或者数组进行 清零操作的最快方法。

对一个数组清零示意

char buf[20];
mmset(buf, 0, sizeof(char)*20);

Python使用progressbar模块实现显示进度条功能

首先用pip安装progressbar。pip install progressbar

用法一

import time 
from progressbar import * 
total=1000 
def dosomework():
     time.sleep(0.01) 
progress =ProgressBar() 
for i in progress(range(1000)): 
    dosomework()

显示效果:

 5% |###                                                                      |
100% |######################################################################|

用法二

from __future__ import division
import sys, time
from progressbar import *
total=1000
def dosomework():
    time.sleep(0.01)
pbar = ProgressBar().start()
for i inrange(1000):
    pbar.update(int((i /(total -1)) *100))
    dosomework()
pbar.finish()

用法三

import time
from progressbar import *
total=1000
def dosomework():
    time.sleep(0.01)
widgets =['Progress: ',Percentage(), ' ', Bar('#'),' ', Timer(),' ', ETA(), ' ', FileTransferSpeed()]
pbar=ProgressBar(widgets=widgets, maxval=10*total).start()
for i inrange(total):
    pbar.update(10*i +1)
    dosomework()
pbar.finish()

显示效果:

Progress:   3% |###                                                                                | Elapsed Time: 0:00:15 ETA: 0:09:02 919.67  B/s
Progress: 100% |###################################################################################| Elapsed Time: 0:10:10 Time: 0:10:10 917.42  B/s

widgets可选参数含义:

‘Progress: ‘ :设置进度条前显示的文字
Percentage() :显示百分比
Bar(‘#’) : 设置进度条形状
ETA() : 显示预计剩余时间
Timer() :显示已用时间

在pycharm中使用时,需要在Run —>Edit Configurations里勾上Emulate terminal in output console