tensorflow notes

tf 生成 tensor、序列 和 随机数方法

  • 生成tensor
tf.zeros(shape, dtype=tf.float32, name=None)
tf.zeros_like(tensor, dtype=None, name=None)
tf.constant(value, dtype=None, shape=None, name='Const')
tf.fill(dims, value, name=None)
tf.ones_like(tensor, dtype=None, name=None)
tf.ones(shape, dtype=tf.float32, name=None)
  • 生成序列
tf.range(start, limit, delta=1, name='range')
tf.linspace(start, stop, num, name=None)
  • 生成随机数
tf.random_normal(shape, mean=0.0, stddev=1.0, dtype=tf.float32, seed=None, name=None)
tf.truncated_normal(shape, mean=0.0, stddev=1.0, dtype=tf.float32, seed=None, name=None)
tf.random_uniform(shape, minval=0.0, maxval=1.0, dtype=tf.float32, seed=None, name=None)
tf.random_shuffle(value, seed=None, name=None)

例子

import tensorflow as tf
import numpy as np

# 生成0和1矩阵
v1 = tf.Variable(tf.zeros([3, 3, 3]), name="v1")
v2 = tf.Variable(tf.ones([10, 5]), name="v2")
# 填充单值矩阵
v3 = tf.Variable(tf.fill([2, 3], 9))
# 常量矩阵
v4_1 = tf.constant([1, 2, 3, 4, 5, 6, 7])
v4_2 = tf.constant(-1.0, shape=[2, 3])
# 生成等差数列
v6_1 = tf.linspace(10.0, 12.0, 30, name="linspace")  # float32 or float64
v7_1 = tf.range(10, 20, 3)  # just int32
# 生成各种随机数据矩阵
v8_1 = tf.Variable(tf.random_uniform([2, 4], minval=0.0, maxval=2.0, dtype=tf.float32, seed=1234, name="v8_1"))
v8_2 = tf.Variable(tf.random_normal([2, 3], mean=0.0, stddev=1.0, dtype=tf.float32, seed=1234, name="v8_2"))
v8_3 = tf.Variable(tf.truncated_normal([2, 3], mean=0.0, stddev=1.0, dtype=tf.float32, seed=1234, name="v8_3"))
v8_4 = tf.Variable(tf.random_uniform([2, 3], minval=0.0, maxval=1.0, dtype=tf.float32, seed=1234, name="v8_4"))
v8_5 = tf.random_shuffle([[1, 2, 3], [4, 5, 6], [6, 6, 6]], seed=134, name="v8_5")

# 初始化
init_op = tf.initialize_all_variables()
# 保存变量,也可以指定保存的内容
saver = tf.train.Saver()
# saver = tf.train.Saver({"my_v2": v2})

# 运行
with tf.Session() as sess:
    sess.run(init_op)
    # 输出形状和值
    print(tf.Variable.get_shape(v1))# shape
    print(sess.run(v1))# vaule
    # numpy保存文件
    np.save("v1.npy", sess.run(v1))  # numpy save v1 as file
    test_a = np.load("v1.npy")
    print(test_a[1, 2])
    # 一些输出
    print(sess.run(v3))
    v5 = tf.zeros_like(sess.run(v1))
    print(sess.run(v6_1))
    print(sess.run(v7_1))
    print(sess.run(v8_5))
    # 保存图的变量
    save_path = saver.save(sess, "/tmp/model.ckpt")
    # 加载图的变量
    # saver.restore(sess, "/tmp/model.ckpt")
    print("Model saved in file: ", save_path)

全连接层函数tf.layers.dense()原理

tf.layers.dense( input, units=k )会在内部自动生成一个权矩阵kernel和偏移项bias,各变量具体尺寸如下:对于尺寸为[m, n]的二维张量input, tf.layers.dense()会生成:尺寸为[n, k]的权矩阵kernel,和尺寸为[m, k]的偏移项bias。内部的计算过程为y = input * kernel + bias,输出值y的维度为[m, k]

