1、Why TensorFlow?
网上有关介绍太多了,我就不多说了,这里主要注重使用。
Intro.PNG
github.PNG
2、Programing model
2.1.Big Idea
将数值的计算转化为图(computational graph),任何tensorflow的计算都是基于图的。
2.2 Graph Nodes
2.3 Graph Edges
图的边是在结点见浮动的张量(tensors),tensors可以理解为n-维数组。
2.4 Advantages
使用flow graphs作为deep learning framework的优点是可以通过简单少量的operations来构建复杂模型,使梯度的计算容易很多。当你在编写比较大的模型时,自动微分将会帮助到你。
2.5 Another way to think it
每一个operation可以理解为在某一点可以执行的函数。
2. 6 举个详细使用的例子
下面这个图展示了只有一个隐藏层的神经网络在Tensorflow中的计算,我们以Relu作为激活函数。
Nodes.PNG
ReLu Function.PNG
下面将介绍一下上图中出现的几个结点:
W 和 b 参数作为TensorFlow中的Variables,在训练的过程中你需要调整这些参数,使得你的loss function最小,这些变量是有状态的结点,在图中多种的计算结点之间保持他们的状态,所谓保持状态就是指它们的值会被存下来,因此想要复原数据很容易,并且可以随时输出他们当前的值(current value),这些变量还有一些其他的features,可以在训练或者训练结束后持久化到disk中,因此可以允许不同的公司不同的组织去使用这些大型模型训练好的参数,并且默认进行梯度更新。
W 和 b这些变量也是operations。
是一些在执行的过程中才会被赋值的结点,如果你网络的input 需要依赖一些其他外界的数据。
比如你不想用真实的值来计算。placeholders是你在训练过程中可以加入数据的地方。对于placeholders,我们不用对其进行任何初始化,我们只定义一个data type,并且赋值一个给定大小的tensor,我们的计算图就可以知道怎么去计算,甚至不用存储任何的数据。
用于矩阵的乘法,加法,ReLu函数的计算。
# 导入tensorflow包 import tensorflow as tf # 创建一个有100个值的vector,作为bias, 默认为0 b=tf.Variable(tf.zeros((100,))) # 创建并出示化权重,一个784*100 的矩阵,矩阵的初始值在-1到1之间 W=tf.Variable(tf.random_uniform((784,100),-1,1)) #为输入创建一个placeholder,不需要任何数据,只需要定义数据类型为一个32位浮点数, shape 为100*784 x=tf.placeholder(tf.float32,(100,784)) # tensorflow mathematical operations h=tf.nn.relu(tf.matmul(x,W)+b)
关于h我想说:和numpy中很像,就是调用了tensorflow mathematical operations,我们没有真的乘某个数值,而仅仅在图中创建了一个符号来表示他,所以你不能输出该值,因为x只是一个placeholder,没有任何真值。我们现在只为我们的model创建了一个骨架。
看了半天,这不和numpy手撸一样吗,其实作为程序员我们只要心里有着种抽象的概念就好,底层确实是以这种结点来实现的,如果你想看到,可以调用
tf.get_default_graph().get_operations()
你将会看到如下内容:
Absta.PNG
目前为止,我们已经定义了一个graph,我们需要把这个graph部署到一个session中,一个session可以绑定到一个具体的执行环境中(CPU或者GPU)
接着刚才的代码,我们在后面补充三行:
import numpy as np import tensorflow as tf b=tf.Variable(tf.zeros((100,))) W=tf.Variable(tf.random_uniform((784,100),-1,1)) x=tf.placeholder(tf.float32,(100,784)) h=tf.nn.relu(tf.matmul(x,W)+b) #创建session对象,初始化相关的参数 sess=tf.Session() # initialize b 和 w sess.run(tf.initialize_all_variables()) # 第一个参数是图中结点的输出,第二个参数是给placeholder赋的值,是一个map,定义每个结点的具体值 sess.run(h,{x : np.random.random(100,784)})
更多的关于Session的使用方法:
#自己创建一个session,不使用默认的session,使用完记得关了 sess=tf.Session() sess=tf.run(train_step) sess.close() with tf.Session() as sess: #使用这个创建的session计算结果 sess.run(train_step) #不用close,with体帮我们进行资源的回收 #with体使用默认的 session sess=tf.Session() with sess.as_default(): print(train_step.eval()) #也是使用默认的session sess=tf.Session() print(train_step.eval(session=sess)) #定义一个可交互式的session,自动将会话注册为默认会话 sess=tf.InteractiveSession() train_step.eval() sess.close() #用自己的参数配置session config=tf.ConfigProto(allow_aoft_placement=True, log_device_placement=True) sess1=tf.InteractiveSession(config=config) sess2=tf.Session(config=config)
通过prediction 和 labels 创建loss node
# neural network的最后一步,用softmax做一个逻辑回归 prediction=tf.nn.softmax(...) label=tf.placeholder(tf.float32,[100,10]) # 损失函数,用label乘上logP在列上的值 cross_entropy=-tf.reduce_sum(label* tf.log(prediction),axis=1)
tf.train.GradientDescentOptimizer创建了一个Optimizer是TensorFlow中定义的一个抽象类,它的每个子类,可以作为一个特定的学习算法,默认是梯度下降。在我们的图上面加了一个optimization operation,当我们执行这个train_step方法时(sess.run(train_step,feed_dict={x: batch_x, label: batch_label})),将会应用所有的梯度到模型中的变量中。这是因为minimize函数做了两件事情,首先是计算cross_entropy的梯度,然后进行梯度更新。
# 梯度下降,learning rate 为0.5,minimize方法的参数是一个需要被梯度下降的结点。 train_step= tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy)
sess=tf.Session() sess.run(tf.initialize_all_variables()) # 创建一个learning schedule, iterate 1000 次 for i in range(1000): batch_x, batch_label = data.next_batch() sess.run(train_step,feed_dict={x: batch_x, label: batch_label})
3、变量共享
当你在使用Tensorflow时,你想在一个地方初始化所有的变量,比如我想多次实例化我的graph或者我想在GPU集群上训练,我们需要共享变量。有以下两个解决方案:
其中一个方法是创建一个map,在需要使用的地方调用key获得value。但缺点是它大破了封装的思想。
TensorFlow的variable scope解决了这个问题,它为我们提供了一个提供了一个命名空间,避免了冲突。
with tf.variable_scope("hello world"): v=tf.get_variable("v",shape=[1]) # v.name== " hello world/v:0" with tf.variable_scope("hello world" reuse=True): v=tf.get_variable("v",shape=[1]) # 可以找到共享的变量v with tf.variable_scope("hello world" reuse=False): v=tf.get_variable("v",shape=[1]) # CRASH hello world/v:0 已经存在了
4、官方demo (Official Demo)
MNIST手写体识别
4、1 基于softmax逻辑回归
利用softmax regression,训练一个手写体分类:
from __future__ import absolute_import from __future__ import division from __future__ import print_function import gzip import os import tempfile import numpy from six.moves import urllib from six.moves import xrange # pylint: disable=redefined-builtin import tensorflow as tf from tensorflow.contrib.learn.python.learn.datasets.mnist import read_data_sets from tensorflow.examples.tutorials.mnist import input_data mnist = input_data.read_data_sets("MNIST_data/", one_hot=True) # 定义一个placeholder, x = tf.placeholder(tf.float32, [None, 784]) W = tf.Variable(tf.zeros([784, 10])) b = tf.Variable(tf.zeros([10])) y = tf.nn.softmax(tf.matmul(x, W) + b) #定义一个用于存储正确标示的占位符 y_=tf.placeholder("float",[None,10]) #交叉熵损失函数 cross_entropy=-tf.reduce_sum(y_*tf.log(y)) #梯度下降进行训练 train_step=tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy) init=tf.initialize_all_variables() sess=tf.Session()
sess.run(init) #随机梯度下降 for i in range(1000): batch_xs, batch_ys=mnist.train.next_batch(100) print(sess.run(train_step,feed_dict={x:batch_xs,y_:batch_ys})) correct_prediction=tf.equal(tf.argmax(y,1),tf.argmax(y_,1)) accuracy=tf.reduce_mean(tf.cast(correct_prediction,"float")) print(sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels}))
4、2 基于CNN神经网络
# 利用CNN,训练一个手写体分类 """Functions for downloading and reading MNIST data.""" from __future__ import absolute_import from __future__ import division from __future__ import print_function import gzip import os import tempfile import numpy from six.moves import urllib from six.moves import xrange # pylint: disable=redefined-builtin import tensorflow as tf from tensorflow.contrib.learn.python.learn.datasets.mnist import read_data_sets from tensorflow.examples.tutorials.mnist import input_data # 将系统默认的session作ion sess = tf.InteractiveSession() mnist = input_data.read_data_sets("MNIST_data/", one_hot=True) # 正确答案
y_ = tf.placeholder('float', [None, 10]) # 定义函数用于初始化权值,和bias def weight_initialize(shape): # 标准差为一,初始化权值 initial = tf.truncated_normal(shape, stddev=0.1) return tf.Variable(initial) def bias_variable(shape): initail = tf.constant(0.1, shape=shape) return tf.Variable(initail) x = tf.placeholder('float', [None, 784]) # 卷积 def conv2d(x, W): #tf.nn.conv2d提供了一个非常方便的函数来实现卷积层向前传播的算法,这个函数的第一个输入为 #当前层节点矩阵,这个矩阵是一个四维矩阵,后面的三个维度对应一个节点矩阵,第一个维度对应一个 #输入batch.比如在输入层,input[0,:,:,:]表示第一张图片,input[1,:,:,:]表示第张图片二,tf.nn.conv2d #第二个参数提供了卷积层的权重,第三个参数为步长,步长第一维,和最后一维固定是1,最后一个参数是填充方法 #SAME表示全0填充,VALID表示不添加 return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME') # 池化 def max_pool_2x2(x): #ksize提供了过滤器的大小为2*2 return tf.nn.max_pool(x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME') # 卷积层第一层 W_conv1 = weight_initialize([5, 5, 1, 32]) b_conv1 = bias_variable([32]) x_image = tf.reshape(x, [-1, 28, 28, 1]) # 卷积层第一层的relu和池化 h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1) h_pool1 = max_pool_2x2(h_conv1) # 5*5*32 # 卷积层第二层 W_conv2 = weight_initialize([5, 5, 32, 64]) b_conv2 = bias_variable([64]) # 卷积层第二层的relu和池化 h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2) h_pool2 = max_pool_2x2(h_conv2) # 全连接层的weight和bias W_fc1 = weight_initialize([7 * 7 * 64, 1024]) b_fc1 = bias_variable([1024]) # output层 h_pool2_flat = tf.reshape(h_pool2, [-1, 7 * 7 * 64]) h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1) # 使用dropout防止过拟合 # 过拟合概率 keep_prob = tf.placeholder("float") h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob) # 1024个神经元*10个输出 W_fc2 = weight_initialize([1024, 10]) b_fc2 = bias_variable([10]) y_conv = tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2)) # 定义一个损失函数 cross_entropy = -tf.reduce_sum(y_ * tf.log(y_conv)) train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy) correct_prediction = tf.equal(tf.argmax(y_conv, 1), tf.argmax(y_, 1)) accuracy = tf.reduce_mean(tf.cast(correct_prediction,"float")) # 初始化所有变量 sess.run(tf.initialize_all_variables()) for i in range(2000): batch = mnist.train.next_batch(50) if i % 100 == 0: train_accuracy = accuracy.eval(feed_dict={ x: batch[0], y_: batch[1], keep_prob: 1.0 }) print("step %d, train accuracy %g" % (i, train_accuracy)) train_step.run(feed_dict={x: batch[0], y_: batch[1], keep_prob: [0.5]}) print("test accuracy %g" % accuracy.eval(feed_dict={ x: mnist.test.images, y_: mnist.test.labels, keep_prob: 1.0}))
训练结果如下:
result.png
5、 总结