Brief 概述
基于对 Tensorflow 大致的了解,并理解了流程图设置的逻辑和运行方法后,我们逐渐的会发现其设计理念与机器学习深远的匹配性。延续前面一章节最后的代码,此单元记录的模型和方法主要也是围绕 「监督学习」 为重点展开。构建一个内涵机器学习算法的流程图后,我们就可以以一个参数作为输入,启动计算流程并等待最终结果,大致的训练过程如下流程:
- 建构好数学模型指向图
- 初始化模型参数
- 输入训练用的数据集
- 从初始化的参数出发,推断模型走向
- 和训练集数据样本比较,计算差异多寡, 此差异名为损失
- 根据损失调整参数,重新回到步骤 3. 并不断循环下去
模型在一次又一次的迭代训练时,学习效率这个参数需要我们人工调整,只要确保整个学习结果朝向一个正确的方向走就是一个好的参数。一个完整的代码框架如下演示:
import tensorflow as tf
# initialize variables and arguments in the math model
# define the operations within the training loop
def inference(X):
# calculate the result when substituting data X into the model
pass
def loss(X, Y):
# calculate loss value by substracting model output and training data
pass
def inputs():
# read or generate the training data X and the expected output Y
pass
def train(total_loss):
# adjust the model parameters based on the loss value
pass
def evaluate(sess, X, Y):
# evaluate the performance of a trained model
pass
# here is the routine procedure below
with tf.Session() as sess:
tf.global_variables_initializer().run()
X, Y = inputs()
total_loss = loss(X, Y)
train_op = train(total_loss)
cdr = tf.train.Coordinator()
threads = tf.train.start_queue_runners(sess=sess, coodr=cdr)
for step in range(1000):
sess.run([train_op])
if step % 10 == 0:
print('loss:', sess.run([total_loss]))
evaluate(sess, X, Y)
cdr.request_stop()
cdr.join(threads)
sess.close()
如代码有些陌生之处,可以点击此超链接阅读上一篇文章: Tensorflow_01_Overview 全局概述
p.s. 编写神经网络代码的时候,我们会习惯把一些功能集成到自定义的函数中,让最后的代码写出来更易读。
Functions in The Model 模型中的函数总览
说到模型,里面总会有许多 Tensorflow 所包含的类和方法是看着陌生的东西,下面是对于许多示范代码中提取出来常见的函数列举与附上代码的详细解释,在理解的过程中可以逐渐对此模块的构建逻辑有更清晰的认识。
p.s. 点击 此链接 可以查看中文版的 Tensorflow 官方文档
Tool Box 工具集函数
- tf.equal()
- tf.range()
- tf.stack()
- tf.unstack()
- tf.reshape()
- tf.cast()
- tf.split()
- tf.concat()
- tf.one_hot()
- tf.to_float()
- tf.transpose()
- tf.squeeze()
- tf.argmax()
- tf.map_fn()
- tf.random_crop()
- tf.minimum()
- tf.maximum()
Calculating Operations 运算操作
Deep Learning 深度学习
- tf.nn.sigmoid()
- tf.nn.relu()
- tf.nn.softmax()
- tf.nn.conv2d()
- tf.nn.max_pool()
- tf.nn.dropout() ?????
- tf.nn.batch_normalization()
Gradient Descent 梯度下降
- tf.train.GradientDescentOptimizer()
- tf.train.MomentumOptimizer()
- tf.train.AdagradOptimizer()
- tf.train.RMSPropOptimizer()
- tf.train.AdamOptimizer()
- apply_gradients()
- compute_gradients()
- get_name()
- get_slot()
- get_slot_name()
- minimize()
- variables()
Tool Box 工具集函数
1. tf.equal(x, y, name=None) / tf.math.equal(x, y, name=None)
- x: 必须是一个张量 (Tensor) ,并且同时定义清楚该张量的数据类型
- y: 必须是一个跟 x 同类型,且维度也一模一样的张量 (Tensor)
- name: 自定义此节点的名称,用字符串表示
回传结果: 一个同样维度的张量,元素是 x 与 y 匹配结果的布尔值
import tensorflow as tf
a = [1, 2, 3, 3, 4]
b = [2, 2, 3, 4, 5]
sess = tf.Session()
print(sess.run(tf.equal(a, b, name='equal')))
sess.close()
### ----- Result is shown below ----- ###
[False True True False False]
2. tf.range(start, limit, delta=1, dtype=None, name='range')
- start: 一个范围的起头,回传值**包含**此值
- limit: 一个范围的结束,回传值**不包含**此值
- delta: 开始结束值中间的取值间隔是多少,会取到最靠近 limit 值的值为止
- dtype: 此回传值全部的数据类型
- name: 自定义此节点的名称,用字符串表示
回传结果: 一个向量格式的列表数据 (只有一个维度)
import tensorflow as tf
sess = tf.Session()
print(sess.run(tf.range(3, 10, delta=2, dtype=tf.float32)))
sess.close()
### ----- Result is shown below ----- ###
[3. 5. 7. 9.]
3. tf.stack(values, axis=0, name='stack')
- values: 为一个张量值 (Tensor),最好有明确的数据类型
- axis: 只有 0 与 1 两个值, 0 表示维持张量的单纯横向元素叠加,增加维度;反之如果是 1 ,则叠加后的结果会被纵向元素堆叠后才回传结果
- name: 自定义此节点的名称,用字符串表示
p.s. 此函数的原本名称为: tf.pack()
回传结果: 是一个元素堆叠过后的总列表 (并不限制堆叠的元素有几个维度,但是被堆叠在一起的元素必须形状完全相同)
import tensorflow as tf
a = tf.constant([[1, 2, 3, 4], [2, 3, 4, 5]], dtype=tf.float32)
b = tf.constant([[3, 4, 5, 6], [5, 6, 7, 8]], dtype=tf.float32)
c = tf.constant([[11, 12, 13, 14], [13, 14, 15, 16]], dtype=tf.float32)
sess = tf.Session()
print(sess.run(tf.stack([a, b, c], axis=0, name=None)))
print('----- Separation -----')
print(sess.run(tf.stack([a, b, c], axis=1, name=None)))
sess.close()
### ----- Result is shown below ----- ###
[[[ 1. 2. 3. 4.]
[ 2. 3. 4. 5.]]
[[ 3. 4. 5. 6.]
[ 5. 6. 7. 8.]]
[[11. 12. 13. 14.]
[13. 14. 15. 16.]]]
----- Separation -----
[[[ 1. 2. 3. 4.]
[ 3. 4. 5. 6.]
[11. 12. 13. 14.]]
[[ 2. 3. 4. 5.]
[ 5. 6. 7. 8.]
[13. 14. 15. 16.]]]
4. tf.unstack(value, num=None, axis=0, name='unstack')
- value: 只能放入一个可以被分拆的张量中, 最好有宣告好数据类型
- num: 表示要被分割的段数,但是经过尝试我们没办法把例如四段张量用其公因数切分,还是比需按照原本的总量尺寸逐一切分,因此为了方便起见我们就填 None ,但是初始值就是 None ,一番折腾后发现有跟没有是一样的
- axis: 只有 0 与 1 两个值, 类似 stack , 0 是横向拆分,而 1 是纵向拆分
- name: 自定义此节点的名称,用字符串表示
回传结果: 是一个拆分后的子张量,并用一个列表的形式回传
import tensorflow as tf
a = tf.constant([[1, 2, 3, 4], [4, 5, 6, 7], [7, 8, 9, 10]],
dtype=tf.float32)
sess = tf.Session()
print(sess.run(tf.unstack(a, num=3, axis=0, name=None)))
sess.close()
### ----- Result is shown below ----- ###
[array([1., 2., 3., 4.], dtype=float32),
array([4., 5., 6., 7.], dtype=float32),
array([7., 8., 9., 10.], dtype=float32)]
5. tf.reshape(Tensor, shape, name=None)
- Tensor: 给定一个需要被重组的张量值
- shape: 必填,给定一个重组后的张量形状,描述形状的数字类型必须是 int32/int64,维度等信息。其中 「-1」 是一个特殊的存在,最多可以填在一个维度上,而 tf 会自动计算该张量变换形状后填了 -1 的维度值大小
- name: 自定义此节点的名称,用字符串表示
回传结果: 是一个改变形态后的新的张量,里面的元素内容原封不动
import tensorflow as tf
k = tf.constant([1, 2, 3, 4, 5, 6, 7, 8, 9])
h = tf.constant([[[1, 1, 1],
[2, 2, 2]],
[[3, 3, 3],
[4, 4, 4]],
[[5, 5, 5],
[6, 6, 6]]])
sess = tf.Session()
print(sess.run(tf.reshape(k, shape=[3, 3])))
print('----- Separation -----')
print(sess.run(tf.reshape(h, shape=(2, 3, -1))))
sess.close()
### ----- Result is shown below ----- ###
[[1 2 3]
[4 5 6]
[7 8 9]]
----- Separation -----
[[[1 1 1]
[2 2 2]
[3 3 3]]
[[4 4 4]
[5 5 5]
[6 6 6]]]
6. tf.cast(x, dtype, name=None)
- x: 一个张量传入,抑或一个数字类型的数据
- dtype: 把传入的数据转换成这里指定的数据类型
- name: 自定义此节点的名称,用字符串表示
回传结果: 还是原来的函数,只是数据类型变了
import tensorflow as tf
x = tf.constant([1.8, 2.2], dtype=tf.float32)
sess = tf.Session()
print(sess.run(tf.cast(x, tf.int32)))
sess.close()
### ----- Result is shown below ----- ###
[1 2]
7. tf.split(value, num_or_size_splits, axis=0, num=None, name='split')
- value: 一个准备被拆分的张量值
- num_or_size_splits: 可以是一个数字,意味着横着把输入的张量批成几刀,也可以是向量,意味着把一个张量拆成两个内涵向量中数字多寡之元素的张量,如下代码
- axis: 只有 0 和 1 的输入, 0 表示正常形状切割, 1 表示先转置过后再切割
- num: 一般不写,只是用来表明即将要被分成几块,如果我们预期的结果与实际上不同,则报错,是一个让代码与逻辑更清晰的工具
- name: 自定义此节点的名称,用字符串表示
回传结果: 一个被拆分后的新张量, 使用一个列表数据形态概括拆分后的结果
import tensorflow as tf
p = tf.constant([1, 2, 3, 4, 5, 6], shape=(4, 2), dtype=tf.float32)
sess = tf.Session()
print(sess.run(p))
print('----- Separation -----')
print(sess.run(tf.split(p, 2, axis=0)))
print('----- Separation -----')
print(sess.run(tf.split(p, [1, 3], axis=0, num=2)))
sess.close()
### ----- Result is shown below ----- ###
[[1. 2.]
[3. 4.]
[5. 6.]
[6. 6.]]
----- Separation -----
[array([[1., 2.],
[3., 4.]], dtype=float32), array([[5., 6.],
[6., 6.]], dtype=float32)]
----- Separation -----
[array([[1., 2.]], dtype=float32), array([[3., 4.],
[5., 6.],
[6., 6.]], dtype=float32)]
8. tf.concat(values, axis, name='concat')
- values: 一个即将要被合在一起之列表组成的多个张量,或是单一个张量
- axis: 我们指定沿着哪一个维度来合并两个要被连在一起的张量, 0 表示 1D, 1 表示 2D, 以此类推
- name: 自定义此节点的名称,用字符串表示
回传结果: 回传一个沿着指定的坐标轴叠加了几个目标张量的张量,用列表方式展示
import tensorflow as tf
T1 = tf.constant([[[1, 1, 1], [2, 2, 2]], [[3, 3, 3], [4, 4, 4]]])
T2 = tf.constant([[[5, 5, 5], [6, 6, 6]], [[7, 7, 7], [8, 8, 8]]])
sess = tf.Session()
print(sess.run(tf.concat([T1, T2], 0)))
print('----- Separation -----')
print(sess.run(tf.concat([T1, T2], 1)))
print('----- Separation -----')
print(sess.run(tf.concat([T1, T2], 2)))
sess.close()
### ----- Result is shown below ----- ###
[[[1 1 1]
[2 2 2]]
[[3 3 3]
[4 4 4]]
[[5 5 5]
[6 6 6]]
[[7 7 7]
[8 8 8]]]
----- Separation -----
[[[1 1 1]
[2 2 2]
[5 5 5]
[6 6 6]]
[[3 3 3]
[4 4 4]
[7 7 7]
[8 8 8]]]
----- Separation -----
[[[1 1 1 5 5 5]
[2 2 2 6 6 6]]
[[3 3 3 7 7 7]
[4 4 4 8 8 8]]]
9. tf.one_hot(indices, depth, on_value=None, off_value=None, axis=None, dtype=None, name=None)
- indices: 一个一维的列表数组,内部只能是数字元素,数字只能是整数类型,数字表示的是生成结果元素在该维度下的 「位置」 信息,意味着列表里面的数字不能够大于列表的总长度,不然该位置不存在。函数的结果将以此列表加一个维度的方式展现
- depth: 根据 indices 提供的总位置信息,可以用此参数选择打印出来的比例,最大值就是该信息列表的总长,函数的结果就是一个方阵
- on_value: 根据选中的位置,统一填上的值在这里设定,数据类型需要统一
- off_value: 根据选中位置之外的位置,填上的值在这里设定,数据类型也需要统一
- axis: 要沿着什么轴打印,默认值是 -1, 0 在这边反而被转置过, 1 功能等于 -1
- dtype: 必须跟 indices 的数据类型相同,且只限制整数的数据类型,否则报错
- name: 自定义此节点的名称,用字符串表示
回传结果: 一个比 indices 还要多一个维度的张量,只有两种元素组成,分别是 on_value 和 off_value,如下代码
import tensorflow as tf
t = tf.constant([0, 1, 2, 0, 3, 5], dtype=tf.int32)
sess = tf.Session()
print(sess.run(tf.one_hot(t, depth=6, on_value=1, off_value=0,
axis=-1, dtype=tf.int32)))
print('----- Separation -----')
print(sess.run(tf.one_hot(t, depth=6, on_value=9, off_value=1,
axis=0, dtype=tf.int32)))
print('----- Separation -----')
print(sess.run(tf.one_hot(t, depth=4, on_value=1, off_value=0,
axis=1, dtype=tf.int32)))
sess.close()
### ----- Result is shown below ----- ###
[[1 0 0 0 0 0]
[0 1 0 0 0 0]
[0 0 1 0 0 0]
[1 0 0 0 0 0]
[0 0 0 1 0 0]
[0 0 0 0 0 1]]
----- Separation -----
[[9 1 1 9 1 1]
[1 9 1 1 1 1]
[1 1 9 1 1 1]
[1 1 1 1 9 1]
[1 1 1 1 1 1]
[1 1 1 1 1 9]]
----- Separation -----
[[1 0 0 0]
[0 1 0 0]
[0 0 1 0]
[1 0 0 0]
[0 0 0 1]
[0 0 0 0]]
10. tf.to_float(x, name='ToFloat')
- x: 传入一个要被改成 tf.float32 数据形态的张量
- name: 自定义此节点的名称,用字符串表示
p.s. 同样类似的函数方法可以在官网链接中查找并使用,如下代码
回传结果: 回传一个外观和值都一模一样的张量数据,只是数据类型改成了 tf.float32
import tensorflow as tf
t = tf.constant([1, 2, 3, 4], shape=(2, 2), dtype=tf.int32)
sess = tf.Session()
print(sess.run(t))
print('----- Separation -----')
print(sess.run(tf.to_float(t)))
print('----- Separation -----')
print(sess.run(tf.to_complex64(t)))
print('----- Separation -----')
print(sess.run(tf.to_bfloat16(t)))
sess.close()
### ----- Result is shown below ----- ###
[[1 2]
[3 4]]
----- Separation -----
[[1. 2.]
[3. 4.]]
----- Separation -----
[[1.+0.j 2.+0.j]
[3.+0.j 4.+0.j]]
----- Separation -----
[[bfloat16(1) bfloat16(2)]
[bfloat16(3) bfloat16(4)]]
11. tf.transpose(a, perm=None, name='transpose', conjugate=False)
- a: 一个即将要被转置的张量
- perm: 默认是 None ,用一个列表表示,内部的元素值代表输入张量 a 的维度排列位置, 如果 a 是一个三维矩阵,此列表元素值就不能大于 2 ,原始的张量排列就是 0 1 2, 如果要转置, 就调换 0 1 2 彼此的排列,以此告诉此函数转制的方向
- name: 自定义此节点的名称,用字符串表示
- conjugate: 布尔值,是否回传如果是复数的共轭结果
回传结果: 即 a 张量沿着我们设定的方向转置之后的新张量
import tensorflow as tf
x = tf.constant([i+1 for i in range(12)], shape=(2, 3, 2), dtype=tf.complex64)
sess = tf.Session()
print(sess.run(x))
print('----- Separation -----')
print(sess.run(tf.transpose(x, perm=[0, 2, 1], conjugate=True)))
print('----- Separation -----')
print(sess.run(tf.transpose(x, perm=[1, 2, 0], conjugate=False)))
### ----- Result is shown below ----- ###
[[[ 1.+0.j 2.+0.j]
[ 3.+0.j 4.+0.j]
[ 5.+0.j 6.+0.j]]
[[ 7.+0.j 8.+0.j]
[ 9.+0.j 10.+0.j]
[11.+0.j 12.+0.j]]]
----- Separation -----
[[[ 1.-0.j 3.-0.j 5.-0.j]
[ 2.-0.j 4.-0.j 6.-0.j]]
[[ 7.-0.j 9.-0.j 11.-0.j]
[ 8.-0.j 10.-0.j 12.-0.j]]]
----- Separation -----
[[[ 1.+0.j 7.+0.j]
[ 2.+0.j 8.+0.j]]
[[ 3.+0.j 9.+0.j]
[ 4.+0.j 10.+0.j]]
[[ 5.+0.j 11.+0.j]
[ 6.+0.j 12.+0.j]]]
12. tf.squeeze(input, axis=None, name=None)
- input: 一个预计要被压缩的张量
- axis: 可以让使用者自定义张量的哪几个只有一个元素的维度要被压缩,一般使用列表来表示维度位置
- name: 自定义此节点的名称,用字符串表示
回传结果: 一个被压缩过后的张量,内部的值全部保持不动,是一个单纯维度上的调整
import tensorflow as tf
t = tf.constant([i+1 for i in range(12)], shape=(1, 2, 1, 3, 2, 1, 1))
sess = tf.Session()
print(sess.run(tf.squeeze(t)))
print('----- Separation -----')
print(sess.run(tf.squeeze(t, axis=[2, 5])))
# the shape of t would be shape=(1, 2, 3, 2, 1)
### ----- Result is shown below ----- ###
[[[ 1 2]
[ 3 4]
[ 5 6]]
[[ 7 8]
[ 9 10]
[11 12]]]
----- Separation -----
[[[[[ 1]
[ 2]]
[[ 3]
[ 4]]
[[ 5]
[ 6]]]
[[[ 7]
[ 8]]
[[ 9]
[10]]
[[11]
[12]]]]]
13. tf.argmax(input, axis=None, name=None, output_type=tf.int64)
- input: 一个张量,数据类型必须是 tf.int8/16/32/64, tf.uint8/16/32/64, tf.float32/64, tf.complex64/128, 更多查看官网
- axis: 从哪一个维度来比较数值大小, 0 表示直行方向, 1 表示横列方向
- name: 自定义此节点的名称,用字符串表示
- output_type: 定义输出结果的数字类型,只有 tf.int32/64 两种
回传结果: 一个比较行或是列数字大小后回传了最大值的 「位置」 的结果,组成一个列表回传
import tensorflow as tf
import numpy as np
tensor = tf.constant(np.random.randint(10, 50, 30), shape=[3, 10])
sess = tf.Session()
print(sess.run(tensor))
print('----- Separation -----')
print(sess.run(tf.argmax(tensor, axis=0, output_type=tf.int64)))
print('----- Separation -----')
print(sess.run(tf.argmax(tensor, axis=1, output_type=tf.int32)))
sess.close()
### ----- Result is shown below ----- ###
[[19 39 22 30 28 44 32 14 49 32]
[11 36 14 27 16 32 47 19 40 18]
[21 14 27 24 42 16 38 10 31 47]]
----- Separation -----
[2 0 2 0 2 0 1 1 0 2]
----- Separation -----
[8 6 9]
14. tf.map_fn(fn, elems, dtype=None, parellel_iterations=10, back_prop=True, sway_memory=False, infer_shape=True, name=None)
- fn: 是一个要用来让所有 elems 元素过水一边的函数,每个元素都因为这个函数的运算而改变,然后把改变过后的状态回传给自己
- elems: 一个将要被改变的元素,如果是像列表这类的数据类型,则该元素逐一被改变
- dytpe: 用来定义改变后元素的数据类型,不过它算是一个重复确认的功能,因为如果 elems 的数据类型与这里定义的不同,则会报错
- parallel_iterations: 可以同时平行处理的总数值,默认为 10
- back_prop: 调整此模型是否可以被反向传播,如梯度下降
- swap_memory: 调成 True 的话,可以让 GPU 和 CPU 的缓存相互转换
- infer_shape: ?????
- name: 自定义此节点的名称,用字符串表示
回传结果: 一个被过过水的同样数据类型与尺寸,但是数据本身被加工过的数据
import tensorflow as tf
def func(x):
x = x + 10
return x
t = tf.constant([1, 2, 3, 4, 5], dtype=tf.float32)
sess = tf.Session()
print(sess.run(tf.map_fn(lambda a: func(a), t, dtype=tf.float32)))
### ----- Result is shown below ----- ###
[11. 12. 13. 14. 15.]
15. tf.random_crop(value, size, seed=0, name=None)
- value: 一个即将要被裁切的 tensor
- size: 一个将要被改变的元素,如果是像列表这类的数据类型,则该元素逐一被改变
- seed: 如同 numpy 的功能,可以定格该随机的数字,让同一个 seed 的数字背后的大小都一样
- name: 自定义此节点的名称,用字符串表示
回传结果: 一个被随意裁切的新张量,非常适合用在图像的裁切上
import tensorflow as tf
import numpy as np
sess = tf.Session() # no matter where "sess" is put, it's fine
t = tf.constant(np.linspace(1, 60, 60), shape=[4, 5, 3])
# sess = tf.Session()
# t = np.linspace(1, 60, 60).reshape([4, 5, 3])
r = tf.random_crop(t, size=[3, 4, 3], seed=1)
# sess = tf.Session()
# print(sess.run(t))
a = sess.run(r) # tf method should be run first so that it can
# become numpy array again. So hard to validate this theory...
print(a)
print('----- Separation -----')
print(a[[1, 2]])
### ----- Result is shown below ----- ###
[[[ 1. 2. 3.]
[ 4. 5. 6.]
[ 7. 8. 9.]
[10. 11. 12.]]
[[16. 17. 18.]
[19. 20. 21.]
[22. 23. 24.]
[25. 26. 27.]]
[[31. 32. 33.]
[34. 35. 36.]
[37. 38. 39.]
[40. 41. 42.]]]
----- Separation -----
[[[16. 17. 18.]
[19. 20. 21.]
[22. 23. 24.]
[25. 26. 27.]]
[[31. 32. 33.]
[34. 35. 36.]
[37. 38. 39.]
[40. 41. 42.]]]
16-17. tf.minimum(x, y, name=None) / tf.maximum(x, y, name=None)
- x: 目标要被比较的 tensor,数据类型必须是 int32/64,float32/64,bfloat16,half
- y: 限定该张量的值
- name: 自定义此节点的名称,用字符串表示
回传结果: 一个原来一摸一样的张量,只是顶到天花板的值都会被抹平
import tensorflow as tf
a = tf.constant([1, 5, 5, 3, 1], dtype=tf.int32)
b = tf.maximum(a, 3)
c = tf.minimum(a, 4)
sess = tf.Session()
print(sess.run(b))
print(sess.run(c))
### ----- Result is shown below ----- ###
[3 5 5 3 3]
[1 4 4 3 1]
Calculating Operations 运算操作
1. tf.matmul(a, b, transpose_a=False, transpose_b=False, adjoint_a=False, adjoint_b=False, a_is_sparse=False, b_is_sparse=False, name=None)
- a, b: 为两个同样尺寸和数据类型的矩阵,两个预备做內积的矩阵 a*b, 支持的数据类型有 int32, float16/32/64, complex64/128
- transpose: 使用布尔值设置矩阵内积前是否先被转置
- adjoint: 使用布尔值设置矩阵内积前是否先做伴随矩阵
- a_is_sparse: 如果相乘的矩阵中有很多 0 元素,则可以把这个布尔值调成 True 加速运算
- name: 自定义此节点的名称,用字符串表示
回传结果: 得到两个矩阵的内积答案,并维持计算完的尺寸和数据类型
import tensorflow as tf
t_1 = tf.constant([1, 2, 3, 4, 5, 6], shape=(2, 3), dtype=tf.float32)
t_2 = tf.constant([6, 7, 8, 0, 0, 0], shape=[3, 2], dtype=tf.float32)
sess = tf.Session()
print(sess.run(t_1), '\n', sess.run(t_2))
print('----- Separation -----')
print(sess.run(tf.matmul(t_1, t_2, b_is_sparse=True)))
sess.close()
### ----- Result is shown below ----- ###
[[1. 2. 3.]
[4. 5. 6.]]
[[6. 7.]
[8. 0.]
[0. 0.]]
----- Separation -----
[[22. 7.]
[64. 28.]]
2-4. tf.reduce_sum(Tensor, axis=None, keepdims=False, name=None, reduction_indices=None)
- Tensor: 一个任意数字类型的张量,不限形状
- axis: 要沿着哪一个维度缩减,值为 0 表示横向, 1 表示纵向,如果是默认值 None 就尺寸都缩减成只有 1
- keepdims: 如果设为 True, 则保留缩减后原本的维度,不整合成一个
- name: 自定义此节点的名称,用字符串表示
p.s. 此模块部分没有写出来的参数意义就是一些即将被淘汰的部分,因此不重要。 reduce_mean() 和 reduce_max() 也都是一模一样的原理
回传结果:一个被缩减其中某写维度的张量,缩减的办法是使用加法把所有的元素加总起来,回传到一个自定义的张量中,必须限定是数字的数据类型
import tensorflow as tf
e = tf.constant([[1, 2, 3], [4, 5, 6], [7, 8, 9], [0, 0, 0]])
sess = tf.Session()
print(sess.run(tf.reduce_sum(e, axis=1)))
print('----- Separation -----')
print(sess.run(tf.reduce_mean(e, axis=1, keepdims=True)))
print('----- Separation -----')
print(sess.run(tf.reduce_max(e, axis=0, keepdims=True)))
sess.close()
### ----- Result is shown below ----- ###
[ 6 15 24 0]
----- Separation -----
[[2]
[5]
[8]
[0]]
----- Separation -----
[[7 8 9]]
Deep Learning 深度学习
1. tf.nn.sigmoid(x, name=None)
- x: 是一个不限维度的张量值传入,限制数据类型只能是 float16/32/64, complex64/128
- name: 自定义此节点的名称,用字符串表示
p.s. tf.nn.sigmoid() == tf.sigmoid() 目前两者并存
回传结果: 即 1 / (1 + exp(-x)) 的计算结果,如果张量里面不止一个数值,则分别带入计算后,返回同样尺寸和和数据类型的结果
2. tf.nn.relu(features, name=None)
- features: 是一个不限维度的张量值传入,限制数据类型不能是复数,详情点击上面超链接查看官方文档
- name: 自定义此节点的名称,用字符串表示
回传结果: 即 max(features, 0) ,在大于零的情况下维持线性关系,小于零的情况下皆为零
import tensorflow as tf
m = tf.constant([3, 0.8, 0.2], dtype=tf.float32)
sess = tf.Session()
print(sess.run(tf.nn.sigmoid(m)))
print(sess.run(tf.nn.relu(m)))
# so did the other activation functions
sess.close()
### ----- Result is shown below ----- ###
[0.95257413 0.6899745 0.54983395]
[3. 0.8 0.2]
3. tf.nn.softmax(logits, axis=None, name=None)
- logits: 即一个非空着的张量,其数据类型必须是 tf.float32/64, half
- axis: 可以选择一个张量其中一个横排套如此公式,得出的结果
- name: 自定义此节点的名称,用字符串表示
softmax formula:
- softmax = tf.exp(logits) / tf.reduce_sum(tf.exp(logits), axis)
回传结果: 一个张量经过 softmax 数学运算后得出来同样形状与数据类型的结果
import tensorflow as tf
t = tf.constant([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], shape=(3, 4), dtype=tf.float32)
t2 = tf.constant([1, 5, 9], dtype=tf.float32)
t3 = tf.constant([1, 2, 3, 4], dtype=tf.float32)
sess = tf.Session()
print(sess.run(t))
print('----- Separation -----')
print(sess.run(tf.nn.softmax(t, axis=-1)))
print('----- Separation -----')
print(sess.run(tf.nn.softmax(t, axis=0)))
print('----- Separation -----')
print(sess.run(tf.nn.softmax(t2)))
print('----- Separation -----')
print(sess.run(tf.nn.softmax(t3)))
sess.close()
### ----- Result is shown below ----- ###
[[ 1. 2. 3. 4.]
[ 5. 6. 7. 8.]
[ 9. 10. 11. 12.]]
----- Separation -----
[[0.0320586 0.08714432 0.23688284 0.6439143 ]
[0.0320586 0.08714432 0.23688284 0.6439143 ]
[0.0320586 0.08714432 0.23688284 0.6439143 ]]
----- Separation -----
[[3.2932041e-04 3.2932041e-04 3.2932041e-04 3.2932041e-04]
[1.7980287e-02 1.7980287e-02 1.7980287e-02 1.7980287e-02]
[9.8169035e-01 9.8169035e-01 9.8169035e-01 9.8169035e-01]]
----- Separation -----
[3.2932041e-04 1.7980287e-02 9.8169035e-01]
----- Separation -----
[0.0320586 0.08714432 0.23688284 0.6439143 ]
4. tf.nn.conv2d(input, filter, strides, padding, use_cudnn_on_gpu=True, data_format='NHWC', dilations=[1, 1, 1, 1], name=None)
- input: 为一个需要做卷积的图像四维张量数据,数据类型只能都是 tf.float32/64, half, 其中张量中包含了 [batch, in_height, in_width, in_channels], 分别对应的是, 1)每一批次训练的图片张数 2)每张图片的高 3)每张照片的宽 4) 每张照片的颜色通道(照片数据深度)
- filter: 为一个卷积核,用来跟别人做卷积之同维度的张量数据,张量包含了 [filter_height, filter_width, in_channels, out_channels], 分别对应到的是 1)匹配被扫描数据的高 2)匹配被扫描数据的宽 3)匹配被扫描数据的颜色通道 4)卷积核的个数
- strides: 为一个内涵四个整数形态元素的一维列表数据,注意只能是整数,该四个整数分别表示卷积核在输入数据的每个维度上每次移动的距离,参数顺序由 data_format 明确定义
- padding: 只有两组字符串输入 1)'SAME'表示需添加 0 元素到被扫描数据的边框,使得卷积核扫描过后的输出数据尺寸保持保持不变 2)'VALID'则不加 0 元素,让扫描结果的尺寸自然递减
- use_cudnn_on_gpu: 输入必须是布尔值,是一个是否使用 GPU 加速运算的开关
- data_format: 使用字符串表明输入数据格式, NHWC 是默认值 (batch, height, width, channels), 也可以调成 NCHW (batch, channels, height, width)
- dilations: 为一个内涵四个整数形态元素的一维列表数据,注意只能是整数,该四个整数分别表示卷积核在输入数据的每个维度上扫描时跳过了(对应该维度数字 -1 )个数据后得出来的结果,跟感受野的原理同源,参数顺序由 data_format 明确定义
- name: 自定义此节点的名称,用字符串表示
回传结果: 同样数据类型的张量,不过经过卷积核的一番扫描和运算,其各个维度的尺寸很可能都会受到影响。需要注意的是,卷积运算时使用的格式是以 「图片」 在 Python 中的数据形式来展开计算,需要把图片的数据形态 「侧着看」, 使得图片颜色数据的元素个数用 column 的行数来表示,等所有运算都完成后,我们再使用其他方法把此 「侧着」 的列表数据翻成正面方可直观理解运算结果
import tensorflow as tf
i = tf.constant([[4, 3, 1, 0, 5],
[2, 1, 0, 1, 3],
[1, 2, 4, 1, 4],
[3, 1, 0, 2, 0],
[2, 2, 4, 5, 1]], dtype=tf.float32, name='i')
k = tf.constant([[1, 0, 1],
[2, 1, 0],
[0, 0, 1]], dtype=tf.float32, name='k')
image = tf.reshape(i, [1, 5, 5, 1], name='image')
kernel = tf.reshape(k, [3, 3, 1, 1], name='kernel')
result = tf.nn.conv2d(image, kernel, strides=[1, 1, 1, 1],
padding="VALID", use_cudnn_on_gpu=False,
data_format='NHWC', dilations=[1, 1, 1, 1])
Format = tf.squeeze(result)
sess = tf.Session()
# print(sess.run(image))
# print(sess.run(kernel))
# print(sess.run(result))
print(sess.run(Format))
sess.close()
### ----- Result is shown below ----- ###
[[14. 6. 11.]
[ 6. 12. 12.]
[16. 10. 11.]]
5. tf.nn.max_pool(value, ksize, strides, padding, data_format='NHWC', name=None)
- value: 为一个需要做缩减的图像四维张量数据,数据类型只要是数字都可以,其四维的排列顺序预设是 batch, height, width, channels ,具体的顺序还需要 data_format 给出最终的判断
- ksize: 为一个内涵四个整数类型数据的列表, 设定每个维度的缩减单元大小, 预设序列是 batch, height, width, channels, batch 同样也可以被用来池化
- strides: 为一个内涵四个整数形态元素的一维列表数据,注意只能是整数,该四个整数分别表示卷积核在输入数据的每个维度上每次移动的距离,参数顺序由 data_format 明确定义
- padding: 只有两组字符串输入 1)'SAME'表示需添加 0 元素到被扫描数据的边框,使得卷积核扫描过后的输出数据尺寸保持保持不变 2)'VALID'则不加 0 元素,让扫描结果的尺寸自然递减
- data_format: 使用字符串表明输入数据格式, NHWC 是默认值 (batch, height, width, channels), 也可以调成 NCHW (batch, channels, height, width),另一个新的 NCHW_VECT_C 也同样支持
- name: 自定义此节点的名称,用字符串表示
p.s. 尚有如 tf.nn.avg_pool() 同类的函数,参数一模一样,只是运算是取平均
回传结果: 为一个同样维度的张量, 经过池化处理后每个维度上的元素总量都有一定的缩减
import tensorflow as tf
i = tf.constant([[4, 3, 1, 0, 5, 3],
[2, 1, 0, 1, 3, 4],
[1, 2, 4, 1, 4, 2],
[3, 1, 0, 2, 0, 1],
[2, 2, 4, 5, 1, 2],
[3, 4, 2, 4, 1, 2]], dtype=tf.float32)
image = tf.reshape(i, [1, 6, 6, 1])
result = tf.nn.max_pool(image, [1, 2, 2, 1], strides=[1, 1, 1, 1],
padding='VALID', data_format='NHWC')
Format = tf.squeeze(result)
sess = tf.Session()
print(sess.run(Format))
sess.close()
### ----- Result is shown below ----- ###
[[4. 3. 1. 5. 5.]
[2. 4. 4. 4. 4.]
[3. 4. 4. 4. 4.]
[3. 4. 5. 5. 2.]
[4. 4. 5. 5. 2.]]
6. tf.nn.dropout(x, keep_prob, noise_shape=None, seed=None, name=None)
- x: 为一个随意尺寸的张量,只要张量内部元素皆可为浮点数即可
- keep_prob: 每一个元素被保存下来的几率, 用 0.xx 的形式表示,最小不能够为 0 ,而最大可以是 1 ,意味着全部元素都被保留下来
- nosie_shape: ?????
- seed: ?????
- name: 定义此节点的名称,用字符串表示
p.s. 经过 dropout 训练出来的值需要乘上 (1-p)% ,p 表示在 dropout 中有多少比例的神经单元被丢弃
回传结果: 一个同样尺寸的张量,不过其内部元素中依照 keep_prob 的比例被设成了 0 ,造成在后面的函数运算中不起作用
import tensorflow as tf
i = tf.constant([[4, 3, 1, 0, 5, 3],
[2, 1, 0, 1, 3, 4],
[1, 2, 4, 1, 4, 2],
[3, 1, 0, 2, 0, 1],
[2, 2, 4, 5, 1, 2],
[3, 4, 2, 4, 1, 2]], dtype=tf.float32)
c = tf.reshape(i, shape=(1, 3, 3, 4))
Dropout = tf.nn.dropout(i, 0.5, noise_shape=[1, 1, 3, 4])
sess = tf.Session()
print(sess.run(Dropout))
sess.close()
### ----- Result is shown below ----- ###
[[[[0. 0. 0. 0.]
[0. 0. 0. 2.]
[0. 0. 6. 0.]]
[[0. 0. 0. 0.]
[0. 0. 0. 2.]
[0. 0. 0. 0.]]
[[0. 0. 0. 0.]
[0. 0. 0. 8.]
[0. 0. 2. 0.]]]]
7. tf.nn.batch_normalization(x, mean, variance, offset, scale, variance_epsilon, name=None)
- x: 为一个随意维度的张量,最好是浮点数形态不容易出错
- mean: 一个代表平均数的张量
- variance: 一个代表统计中方差的张量
- offset: 表示此公式算法中 beta 的值,也是一个张量
- scale: 表示此公式算法中 gama 的值,也是一个张量
- variance_epsilon: 一个用来避免被 0 所除所造成错误的浮点数
- name: 定义此节点的名称,用字符串表示
p.s. 每个参数都是必填项目,都是公式计算的必须参数 p.s.s. 其他的归一化方法也都是类似的,都给定一个公式,然后该公式后面依序挂着一个又一个公式必要得参数项,如 tf.nn.local_response_normalization() 也是另一个典型的归一化方法之一
回传结果: 为一个尺寸与 x 一模一样的张量,不过张量中的每个元素都会被 Batch Normalization 算法套过一遍然后得出来的运算结果取代该元素作为回传张量
import tensorflow as tf
x = tf.constant([i+1 for i in range(36)], shape=(3, 4, 3), dtype=tf.float32)
BN = tf.nn.batch_normalization(x, mean=2, variance=1, offset=3,
scale=1, variance_epsilon=0.01)
sess = tf.Session()
print(sess.run(BN))
sess.close()
### ----- Result is shown below ----- ###
[[[ 2.004963 3. 3.995037 ]
[ 4.990074 5.9851117 6.980149 ]
[ 7.975186 8.970222 9.9652605]
[10.960298 11.955335 12.950372 ]]
[[13.945409 14.940446 15.935483 ]
[16.93052 17.925558 18.920595 ]
[19.915632 20.91067 21.905706 ]
[22.900743 23.89578 24.890818 ]]
[[25.885855 26.880892 27.875929 ]
[28.870966 29.866003 30.86104 ]
[31.856077 32.851112 33.846153 ]
[34.84119 35.836227 36.831264 ]]]
Gradient Descent 梯度下降
1-5. tf.train.AdamOptimizer(learning_rate=0.001, beta1=0.9, beta2=0.999, epsilon=1e-08, use_locking=False, name='Adam')
- learning_rate: 一个浮点数张量,或是一个浮点数值
- beta1: 一个浮点数张量,或是一个浮点数值, 第一个函数动量的指数下降率
- beta2: 一个浮点数张量,或是一个浮点数值, 第二个函数动量的指数下降率
- epsilon: 一个很小的常数,用来确保数字的稳定性
- use_locking: 如果是 True ,则使用 locks 在操作子上 ?????
- name: 定义此节点的名称,用字符串表示
回传结果: 这些梯度下降的算法都是 「类」 ,意味着他们还可以用来创造示例然后呼叫方法,下面是他们的方法列举:
- apply_gradients()
- compute_gradients()
- get_name()
- get_slot()
- get_slot_name()
- minimize()
- variables()
等到方法被呼叫后,才会回传一个计算好梯度的结果。
下一篇文章: Tensorflow_03_Save and Restore 储存和载入