TF实现神经网络举例
本节我们主要看一下TensorFlow如何愉快的做神经网络!神经网络的结构及训练过程我就不说了,我们现在可以用Python中的Numpy独立的完成神经网路的设计过程,那么如何用tensorflow完成呢?
1.TF训练DNN
老规矩直接解释代码:
法1:以一种简单的形式
import tensorflow as tf
import matplotlib.pyplot as plt
import requests
import numpy as np
sess = tf.Session()
def fully_connected(input_layer, weights, biases):
#1st
layer = tf.add(tf.matmul(input_layer, weights), biases)
return(tf.nn.relu(layer))
# 2 (25 hidden nodes)
weight_1 = init_weight(shape=[8, 25], st_dev=10.0)
bias_1 = init_bias(shape=[25], st_dev=10.0)
layer_1 = fully_connected(x_data, weight_1, bias_1)
# 3 (10 hidden nodes)
weight_2 = init_weight(shape=[25, 10], st_dev=10.0)
bias_2 = init_bias(shape=[10], st_dev=10.0)
layer_2 = fully_connected(layer_1, weight_2, bias_2)
# 4 (3 hidden nodes)
weight_3 = init_weight(shape=[10, 3], st_dev=10.0)
bias_3 = init_bias(shape=[3], st_dev=10.0)
layer_3 = fully_connected(layer_2, weight_3, bias_3)
# output layer (1 output value)
weight_4 = init_weight(shape=[3, 1], st_dev=10.0)
bias_4 = init_bias(shape=[1], st_dev=10.0)
final_output = fully_connected(layer_3, weight_4, bias_4)
loss = tf.reduce_mean(tf.abs(y_target - final_output))
my_opt = tf.train.AdamOptimizer(0.05)
train_step = my_opt.minimize(loss)
init = tf.initialize_all_variables()
sess.run(init)
# Initialize the loss vectors
loss_vec = []
test_loss = []
for i in range(200):
# 划分训练集
rand_index = np.random.choice(len(x_vals_train), size=batch_size)
rand_x = x_vals_train[rand_index]
rand_y = np.transpose([y_vals_train[rand_index]])
# 训练模型
sess.run(train_step, feed_dict={x_data: rand_x, y_target:rand_y})
#loss
temp_loss = sess.run(loss, feed_dict={x_data: rand_x, y_target:rand_y})
loss_vec.append(temp_loss)
# test loss
test_temp_loss = sess.run(loss, feed_dict={x_data: x_vals_test, y_target: np.transpose([y_vals_test])})
test_loss.append(test_temp_loss)
if (i+1)%25==0:
print('Generation: ' + str(i+1) + '. Loss = ' + str(temp_loss))
# metrics的可视化
plt.plot(loss_vec, 'k-', label='Train Loss')
plt.plot(test_loss, 'r--', label='Test Loss')
plt.title('Loss per Generation')
plt.xlabel('Generation')
plt.ylabel('Loss')
plt.legend(loc='upper right')
plt.show()
上面的代码很简单,如果我们的DNN有50层,是不是我们要写好多变量,weight1,weight2,...,在def中要罗列好多变量,自己可能就晕掉了,在后期可视化模型时也不可以。并且我们并没有采取一些像正则化,变量的滑动平均(提高测试数据在模型中的稳健性,接触过时间序列可以对此有更深入的理解,这里不是我们的重点),dropout等的一些辅助优化技术,如果加上这些是不是这种办法显的更笨拙?
法2:对代代码做变量管理
def inference(input_tensor,resuse=False):
#1st
with tf.variable_scope("layer1",resuse=resuse):
#根据传进来的resuse来判断是创建新变量还是使用已经创建好的,在第一次构造网络时
#需要创建新的变量,以后每次调用这个函数直接使用resuse=True就不需要每次将变量传进来了
weights = tf.get_variable('weights',[INPUT_NODE,LAYER1_NODE],
initializer = tf.truncated_normal_initializer(stddev = 0.1))
biases = tf.get_varible('biases',[LAYER1_NODE],initializer = tf.constant_initializer(0.))
layer1 = tf.nn.relu(tf.matmul(input_tensor,weights) + biases)
#类似的定义layer2
with tf.variable_scope("layer2",resuse=resuse):
#根据传进来的resuse来判断是创建新变量还是使用已经创建好的,在第一次构造网络时
#需要创建新的变量,以后每次调用这个函数直接使用resuse=True就不需要每次将变量传进来了
weights = tf.get_variable('weights',[INPUT_NODE,OUTPUT_NODE],
initializer = tf.truncated_normal_initializer(stddev = 0.1))
biases = tf.get_varible('biases',[OUTPUT_NODE],initializer = tf.constant_initializer(0.))
layer2 = tf.nn.relu(tf.matmul(input_tensor,weights) + biases)
#返回最后的前向传播结果
return layer2
x = tf.placeholder(tf.float32,[None,INPUT_NODE],name='x-input')
y = inference(x)
#在程序中使用训练好的神经网络进行推倒时,可以直接调用inference(new_x,True)
#当加入指数滑动平均等方法时,变量管理机制会会体现出更方便。
#注意:当resuse=True时,tf.get_variable函数将直接获取已经声明的变量,如果变量在命名空间中没有被声明过,此时会报错。
2.TF模型的持久化
我们训练一个深层模型可能需要几周或几个月的时间,训练完了,如果不去保存下次使用还得几周的时间,模型的持久化就是解决这个问题,我们知道在MXNet和Keras中都有相应的机制,这也为迁移学习提供了方便。
TensorFlow提供了一个非常简单的API来保存和还原一个神经网络模型,这个API就是tf.train.Saver类
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
init_op = tf.global_variables_initializer()
#声明tf.train.Saver类用于保存模型
saver = tf.train.Saver()
with tf.Session() as sess:
sess.run(init_op)
#将模型保存在C:/model/model.ckpt文件
path = "C:/model/model.ckpt"
saver.save(sess,path)
TF模型一般会保存在后缀为.ckpt(CheckPoint),虽然上面的程序指定了一个文件路径,但在这个文件路径下会出现三个文件,这是因为TensorFlow会将计算图的结构和图上参数取值分开来保存
-
model.ckpt.meta: 保存了计算图的结构(简单的可以理解为神经网络的网络结构)
-
model.ckpt: 这个文件保存了TensorFlow程序中每一个变量的取值
-
checkpoint文件:这个文件保存了一个目录下所有的模型文件列表
了解更多这些文件可搜索大量的介绍信息
- 加载已经保存的TensorFlow模型
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()
with tf.Session() as sess:
#加载以保存的模型,并通过已保存的模型中的变量来计算加法
saver.restore(sess,path)
print sess.run(result)
区别:加载模型的代码中没有运行变量初始化过程,而是将变量的值通过已经保存的吗模型加载进来。
- 如果不希望重复定义图上的运算,可以加载已经持久化的图
import tensorflow as tf
#直接加载持久化的图
saver = tf.train.import_meta_graph(path+'.meta')
with tf.Session() as sess:
saver.restore(ress,path)
#通过张量的名称来获取张量
print sess.run(tf.get_default_graph().get_tensor_by_name('add:0'))
#输出结果:[3.]
- 保存或加载部分变量
默认加载和保存TF计算图上的所有变量,但有时可能只需要保存和加载部分变量,比如,我们有一个训练好的5层网络,但现在想尝试6层的网络,那么可以将前5层参数加载进来,训练最后一层网络即可(迁移学习)
tf.train.Saver类可以提供一个列表来指定需要保存和加载的变量,saver = tf.train.Saver([v1]),只有变量v1被加载进来
- 变量重命名
tf.train.Saver支持保存和加载时的变量重命名
v1 = tf.Variable(tf.constant(1.0,shape=[1]),name='other-v1')
v2 = tf.Variable(tf.constant(2.0,shape=[1]),name='other-v2')
saver = tf.train.Saver({'v1':v1,'v2':v2})
#原来名称为v1的变量现在加载到变量v1中(名称为other-v1)。
- 其他
tf.train.Saver会保存运行TF程序的全部信息,有时并不需要,比如在测试或离线预测时,我们只需知道神经网络的前向传播计算到输出就可以了,而不需要类似额变量初始化等辅助节点信息,在迁移学习中会遇到这些问题,于是TensorFlow提供了convert_variables_to _constants函数,通过这个函数可以将计算图中的变量及其取值通过常量的方式保存,这样TF计算图可以统一保存在一个文件中
imort tensorflow as tf
from tensrflow.python.framework import graph_util
v1 = tf.Variable(tf.constant(1.0,shape=[1]),name='v1')
v2 = tf.Variable(tf.constant(2.0,shape=[2]),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()
output_graph_def = graph_util.convert_variables_to_constants(sess,graph_def,['add'])
#将导出的模型保存成文件
with tf.gfile.GFile('C:/model.pb','wb') as f:
f.write(output_graph_def.SerializeToString())
import tensorflow as tf
from tensorflow.python.platform import gfile
with tf.Session() as sess:
path = 'C:/model.pb'
#读取保存的文件,并将文件解析成对应的GraphDef Protocol Buffer
with gfile.FastGFile(path,'rb') as f:
graph_def = tf.GraphDef()
graph_def.ParseFromeString(f.read())
result = tf.import_graph_def(graph_def,return_element=['add:0'])
print sess.run(result)