深度学习——Tensorflow(1)

一、Tensorflow简单示例

1. 基本运算

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#定义一个常量
a = tf.constant([3,3])
#定义一个变量
x = tf.Variable([1,2])

#定义一个加法op
add = tf.add(a,x)
#定义一个减法
sub = tf.subtract(a,x)
#定义一个乘法op
mul = tf.multiply(a,x)
#定义初始化
init = tf.global_variables_initializer()
#定义多个操作
add2 = tf.add(a,add)

with tf.Session() as sess:
sess.run(init)
print("加法:",sess.run(add)) #执行加法
print("减法:",sess.run(sub)) #执行减法
print("乘法:",sess.run(mul)) #执行乘法
#同时执行乘法op和加法op
result = sess.run([add,add2,sub,mul])
print("执行多个:",result)

2. 使用占位符

1
2
3
4
5
6
7
8
9
10
11
#Feed:先定义占位符,等需要的时候再传入数据
#创建占位符
input1 = tf.placeholder(tf.float32)
input2 = tf.placeholder(tf.float32)
#定义乘法op
output = tf.multiply(input1,input2)
add = tf.add(input1,input2)

with tf.Session() as sess:
#feed的数据以字典的形式传入
print(sess.run(add, feed_dict={input1:[8.],input2:[2.]}))

二、Tensorflow简单回归模型

1. 最简单的线性回归模型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import tensorflow as tf
import numpy as np

#使用numpy生成100个随机点
#样本点
x_data = np.random.rand(100)
y_data = x_data*0.1 + 0.2

#构造一个线性模型
d = tf.Variable(1.1)
k = tf.Variable(0.5)
y = k*x_data + d

#二次代价函数<均方差>
loss = tf.losses.mean_squared_error(y_data,y)
#定义一个梯度下降法来进行训练的优化器
optimizer = tf.train.GradientDescentOptimizer(0.3)
#最小化代价函数
train = optimizer.minimize(loss)

#初始化变量
init = tf.global_variables_initializer()

with tf.Session() as sess:
sess.run(init)
for step in range(1000):
sess.run(train)
if step%100 ==0:
print(step,sess.run([k,d]))

2. 非线性回归的问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt

#使用numpy生成200个随机点
x_data = np.linspace(-0.5,0.5,200).reshape(-1,1)
noise = np.random.normal(0,0.015,x_data.shape)
y_data = np.square(x_data) + noise


#定义两个placeholder,列数为1,行数未知
x = tf.placeholder(tf.float32,[None,1])
y = tf.placeholder(tf.float32,[None,1])

#定义神经网络结构:1-20-1,一个输入一个输出一个隐藏层包含20个神经元

#定义神经网络中间层
Weights_L1 = tf.Variable(tf.random_normal([1,20])) # 初始化1行20列权值
biases_L1 = tf.Variable(tf.zeros([1,20])) # 初始化1行20列偏置
Wx_plus_b_L1 = tf.matmul(x,Weights_L1) + biases_L1 # 计算神经元信号
L1 = tf.nn.tanh(Wx_plus_b_L1) # 使用激活函数计算神经元输出信号

#定义神经网络输出层
Weights_L2 = tf.Variable(tf.random_normal([20,1]))
biases_L2 = tf.Variable(tf.zeros([1,1]))
Wx_plus_b_L2 = tf.matmul(L1,Weights_L2) + biases_L2
prediction = tf.nn.tanh(Wx_plus_b_L2)
# prediction = Wx_plus_b_L2

#二次代价函数
loss = tf.losses.mean_squared_error(y,prediction)
#使用梯度下降法最小化代价函数训练
train_step = tf.train.GradientDescentOptimizer(0.1).minimize(loss)

with tf.Session() as sess:
#变量初始化
sess.run(tf.global_variables_initializer())
for _ in range(1000):
sess.run(train_step,feed_dict={x:x_data,y:y_data})


#获得预测值
prediction_value = sess.run(prediction,feed_dict={x:x_data})
#画图
plt.figure()
plt.scatter(x_data,y_data)
plt.plot(x_data,prediction_value,'r-',lw=5)
plt.show()
这里思考下中间层和输出层的激活函数的选取问题。
1. 中间层和输出层的激活函数均采用tanh函数,当迭代1000次时,数据拟合效果良好;输出层激活函数换成恒等函数时,效果会更好一点。
2. 这里使用sigmoid函数或者softmax函数,当迭代1000次时,无法拟合。事实证明在这个数据集里sigmoid函数和softmax函数均不能作为输出层的激活函数。当输出层激活函数为softmax时预测值恒为1这个很好理解;同理sigmoid此类函数收到输出值域的限制,在该数据里是无法用来作为输出激活函数的。
3. 经过有限次的测试发现,很对该数据情况下输出层的激活函数可以使用tanh、softsign和恒等函数;其中恒等激活函数表现最好(个人考虑是因为该数据非常简单)。
4. 经过有限次的测试发现,sigmoid、softmax、softsign、tanh均可作为该数据情况下的中间层激活函数(恒等函数除外)。其中tanh和softsign拟合的最快但softsign效果不好;sigmoid和softmax函数拟合较慢。随着迭代次数增加到20000次,最终都能很好地拟合数据。
5. sigmoid作为激活函数对神经炎要求的数量一般情况下要比tanh高。

