2.线性回归实例
2.1通过神经网络训练线性回归
知识点
-
np.linspace(a,b,n) 在a,b之间生成n个均匀分布的数
-
x_data = np.linspace(-0.5,0.5,200)
[:,np.newaxis][:,np.newaxis]的作用是将原本被(n,)类型的数值,转化为(n,1)类型
-
noise = np.random.normal(0,0.02,x_data.shape) x_data.shape就是将noise设成x_data的类型
-
loss = tf.reduce_mean(tf.square(y-L2)) tensorflow中的求平均值函数
-
promise = tf.train.GradientDescentOptimizer(0.2) 梯度下降函数
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
x_data = np.linspace(-0.5,0.5,200)[:,np.newaxis]
noise = np.random.normal(0,0.02,x_data.shape)
y_data = np.square(x_data) + noise
x = tf.placeholder(tf.float32,[None,1])
y = tf.placeholder(tf.float32,[None,1])
###构建中间层####
weights1 = tf.Variable(tf.random_normal([1,10]))
biase1 = tf.Variable(tf.zeros([1,10]))
wx_plus_b_L1 = tf.matmul(x,weights1) +biase1
L1 = tf.nn.tanh(wx_plus_b_L1)
#####构建输出层#####
weights2 = tf.Variable(tf.random_normal([10,1]))
biase2 = tf.Variable(tf.zeros([1,1]))
wx_plus_b_L2 = tf.matmul(L1,weights2) +biase2
L2 = tf.nn.tanh(wx_plus_b_L2)
###loss
loss = tf.reduce_mean(tf.square(y-L2))
##3#梯度下降
promise = tf.train.GradientDescentOptimizer(0.2)
##训练结果取loss最小的
train = promise.minimize(loss)
init = tf.global_variables_initializer()
with tf.Session() as sess:
sess.run(init)
for step in range(200):
sess.run(train,feed_dict={x:x_data,y:y_data})
prediction = sess.run(L2, feed_dict={x:x_data})
print(prediction)
plt.figure()
plt.scatter(x_data,y_data)
plt.plot(x_data,prediction,'r-',lw = 5)
plt.show()
2.2 手写数字识别
2.2.1 简单实现
手写数据集网站:http://yann.lecun.com/exdb/mnist/
通过tensorflow实现简单的神经网络,进行手写数字识别
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets('MNIST_data', one_hot=True)
# 批次的大小
batch_size = 100
n_batch = mnist.train.num_examples // batch_size
x = tf.placeholder(tf.float32, [None,784])
y = tf.placeholder(tf.float32, [None, 10])
# 创建一个简单的神经网络
W = tf.Variable(tf.zeros([784,10]))
b = tf.Variable(tf.zeros([1, 10]))
prediction = tf.nn.softmax(tf.matmul(x,W) + b)
# 代价函数
loss = tf.reduce_mean(tf.square(y-prediction))
# 梯度下降法
train_step = tf.train.GradientDescentOptimizer(0.2).minimize(loss)
# 初始化变量
init = tf.global_variables_initializer()
# 得到一个布尔型列表,存放结果是否正确
correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(prediction,1)) #argmax 返回一维张量中最大值索引
# 求准确率
accuracy = tf.reduce_mean(tf.cast(correct_prediction,tf.float32)) # 把布尔值转换为浮点型求平均数
with tf.Session() as sess:
sess.run(init)
for epoch in range(2):
for batch in range(n_batch):
# 获得批次数据
batch_xs, batch_ys = mnist.train.next_batch(batch_size)
sess.run(train_step, feed_dict={x:batch_xs, y:batch_ys})
prediction1 = sess.run(prediction,feed_dict={x:mnist.test.images})
print(prediction1)
acc = sess.run(accuracy, feed_dict={x:mnist.test.images,y:mnist.test.labels})
print("Iter " + str(epoch) + " Testing Accuracy: " + str(acc))
注意事项:在tensorflow中,输入变量的名字,不能与接受结果的变量相等,主要是在循环中。原因:tensorflow的run()里边接受的是tensor张量,如果接收结果的的变量名相等,再次输入是,会输入接受的结果变量,但结果的类型一般为数组、矩阵等,错误示例:
prediction = sess.run(prediction,feed_dict={x:mnist.test.images})
print(prediction)
输出的结果:
[外链图片转存失败(img-IJO1MOx5-1564902809837)(C:\Users\hp\AppData\Roaming\Typora\typora-user-images\1564834538676.png)]
以下程序学习自:https://github.com/Parker-Lyu/TensorFLow-Learning/blob/master/3-2MNIST数据集分类简单版本.ipynb
2.2.2 优化代码
创建三层的神经网络,添加激活层,drop层,并使用交叉熵计算loss
1.dropout
- 什么是drop
dropout是指在深度学习网络的训练过程中,对于神经网络单元,按照一定的概率将其暂时从网络中丢弃。注意是暂时,对于随机梯度下降来说,由于是随机丢弃,故而每一个mini-batch都在训练不同的网络。
一个非常好的解释:http://f.dataguru.cn/thread-714116-1-1.html
- drop的作用原理
Dropout说的简单一点就是我们让在前向传导的时候,让某个神经元的激活值以一定的概率p,让其停止工作,示意图如下:
左边是原来的神经网络,右边是采用Dropout后的网络。怎么让某个神经元以一定的概率停止工作?这个我想很多人还不是很了解,代码层面的实现方法,下面就讲解一下其代码层面的实现。以前我们网络的计算公式是:
[外链图片转存失败(img-nLwLUEHB-1564902809840)(C:\Users\hp\AppData\Roaming\Typora\typora-user-images\1564835436421.png)]
上面公式中Bermoull函数,是为了以概率p,随机生成一个0、1的向量。
- dropout的源代码
#dropout函数的实现
def dropout(x, level):
if level < 0. or level >= 1:#level是概率值,必须在0~1之间
raise Exception('Dropout level must be in interval [0, 1[.')
retain_prob = 1. - level
#我们通过binomial函数,生成与x一样的维数向量。binomial函数就像抛硬币一样,我们可以把每个神经元当做抛硬币一样
#硬币 正面的概率为p,n表示每个神经元试验的次数
#因为我们每个神经元只需要抛一次就可以了所以n=1,size参数是我们有多少个硬币。
sample=np.random.binomial(n=1,p=retain_prob,size=x.shape)#即将生成一个0、1分布的向量,0表示这个神经元被屏蔽,不工作了,也就是dropout了
print sample
x *=sample#0、1与x相乘,我们就可以屏蔽某些神经元,让它们的值变为0
print x
x /= retain_prob
return x
#对dropout的测试,大家可以跑一下上面的函数,了解一个输入x向量,经过dropout的结果
x=np.asarray([1,2,3,4,5,6,7,8,9,10],dtype=np.float32)
dropout(x,0.4)</span>
-
dropout在tensorflow中的应用
在tensorflow中dropout的应用
tf.nn.dropout(x, keep_prob, noise_shape=None, seed=None,name=None)
- x : 输入tensor
- keep_prob : float类型,每个元素被保留下来的概率。 设置神经元被选中的概率,在初始化时keep_prob是一个占位符, keep_prob = tf.placeholder(tf.float32) 。tensorflow在run时设置keep_prob具体的值,例如keep_prob: 0.5
- noise_shape : 一个1维的int32张量,代表了随机产生“保留/丢弃”标志的shape。
- seed : 整形变量,随机数种子。
- name : 名字,没啥用。
-
区别
tf.layers.dropout()
与tf.nn.dropout()
在tf.layers中也有一个函数叫dropout(),他的作用是与上边的相同,不同在于
- tf.nn.dropout 中参数 keep_prob :每一个元素被保存下的概率。而 tf.layer.dropout 中参数 rate :每一个元素丢弃的概率。所以,keep_prob = 1 - rate。
- 在 tf.layer.dropout 中有一个 training 参数:在training模式中,返回应用dropout后的输出;或者在非training模式下,正常返回输出(没有dropout)。这里说的training模式也即是training参数为True的时候。
2.交叉熵
在tensorflow中,交叉熵一般调用以下函数:tf.nn.softmax_cross_entropy_with_logits(logits,labels,name=None)
除去name参数用以指定该操作的name,与方法有关的一共两个参数:
第一个参数logits:就是神经网络最后一层的输出,如果有batch的话,它的大小就是
[batchsize,num_classes],单样本的话,大小就是num_classes第二个参数labels:实际的标签,大小同上
具体的执行流程大概分为两步:
第一步是先对网络最后一层的输出做一个softmax,这一步通常是求取输出属于某一类的概率,对于单样本而言,输出就是一个num_classes大小的向量([Y1,Y2,Y3…]其中Y1,Y2,Y3…分别代表了是属于该类的概率)
其中softmax:
第二步是softmax的输出向量[Y1,Y2,Y3…]和样本的实际标签做一个交叉嫡,公式如下:
其中 y i ′ y_{i}^{'} yi′指代实际的标签中第i个的值(用mnist数据举例,如果是3,那么标签是[0,0,0,1,0,0,0,0,0,0],除了第4个值为1,其他全为0)
y i y_{i} yi就是softmax的输出向量[Y1,Y2,Y3…]中,第i个元素的值显而易见,预测越准确,结果的值越小(别忘了前面还有负号),最后求一个平均,得到我们想要的loss注意!!!这个函数的返回值并不是一个数,而是一个向量,如果要求交叉篇,我们要再做一步tf.reduce_sum操作,就是对向量里面所有元素求和,最后才得到结果
如果求loss,则要做一步tf.reduce_mean操作,对向量求均值!
3.正式进入优化代码
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets('MNIST_data', one_hot=True)
# 批次的大小
batch_size = 100
n_batch = mnist.train.num_examples // batch_size
x = tf.placeholder(tf.float32, [None,784])
y = tf.placeholder(tf.float32, [None, 10])
keep_prob = tf.placeholder(tf.float32) ##为什么需要这个变量,为了dropout时输入一个概率
#####################################创建一个三层的神经网络############################
W1 = tf.Variable(tf.truncated_normal([784,200],stddev=0.1))
b1 = tf.Variable(tf.zeros([1, 200]))
#######激活层
L1 = tf.nn.relu(tf.matmul(x,W1) + b1)
#######drop层
L1 = tf.nn.dropout(L1, keep_prob=keep_prob)
######第二层
W2 = tf.Variable(tf.truncated_normal([200,50],stddev=0.1))
b2 = tf.Variable(tf.zeros([1, 50]))
L2 = tf.nn.relu(tf.matmul(L1,W2) + b2)
L2 = tf.nn.dropout(L2, keep_prob=keep_prob)
#####第三层
W3 = tf.Variable(tf.truncated_normal([50,10],stddev=0.1)) ###stddev表示标准差
b3 = tf.Variable(tf.zeros([1, 10]))
L3 = tf.nn.relu(tf.matmul(L2,W3) + b3)
L3 = tf.nn.dropout(L3, keep_prob=keep_prob)
# 代价函数
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels = y,logits= L3))
# 梯度下降法
train_step = tf.train.GradientDescentOptimizer(0.2).minimize(loss)
# 初始化变量
init = tf.global_variables_initializer()
prediction = tf.nn.softmax(L3)
# 得到一个布尔型列表,存放结果是否正确
correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(prediction, 1))
'''argmax 返回一维张量中最大值索引,例如对于y而言,[0 0 0 1 0 0 0 0 0 0],则返回3
对于prediction,[4.8889524e-05 4.8889524e-05 4.8889524e-05 9.1617345e-05 4.8889524e-05 4.8889524e-05 4.8889524e-05 9.9951732e-01 4.8889524e-05 4.8889524e-05]则返回7。
如果这两个返回的数值相等,则tf.equal()返回Ture,否则返回False
'''
# 求准确率
accuracy = tf.reduce_mean(tf.cast(correct_prediction,tf.float32))
# cast把布尔值转换为浮点型求平均数 Ture转换为1.0,False转换为0.0
with tf.Session() as sess:
sess.run(init)
for epoch in range(2):
for batch in range(n_batch):
# 获得批次数据
batch_xs, batch_ys = mnist.train.next_batch(batch_size)
#mnist.train.next_batch(batch_size) 每次从训练集中取出batch_size大小的数据集,然后后移,下一次取时,从本次取值的后一位开始取
sess.run(train_step, feed_dict={x:batch_xs, y:batch_ys,keep_prob:0.8})
prediction1 = sess.run(prediction,feed_dict={x:mnist.test.images,keep_prob:0.8})
print(prediction1)
acc = sess.run(accuracy, feed_dict={x:mnist.test.images,y:mnist.test.labels,keep_prob:1.0})
print("Iter " + str(epoch) + " Testing Accuracy: " + str(acc))
相关函数说明:
-
tf.truncated_normal(shape, mean=0.0, stddev=1.0, dtype=tf.float32, seed=None, name=None)
- shape: 一维的张量,也是输出的张量。
- mean: 正态分布的均值。
- stddev: 正态分布的标准差。
- dtype: 输出的类型。seed: 一个整数,当设置之后,每次生成的随机数都一样。
- seed 随机种子,指定后,每次循环,生成的随机数都不变
- name: 操作的名字
该函数 从截断的正态分布中输出随机值。这是一个截断的产生正太分布的函数,就是说产生正太分布的值如果与均值的差值大于两倍的标准差,那就重新生成。和一般的正太分布的产生随机数据比起来,这个函数产生的随机数与均值的差距不会超过两倍的标准差,但是一般的别的函数是可能的。
在正态分布的曲线中,横轴区间 ( μ − σ , μ + σ ) (\mu-\sigma, \mu+\sigma) (μ−σ,μ+σ)内的面积为68.268949%。
横轴区间 ( μ − 2 σ , μ + 2 σ ) (\mu-2\sigma, \mu+2\sigma) (μ−2σ,μ+2σ))内的面积为95.449974%。横轴区间 ( μ − 3 σ , μ + 3 σ ) (\mu-3\sigma, \mu+3\sigma) (μ−3σ,μ+3σ)内的面积为99.730020%。
X落在( ( μ − 3 σ , μ + 3 σ ) (\mu-3\sigma, \mu+3\sigma) (μ−3σ,μ+3σ)以外的概率小于千分之三,在实际问题中常认为相应的事件是不会发生的,基本上可以把区间 ( μ − 3 σ , μ + 3 σ ) (\mu-3\sigma, \mu+3\sigma) (μ−3σ,μ+3σ)看作是随机变量X实际可能的取值区间,这称之为正态分布的“30”原则。
在tf.truncated_normal中如果x的取值在区间 ( μ − 2 σ , μ + 2 σ ) (\mu-2\sigma, \mu+2\sigma) (μ−2σ,μ+2σ))内的之外则重新进行选择。这样保证了生成的值都在均值附近。
)内的面积为95.449974%。横轴区间
(
μ
−
3
σ
,
μ
+
3
σ
)
(\mu-3\sigma, \mu+3\sigma)
(μ−3σ,μ+3σ)内的面积为99.730020%。
X落在(
(
μ
−
3
σ
,
μ
+
3
σ
)
(\mu-3\sigma, \mu+3\sigma)
(μ−3σ,μ+3σ)以外的概率小于千分之三,在实际问题中常认为相应的事件是不会发生的,基本上可以把区间
(
μ
−
3
σ
,
μ
+
3
σ
)
(\mu-3\sigma, \mu+3\sigma)
(μ−3σ,μ+3σ)看作是随机变量X实际可能的取值区间,这称之为正态分布的“30”原则。
在tf.truncated_normal中如果x的取值在区间
(
μ
−
2
σ
,
μ
+
2
σ
)
(\mu-2\sigma, \mu+2\sigma)
(μ−2σ,μ+2σ))内的之外则重新进行选择。这样保证了生成的值都在均值附近。