TensorFlow CNN卷积神经网络实现工况图分类识别!
- Tensorflow知识点
1.1. 张量
在Tensorflow程序中,所有的数据都是通过张量的形式来表示。从功能的角度上看,张量可以简单的理解为多维数组。
Python学习交流群:1004391443,这里是python学习者聚集地,有大牛答疑,有资源共享!小编也准备了一份python学习资料,有想学习python编程的,或是转行,或是大学生,还有工作中想提升自己能力的,正在学习的小伙伴欢迎加入学习。
(1)占位符Placeholder
可以把占位符看作为函数的未知数。假设函数f(x)=wx,其中w是3行2列的矩阵,
w=⎡⎣⎢135246⎤⎦⎥
w=⎣⎡135246⎦⎤
那么x只要满足行数为2,列数不定的矩阵就可以了。
例如,本案例中x = tf.placeholder("float", shape=[None, 160 * 120 * 3]),输入变量的占位符是3个数的乘积57600。
(2)Variable对象
Variable类用于存储随时变化的值,创建Variable对象后,要调用tf.global_variables_initializer(),才可以使用Variable对象的值。
(3)张量基本运算
本案例用到乘法:关于矩阵(二维张量)乘法函数为matmul,例如:tf.matmul(h_pool3_flat, W_fc1)。
(4)张量Reduction
TensorFlow提供了几个操作,您可以使用这些操作执行常见的数学计算,以减少张量的各种维。本案例中用到:
reduce_sum(),压缩求和,对于多维数组元素的相加,如果不指定是进行哪一维度的相加,结果是未定义的。tensorflow指定了默认行为:把所有元素全加在一起。
例如:
'x' is [[1, 1, 1]]
[1, 1, 1]]
tf.reduce_sum(x) ==> 6
tf.reduce_sum(x, 0) ==> [2, 2, 2]
tf.reduce_sum(x, 1) ==> [3, 3]
1
2
3
4
5
reduce_mean(), 函数用于计算张量tensor沿着指定的数轴(tensor的某一维度)上的的平均值,主要用作降维或者计算tensor(图像)的平均值。
例如:
'x' is [[1., 1. ]]
[2., 2.]]
tf.reduce_mean(x) ==> 1.5
tf.reduce_mean(x, 0) ==> [1.5, 1.5]
tf.reduce_mean(x, 1) ==> [1., 2.]
1
2
3
4
5
(5)其他张量函数
argmax(),tf.argmax是tensorflow用numpy的np.argmax实现的,它能给出某个tensor对象在某一维上的其数据最大值所在的索引值,tf.argmax()函数中有个axis参数(轴),该参数能指定按照哪个维度计算。如在矩阵的结构中,axis可被设置为0或1,分别表示:0—按列计算,1—行计算。例如:tf.argmax(y_conv,1)
equal(),比较两个张量是否相等,是逐个元素进行判断,如果相等就是 True,不相等,就是 False。例如:correct_prediction = tf.equal(tf.argmax(y_conv,1), tf.argmax(y_,1))。
cast(),把比较结果转换为浮点型,例如:tf.cast(correct_prediction, "float")。
1.2. 运行模型——会话
Tensorflow中使用会话(session)来执行定义好的运算。会话拥有并管理程序运行时的所有资源。会话使用有两种模式。
第一种模式:需要明确调用会话生成函数和关闭会话函数,手动管理所有资源。
sess = tf.InteractiveSession()
sess.run(tf.initialize_all_variables())
for i in range(200):
batch = mnist.train.next_batch(50)
if i%100 == 0:
train_accuracy = accuracy.eval(feed_dict={x:batch[0], y_: batch[1], keep_prob: 1.0})
print ("step {}, training accuracy {}".format(i, train_accuracy))
train_step.run(feed_dict={x: batch[0], y_: batch[1], keep_prob: 0.5})
sess.close()
1
2
3
4
5
6
7
8
9
注:参考mnist手写数字识别示例。
第二种模式:通过Python上下文管理器的机制,将所有的计算放到“with”的内部,自行管理所有资源。
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
filelist = get_data_filename('mydata')
......
if i%50 == 0:
train_accuracy = accuracy.eval(feed_dict={x:batch_x, y_: batch_y, keep_prob: 1.0})
print ("step {}, training accuracy {}".format(i, train_accuracy))
train_step.run(feed_dict={x: batch_x, y_: batch_y, keep_prob: 0.5})
1
2
3
4
5
6
7
8
- 卷积网络模型
2.1. 神经元概述
在这里插入图片描述
将上述的神经元结构抽象成数学概念,可以得到如上图所示的神经元模型。
模型的输入是数据里的自变量,比如图中的x1、x2、x3。它们用圆点表示,对应着神经元里的树突。
接收输入变量的是一个线性模型,在图中用正方形表示。这个线性模型对应着神经元的细胞体。对于神经元中的线性模型,用wi
wi表示权重,用b表示截距,∑3iwixi+b
∑i3wixi+b
接下来是一个非线性的激活函数f()
f()(activation function),它将控制是否对外发送信号,如图中用三角形表示,对应这神经元里的轴突。在神经网络领域,常常用一个圆圈来概括地表示线性模型和激活函数。
将模型的各个部分联结起来得到最后的输出f(∑3iwixi+b)
f(∑i3wixi+b),这个值将传递给下一个神经元模型,在图中用箭头表示,对应着神经元里的突触。
在神经元模型中,非线性的激活函数是整个模型的核心。例如本案例中使用的是激活函数 ReLU。神经元模型代码如下:
增加第二层全连接
W_fc2 = weight_variable([512,256])
b_fc2 = bias_variable([256])
h_fc2 = tf.nn.relu(tf.matmul(h_fc1_drop,W_fc2)+b_fc2)
1
2
3
4
在深度学习中,常用的激活函数主要有:sigmoid函数,tanh函数,ReLU函数等。例如本案例使用的是ReLU函数。
nn.relu(),函数的作用是计算激活函数 ReLU,即 max(features, 0)。即将矩阵中每行的非最大值置0。例如:h_fc2 = tf.nn.relu(tf.matmul(h_fc1_drop,W_fc2)+b_fc2)
在这里插入图片描述
relu(x)=max(x,0)={x,0x⩾0x<0
relu(x)=max(x,0)={x,0x⩾0x<0
2.2. 网络结构
卷积网络模型基于LeNet-5模型,使用3层卷积(卷积层和池化层)和3层全连接层。
在这里插入图片描述
序号 层 输入 输出
1 输入层 输入图像和标签 160×120×3(RGB图像,3个通道)
2 第一卷积层 x=[-1,120,160,3], W=[3, 3, 3, 16], strides=[1, 1, 1, 1], padding=‘SAME’ 160×120×3,3个特征(通道)
3 第一池化层 x=[-1,120,160,3], ksize=[1, 2, 2, 1],strides=[1, 2, 2, 1], padding=‘SAME’ 80×60×16,16个特征(通道)
4 第二卷积层 x=[-1,60,80,16], W=[3, 3, 16, 32], strides=[1, 1, 1, 1], padding=‘SAME’ 80×80×32,32个特征(通道)
5 第二池化层 x=[-1,60,80,16], ksize=[1, 2, 2, 1],strides=[1, 2, 2, 1], padding=‘SAME’ 40×30×32,32个特征(通道)
6 第三卷积层 x=[-1,30,40,32], W=[3, 3, 32, 64], strides=[1, 1, 1, 1], padding=‘SAME’ 40×30×32,32个特征(通道)
7 第三池化层 x=[-1,30,40,32], ksize=[1, 2, 2, 1],strides=[1, 2, 2, 1], padding=‘SAME’) 20×15×64,64个特征(通道)
8 第一全连接层 x=[-1,20×15×64], W=[20×15×64, 512] 512神经元
9 第二全连接层 x=[-1,512], W=[512, 256] 256神经元
10 第三全连接层 x=[-1,256], W=[256, 4] 4个输出值
损失函数,nn.softmax()
如上图所示,全连接最后输出(full3),使用了softmax损失函数,TensorFlow中,Softmax回归参数被去掉,它只是一层额外的处理层,将神经网络的输出变成了一个概率分布。
假设经过第三层(full3)全连接网络输出为y1,y2,...,yn
y1,y2,...,yn,那么经过Softmax回归处理之后的输出为:
softmax(y)i=y′i=eyi∑nj=1eyi
softmax(y)i=yi′=∑j=1neyieyi
从以上公式可以看出,损失函数的输出是概率。本案例的代码如下:
y_conv=tf.nn.softmax(tf.matmul(h_fc2_drop, W_fc3) + b_fc3,name='y_conv')
交叉熵
假设p代表正确答案,q代表预测值,交叉熵用来描述两个概率分布的距离,也就是说交叉熵值越小,两个概率分布越接近,表示为:H=∑ni=1yilog(y′i)
H=∑i=1nyilog(yi′),其中yiyi为真实值,y′i
yi′为预测值。例如本案例中的代码如下:
cross_entropy = -tf.reduce_sum(y_*tf.log(y_conv))
2.3. 卷积及网络操作
(1)卷积操作
设矩形图像尺寸为W×H,卷积核的尺寸为FxF,步幅为S,图像深度(通道数)为C,Padding使用P,则卷积后输出图像大小:
W1=W0−F+2PS+1
W1=SW0−F+2P+1,H1=H0−F+2PS+1
H1=SH0−F+2P+1
注意:Padding的作用用于解决图像边缘信息损失的问题。
本文案例中,卷积核尺寸为3x3,S(步长)= 1 。
如卷积核为3时 padding 选择1
如卷积核为5时 padding 选择2
如卷积核为7时 padding 选择3
(2)池化操作
设输入图像尺寸为WxH,其中W为图像宽,H为图像高,D:图像深度(通道数),卷积核的尺寸为FxF,S为步长,则池化后输出图像大小:
W1=W0−F+S+1
W1=SW0−F++1,H1=H0−FS+1
H1=SH0−F+1
注:本文案例中,卷积核尺寸为2x2,S(步长)= 2。
- 模型训练
随着工业互联网高速发展,工业大数据人工智能应运而生,通过探索,发现工业生产中,大量物联网数据形成的工况监控图,存在人工识别标准不统一、学习周期长等情况,先前所开发的极限值、趋势对比等监控软件效果差,需要人工智能技术来提高识别效率和准确率。
3.1. 输入数据
输入是石油工业采油生产工况——示功图,来自物联网采集数据所绘制的示功图。本次实验采用部分数据,分类如下:0-正常,1- 抽油杆断,2- 供液不足,3- 气影响。
在这里插入图片描述
3.2. 训练参数
学习率设置为1e-4,batch_size为50。
每个分类样本数为1000,学习率分别是1e-4、5e-5情况下,batch size分别是50、100的情况下,测试准确率接近80%。如果增加样本,优化模型和学习算法,很容易达到90%以上。
3.3. 训练结果
在这里插入图片描述
import tensorflow as tf
import cv2
import os
import numpy as np
创建大量的权重和偏置项。这个模型中的权重在初始化时应该加入少量的噪声来打破对称性以及避免0梯度。
def weight_variable(shape):
initial = tf.truncated_normal(shape, stddev=0.01)
return tf.Variable(initial)
def bias_variable(shape):
initial = tf.constant(0.01, shape=shape)
return tf.Variable(initial)
卷积使用1步长(stride size),0边距(padding size)的模板,保证输出和输入是同一个大小。
我们的池化用简单传统的2x2大小的模板做max pooling。为了代码更简洁,我们把这部分抽象成一个函数。
def conv2d(x, W):
return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')
def max_pool_2x2(x):
return tf.nn.max_pool(x, ksize=[1, 2, 2, 1],strides=[1, 2, 2, 1], padding='SAME')
batch_size = 10
learning_rate=1e-5 #学习率
占位符,通过为输入图像和目标输出类别创建节点,来开始构建计算图。
x = tf.placeholder("float", shape=[None, 160 * 120 * 3]) #图片像素160*120
y_ = tf.placeholder("float", shape=[None, 4])
输入图片x是一个2维的浮点数张量。这里,分配给它的shape为[None, 160 * 120 * 3],其中160 * 120 * 3是一张展平的图片的维度。
None表示其值大小不定,在这里作为第一个维度值,用以指代batch的大小,意即x的数量不定。
输出类别值y_也是一个2维张量,其中每一行为一个4维的one-hot向量,用于代表对应某一图片的类别。
第一层卷积,由一个卷积接一个max pooling完成。
卷积在每个3x3的patch中算出16个特征。卷积的权重张量形状是[3, 3, 3, 16],前两个维度是patch的大小,接着是输入的通道数目,最后是输出的通道数目。
而对于每一个输出通道都有一个对应的偏置量。
W_conv1 = weight_variable([3, 3, 3, 16])
b_conv1 = bias_variable([16])
把x变成一个4d向量,其第2、第3维对应图片的宽、高,最后一维代表图片的颜色通道数(因为是rgb彩色所以这里是3,如果是灰度图这里的通道数为1)
x_image = tf.reshape(x, [-1,120,160,3])
把x_image和权值向量进行卷积,加上偏置项,然后应用ReLU激活函数,最后进行max pooling。
h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)
h_pool1 = max_pool_2x2(h_conv1)
为了构建一个更深的网络,我们会把几个类似的层堆叠起来。第二层中,每个3x3的patch会得到32个特征。
W_conv2 = weight_variable([3, 3, 16, 32])
b_conv2 = bias_variable([32])
h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)
h_pool2 = max_pool_2x2(h_conv2)
第三层卷积
W_conv3 = weight_variable([3, 3, 32, 64])
b_conv3 = bias_variable([64])
h_conv3 = tf.nn.relu(conv2d(h_pool2, W_conv3) + b_conv3)
h_pool3 = max_pool_2x2(h_conv3)
现在,图片尺寸减小到15x20,我们加入一个有512个神经元的全连接层,用于处理整个图片。
我们把池化层输出的张量reshape成一些向量,乘上权重矩阵,加上偏置,然后对其使用ReLU。
W_fc1 = weight_variable([15 * 20 * 64, 512])
b_fc1 = bias_variable([512])
h_pool3_flat = tf.reshape(h_pool3, [-1, 152064])
h_fc1 = tf.nn.relu(tf.matmul(h_pool3_flat, W_fc1) + b_fc1)
Dropout,为了减少过拟合,我们在输出层之前加入dropout。
keep_prob = tf.placeholder("float")
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)
增加第二层全连接
W_fc2 = weight_variable([512,256])
b_fc2 = bias_variable([256])
h_fc2 = tf.nn.relu(tf.matmul(h_fc1_drop,W_fc2)+b_fc2)
h_fc2_drop = tf.nn.dropout(h_fc2,keep_prob)
'''softmax层,根据256个特征计算输出标签'''
输出层,我们添加一个softmax层,就像前面的单层softmax regression一样。
W_fc3 = weight_variable([256, 4])
b_fc3 = bias_variable([4])
y_conv=tf.nn.softmax(tf.matmul(h_fc2_drop, W_fc3) + b_fc3,name='y_conv') # softmax层,计算输出标签
cross_entropy = -tf.reduce_sum(y_*tf.log(y_conv))
使用TensorFlow内置的交叉熵函数避免出现权重消失问题
cross_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits_v2(labels=y_, logits=y_conv))
tf.reduce_sum :计算tensor指定轴方向上的所有元素的累加和;
tf.reduce_mean 函数用于计算张量tensor沿着指定的数轴(tensor的某一维度)上的的平均值,主要用作降维或者计算tensor(图像)的平均值。
train_step = tf.train.AdamOptimizer(learning_rate).minimize(cross_entropy)
correct_prediction = tf.equal(tf.argmax(y_conv,1), tf.argmax(y_,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
saver = tf.train.Saver() #定义saver
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print("开始训练!")
filelist = get_data_filename('mydata')
lenth = len(filelist)
k = 0
for i in range(int(lenth/3)):
# 每个batch为50组数据,梯度下降
batch_x,batch_y = get_batch(filelist,k*batch_size,batch_size)
k +=1
if k*batch_size>=lenth:
k = 0
if i%50 == 0:
train_accuracy = accuracy.eval(feed_dict={x:batch_x, y_: batch_y, keep_prob: 1.0})
print ("step {}, training accuracy {}".format(i, train_accuracy))
train_step.run(feed_dict={x: batch_x, y_: batch_y, keep_prob: 0.5})
saver.save(sess, 'D:/06Study/Workspace/Python/Machine Learning/SAVE/model.ckpt') #模型储存位置
print("开始测试!")
filelist = get_data_filename('testdata')
lenth = int(len(filelist)/100)
for i in range(lenth):
x_test_batch,y_test_batch = get_batch(filelist,i*100,100)
print ("test accuracy {}".format(accuracy.eval(feed_dict={x: x_test_batch, y_: y_test_batch, keep_prob: 1.0})))
代码中提到的“get_batch”函数,是需要自行收集图片,组织数据,本文不提供数据。可以参考[2]中人脸数据。关于模型的使用、数据的准备、集成模型等内容,后续再总结。
由于作者水平有限,初入人工智能,欢迎一起讨论、指导。