三、Tensorflow分类模型

本节用到Tensorflow自带的 mnist 数据集。这里使用独热编码将多元回归的问题转换成10个数值的二元分类问题。使用softmax作为输出层激活函数的意义在于将输出的概率数组归一化并凸显概率最大的值。当然这里也可以使用sigmoid或其他作为输出层激活函数。

1. 简单的MNIST数据集分类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
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 = 64
#计算一共有多少个批次
n_batch = mnist.train.num_examples // batch_size

#定义两个placeholder
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([10]))
prediction = tf.nn.softmax(tf.matmul(x,W)+b)

#二次代价函数
loss = tf.losses.mean_squared_error(y,prediction)
#交叉熵代价函数
loss = tf.losses.softmax_cross_entropy(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)
#epoch:所有数据训练一次,就是一个epoch周期
for epoch in range(21):
#batch:一般为32,64个数据
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})

acc = sess.run(accuracy,feed_dict={x:mnist.test.images,y:mnist.test.labels})
print("Iter " + str(epoch) + ",Testing Accuracy " + str(acc))

2. 过拟合解决及梯度下降优化器

Dropout采用随机的方式“做空”神经元的权重,L1正则化采用的是“做空”贡献非常小的神经元权重,L2正则化是消弱每个神经元的权重让每个都有少许的贡献。
在神经网络中它们之间也可以结合使用,dropout应用较多些。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
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 = 64
#计算一共有多少个批次
n_batch = mnist.train.num_examples // batch_size

#定义三个placeholder
x = tf.placeholder(tf.float32,[None,784])
y = tf.placeholder(tf.float32,[None,10])
keep_prob=tf.placeholder(tf.float32)

# 784-1000-500-10
W1 = tf.Variable(tf.truncated_normal([784,1000],stddev=0.1))
b1 = tf.Variable(tf.zeros([1000])+0.1)
L1 = tf.nn.tanh(tf.matmul(x,W1)+b1)
L1_drop = tf.nn.dropout(L1,keep_prob)

W2 = tf.Variable(tf.truncated_normal([1000,500],stddev=0.1))
b2 = tf.Variable(tf.zeros([500])+0.1)
L2 = tf.nn.tanh(tf.matmul(L1_drop,W2)+b2)
L2_drop = tf.nn.dropout(L2,keep_prob)

W3 = tf.Variable(tf.truncated_normal([500,10],stddev=0.1))
b3 = tf.Variable(tf.zeros([10])+0.1)
prediction = tf.nn.softmax(tf.matmul(L2_drop,W3)+b3)

#同样这里也可以使用正则项
#l2_loss = tf.nn.l2_loss(W1) + tf.nn.l2_loss(b1) + #tf.nn.l2_loss(W2) + tf.nn.l2_loss(b2) + tf.nn.l2_loss(W3) + #tf.nn.l2_loss(b3)

#交叉熵代价函数
loss = tf.losses.softmax_cross_entropy(y,prediction)

#正则后的交叉熵代价函数
#loss = tf.losses.softmax_cross_entropy(y,prediction) + #0.0005*l2_loss #这里0.0005为学习率
#使用梯度下降法
train_step = tf.train.GradientDescentOptimizer(0.5).minimize(loss)

#train_step = tf.train.AdamOptimizer(0.001).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(31):
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,keep_prob:0.5}) #这里keep_prob:0.5 表示保留50%的神经元,这里把另它为1的时候保留所有神经元测试结果准确率提高了2个百分点,同时相对应的计算量也增大了

test_acc = sess.run(accuracy,feed_dict={x:mnist.test.images,y:mnist.test.labels,keep_prob:1.0})
train_acc = sess.run(accuracy,feed_dict={x:mnist.train.images,y:mnist.train.labels,keep_prob:1.0})
print("Iter " + str(epoch) + ",Testing Accuracy " + str(test_acc) +",Training Accuracy " + str(train_acc))

3. 神经网络优化

这里的优化方式是不断减小学习率,使得在极小值附近迭代速度放缓,解决因学习率过大反复震荡无法拟合的问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
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 = 64
#计算一共有多少个批次
n_batch = mnist.train.num_examples // batch_size

#定义三个placeholder
x = tf.placeholder(tf.float32,[None,784])
y = tf.placeholder(tf.float32,[None,10])
keep_prob=tf.placeholder(tf.float32)
lr = tf.Variable(0.001, dtype=tf.float32)

