本笔记基于莫烦python的Tensorflow教程
个人认为莫烦大神的视频教程不适合零基础的小白,如果是小白可以先观看李宏毅或者吴恩达的视频或者直接看书。莫烦大神的教程适合对深度学习已经有一定的理论知识,但是欠缺代码基础的同学(比如说我),基本跟着莫烦写一遍代码下来,小编已经对tensorflow的运用有了一定的了解,也掌握了神经网络一些训练技巧。
以下对应莫烦视频中的Tensorflow教程(10)(11)(12),小编会根据莫烦的讲解加上我本人的理解进行记录。
这个教程的目的就是要建立一个最简单的神经网络。最简单的神经网络的结构就是只包含一个input layer(输入层),一个hidden layer,一个output layer(输出层)。每一层中都包含神经元,除了hidden layer 的神经元个数是一个超参数以外,输入层和输出层的神经元个数都是与输入数据和输出数据密切关联的。比如说,该程序中定义输入数据是:x_data,那么输入层神经元的个数就与输入数据的data的个数有关。注意!不是与data中的样本数量有关!输出层同理。
而隐藏层中的神经元个数也不宜过多,因为深度学习应该是体现在隐藏层的个数,如果在一层中神经元个数过多,那么就应该是广度学习了。同样重要的还有隐藏层的层数,盲目地添加隐藏层则会导致over fitting(过拟合)问题。所以隐藏层的设计是一个基于经验的学问。
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.matmul(inputs,Weights)+biases
if activation_function is None:
outputs=Wx_plus_b
else:
outputs=activation_function(Wx_plus_b)
return outputs
先定义函数作为后续创建输入层,隐藏层和输出层的基础。在这里需要特别注意的是,在很多时候我们在定义bias时都会令bias=0,但是习惯上是不希望bias=0,所以会在biases后加上0.1,保证不为零。
对activation_function的判断:在输入层到隐藏层的连接当中,我们是需要使用activation_function将数据转化为非线性的形式,但是在隐藏层到输出层的连接当中,我们就不再需要激活函数。因为这里有一个判断,当不需要激活函数时,直接输出Wx_plus_b;需要时,就将Wx_plus_b经过激活函数再输出。
x_data=np.linspace(-1,1,300)[:,np.newaxis]
noise=np.random.normal(0,0.05,x_data.shape)
y_data=np.square(x_data)-0.5+noise
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)#l1 is an input layer
#activation function is a relu function
prediction=add_layer(l1,10,1,activation_function=None)#prediction is an hidden layer
loss=tf.reduce_mean(tf.reduce_sum(tf.square(ys-prediction),reduction_indices=[1]))
#loss function is based on MSE(mean square error)
train_step=tf.train.GradientDescentOptimizer(0.1).minimize(loss)
init=tf.global_variables_initializer() #initialize all variables
sess=tf.Session()
sess.run(init) #very important
数据的导入我们采用了噪声(noise)。采用noise是为了得到的y_data不是完全按照一元二次函数的走向得到的,y_data的结果必须具有随机性,因此在bias位置上添加了noise,得到的y-x图像如下图所示:
在这里采用了tensorflow中的placeholder函数。placeholder()函数是在神经网络构建graph的时候在模型中的占位,此时并没有把要输入的数据传入模型,它只会分配必要的内存。等建立session,在会话中,运行模型的时候通过feed_dict()函数向占位符传入数据。
采用placeholder的好处就是,可以自定义传入数据的多少。在深度学习的训练中,一般不会直接就对整个数据集进行训练,例如随机梯度下降(Stochastic Gradient Descent)是采取mini batch的方式对数据进行训练。
在该程序中可视化使用的是matplotlib库,并且动态显示训练结果。但莫烦的代码直接在jupyter notebook上运行会发生只能显示函数图像,不能动态显示图像的问题。在youtube莫烦的视频下的评论里,众多小伙伴也反映无论是IDLE还是terminal或者是其他编译环境,及时在前面加上%matplotlib inline也无法达到预期效果。小编遍寻数法,结合几种方法找到了可以在jupyter notebook上动态显示的方法。但此法要安装Qt,jupyter 会使用Qt作为绘图后端。
代码如下:
%matplotlib #在导入库的时候声明
fig=plt.figure()
ax=fig.add_subplot(1,1,1)
ax.scatter(x_data,y_data)
plt.ion()
plt.show()
for i in range(2000):
sess.run(train_step,feed_dict={xs:x_data,ys:y_data})
if i%50==0:
try:
plt.pause(0.5)
except Exception:
pass
try:
ax.lines.remove(lines[0])
plt.show()
except Exception as e:
pass
prediction_value=sess.run(prediction,feed_dict={xs:x_data})
lines=ax.plot(x_data,prediction_value,'r-',lw=10)
这是添加动态图像后的训练效果,红色曲线就是由电脑训练的曲线,蓝色点的区域就是x、y点的真实值的区域。可以看到经过电脑训练,我们可以得到一个大致符合区域走向的曲线。
以上就是该教程的全部内容,有问题欢迎大家在评论区里交流!