深度学习之TensorFlow构建神经网络层
深度学习之TensorFlow构建神经网络层
基本法
深度神经网络是一个多层次的网络模型,包含了:输入层,隐藏层和输出层,其中隐藏层是最重要也是深度最多的,通过TensorFlow,python代码可以构建神经网络层函数,比如我们称之为add_layer()函数,由于神经网络层的工作原理是一层的神经元处理完成后得到一个结果,然后传递给下一个神经元,这就类似于函数的return与参数变量,所以最终代码的模型应该如下图所示:
通过add_layer的层层嵌套,实现上一个add_layer的结果返回给下一个add_layer作为参数变量。
激励函数
在深度神经网络中,激励函数的概念非常重要,TensorFlow已经包含了许多的激励函数。
什么是激励函数呢?
在神经网络中,隐层和输出层节点的输入和输出之间具有函数关系,这个函数称为激励函数。常见的激励函数有:线性激励函数、阈值或阶跃激励函数、S形激励函数、双曲正切激励函数和高斯激励函数等。(百度百科)
简而言之:隐藏层在处理后得到一个值,这个值要么直接传递给下一层,要么先处理一下再传递下一层,这个处理的过程就是激励函数。从数学角度说,激励就是上一层输出和下一层输入存在一种映射关系,即:
F (上一层结果->下一层输入)
为何需要激励函数?
想起上一回中介绍了使用TensorFlow求一次函数的系数与偏量的方法,那并没有用到激励函数,是因为输入与输出的数据呈现为线性关系,也就是y=kx+b这样的简单关系,但实际的问题中输入数据与输出数据可能会存在某种非线性关系。
如图要区分蓝红点,可以使用线性函数y>kx+b或者kx+b>y让神经网络快速学会分类
如图再要区分蓝红点,使用线性函数是做不到的,当然可以选择直接使用非线性函数来处理,在TensorFlow中亦可给出非线性计算的训练单元,但是另一种更为取巧的办法就是给线性函数嵌套一个非线性函数,使得原来的线性关系变成非线性关系,这就使得隐藏层处理的关注点放在了权重k与偏量b上,这就是激励函数的作用!他把本来复杂的问题简化为只调整两个简单的参数上来。
为什么需要分层,深度对学习能力有什么影响?
首先既然说到深度学习,隐藏层应该是多层才算“深”,分层就是为了提高学习能力嘛!那么分层如何做到了学习能力提升?
假定如下场景,我们有三层隐藏层,每个层都有一个神经元,我们对神经元在进行简化,就说他是一个函数y=kx+b,我们得出下图:
图中每一层都会产生出一个不同的f(x)=kx+b函数,而且不同层的函数的系数和偏量都是不一样的,通过神经元连接将这些f(x)串联起来,这有点像PHP里的链式操作,而且图中只是简单的线性关系(正如前面所述这些y函数外层还可以嵌套一个激励函数做非线性化转换)。
神经网络存在一个“逆向工程”,就是当最终输出神经元发现与真实值有差距时就会反向传递,通过调整每一层里的函数来纠正,调整的就是系数k和偏量b,调整出来的k,b在不同层中也是不一样的,具体如何调整这就是个黑盒,人类无法掌控,但他最后就是会到达一个合适的值,这个专业名词叫做:拟合!
综上所述:层数越多,k,b可能性越多,函数越多,那么所能代表的可能性越多,从数学上说,无穷多的可能性可以表达宇宙一切信息。
Show me the code!
Talking is cheap, show me the code!
以下我们给出一个实际的案例,实现上述所述的神经网络设计和构建过程:
import tensorflow as tf
import numpy as np
#the function to create layer
def add_layer(inputs,in_size,out_size,activation_function=None):
w = tf.Variable(tf.random_normal([in_size,out_size]))
b = tf.Variable(tf.zeros([1,out_size])+0.1)
f = tf.matmul(inputs,w) + b
if activation_function is None:
outputs = f
else:
outputs = activation_function(f)
return outputs
#create test data(as real data)
x_data = np.linspace(-1,1,300,dtype=np.float32)[:,np.newaxis]
noise = np.random.normal(0,0.05,x_data.shape)
y_data = np.square(x_data)-0.5+noise
#give tensorflow input placeholder
xs = tf.placeholder(tf.float32,[None,1])
ys = tf.placeholder(tf.float32,[None,1])
l1 = add_layer(x_data,1,10,activation_function=tf.nn.relu)
prediction = add_layer(l1,10,1,activation_function=None)
loss = tf.reduce_mean(tf.reduce_sum(tf.square(y_data-prediction),reduction_indices=[1]))
train = tf.train.GradientDescentOptimizer(0.1).minimize(loss)
init = tf.global_variables_initializer()
sess = tf.Session()
sess.run(init)
for i in range(1000):
sess.run(train,feed_dict={xs:x_data,ys:y_data})
if(i % 50 == 0):
print sess.run(loss,feed_dict={xs:x_data,ys:y_data})
额,不要在意代码中我垃圾的英语注释。
我们简单分析一下代码的含义,其实如果读懂了代码前所述的理论概念,代码就能一下理解了。
首先,我们开头定义了一个create_layer函数,这个函数作用是创建一个神经网络层!参数变量是:输入值,输入值的矩阵行数,矩阵列数,激励函数。这里为什么是矩阵?因为实际处理的现实问题所携带的数据是多个维度的,人类一般能理解到三维,三维以上计算机可以理解。不用过于在意这个细节,以后结合实际问题解释为什么是矩阵的y=kx+b运算,现在要记住x是个多维矩阵就好了,不是简单的数。
create_layer内部做了什么?
函数内部首先是使用numpy给出了随机数,这个随机数也是个矩阵,代表了系数k与偏量b,tf.Varible()让TensorFlow学习过程中改变这两个变量(叫做权重,偏量调整),然后tf.matmul进行了矩阵的运算,给出这一层的输出值,if—else语句负责判断是否要给输出值套上一个激励函数,将其非线性化。
placeholder干什么的?
由于神经网络的学习要求我们输入测试的数据,placeholder的作用是提供输入数据的空位,实际问题产生的原始数据丢入到placeholder中,然后被一个叫feed_dict的对象收集到TensorFlow当中,再交给神经网络去处理得到一个预测结果。placeholder就是是原始数据的入口。
loss是什么?
损失值,用于优化训练过程,很简单,我们要让学习结果和真实结果接近,就要求他们之间的差越来越小,这个值就代表了他们的“差”,这个差可不是数学上的减减就行的,可以看到我们用到了:
tf.reduce_sum(tf.square(y_data-prediction),reduction_indices=[1])
这么长的计算方式,实际值和真实值的差的平方,然后还累加了矩阵中的差平方值,很复杂呢。反正这个值越小越好就对了。
控制台输出结果
运行以上python代码,得到的是损失值,这是为了验证TensorFlow在学习过程中是不是真的在优化自己,loss越来越小就是优化了:
确认:损失值减小,学习优化了!
题外话
个人觉得现在的深度学习的人工智能和传统的人工智能对比,就好像物理上的“量子力学”与“相对论”,怎么说?传统的人工智能认为机器学习过程是正向的,人类为机器设定好规则,在代码中呈现为if then if then......的特点,而深度学习是只给出输入值,让机器去“推理”出一个结果,与正确结果对比,错了就逆向去重新修改“推理”的逻辑,这就是一个无穷多可能的事情,这有点像“量子力学”中只有当观察量子世界中某一个现象时,才能得到一个确定的状态(结果),不观察时,这个魔盒中的可能性是无穷多的,答案落在任何一块区域中,怎么样,是不是很神奇?再通俗比喻一下,这就像武功的最高境界“无招胜有招”!只要能赢就是厉害!通过不断的输,修改招式,最后取得胜利,成为大师的时候固定招式已经不复存在了。