# 784-500-300-10
#创建一个神经网络
W1 = tf.Variable(tf.truncated_normal([784,500],stddev=0.1))
b1 = tf.Variable(tf.zeros([500])+0.1)
L1 = tf.nn.tanh(tf.matmul(x,W1)+b1)
L1_drop = tf.nn.dropout(L1,keep_prob)

W2 = tf.Variable(tf.truncated_normal([500,300],stddev=0.1))
b2 = tf.Variable(tf.zeros([300])+0.1)
L2 = tf.nn.tanh(tf.matmul(L1_drop,W2)+b2)
L2_drop = tf.nn.dropout(L2,keep_prob)

W3 = tf.Variable(tf.truncated_normal([300,10],stddev=0.1))
b3 = tf.Variable(tf.zeros([10])+0.1)
prediction = tf.nn.softmax(tf.matmul(L2_drop,W3)+b3)

#交叉熵代价函数
loss = tf.losses.softmax_cross_entropy(y,prediction)
#训练
train_step = tf.train.AdamOptimizer(lr).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(21):
sess.run(tf.assign(lr, 0.001 * (0.95 ** epoch)))
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,keep_prob:1.0})

learning_rate = sess.run(lr)
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) + ", Learning Rate= " + str(learning_rate))

四、CNN卷积神经网络

以上的案例采用的都是BP神经网络。考虑一张图片像素为100*100,则需要一万个输入神经元,若隐藏层也有一万个神经元则需要训练一亿个参数,这不仅需要更多计算昂还需要大量额训练样本用来“求解”。因此下面我们考虑用卷积神经网络来解决这个问题。

  • CNN通过局部感受野权值共享减少了神经网络需要训练的参数(权值)的个数。
  • 卷积核/滤波器

  • 卷积Padding

    • SAME PADDING
    • VALID PADDING
  • 池化

    • max-pooling 提取卷积后特征的最大值也就是最重要的特征,进一步压缩参数
    • mean-pooling
    • 随机-pooling
  • 池化Padding

    • SAME PADDING
    • VALID PADDING

下面看一个 CNN 卷积神经网络用于 MINIST 数据的分类问题。在CPU上运行比较耗时,16G内存的Mac-Pro大概两三分钟一个周期。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
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 = 64
#计算一共有多少个批次
n_batch = mnist.train.num_examples // batch_size
#定义两个placeholder
x = tf.placeholder(tf.float32,[None,784])#28*28
y = tf.placeholder(tf.float32,[None,10])

#初始化权值
def weight_variable(shape):
initial = tf.truncated_normal(shape,stddev=0.1)#生成一个截断的正态分布
return tf.Variable(initial)

#初始化偏置
def bias_variable(shape):
initial = tf.constant(0.1,shape=shape)
return tf.Variable(initial)

#卷积层
def conv2d(x,W):
#x input tensor of shape `[batch, in_height, in_width, in_channels]`
#W filter / kernel tensor of shape [filter_height, filter_width, in_channels, out_channels]
#`strides[0] = strides[3] = 1`. strides[1]代表x方向的步长,strides[2]代表y方向的步长
#padding: A `string` from: `"SAME", "VALID"`
return tf.nn.conv2d(x,W,strides=[1,1,1,1],padding='SAME')

#池化层
def max_pool_2x2(x):
#ksize [1,x,y,1]
return tf.nn.max_pool(x,ksize=[1,2,2,1],strides=[1,2,2,1],padding='SAME')

#改变x的格式转为4D的格式[batch, in_height, in_width, in_channels]`
x_image = tf.reshape(x,[-1,28,28,1])

#初始化第一个卷积层的权值和偏置
W_conv1 = weight_variable([5,5,1,32])#5*5的采样窗口,32个卷积核从1个平面抽取特征
b_conv1 = bias_variable([32])#每一个卷积核一个偏置值

#把x_image和权值向量进行卷积,再加上偏置值,然后应用于relu激活函数
h_conv1 = tf.nn.relu(conv2d(x_image,W_conv1) + b_conv1)
h_pool1 = max_pool_2x2(h_conv1)#进行max-pooling

#初始化第二个卷积层的权值和偏置
W_conv2 = weight_variable([5,5,32,64])#5*5的采样窗口,64个卷积核从32个平面抽取特征
b_conv2 = bias_variable([64])#每一个卷积核一个偏置值

#把h_pool1和权值向量进行卷积,再加上偏置值,然后应用于relu激活函数
h_conv2 = tf.nn.relu(conv2d(h_pool1,W_conv2) + b_conv2)
h_pool2 = max_pool_2x2(h_conv2)#进行max-pooling