测试代码

import tensorflow as tf

# 1. 调用tf.layers.dense计算
input = tf.reshape(tf.constant([[1., 2.], [2., 3.]]), shape=[4, 1])    
b1 = tf.layers.dense(input,
                     units=2,
                     kernel_initializer=tf.constant_initializer(value=2),   # shape: [1,2]
                     bias_initializer=tf.constant_initializer(value=1))     # shape: [4,2]

# 2. 采用矩阵相乘的方式计算
kernel = tf.reshape(tf.constant([2., 2.]), shape=[1, 2])
bias = tf.reshape(tf.constant([1., 1., 1., 1., 1., 1., 1., 1.]), shape=[4, 2])
b2 = tf.add(tf.matmul(input, kernel), bias)

with tf.Session()as sess:
    sess.run(tf.global_variables_initializer())
    print(sess.run(b1))
    print(sess.run(b2)) 

可以发现两种方法的结果相同。。

tf.global_variables_initializer()

  • 初始化参数
  • 旧版本的tf.initialize_all_variables() 已弃用
#-*-coding:UTF-8-*-
import tensorflow as tf

state = tf.Variable(0 , name='counter')
one = tf.constant(1)

new_value = tf.add(state, one)
update = tf.assign(state, new_value)

# init = tf.initialize_all_variables() 旧版本已被弃用了,用下面的global_variables_initializer方法初始化参数
init = tf.global_variables_initializer()

with tf.Session() as sess:
    sess.run(init)
    for _ in range(3): 
        print(sess.run(update))
# 输出 1 2 3

tf.assign() 用法

  • 近日在使用tensorflow的过程中,对于tf.assign函数使用有点迷惑,经过仔细看API才发现这函数的妙处。

tf.assign(ref, value, validate_shape=None, use_locking=None, name=None)

  • 函数完成了将value赋值给ref的作用。其中:ref 必须是tf.Variable创建的tensor,如果ref=tf.constant()会报错!
  • 同时,shape(value)==shape(ref)
import tensorflow as tf

A = tf.Variable([1,2,3])

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    print (sess.run(A))  ## [1,2,3]
    assign = tf.assign(A, [1,2,5])
    print(sess.run(assign))  ##输出 [1,2,5]
    print (sess.run(A))  ##输出 [1,2,5]
  • 如果把validate_shape设置为False就可以在两个不同维度之间使用
import tensorflow as tf

A = tf.Variable([1,2,3])

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    print (sess.run(A))  ## [1,2,3]
    assign = tf.assign(A, [1,2], validate_shape=False)
    print(sess.run(assign))  ##输出 [1,2]
    print (sess.run(A))  ##输出 [1,2]

tensorboard 使用

  • 背景
    在复杂的问题中,网络往往都是很复杂的。为了方便调试参数以及调整网络结构,我们需要将计算图可视化出来,以便能够更好的进行下一步的决策。Tensorflow提供了一个TensorBoard工具,可以满足上面的需求。
  • 介绍
    TensorBoard是一个可视化工具,能够有效地展示Tensorflow在运行过程中的计算图、各种指标随着时间的变化趋势以及训练中使用到的数据信息。可以查看TensorBoard Github ReadMe 详细阅读适应方法。
  • 简单的例子
    下面通过一个简单的例子来显示一下使用方式,下面的图是一个向量加法的图结构。
import tensorflow as tf
a = tf.constant([1.0,2.0,3.0],name='input1')
b = tf.Variable(tf.random_uniform([3]),name='input2')
add = tf.add_n([a,b],name='addOP')
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    writer = tf.summary.FileWriter("./model_path",sess.graph)
    print(sess.run(add))
writer.close()

