tensorflow 进阶
tensorflow中的mnist数据集读取以及一些高级操作
tensorflow的封装让使用MNIST数据集变得更加方便,它包含了60000张图片作为训练数据,10000张图片作为测试数据,每张图片大小为28x28
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("data/",one_hot=True)
Successfully downloaded train-images-idx3-ubyte.gz 9912422 bytes.
Extracting data/train-images-idx3-ubyte.gz
Successfully downloaded train-labels-idx1-ubyte.gz 28881 bytes.
Extracting data/train-labels-idx1-ubyte.gz
Successfully downloaded t10k-images-idx3-ubyte.gz 1648877 bytes.
Extracting data/t10k-images-idx3-ubyte.gz
Successfully downloaded t10k-labels-idx1-ubyte.gz 4542 bytes.
Extracting data/t10k-labels-idx1-ubyte.gz
print(mnist.train.num_examples)
print(mnist.validation.num_examples)
print(mnist.test.num_examples)
55000
5000
10000
mnist.train.images.shape
(55000, 784)
为了方便使用随机梯度下降,提供了mnist.train.next_batch函数,可以从所有训练数据中读取一小部分作为一个bacth
变量管理
inference这个函数中包含了神经网络中的所有参数,调用这个函数时需要传入所有这些函数,非常麻烦,有没有什么更简单的办法呢?
tensorflow提供了通过变量名称来创建或者获取一个变量的机制,通过这个机制在不同函数中可以直接通过变量的名字来使用变量而不需要将变量通过参数的形式到处传递
主要通过tf.get_variable和tf.variable_scope来实现
import tensorflow as tf
# 下面两个定义等价
v1 = tf.get_variable('v1', shape=[1], initializer=tf.constant_initializer(1.0))
v2 = tf.Variable(tf.constant(1.0, shape=[1]), name='v2')
v1
<tf.Variable 'v1:0' shape=(1,) dtype=float32_ref>
v2
<tf.Variable 'v2:0' shape=(1,) dtype=float32_ref>
对于tf.Variable,变量名称name是一个可选的参数,然而对于tf.get_variable,变量名称必须指定,它会根据这个名字去创建或者获取变量。
如果需要通过tf.get_variable获取一个已创建的变量,需要通过tf.variable_scope来生成一个上下文管理器,并明确指定在这个上下文管理器中,tf.get_variable将直接获取已经生成的变量
# 在名字为foo的命名空间内创建名字为v的变量
with tf.variable_scope('foo'):
v = tf.get_variable('v', [1], initializer=tf.constant_initializer(1.0))
# 将参数reuse设置为True这样tf.get_varible可以直接获取已经声明的变量
with tf.variable_scope('foo', reuse=True):
v1 = tf.get_variable('v',[1])
print(v1==v)
print(v1)
True
<tf.Variable 'foo/v:0' shape=(1,) dtype=float32_ref>
除此之外tf.variable_scope是可以嵌套的
with tf.variable_scope('root'):
# 可以通过tf.get_variable_scope().reuse获取当前上下文管理器中reuse参数的值
print(tf.get_variable_scope().reuse)
with tf.variable_scope('foo', reuse=True):
print(tf.get_variable_scope().reuse)
with tf.variable_scope('bar'):
print(tf.get_variable_scope().reuse)
print(tf.get_variable_scope().reuse)
False
True
True
False
# 可以直接通过带命名空间名称的变量名来获取其他命名空间的变量
with tf.variable_scope("", reuse=True):
v5 = tf.get_variable('foo/bar/v', [1])
利用这两个函数对inference做出改进
def inference(input_tensor, reuse=False):
with tf.variable_scope('layer1', reuse=reuse):
# 根据传进来的reuse来判断是创建新变量还是使用已经创建好的
weights = tf.get_variable('weights', [INPUT_NODE, LAYER1_NODE], initializer=tf.truncated_normal_initializer(stddev=0.1))
biases = tf.get_variable('biases', [LAYER1_NODE], initializer=tf.constant_initializer(0.0))
layer1 = tf.nn.relu(tf.matmul(input_tensor, weights) + biases)
with tf.variable_scope('layer2', reuse=reuse):
# 根据传进来的reuse来判断是创建新变量还是使用已经创建好的
weights = tf.get_variable('weights', [LAYER1_NODE, OUTPUT_NODE], initializer=tf.truncated_normal_initializer(stddev=0.1))
biases = tf.get_variable('biases', [OUTPUT_NODE], initializer=tf.constant_initializer(0.0))
layer2 = tf.matmul(layer1, weights) + biases
return layer2
# 在程序中如果需要使用训练好的神经网络进行推导时,可以直接调用inference(x, True)
模型持久化
以往的代码在训练完成后就直接退出了,并没有将训练得到的模型保存下来便于以后使用。tensorflow提供了可以持久化模型的方法,便于保存和还原
v1 = tf.Variable(tf.constant(1.0,shape=[1]), name='v1')
v2 = tf.Variable(tf.constant(2.0,shape=[1]), name='v2')
result = v1 + v2
init_op = tf.global_variables_initializer()
saver = tf.train.Saver()
with tf.Session() as sess:
sess.run(init_op)
# 将模型保存到 'tensorboard\model.ckpt'文件
saver.save(sess,'tensorboard\model.ckpt')
tensorflow模型一般保存在后缀为.ckpt的文件中,虽然上面只指定了一个文件路径,但是在这个文件目录下会出现三个文件,因为tensorflow会将计算图的结构和图上参数取值分开保存
第一个文件为model.ckpt.meta,它保存了计算图的结构(可以理解为神经网络的结构)
第二个文件为model.ckpt,保存了每一个变量的取值。
最后一个文件为checkpoint,保存了一个目录下所有模型的文件列表
# 加载已保存的模型,没有运行变量初始化的过程而是将变量的值通过已保存的模型加载及进来
with tf.Session() as sess:
saver.restore(sess, 'tensorboard\model.ckpt')
print(sess.run(result))
INFO:tensorflow:Restoring parameters from tensorboard\model.ckpt
[ 3.]
如果不希望重复定义图上的运算,也可以直接加载已经持久化的图
saver = tf.train.import_meta_graph( 'tensorboard\model.ckpt.meta')
with tf.Session() as sess:
saver.restore(sess, 'tensorboard\model.ckpt')
print(sess.run(tf.get_default_graph().get_tensor_by_name('add:0')))
INFO:tensorflow:Restoring parameters from tensorboard\model.ckpt
[ 3.]
有时只希望加载部分变量,这时可以在加载模型时指定需要加载的变量
saver = tf.train.Saver([v1])这样就只有v1会被加载进来
除此之外,也可以在保存或加载时给变量重命名
变量取值和计算图结构分成不同的文件存储有时候并不方便,tensorflow提供了convert_variables_to_constants函数,可以将计算图中的变量及其取值通过常量的方式保存,这样整个计算图就可以统一存放在一个文件中。
from tensorflow.python.framework import graph_util
v1 = tf.Variable(tf.constant(1.0, shape=[1]), name='v1')
v2 = tf.Variable(tf.constant(2.0, shape=[1]), name='v2')
result = v1 + v2
init_op = tf.global_variables_initializer()
with tf.Session() as sess:
sess.run(init_op)
# 导出当前计算图的GraphDef
graph_def = tf.get_default_graph().as_graph_def()
#将图中变量及其取值转换为常量
out_graph_def = graph_util.convert_variables_to_constants(sess, graph_def, ['add'])
# 将导出的模型存入文件中
with tf.gfile.GFile('tensorboard\combined_model.pb', 'wb') as f:
f.write(out_graph_def.SerializeToString())
INFO:tensorflow:Froze 2 variables.
Converted 2 variables to const ops.
读取已保存的模型
from tensorflow.python.platform import gfile
with tf.Session() as sess:
model_filename = 'tensorboard\combined_model.pb'
# 读取保存的模型,并将文件解析成GraphDef Protocol Buffer
with gfile.FastGFile(model_filename, 'rb') as f:
graph_def = tf.GraphDef()
graph_def.ParseFromString(f.read())
# 将graph_def中保存的图加载到当前的图中
result = tf.import_graph_def(graph_def, return_elements=['add:0'])
print(sess.run(result))
[array([ 3.], dtype=float32)]
持久化原理及数据格式
tensorflow通过元图(MetaGraph)来记录计算图节点的信息以及计算图中节点所需要的元数据,它是由MetaGraphDef Protocol Buffer定义的,这就构成了持久化的第一个文件medel.ckpt.meta
message MetaGraphDef {
MetaInfoDef meta_info_def =1;
GraphDef graph_def = 2;
SaverDef saver_def = 3;
map<string, CollectionDef> collection_def = 4;
map<string, SignatureDef> signature_def = 5;
}
# 通过export_meta_graph函数将以json格式导出MetaGraphDef
import tensorflow as tf
v1 = tf.Variable(tf.constant(1.0, shape=[1]), name='v1')
v2 = tf.Variable(tf.constant(2.0, shape=[1]), name='v2')
result = v1 + v2
saver = tf.train.Saver()
saver.export_meta_graph('tensorboard\model.ckpt.meta.json', as_text=True)
meta_info_def {
stripped_op_list {
op {
name: "Add"
input_arg {
name: "x"
type_attr: "T"
}
input_arg {
name: "y"
type_attr: "T"
}
output_arg {
name: "z"
type_attr: "T"
}
attr {
name: "T"
type: "type"
allowed_values {
list {
type: DT_HALF
type: DT_FLOAT
type: DT_DOUBLE
type: DT_UINT8
type: DT_INT8
type: DT_INT16
type: DT_INT32
type: DT_INT64
type: DT_COMPLEX64
type: DT_COMPLEX128
type: DT_STRING
}
}
}
}
op {
name: "Assign"
input_arg {
name: "ref"
type_attr: "T"
is_ref: true
}
input_arg {
name: "value"
type_attr: "T"
}
output_arg {
name: "output_ref"
type_attr: "T"
is_ref: true
}
attr {
name: "T"
type: "type"
}
attr {
name: "validate_shape"
type: "bool"
default_value {
b: true
}
}
attr {
name: "use_locking"
type: "bool"
default_value {
b: true
}
}
allows_uninitialized_input: true
}
op {
name: "Const"
output_arg {
name: "output"
type_attr: "dtype"
}
attr {
name: "value"
type: "tensor"
}
attr {
name: "dtype"
type: "type"
}
}
op {
name: "Identity"
input_arg {
name: "input"
type_attr: "T"
}
output_arg {
name: "output"
type_attr: "T"
}
attr {
name: "T"
type: "type"
}
}
op {
name: "NoOp"
}
op {
name: "RestoreV2"
input_arg {
name: "prefix"
type: DT_STRING
}
input_arg {
name: "tensor_names"
type: DT_STRING
}
input_arg {
name: "shape_and_slices"
type: DT_STRING
}
output_arg {
name: "tensors"
type_list_attr: "dtypes"
}
attr {
name: "dtypes"
type: "list(type)"
has_minimum: true
minimum: 1
}
}
op {
name: "SaveV2"
input_arg {
name: "prefix"
type: DT_STRING
}
input_arg {
name: "tensor_names"
type: DT_STRING
}
input_arg {
name: "shape_and_slices"
type: DT_STRING
}
input_arg {
name: "tensors"
type_list_attr: "dtypes"
}
attr {
name: "dtypes"
type: "list(type)"
has_minimum: true
minimum: 1
}
}
op {
name: "VariableV2"
output_arg {
name: "ref"
type_attr: "dtype"
is_ref: true
}
attr {
name: "shape"
type: "shape"
}
attr {
name: "dtype"
type: "type"
}
attr {
name: "container"
type: "string"
default_value {
s: ""
}
}
attr {
name: "shared_name"
type: "string"
default_value {
s: ""
}
}
is_stateful: true
}
}
tensorflow_version: "1.2.1"
tensorflow_git_version: "b\'unknown\'"
}
graph_def {
node {
name: "Const"
op: "Const"
attr {
key: "_output_shapes"
value {
list {
shape {
dim {
size: 1
}
}
}
}
}
attr {
key: "dtype"
value {
type: DT_FLOAT
}
}
attr {
key: "value"
value {
tensor {
dtype: DT_FLOAT
tensor_shape {
dim {
size: 1
}
}
float_val: 1.0
}
}
}
}
node {
name: "v1"
op: "VariableV2"
attr {
key: "_output_shapes"
value {
list {
shape {
dim {
size: 1
}
}
}
}
}
attr {
key: "container"
value {
s: ""
}
}
attr {
key: "dtype"
value {
type: DT_FLOAT
}
}
attr {
key: "shape"
value {
shape {
dim {
size: 1
}
}
}
}
attr {
key: "shared_name"
value {
s: ""
}
}
}
node {
name: "v1/Assign"
op: "Assign"
input: "v1"
input: "Const"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
attr {
key: "_class"
value {
list {
s: "loc:@v1"
}
}
}
attr {
key: "_output_shapes"
value {
list {
shape {
dim {
size: 1
}
}
}
}
}
attr {
key: "use_locking"
value {
b: true
}
}
attr {
key: "validate_shape"
value {
b: true
}
}
}
node {
name: "v1/read"
op: "Identity"
input: "v1"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
attr {
key: "_class"
value {
list {
s: "loc:@v1"
}
}
}
attr {
key: "_output_shapes"
value {
list {
shape {
dim {
size: 1
}
}
}
}
}
}
node {
name: "Const_1"
op: "Const"
attr {
key: "_output_shapes"
value {
list {
shape {
dim {
size: 1
}
}
}
}
}
attr {
key: "dtype"
value {
type: DT_FLOAT
}
}
attr {
key: "value"
value {
tensor {
dtype: DT_FLOAT
tensor_shape {
dim {
size: 1
}
}
float_val: 2.0
}
}
}
}
node {
name: "v2"
op: "VariableV2"
attr {
key: "_output_shapes"
value {
list {
shape {
dim {
size: 1
}
}
}
}
}
attr {
key: "container"
value {
s: ""
}
}
attr {
key: "dtype"
value {
type: DT_FLOAT
}
}
attr {
key: "shape"
value {
shape {
dim {
size: 1
}
}
}
}
attr {
key: "shared_name"
value {
s: ""
}
}
}
node {
name: "v2/Assign"
op: "Assign"
input: "v2"
input: "Const_1"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
attr {
key: "_class"
value {
list {
s: "loc:@v2"
}
}
}
attr {
key: "_output_shapes"
value {
list {
shape {
dim {
size: 1
}
}
}
}
}
attr {
key: "use_locking"
value {
b: true
}
}
attr {
key: "validate_shape"
value {
b: true
}
}
}
node {
name: "v2/read"
op: "Identity"
input: "v2"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
attr {
key: "_class"
value {
list {
s: "loc:@v2"
}
}
}
attr {
key: "_output_shapes"
value {
list {
shape {
dim {
size: 1
}
}
}
}
}
}
node {
name: "add"
op: "Add"
input: "v1/read"
input: "v2/read"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
attr {
key: "_output_shapes"
value {
list {
shape {
dim {
size: 1
}
}
}
}
}
}
node {
name: "save/Const"
op: "Const"
attr {
key: "_output_shapes"
value {
list {
shape {
}
}
}
}
attr {
key: "dtype"
value {
type: DT_STRING
}
}
attr {
key: "value"
value {
tensor {
dtype: DT_STRING
tensor_shape {
}
string_val: "model"
}
}
}
}
node {
name: "save/SaveV2/tensor_names"
op: "Const"
attr {
key: "_output_shapes"
value {
list {
shape {
dim {
size: 2
}
}
}
}
}
attr {
key: "dtype"
value {
type: DT_STRING
}
}
attr {
key: "value"
value {
tensor {
dtype: DT_STRING
tensor_shape {
dim {
size: 2
}
}
string_val: "v1"
string_val: "v2"
}
}
}
}
node {
name: "save/SaveV2/shape_and_slices"
op: "Const"
attr {
key: "_output_shapes"
value {
list {
shape {
dim {
size: 2
}
}
}
}
}
attr {
key: "dtype"
value {
type: DT_STRING
}
}
attr {
key: "value"
value {
tensor {
dtype: DT_STRING
tensor_shape {
dim {
size: 2
}
}
string_val: ""
string_val: ""
}
}
}
}
node {
name: "save/SaveV2"
op: "SaveV2"
input: "save/Const"
input: "save/SaveV2/tensor_names"
input: "save/SaveV2/shape_and_slices"
input: "v1"
input: "v2"
attr {
key: "dtypes"
value {
list {
type: DT_FLOAT
type: DT_FLOAT
}
}
}
}
node {
name: "save/control_dependency"
op: "Identity"
input: "save/Const"
input: "^save/SaveV2"
attr {
key: "T"
value {
type: DT_STRING
}
}
attr {
key: "_class"
value {
list {
s: "loc:@save/Const"
}
}
}
attr {
key: "_output_shapes"
value {
list {
shape {
}
}
}
}
}
node {
name: "save/RestoreV2/tensor_names"
op: "Const"
attr {
key: "_output_shapes"
value {
list {
shape {
dim {
size: 1
}
}
}
}
}
attr {
key: "dtype"
value {
type: DT_STRING
}
}
attr {
key: "value"
value {
tensor {
dtype: DT_STRING
tensor_shape {
dim {
size: 1
}
}
string_val: "v1"
}
}
}
}
node {
name: "save/RestoreV2/shape_and_slices"
op: "Const"
attr {
key: "_output_shapes"
value {
list {
shape {
dim {
size: 1
}
}
}
}
}
attr {
key: "dtype"
value {
type: DT_STRING
}
}
attr {
key: "value"
value {
tensor {
dtype: DT_STRING
tensor_shape {
dim {
size: 1
}
}
string_val: ""
}
}
}
}
node {
name: "save/RestoreV2"
op: "RestoreV2"
input: "save/Const"
input: "save/RestoreV2/tensor_names"
input: "save/RestoreV2/shape_and_slices"
attr {
key: "_output_shapes"
value {
list {
shape {
unknown_rank: true
}
}
}
}
attr {
key: "dtypes"
value {
list {
type: DT_FLOAT
}
}
}
}
node {
name: "save/Assign"
op: "Assign"
input: "v1"
input: "save/RestoreV2"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
attr {
key: "_class"
value {
list {
s: "loc:@v1"
}
}
}
attr {
key: "_output_shapes"
value {
list {
shape {
dim {
size: 1
}
}
}
}
}
attr {
key: "use_locking"
value {
b: true
}
}
attr {
key: "validate_shape"
value {
b: true
}
}
}
node {
name: "save/RestoreV2_1/tensor_names"
op: "Const"
attr {
key: "_output_shapes"
value {
list {
shape {
dim {
size: 1
}
}
}
}
}
attr {
key: "dtype"
value {
type: DT_STRING
}
}
attr {
key: "value"
value {
tensor {
dtype: DT_STRING
tensor_shape {
dim {
size: 1
}
}
string_val: "v2"
}
}
}
}
node {
name: "save/RestoreV2_1/shape_and_slices"
op: "Const"
attr {
key: "_output_shapes"
value {
list {
shape {
dim {
size: 1
}
}
}
}
}
attr {
key: "dtype"
value {
type: DT_STRING
}
}
attr {
key: "value"
value {
tensor {
dtype: DT_STRING
tensor_shape {
dim {
size: 1
}
}
string_val: ""
}
}
}
}
node {
name: "save/RestoreV2_1"
op: "RestoreV2"
input: "save/Const"
input: "save/RestoreV2_1/tensor_names"
input: "save/RestoreV2_1/shape_and_slices"
attr {
key: "_output_shapes"
value {
list {
shape {
unknown_rank: true
}
}
}
}
attr {
key: "dtypes"
value {
list {
type: DT_FLOAT
}
}
}
}
node {
name: "save/Assign_1"
op: "Assign"
input: "v2"
input: "save/RestoreV2_1"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
attr {
key: "_class"
value {
list {
s: "loc:@v2"
}
}
}
attr {
key: "_output_shapes"
value {
list {
shape {
dim {
size: 1
}
}
}
}
}
attr {
key: "use_locking"
value {
b: true
}
}
attr {
key: "validate_shape"
value {
b: true
}
}
}
node {
name: "save/restore_all"
op: "NoOp"
input: "^save/Assign"
input: "^save/Assign_1"
}
versions {
producer: 22
}
}
saver_def {
filename_tensor_name: "save/Const:0"
save_tensor_name: "save/control_dependency:0"
restore_op_name: "save/restore_all"
max_to_keep: 5
keep_checkpoint_every_n_hours: 10000.0
version: V2
}
collection_def {
key: "trainable_variables"
value {
bytes_list {
value: "\n\004v1:0\022\tv1/Assign\032\tv1/read:0"
value: "\n\004v2:0\022\tv2/Assign\032\tv2/read:0"
}
}
}
collection_def {
key: "variables"
value {
bytes_list {
value: "\n\004v1:0\022\tv1/Assign\032\tv1/read:0"
value: "\n\004v2:0\022\tv2/Assign\032\tv2/read:0"
}
}
}
meta_info_def属性:
它是通过MetaInfoDef定义的,它记录了计算图中的元数据以及所有使用到的运算方法的信息
meta_graph_version记录了计算图的版本号,如果没在saver中特殊指定,这些属性默认都为空。
stripped_op_list 记录了计算图上使用到的所有运算方法的信息,这个属性的类型是OpList
message MetaInfoDef {
string meta_graph_version = 1;
OpList stripped_op_list = 2;
google.protobuf.Any any_info = 3;
repeated string tags = 4;
}
graph_def属性:
graph_def属性主要记录了计算图上的节点信息,计算图上的每一个节点对应了程序中的一个运算,因为在meta_info_def中已经包含了所有运算的具体信息,所以graph_def属性只关注运算的连接结构
message GraphDef {
repeated NodeDef node = 1;
VersionDef versions = 4;
};
message NodeDef {
string name = 1;
string op = 2;
repeated string input = 3;
string device = 4;
map<string, AttrValue> attr = 5;
};
versions存储了tensorflow的版本号,GraphDef的主要信息都存在node属性中,它记录了计算图上的节点信息。NodeDef 类型有一个name属性,这是一个节点的唯一标识符,在tensorflow中可以通过节点的名称来获取相应的节点,op属性给出了该节点使用的运算方法的名称,可以在meta_info_def中找到该运算的具体信息。
NodeDef类型中的input属性是一个字符串列表,定义了运算的输入。input属性中每个字符串的取值格式为node:src_output,其中node给出了一个节点的名称,src_out表明了这个输入是指定节点的第几个输出。
attr属性指定了和当前运算相关的配置信息
saver_def属性
该属性中记录了持久化模型时需要用到的一些参数,比如保存到文件的文件名,保存操作和加载操作的名称以及保存频率,清理历史记录等
collection_def 属性
计算图可以维护不同集合,而维护这些集合的底层实现就是通过collection_def 这个属性
model.ckpt文件保存了所有变量的取值,大致可以理解为(key,value)列表。
tensorflow提供了tf.train.NewCheckpointReader类来查看model.ckpt中保存的变量信息
reader = tf.train.NewCheckpointReader('tensorboard\model.ckpt')
all_variables = reader.get_variable_to_shape_map()
for variable_name in all_variables:
print(variable_name, all_variables[variable_name])
v2_4 [1]
v2_9 [1]
v2_10 [1]
v1_9 [1]
v1_3 [1]
v1 [1]
v2_11 [1]
v2_6 [1]
v2_2 [1]
v1_2 [1]
v1_10 [1]
v2 [1]
v1_4 [1]
v1_11 [1]
v1_1 [1]
v2_3 [1]
v1_8 [1]
v1_5 [1]
v2_1 [1]
v2_8 [1]
v [1]
v2_7 [1]
v1_7 [1]
v2_5 [1]
foo/v [1]
v_1 [1]
v1_6 [1]
# 获取名称为v1的变量的取值
print('value for variable v1 is ', reader.get_tensor('v1'))
value for variable v1 is [ 1.]