【人工智能实践】用Tensorflow搭建神经网络
用Tensorflow搭建简单的神经网路(NN)之前需要先了解一点Tensorflow的知识。
基本步骤
- 用张量(Tensor)表示数据
- 用计算图(Graph)构建网络
- 用会话(Session)执行计算图并训练网络
Tensorflow的基本知识
张量
我对张量的理解就是——任意维度的数组(好像Python里叫做列表)。
可以是1 x 1的数组,也就是一个单独的数,叫做标量。
可以是1 x N的数组,就是一个一维数组,也就是向量。
可以是N x N的数组,那就是一个二维数组,此时就是矩阵了。
可以是N x N x N的数组,我也不知道该叫什么了。
可以用阶数来描述它,比如标量是0阶的,向量是1阶的,矩阵是2阶的。
数据类型
Tensorflow里,数据类型有tf.int32
,tf.float32
等。
计算图
“搭建神经网络的计算过程,是承载一个或多个计算节点的一张图,只搭建网络,不运算。”
计算图用来描述各个变量之间的关系,表示出每个张量的计算方式,比如c = a + b
。
会话
构建完计算图之后,Tensorflow只是知道每个张量应如何计算,但并不会计算出张量的值。而在会话中,我们可以让Tensorflow计算出某个张量的值。
我们现在可以编写一个简单的Tensorflow程序,用来实践上面学到的内容。
# coding=utf-8 import tensorflow as tf # add 两个1x2的向量相加 a = tf.constant([1.0, 2.0]) b = tf.constant([3.0, 4.0]) c = a + b # mul 一个1x2的矩阵和一个2x1的矩阵相乘 x = tf.constant([[1.0, 2.0]]) y = tf.constant([[1.0], [2.0]]) z = tf.matmul(x, y) # 此时只构建了计算图,并没有真的计算出c和z的值 # 如果输出c和z,只能知道它们的类型 print('c:', c) # c应当是一个1x2的向量 print('z:', z) # z应当是一个1x1的标量 # 如果想计算出c和z的值,就需要用到对话 with tf.Session() as sess: print('c:', sess.run(c)) print('z:', sess.run(z))
上面这段代码的输出是
c: Tensor("add:0", shape=(2,), dtype=float32) z: Tensor("MatMul:0", shape=(1, 1), dtype=float32) c: [4. 6.] z: [[5.]]
Tensorflow中常用的函数
函数 | 用处 |
---|---|
tf.constant |
直接按照给定的参数(数组)生成常量) |
tf.Variable |
按照给定的参数生成变量 |
tf.random_normal |
生成正态分布随机数 |
tf.truncated_normal |
生成去掉过大偏离点的正态分布随机数 |
tf.random_uniform |
生成均匀分布随机数 |
tf.zeros |
生成全0数组 |
tf.ones |
生成全1数组 |
tf.fill |
生成全为指定值的数组 |
举一些例子具体说明。
w = tf.Variable(tf.random_normal([2,3], stddev = 2, mean = 0, seed = 1))
生成正态分布的随机数,是一个2x3的矩阵,标准差为2,均值为0,随机种子为1。若不加随机种子,每次的数据将不一样。后三个参数可以省略。
w = tf.Variable(tf.truncated_normal([2,3], stddev = 2, mean = 0, seed = 1))
生成去掉偏离过大的数据后的正态分布随机数。如果随机出来的数据偏离平均值超过两个标准差,这个数据将重新生成。
w = random_uniform(shape = 7, minval = 0, maxval = 1, dtype = tf.int32, seed = 1)
表示从一个均匀分布[minval maxval)中随机采样。注意定义域是左闭右开,即包含minval,不包含maxval。
w = tf.zeros([3,2], int32)
生成的是[[0,0],[0,0],[0,0]]
。
神经网络的实现过程
- 准备数据集,提取特征,作为输入喂给神经网络(Neural Network,即NN)
- 搭建 NN 结构,从输入到输出,先搭建计算图,再用会话执行( NN 前向传播算法 -> 计算输出)
- 大量特征数据喂给 NN,迭代优化 NN 参数 ( NN 反向传播算法 -> 优化参数训练模型)
- 使用训练好的模型预测和分类
前向传播和反向传播
前向传播就是搭建模型的计算过程,让模型具有推理能力,可以针对一组输入给出相应的输出。
反向传播就是训练模型参数,在所有参数上用梯度下降,使 NN 模型在训练数据上的损失函数最小。
反向传播训练方法有梯度下降、momentum 优化器、adam 优化器等。
train_step = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss) train_step = tf.train.MomentumOptimizer(learning_rate, momentum).minimize(loss) train_step = tf.train.AdamOptimizer(learning_rate).minimize(loss)
learning_rate
是学习率,决定每次参数更新的幅度。过大可能无法收敛,过小训练速度太慢。一般可以取0.01之类的数。
然后大概就可以照葫芦画瓢了——
比如用一个单隐藏层的神经网络来学习一下3x+4y这个函数。
import numpy as np import tensorflow as tf BATCH_SIZE = 256 TRAIN_STEPS = 2048 DATA_SIZE = 4096 X = np.random.randn(DATA_SIZE, 2) Y = [[3.0 * a + 4.0 * b] for (a, b) in X] x = tf.placeholder(tf.float32, shape = (None, 2)) y = tf.placeholder(tf.float32, shape = (None, 1)) w1 = tf.Variable(tf.random_normal([2, 8])) w2 = tf.Variable(tf.random_normal([8, 1])) h = tf.matmul(x, w1) t = tf.matmul(h, w2) init = tf.global_variables_initializer() loss = tf.reduce_mean(tf.square(y - t)) step = tf.train.GradientDescentOptimizer(0.01).minimize(loss) with tf.Session() as sess: sess.run(init) for i in range(TRAIN_STEPS): st = (i * BATCH_SIZE) % DATA_SIZE ed = st + BATCH_SIZE sess.run(step, feed_dict = {x : X[st:ed], y : Y[st:ed]}) if i % 256 == 0: print("loss", sess.run(loss, feed_dict = {x : X, y : Y}))
运行一下可以看到最后的Loss函数还是很小的,效果不错。