运行完程序后,图结构将以日志文件的形式保存到给定的路径下。
然后在命令行启动Tensorboard。Tensorboard作为本地的一个服务已经启动,端口号是6006,我们只需要在浏览器下输入127.0.0.1:6006就可以进入TensorBoard。下图分别是Tensorboard的界面,以及上面代码对用的图结构。

tensorboard --logdir=./model_path

在这里插入图片描述

我们可以简单对下面的图结构进行解读。图中的椭圆代表操作,阴影代表命名空间,小圆圈代表常量。虚线箭头代表依赖,实线箭头代表数据流。
我们的程序想要完成一个加法操作,首先需要利用random_uniform生成一个3元的向量,输入到input2变量节点中,然后input2变量节点需要依赖init操作来完成变量初始化。input2节点将结果输入到addOP操作节点中,同时常量节点input1也将数据输入到addOP中,最终addOP完成计算。
在这里插入图片描述

  • 添加命名空间
    前面的程序,只是一个简单的加法,但是图结构却十分凌乱,而且整个程序的核心add没有在图结构中突出,反而是一些初始化的操作占据了计算图的主要部分。这样不利于对计算图进行分析。因此,我们需要利用一种方式,将计算图的细节部分隐藏,保留关键部分命名空间给我们提供了这种机会。
    上面的计算图中,核心部分是两个输入传递给加法操作完成计算,因此,我们需要将其他部分隐藏,只保留核心部分。
import tensorflow as tf
with tf.variable_scope('input1'):
    input1 = tf.constant([1.0,2.0,3.0],name='input1')
with tf.variable_scope('input2'):
    input2 = tf.Variable(tf.random_uniform([3]),name='input2')
add = tf.add_n([input1,input2],name='addOP')
with tf.Session() as sess:
    init = tf.global_variables_initializer()
    sess.run(init)
    writer = tf.summary.FileWriter("./model_path",sess.graph)
    print(sess.run(add))
writer.close()

在这里插入图片描述
利用同样的方式,我们可以将MNIST神经网络代码重新进行组织(不知道组织的逻辑结构是否正确)

from tensorflow.examples.tutorials.mnist import input_data
import tensorflow as tf

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

batch_size = 100
hidden1_nodes = 200
with tf.name_scope('Input'):
    x = tf.placeholder(tf.float32,shape=(None,784))
    y = tf.placeholder(tf.float32,shape=(None,10))
with tf.name_scope('Inference'):
    w1 = tf.Variable(tf.random_normal([784,hidden1_nodes],stddev=0.1))
    w2 = tf.Variable(tf.random_normal([hidden1_nodes,10],stddev=0.1))
    b1 = tf.Variable(tf.random_normal([hidden1_nodes],stddev=0.1))
    b2 = tf.Variable(tf.random_normal([10],stddev=0.1))
    hidden = tf.nn.relu(tf.matmul(x,w1)+b1)
    y_predict = tf.nn.relu(tf.matmul(hidden,w2)+b2)

with tf.name_scope('Loss'):
    cross_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y, logits=y_predict))
with tf.name_scope('Train'):
    train_step = tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy)
with tf.name_scope('Accuracy'):
    correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_predict, 1))
    accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))


with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    for i in range(10000):
        batch_xs, batch_ys = mnist.train.next_batch(batch_size)
        sess.run(train_step, feed_dict={x: batch_xs, y: batch_ys})
        if i%1000==0:
            print ('Phase'+str(i/1000+1)+':',sess.run(accuracy, feed_dict={x: mnist.test.images, y: mnist.test.labels}))
writer = tf.summary.FileWriter("./mnist_nn_log",sess.graph)
writer.close()

在这里插入图片描述

tf.train.Saver()

  • 作用: tf.train.Saver() 保存和加载模型
  • 参数
