今天我们来实现一个神经网络,其中部分内容参考
https://www.jianshu.com/p/596a30d46f34
如有冒犯请私信我或者留言,希望一些小小的工作能为大家的学习和工作带来便利。
一、神经网络
我在看Michael Nielsen 大神的 《Neural Networks and Deep Learning》这本书时第一次接触到神经网络这个概念。这本书由浅入深,讲述得细致而不失深度。有兴趣的朋友可以看看,下面是中文版链接。
http://www.liuxiao.org/wp-content/uploads/2016/10/nndl-ebook.pdf
那么什么是神经网络?神经网络又能干什么呢?我相信有不少同学听过这句话“神经网络可以计算任何函数”。神经网络拥有一种普遍性。这非常非常有吸引力。关于这点的证明(说是“解释”可能更好)可以参考Approximation by superpositions of a sigmoidal function这篇文章。现在我们更关心怎么实现一个神经网络。
二、实现步骤
先简单说明一下待拟合的函数。毕竟咱们得先找个目标嘛!先从拟合简单的函数来说明下大概流程,后面再逐步复杂起来。
我们需要拟合的函数非常简单——y = x^2 - 0.5,对!就是我们之前演示过的函数。我们通过numpy来生产模拟数据。
def createdata():
x_data = np.linspace(-1,1,300)[:,np.newaxis]
noise = np.random.normal(0,0.05,x_data.shape).astype(np.float32)
y_data = np.square(x_data) - 0.5 + noise
return x_data,y_data
我们需要关注的就是返回值,这个函数返回x_data,y_data。x_data相当于原始inputs,y_data相当于我们需要拟合的对象targets。至此数据便有了。
接下来我们需要做什么?是不是好多时候去实现一个东西的时候一脸懵逼?其实,觉得困惑是因为我们没有理清思路。我们得多问问自己一些问题。
我们首先问问自己一个问题:
我们知不知道,这是 一个什么样的函数,我们有没有先验的知识?
我们为什么要关注函数形态?因为这关系到我们需要怎么设置参数。比如y=kx+b只需要设置两个函数拟合,而y=sin(kx)+b就需要三个。
我们再问一个问题:
我们怎么来拟合一个函数?或者说,函数怎么就三下两下就出结果了?
其实我和大家一样,一开始也很困惑,读完梯度下降算法之后,稍微好了一些,但还是有些不太理解。
关于第一个问题,我们其实可以先通过假设的方式来解决一下,后面我们可以通过更高级的方式来探索“这可能是一个什么函数?”
第二个问题很关键:神经网络的普适性。
Michael Nielsen的书中提到了这个问题,在第四章讲到了“神经网络可以计算任何函数的可视化证明”
下面我们简单探讨一下这个问题。有两点需要注意:
一、一个网络并不能准确地计算任何函数。而是说,我们可以获得尽可能好的一个近似。通过增加隐藏元的数量,可以提升近似的精度
二、近似的函数类是连续函数,对于阶跃函数,我们使用连续函数进行模拟。
大家都学过微积分吧!对于任意函数我们都可以用一个个小方块来拟合,对吧?那么在神经网络中我们的小方块又是什么呢?先看下图,这是一个特殊的sigmod函数,w=999 几乎就是个阶跃函数了。
现在我们有两个参数w,b实际上我们可以用s = −b/w简化我们描述隐藏神经元的方式,这就是阶跃位置。
越来越接近我们的目标了.
下边的绘图是隐藏层的加权输出 w1a1 + w2a2 。这里 a1 和 a2 各自是顶部和底部神经元的输出。这些输出由a表示,是因为它们通常被称为神经元的 激活值(activations)。
我们再看一张图,我相信看完这张图,你就会发现"小方块"在哪里了。
详细内容可以参考上文提到的资料。这里不多说了,再说下去大家可能没兴致看了。
我们回到正题。先用tensorflow构建一个简单的层,输入的参数是该层输入,输入数据的大小,输出数据的大小,以及使用的激活函数,激活函数在默认情况下是None,即不适用激活函数:
def add_layer(inputs,in_size,out_size,activation_function=None):
Weights = tf.Variable(tf.random_normal([in_size,out_size]))
biases = tf.Variable(tf.zeros([1,out_size])+0.1)
Wx_plus_b = tf.add(tf.matmul(inputs,Weights),biases)
if activation_function is None:
outputs = Wx_plus_b
else:
outputs = activation_function(Wx_plus_b)
return outputs
这里,我们定义输入层-隐藏层-输出层的三层神经网络结构,其中输入层和输出层仅有一个神经元,而隐藏层有10个神经元。同时,我们定义我们的损失是平方损失函数,通过梯度下降法来最小化我们的损失。
def createnet():
xs = tf.placeholder(tf.float32,[None,1])
ys = tf.placeholder(tf.float32,[None,1])
l1 = add_layer(xs,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(ys - prediction),
reduction_indices = [1]))
train_step = tf.train.GradientDescentOptimizer(0.1).minimize(loss)
init = tf.global_variables_initializer()
x_data,y_data = createdata()
with tf.Session() as sess:
sess.run(init)
for i in range(1000):
sess.run(train_step,feed_dict={xs:x_data,ys:y_data})
if i % 50 == 0:
print(sess.run(loss,feed_dict={xs:x_data,ys:y_data}))
非常简单的一个例子动手敲一下就会明白了,有些内容在之前的博客里做了记录,比如reduce_sum的用法等等。不多做赘述了。
完整代码如下
import tensorflow as tf
import numpy as np
def add_layer(inputs,in_size,out_size,activation_function=None):
Weights = tf.Variable(tf.random_normal([in_size,out_size]))
biases = tf.Variable(tf.zeros([1,out_size])+0.1)
Wx_plus_b = tf.add(tf.matmul(inputs,Weights),biases)
if activation_function is None:
outputs = Wx_plus_b
else:
outputs = activation_function(Wx_plus_b)
return outputs
def createdata():
x_data = np.linspace(-1,1,300)[:,np.newaxis]
noise = np.random.normal(0,0.05,x_data.shape).astype(np.float32)
y_data = np.square(x_data) - 0.5 + noise
return x_data,y_data
def createnet():
xs = tf.placeholder(tf.float32,[None,1])
ys = tf.placeholder(tf.float32,[None,1])
l1 = add_layer(xs,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(ys - prediction),
reduction_indices = [1]))
train_step = tf.train.GradientDescentOptimizer(0.1).minimize(loss)
init = tf.global_variables_initializer()
x_data,y_data = createdata()
with tf.Session() as sess:
sess.run(init)
for i in range(1000):
sess.run(train_step,feed_dict={xs:x_data,ys:y_data})
if i % 50 == 0:
print(sess.run(loss,feed_dict={xs:x_data,ys:y_data}))
createnet()