#28*28的图片第一次卷积后还是28*28,第一次池化后变为14*14
#第二次卷积后为14*14,第二次池化后变为了7*7
#进过上面操作后得到64张7*7的平面

#初始化第一个全连接层的权值
W_fc1 = weight_variable([7*7*64,1024])#上一层有7*7*64个神经元,全连接层有1024个神经元
b_fc1 = bias_variable([1024])#1024个节点

#把池化层2的输出扁平化为1维
h_pool2_flat = tf.reshape(h_pool2,[-1,7*7*64])
#求第一个全连接层的输出
h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat,W_fc1) + b_fc1)

#keep_prob用来表示神经元的输出概率
keep_prob = tf.placeholder(tf.float32)
h_fc1_drop = tf.nn.dropout(h_fc1,keep_prob)

#初始化第二个全连接层
W_fc2 = weight_variable([1024,10])
b_fc2 = bias_variable([10])

#计算输出
prediction = tf.nn.softmax(tf.matmul(h_fc1_drop,W_fc2) + b_fc2)

#交叉熵代价函数
cross_entropy = tf.losses.softmax_cross_entropy(y,prediction)
#使用AdamOptimizer进行优化
train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)
#结果存放在一个布尔列表中
correct_prediction = tf.equal(tf.argmax(prediction,1),tf.argmax(y,1))#argmax返回一维张量中最大的值所在的位置
#求准确率
accuracy = tf.reduce_mean(tf.cast(correct_prediction,tf.float32))

with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
for epoch in range(21):
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,keep_prob:0.7})

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))

五、RNN递归神经网络

RNN 一个重要的用法就是通过递归的调用神经元,利用之前的信息来决策当前的问题。如下图所示:

RNN 递归的次数由多少批次(上图中的$t$来确定)。本质上还是类似 BP 神经网络,因此随着不断的迭代会存在梯度衰减的问题。 RNN 发明出来的时候还没有出现 Relu 函数,因此针对梯度衰减的问题推出了一种优化的模型 :长段时间记忆模型(LSTM)。

六、LSTM长段时间记忆

LSTM 原理是通过增加输入控制(Input Gate)、遗忘控制(Forget Gate)和输出控制(Output Gate)来快速遗忘不重要的信息持久化重要的信息,具体控制方式如下图所示:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#载入数据集
mnist = input_data.read_data_sets("MNIST_data/",one_hot=True)

# 输入图片是28*28
n_inputs = 28 #输入一行,一行有28个数据
max_time = 28 #一共28行
lstm_size = 100 #隐层单元
n_classes = 10 # 10个分类
batch_size = 50 #每批次50个样本
n_batch = mnist.train.num_examples // batch_size #计算一共有多少个批次

#这里的none表示第一个维度可以是任意的长度
x = tf.placeholder(tf.float32,[None,784])
#正确的标签
y = tf.placeholder(tf.float32,[None,10])

#初始化权值
weights = tf.Variable(tf.truncated_normal([lstm_size, n_classes], stddev=0.1))
#初始化偏置值
biases = tf.Variable(tf.constant(0.1, shape=[n_classes]))

#定义RNN网络
def RNN(X,weights,biases):
# inputs=[batch_size, max_time, n_inputs]
inputs = tf.reshape(X,[-1,max_time,n_inputs])
#定义LSTM
lstm_cell = tf.nn.rnn_cell.LSTMCell(lstm_size)
# final_state[state, batch_size, cell.state_size]
# final_state[0]是cell state
# final_state[1]是hidden_state
# outputs: The RNN output `Tensor`.
# If time_major == False (default), this will be a `Tensor` shaped:
# `[batch_size, max_time, cell.output_size]`.
# If time_major == True, this will be a `Tensor` shaped:
# `[max_time, batch_size, cell.output_size]`.
outputs,final_state = tf.nn.dynamic_rnn(lstm_cell,inputs,dtype=tf.float32)
results = tf.nn.softmax(tf.matmul(final_state[1],weights) + biases)
return results


#计算RNN的返回结果
prediction= RNN(x, weights, biases)
#损失函数
loss = tf.losses.softmax_cross_entropy(y,prediction)
#使用AdamOptimizer进行优化
train_step = tf.train.AdamOptimizer(1e-3).minimize(loss)
#结果存放在一个布尔型列表中
correct_prediction = tf.equal(tf.argmax(y,1),tf.argmax(prediction,1))#argmax返回一维张量中最大的值所在的位置
#求准确率
accuracy = tf.reduce_mean(tf.cast(correct_prediction,tf.float32))#把correct_prediction变为float32类型
#初始化
init = tf.global_variables_initializer()

with tf.Session() as sess:
sess.run(init)
for epoch in range(11):
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})

acc = sess.run(accuracy,feed_dict={x:mnist.test.images,y:mnist.test.labels})
print ("Iter " + str(epoch) + ", Testing Accuracy= " + str(acc))