__init__(var_list=None, 
		reshape=False, 
		sharded=False,   
		max_to_keep=5,    
		keep_checkpoint_every_n_hours=10000.0,  
		name=None,    
		restore_sequentially=False,    
		saver_def=None,  
		builder=None,    
		defer_build=False,   
		allow_empty=False,    
		write_version=tf.train.SaverDef.V2,  
		pad_step_number=False,    
		save_relative_paths=False,  
		filename=None)
		"""
		Args:
      var_list: A list of `Variable`/`SaveableObject`, or a dictionary mapping
        names to `SaveableObject`s. If `None`, defaults to the list of all
        saveable objects. 
      reshape: If `True`, allows restoring parameters from a checkpoint
        where the variables have a different shape.
      sharded: If `True`, shard the checkpoints, one per device.
      max_to_keep: Maximum number of recent checkpoints to keep.
        Defaults to 5.
      keep_checkpoint_every_n_hours: How often to keep checkpoints.
        Defaults to 10,000 hours.
      name: String.  Optional name to use as a prefix when adding operations.
      restore_sequentially: A `Bool`, which if true, causes restore of different
        variables to happen sequentially within each device.  This can lower
        memory usage when restoring very large models.
      saver_def: Optional `SaverDef` proto to use instead of running the
        builder. This is only useful for specialty code that wants to recreate
        a `Saver` object for a previously built `Graph` that had a `Saver`.
        The `saver_def` proto should be the one returned by the
        `as_saver_def()` call of the `Saver` that was created for that `Graph`.
      builder: Optional `SaverBuilder` to use if a `saver_def` was not provided.
        Defaults to `BulkSaverBuilder()`.
      defer_build: If `True`, defer adding the save and restore ops to the
        `build()` call. In that case `build()` should be called before
        finalizing the graph or using the saver.
      allow_empty: If `False` (default) raise an error if there are no
        variables in the graph. Otherwise, construct the saver anyway and make
        it a no-op.
      write_version: controls what format to use when saving checkpoints.  It
        also affects certain filepath matching logic.  The V2 format is the
        recommended choice: it is much more optimized than V1 in terms of
        memory required and latency incurred during restore.  Regardless of
        this flag, the Saver is able to restore from both V2 and V1 checkpoints.
      pad_step_number: if True, pads the global step number in the checkpoint
        filepaths to some fixed width (8 by default).  This is turned off by
        default.
      save_relative_paths: If `True`, will write relative paths to the
        checkpoint state file. This is needed if the user wants to copy the
        checkpoint directory and reload from the copied directory.
      filename: If known at graph construction time, filename used for variable
        loading/saving.
		"""
  • var_list 是要保存的参数,默认是全部
  • 用法
