美文网首页TensorFlow
Tensorflow学习笔记

Tensorflow学习笔记

作者: 湖大李桂桂 | 来源:发表于2020-02-17 11:54 被阅读0次

    中文社区里面好多错误的地方我受不了了!!!所以从上到下一段一段的看,把内容重新理了一下。其实大部分都和中文社区里的没有什么区别,大家也可以直接去看官网

    持续更新中...

    一、基础知识

    1、综述

    TensorFlow:

    • 使用图 (graph)来表示计算任务.
    • 在被称之为 会话 (Session) 的上下文 (context) 中执行图.
    • 使用 tensor 表示数据.
    • 通过 变量 (Variable) 维护状态.
    • 使用 feed 和 fetch 可以为任意的操作(arbitrary operation) 赋值或者从其中获取数据.

    TensorFlow是一个编程系统,使用图(graph)来表示计算任务,并在会话(session)的上下文(context)中执行。图中的节点成为op(operation)。一个op获得0个或多个Tensor(数据),执行计算,产生0个或多个tensor。每个tensor是一个类型化的多维数组。例如,你可以将一小组图像集表示为一个四维浮点数数组,这四个维度分别是

    [batch, height, width, channels
    

    一个 TensorFlow 图描述了计算的过程。为了进行计算,图必须在会话(session)里被启动。 会话将图的 op 分发到诸如 CPU 或 GPU 之类的 设备上,同时提供执行 op 的方法。这些方法执行后, 将产生的 tensor 返回。 在 Python 语言中,返回的 tensor 是 numpyndarray 对象。

    2、计算图

    TensorFlow 程序通常被组织成一个构建阶段和一个执行阶段。在构建阶段,op 的执行步骤被描述成一个图。在执行阶段,使用会话执行执行图中的op。

    例如,通常在 构建阶段 创建一个图来表示和训练神经网络,然后在 执行阶段 反复执行图中的训练op

    3、构建图

    创建源 op (source op)。源 op 不需要任何输入,例如 常量 (Constant)。源 op 的输出被传递给其它 op 做运算。

    TensorFlow Python 库有一个默认图 (default graph),op 构造器可以为其增加节点。这个默认图对许多程序来说已经足够用了。

    import tensorflow as tf
    
    # 创建一个常量 op, 产生一个 1x2 矩阵. 这个 op 被作为一个节点加到默认图中.
    # 构造器的返回值代表该常量 op 的返回值.
    matrix1 = tf.constant([[3., 3.]])
    
    # 创建另外一个常量 op, 产生一个 2x1 矩阵.
    matrix2 = tf.constant([[2.],[2.]])
    
    # 创建一个矩阵乘法 matmul op , 把 'matrix1' 和 'matrix2' 作为输入.
    # 返回值 'product' 代表矩阵乘法的结果.
    product = tf.matmul(matrix1, matrix2)
    
    

    默认图现在有三个节点, 两个 constant() op,和一个matmul() op。为了真正进行矩阵相乘运算, 并得到矩阵乘法的结果,你必须在会话里启动这个图

    4、启动图

    构造阶段完成后,才能启动图。启动图的第一步是创建一个 Session 对象,如果无任何创建参数,会话构造器将启动默认图。

    # 启动默认图.
    sess = tf.Session()
    
    # 调用 sess 的 'run()' 方法来执行矩阵乘法 op, 传入 'product' 作为该方法的参数. 
    # 上面提到, 'product' 代表了矩阵乘法 op 的输出, 传入它是向方法表明, 我们希望取回
    # 矩阵乘法 op 的输出.
    #
    # 整个执行过程是自动化的, 会话负责传递 op 所需的全部输入. op 通常是并发执行的.
    # 
    # 函数调用 'run(product)' 触发了图中三个 op (两个常量 op 和一个矩阵乘法 op) 的执行.
    #
    # 返回值 'result' 是一个 numpy `ndarray` 对象.
    result = sess.run(product)
    print(result)
    # ==> [[ 12.]]
    
    # 任务完成, 关闭会话.
    sess.close()
    

    Session 对象在使用完后需要关闭以释放资源. 除了显式调用 close 外, 也可以使用 "with" 代码块 来自动完成关闭动作.

    with tf.Session() as sess:
      result = sess.run([product])
      print(result)
    

    5、指定硬件

    一般不需要显式指定使用 CPU 还是 GPU,TensorFlow 能自动检测。如果检测到 GPU,TensorFlow会尽可能地利用找到的第一个 GPU 来执行操作。

    如果机器上有超过一个可用的 GPU,除第一个外的其它 GPU 默认是不参与计算的。为了让 TensorFlow 使用这些 GPU,你必须将 op 明确指派给它们执行 with...Device 语句用来指派特定的 CPU 或 GPU 执行操作:

    with tf.Session() as sess:
      with tf.device("/gpu:1"):
        matrix1 = tf.constant([[3., 3.]])
        matrix2 = tf.constant([[2.],[2.]])
        product = tf.matmul(matrix1, matrix2)
        ...
    

    设备用字符串进行标识。目前支持的设备包括:

    • "/cpu:0": 机器的 CPU.
    • "/gpu:0": 机器的第一个 GPU, 如果有的话.
    • "/gpu:1": 机器的第二个 GPU, 以此类推.

    但是在我电脑上没用,永远是用第一个GPU,可能是TensorFlow环境装的有问题。

    6、交互式使用

    文档中的 Python 示例使用一个会话 Session 来 启动图, 并调用 Session.run() 方法执行操作。下面是另外一种使用方法:

    为了便于使用诸如 IPython 之类的 Python 交互环境, 可以使用 InteractiveSession 代替 Session 类, 使用 Tensor.eval()Operation.run() 方法代替 Session.run(). 这样可以避免使用一个变量来持有会话.

    # 进入一个交互式 TensorFlow 会话.
    import tensorflow as tf
    sess = tf.InteractiveSession()
    
    x = tf.Variable([1.0, 2.0])
    a = tf.constant([3.0, 3.0])
    
    # 使用初始化器 initializer op 的 run() 方法初始化 'x' 
    x.initializer.run()
    
    # 增加一个减法 sub op, 从 'x' 减去 'a'. 运行减法 op, 输出结果 
    sub = tf.subtract(x, a)
    print(sub.eval())
    # ==> [-2\. -1.]
    

    7、Tensor

    TensorFlow 程序使用 tensor 数据结构来代表所有的数据,计算图中,操作间传递的数据都是 tensor。可以把 TensorFlow tensor 看作是一个 n 维的数组或列表。一个 tensor 包含一个静态类型 rank,和一个shape。

    8、变量

    变量维护图执行过程中的状态信息

    # 构建图
    import tensorflow as tf
    
    # 创建一个变量, 初始化为标量 0.
    state = tf.Variable(0, name="counter")  # 默认的图中创建op,这个op是一个变量
    
    # 创建一个 op, 其作用是使 state 增加 1
    
    one = tf.constant(1) # 创建常量one,值为1
    new_value = tf.add(state, one)  # 在tf的默认图中添加一个op,这个op是用来做加法操作的
    update = tf.assign(state, new_value)  # 赋值操作。将new_value的值赋值给state变量
    
    # 启动图后, 变量必须先经过`初始化` (init) op 初始化,
    # 首先必须增加一个`初始化` op 到图中.
    init_op = tf.global_variables_initializer()
    
    # 启动图, 运行 op
    with tf.Session() as sess:
      # 运行 'init' op
      sess.run(init_op)
      # 打印 'state' 的初始值
      print(sess.run(state))
      # 运行 op, 更新 'state', 并打印 'state'
      for _ in range(3):
        sess.run(update)
        print(sess.run(state))
    
    # 输出:
    
    # 0
    # 1
    # 2
    # 3
    
    

    代码中 assign() 操作是图所描绘的表达式的一部分, 正如 add() 操作一样. 所以在调用 run() 执行表达式之前,它并不会真正执行赋值操作。

    通常会将一个统计模型中的参数表示为一组变量。例如,你可以将一个神经网络的权重作为某个变量存储在一个 tensor 中。在训练过程中, 通过重复运行训练图, 更新这个 tensor。

    9、Fetch

    为了取回操作的输出内容,可以在使用 Session 对象的 run() 调用执行图时,传入一些 tensor,这些 tensor 会帮助你取回结果。在之前的例子里,我们只取回了单个节点 state,但是你也可以取回多个 tensor:

    input1 = tf.constant(3.0)
    input2 = tf.constant(2.0)
    input3 = tf.constant(5.0)
    intermed = tf.add(input2, input3)
    mul = tf.multiply(input1, intermed)
    
    with tf.Session() as sess:
        result = sess.run([mul, intermed])
        print(result)
    
    # 输出:
    # [21.0, 7.0]
    
    

    需要获取的多个 tensor 值,在 op 的一次运行中一起获得(而不是逐个去获取 tensor)。

    10、Feed

    TensorFlow 还提供了 feed 机制,可以临时替代图中的任意操作。

    例如将某些特殊的操作指定为 "feed" 操作,标记的方法是使用tf.placeholder()为这些操作创建占位符。

    input1 = tf.placeholder(tf.float32)
    input2 = tf.placeholder(tf.float32)
    output = tf.multiply(input1, input2)
    
    with tf.Session() as sess:
        print(sess.run([output], feed_dict={input1: [7.], input2: [2.]}))
    
    # 输出:
    # [array([ 14.], dtype=float32)]  
    
    

    二、MNIST

    softmax regression

    1、入门

    1.1、数据集下载

    方法一:下载input_data.py 代码文件,然后用下面的代码导入到你的项目里面。

    import input_data
    mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
    
    

    方法二:Yann LeCun's MNIST page 也提供了训练集与测试集数据的下载。

    数据集包含:

    文件 内容
    train-images-idx3-ubyte.gz 训练集图片 - 55000 张 训练图片, 5000 张 验证图片
    train-labels-idx1-ubyte.gz 训练集图片对应的数字标签
    t10k-images-idx3-ubyte.gz 测试集图片 - 10000 张 图片
    t10k-labels-idx1-ubyte.gz 测试集图片对应的数字标签

    1.2、MNIST基础知识

    图片向量:

    img

    在MNIST训练数据集中,一共有60000张图片,每一张图片包含28像素 X 28像素,把这个数组展开成一个向量,长度是 28 x 28 = 784。所以mnist.train.images 是一个形状为 [60000, 784] 的张量。

    img

    第一个维度数字用来索引图片,第二个维度数字用来索引每张图片中的像素点。在此张量里的每一个元素,都表示某张图片里的某个像素的强度值,值介于0和1之间。

    标签向量:

    相对应的MNIST数据集的标签是介于0到9的数字,使用one-hot vectors独热编码用来描述给定图片里表示的数字。即用N维的向量来表示N 个类别,每个类别占据独立的一位,任何时候独热表示中只有一位是1 ,其他都为0 。

    img

    1.3、Softmax回归介绍

    我们知道MNIST的每一张图片都表示一个数字,从0到9。我们希望得到给定图片代表每个数字的概率。比如说,我们的模型可能推测一张包含9的图片代表数字9的概率是80%但是判断它是8的概率是5%(因为8和9都有上半部分的小圆),然后给予它代表其他数字的概率更小的值。

    这是一个使用softmax回归(softmax regression)模型的经典案例。softmax模型可以用来给不同的对象分配概率。即使在之后,我们训练更加精细的模型时,最后一步也需要用softmax来分配概率。

    为了得到一张给定图片属于某个特定数字类的证据(evidence),我们对图片像素值进行加权求和。如果这个像素具有很强的证据说明这张图片不属于该类,那么相应的权值为负数,相反如果这个像素拥有有利的证据支持这张图片属于这个类,那么权值是正数。

    下面的图片显示了一个模型学习到的图片上每个像素对于特定数字类的权值。红色代表负数权值,蓝色代表正数权值。

    img

    我们也需要加入一个额外的偏置量(bias),因为输入往往会带有一些无关的干扰量。因此对于给定的输入图片 x 它代表的是数字 i 的证据可以表示为

    img 其中 img 代表权重, img

    代表数字 i 类的偏置量,j 代表给定图片 x 的像素索引,用于像素求和。然后用softmax函数可以把这些证据转换成概率 y

    img

    这里的softmax可以看成是一个激励(activation)函数或者链接(link)函数,把我们定义的线性函数的输出转换成我们想要的格式,也就是关于10个数字类的概率分布。因此,给定一张图片,它对于每一个数字的吻合度可以被softmax函数转换成为一个概率值。softmax函数可以定义为:

    img

    展开等式右边的子式,可以得到:

    img

    也可以用下面的图来理解:

    • 对于输入图片的每个像素加权求和,再分别加上一个偏置量,最后再输入到softmax函数中
    img
    • 或写成一个等式:
    img
    • 或用向量表示这个计算过程:用矩阵乘法和向量相加。这有助于提高计算效率。(也是一种更有效的思考方式)
    img
    • 或写成更加紧凑的方式
    img

    1.4、实现回归模型

    TensorFlow 不单独地运行单一的复杂计算,而是让我们可以先用图描述一系列可交互的计算操作,然后全部一起在Python之外运行。(这样类似的运行方式,可以在不少的机器学习库中看到。)

    使用TensorFlow之前,首先导入它:

    import tensorflow as tf
    

    图像

    我们通过操作符号变量来描述这些可交互的操作单元,可以用下面的方式创建一个:

    x = tf.placeholder("float", [None, 784])
    

    x不是一个特定的值,而是一个占位符placeholder,可以在TensorFlow运行某一计算时根据该占位符输入具体的值。

    输入图片x是一个2维的浮点数张量。这里,分配给它的shape[None, 784],其中784是一张展平的MNIST图片的维度。None表示其值大小不定,我们希望能够输入任意数量的MNIST图像,在这里作为第一个维度值,用以指代batch的大小,意即x的数量不定。

    虽然placeholdershape参数是可选的,但有了它,TensorFlow能够自动捕捉因数据维度不一致导致的错误。

    权重值和偏置量

    一个Variable代表一个可修改的张量,存在在TensorFlow的用于描述交互性操作的图中。它们可以用于计算输入值,也可以在计算中被修改。对于各种机器学习应用,一般都会有模型参数,可以用Variable表示。

    W = tf.Variable(tf.zeros([784,10]))
    b = tf.Variable(tf.zeros([10]))
    

    我们赋予tf.Variable不同的初值来创建不同的Variable:在这里,我们都用全为零的张量来初始化Wb。因为我们要学习Wb的值,它们的初值可以随意设置。

    tf.zeros Creates a tensor with all elements set to zero.

    W的维度是[784,10](一个784 x 10的矩阵),因为我们想要用784维的图片向量[None,784 ]乘以它以得到一个10维的证据值向量,每一位对应不同数字类。b是一个10维的向量,形状是[10](因为我们有10个分类),所以我们可以直接把它加到输出上面。

    y = tf.nn.softmax(tf.matmul(x,W) + b)
    
    

    tf.matmul(X,W)表示x乘以W,对应之前等式里面的

    img

    ,这里x是一个2维张量拥有多个输入。然后再加上b,把和输入到tf.nn.softmax函数里面。

    我们用几行简短的代码来设置变量,然后用一行代码来定义我们的模型。

    1.5、训练模型

    为了训练我们的模型,我们首先需要定义一个指标来评估这个模型是好的。通常定义指标来表示一个模型是坏的,这个指标称为成本(cost)或损失(loss),然后尽量最小化这个指标。

    一个非常常见的,非常漂亮的成本函数是“交叉熵”(cross-entropy)

    img

    y 是我们预测的概率分布, y' 是实际的分布(我们输入的one-hot vector)。比较粗糙的理解是,交叉熵是用来衡量我们的预测用于描述真相的低效性。

    为了计算交叉熵,我们首先需要添加一个新的占位符用于输入正确值:

    y_ = tf.placeholder("float", [None,10])
    

    输出类别值y_是一个2维张量,其中每一行为一个10维的one-hot向量,用于代表对应某一MNIST图片的类别。

    然后我们可以用 img

    计算交叉熵:

    cross_entropy = -tf.reduce_sum(y_*tf.log(y))
    

    首先,用 tf.log 计算 y 的每个元素的对数。接下来,我们把 y_ 的每一个元素和 tf.log(y_) 的对应元素相乘。最后,用 tf.reduce_sum 计算张量的所有元素的总和。(注意,这里的交叉熵不仅仅用来衡量单一的一对预测和真实值,而是所有100幅图片的交叉熵的总和。对于100个数据点的预测表现比单一数据点的表现能更好地描述我们的模型的性能。)

    TensorFlow拥可以自动地使用反向传播算法(backpropagation algorithm)来有效地确定你的变量是如何影响你想要最小化的那个成本值的。然后,TensorFlow会用你选择的优化算法来不断地修改变量以降低成本。

    train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)
    

    在这里,我们要求TensorFlow用梯度下降算法(gradient descent algorithm)以0.01的学习速率最小化交叉熵。梯度下降算法是一个简单的学习过程,TensorFlow只需将每个变量一点点地往使成本不断降低的方向移动。当然TensorFlow也提供了其他许多优化算法:只要简单地调整一行代码就可以使用其他的算法。

    TensorFlow在这里实际上所做的是,它会在后台给描述你的计算的那张图里面增加一系列新的计算操作单元用于实现反向传播算法和梯度下降算法。然后,它返回给你的只是一个单一的操作,当运行这个操作时,它用梯度下降算法训练你的模型,微调你的变量,不断减少成本。

    现在,我们已经设置好了我们的模型。在运行计算之前,我们需要添加一个操作来初始化我们创建的变量:

    init = tf.initialize_all_variables()
    

    现在我们可以在一个Session里面启动我们的模型,并且初始化变量:

    sess = tf.Session()
    sess.run(init)
    

    然后开始训练模型,这里我们让模型循环训练1000次!

    for i in range(1000):
      batch_xs, batch_ys = mnist.train.next_batch(100)
      sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})
    

    该循环的每个步骤中,我们都会随机抓取训练数据中的100个批处理数据点,然后我们用这些数据点作为参数替换之前的占位符来运行train_step

    使用一小部分的随机数据来进行训练被称为随机训练(stochastic training)- 在这里更确切的说是随机梯度下降训练。在理想情况下,我们希望用我们所有的数据来进行每一步的训练,因为这能给我们更好的训练结果,但显然这需要很大的计算开销。所以,每一次训练我们可以使用不同的数据子集,这样做既可以减少计算开销,又可以最大化地学习到数据集的总体特性。

    1.6、评估模型

    首先找出那些预测正确的标签。tf.argmax 能给出某个tensor对象在某一维上的其数据最大值所在的索引值。由于标签向量是由0,1组成,因此最大值1所在的索引位置就是类别标签,比如tf.argmax(y,1)返回的是模型对于任一输入x预测到的标签值,而 tf.argmax(y_,1) 代表正确的标签,我们可以用 tf.equal 来检测我们的预测是否真实标签匹配(索引位置一样表示匹配)。

    correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))
    

    这行代码会给我们一组布尔值。为了确定正确预测项的比例,我们可以把布尔值转换成浮点数,然后取平均值。例如,[True, False, True, True] 会变成 [1,0,1,1] ,取平均值后得到 0.75.

    ccuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
    

    最后,我们计算所学习到的模型在测试数据集上面的正确率,大概91%左右。

    print(sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels}))
    

    2、进阶

    2.1、权重初始化

    为了创建这个模型,我们需要创建大量的权重和偏置项。这个模型中的权重在初始化时应该加入少量的噪声来打破对称性以及避免0梯度。由于我们使用的是ReLU神经元,因此比较好的做法是用一个较小的正数来初始化偏置项,以避免神经元节点输出恒为0的问题(dead neurons)。为了不在建立模型的时候反复做初始化操作,我们定义两个函数用于初始化。

    def weight_variable(shape):
      initial = tf.truncated_normal(shape, stddev=0.1)
      return tf.Variable(initial)
    
    def bias_variable(shape):
      initial = tf.constant(0.1, shape=shape)
      return tf.Variable(initial)
    

    2.2、卷积和池化

    TensorFlow在卷积和池化上有很强的灵活性。我们怎么处理边界?步长应该设多大?在这个实例里,我们会一直使用vanilla版本。我们的卷积使用1步长(stride size),0边距(padding size)的模板,保证输出和输入是同一个大小。我们的池化用简单传统的2 x 2大小的模板做max pooling。为了代码更简洁,我们把这部分抽象成一个函数。

    def conv2d(x, W):
      return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')
    
    def max_pool_2x2(x):
      return tf.nn.max_pool(x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
    

    2.3、第一层卷积

    现在我们可以开始实现第一层了。它由一个卷积接一个max pooling完成。卷积在每个5 x 5的patch中算出32个特征。卷积的权重张量形状是[5, 5, 1, 32],前两个维度是patch的大小,接着是输入的通道数目,最后是输出的通道数目。 而对于每一个输出通道都有一个对应的偏置量。

    W_conv1 = weight_variable([5, 5, 1, 32])
    b_conv1 = bias_variable([32])
    

    为了用这一层,我们把x变成一个4 d向量,其第2、第3维对应图片的宽、高,最后一维代表图片的颜色通道数(因为是灰度图所以这里的通道数为1,如果是rgb彩色图,则为3)。

    x_image = tf.reshape(x, [-1,28,28,1])
    

    我们把x_image和权值向量进行卷积,加上偏置项,然后应用ReLU激活函数,最后进行max pooling。

    h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)
    h_pool1 = max_pool_2x2(h_conv1)
    

    2.4、第二层卷积

    为了构建一个更深的网络,我们会把几个类似的层堆叠起来。第二层中,每个5 x 5的patch会得到64个特征。

    W_conv2 = weight_variable([5, 5, 32, 64])
    b_conv2 = bias_variable([64])
    
    h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)
    h_pool2 = max_pool_2x2(h_conv2)
    

    2.5、密集连接层

    现在,图片尺寸减小到7 x 7,我们加入一个有1024个神经元的全连接层,用于处理整个图片。我们把池化层输出的张量reshape成一些向量,乘上权重矩阵,加上偏置,然后对其使用ReLU。

    W_fc1 = weight_variable([7 * 7 * 64, 1024])
    b_fc1 = bias_variable([1024])
    
    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)
    

    2.6、Dropout

    为了减少过拟合,我们在输出层之前加入dropout。我们用一个placeholder来代表一个神经元的输出在dropout中保持不变的概率。这样我们可以在训练过程中启用dropout,在测试过程中关闭dropout。 TensorFlow的tf.nn.dropout操作除了可以屏蔽神经元的输出外,还会自动处理神经元输出值的scale。所以用dropout的时候可以不用考虑scale。

    keep_prob = tf.placeholder("float")
    h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)
    

    2.7、输出层

    最后,我们添加一个softmax层,就像前面的单层softmax regression一样。

    W_fc2 = weight_variable([1024, 10])
    b_fc2 = bias_variable([10])
    
    y_conv=tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2)
    

    相关文章

      网友评论

        本文标题:Tensorflow学习笔记

        本文链接:https://www.haomeiwen.com/subject/gnkbfhtx.html