saver = tf.train.Saver(max_to_keep=num)  # max_to_keep默认为5,即保存最后的5个ckpt参数文件
saver.save(sess,  '路径 + 模型文件名'
  • 在创建这个 Saver 对象的时候, max_to_keep 参数表示要保留的最近检查点文件的最大数量,创建新文件时,将删除旧文件,默认为 5(即保留最近的 5 个检查点文件),max_to_keep=5。
  • demo如下
import tensorflow as tf
import os
import numpy as np
 
a = tf.Variable(1., tf.float32)
b = tf.Variable(2., tf.float32)

model_save_path = './model/'
model_name = 'model'
 
saver = tf.train.Saver(max_to_keep=3)  # 设置保存最后3个ckpt,之前的会被覆盖
 
with tf.Session() as sess:
    init_op = tf.global_variables_initializer()
    sess.run(init_op)
    for step in np.arange(10):
        c = sess.run(tf.add(a, b))

        # 默认最多同时存放 5 个模型
        saver.save(sess, os.path.join(model_save_path, model_name), global_step=step)

在这里插入图片描述
Tensorflow 会自动生成4个文件

第一个文件为 model.ckpt.meta,保存了 Tensorflow 计算图的结构,可以简单理解为神经网络的网络结构。

model.ckpt.index 和 model.ckpt.data--of- 文件保存了所有变量的取值。

最后一个文件为 checkpoint 文件,保存了一个目录下所有的模型文件列表。

import tensorflow as tf
import os
import numpy as np
 
a = tf.Variable(1., tf.float32)
b = tf.Variable(2., tf.float32)
num = 10
 
model_save_path = './model/'
model_name = 'model'
 
saver = tf.train.Saver()
 
with tf.Session() as sess:
    init_op = tf.global_variables_initializer()
    sess.run(init_op)
    ckpt = tf.train.get_checkpoint_state(model_save_path)
    # 载入模型,不需要提供模型的名字,会通过 checkpoint 文件定位到最新保存的模型
    if ckpt and ckpt.model_checkpoint_path:
        saver.restore(sess, ckpt.model_checkpoint_path)
    print("load success")

在这里插入图片描述

tf.reduce_sum() 用法

在这里插入图片描述

全连接层函数tf.layers.dense()原理

最近在用TensorFlow实现CNN网络时用到了全连接层,在网上看了很多有关全连接层实现的代码,发现相当一部分人都还是倾向于自己构造权重矩阵W和偏移矩阵b,利用矩阵乘法实现全连接层。

而TensorFlow中封装了全连接层函数tf.layers.dense(),但是官方文档中并没有解释其详细原理。网上有部分博客对此提及,但也少有涉及到内部实现原理的。于是今天自己动手做了个对比试验,来探究一下tf.layers.dense()函数的详细原理。

先贴结论:tf.layers.dense( input, units=k )会在内部自动生成一个权矩阵kernel和偏移项bias,各变量具体尺寸如下:对于尺寸为[m, n]的二维张量input, tf.layers.dense()会生成:尺寸为[n, k]的权矩阵kernel,和尺寸为[m, k]的偏移项bias。内部的计算过程为y = input * kernel + bias,输出值y的维度为[m, k]。

import tensorflow as tf

# 1. 调用tf.layers.dense计算
input = tf.reshape(tf.constant([[1., 2.], [2., 3.]]), shape=[4, 1])    
b1 = tf.layers.dense(input,
                     units=2,
                     kernel_initializer=tf.constant_initializer(value=2),   # shape: [1,2]
                     bias_initializer=tf.constant_initializer(value=1))     # shape: [4,2]

# 2. 采用矩阵相乘的方式计算
kernel = tf.reshape(tf.constant([2., 2.]), shape=[1, 2])
bias = tf.reshape(tf.constant([1., 1., 1., 1., 1., 1., 1., 1.]), shape=[4, 2])
b2 = tf.add(tf.matmul(input, kernel), bias)

with tf.Session()as sess:
    sess.run(tf.global_variables_initializer())
    print(sess.run(b1))
    print(sess.run(b2)) 

计算的结果如图所示,两种方法得到的结果相同。
在这里插入图片描述

tf.placeholder作用

例子 - bert 输入op

# shape=(None, self._max_seq_len) 第一维一般是 batch_size
self._input_ids_ph = tf.placeholder(
  shape=(None, self._max_seq_len), dtype=tf.int32, name="input_ids_ph")
# self._input_ids_mask 和 self._input_ids_ph 是相同的维度
self._input_ids_mask = tf.to_int32(
  self._input_ids_ph>0, name="input_ids_mask")
  • 为什么要使用tf.placeholder?

因为每一个tensor值在graph上都是一个op,
当我们将train数据分成一个个minibatch然后传入网络进行训练时,
每一个minibatch都将是一个op,
这样的话,一副graph上的op未免太多,也会产生巨大的开销;
于是就有了tf.placeholder,
我们每次可以将 一个minibatch传入到x = tf.placeholder(tf.float32,[None,32])上,
下一次传入的x都替换掉上一次传入的x,
这样就对于所有传入的minibatch x就只会产生一个op,
不会产生其他多余的op,进而减少了graph的开销。

在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值