本人是神经网络的小白,第一次学习搭建神经网络,写下这篇文章目的是帮助自己更加理解TensorFlow。以及分享一些代码给需要的人。
1.卷积神经网络(Convolutional Neural Networks, CNN)是一类包含卷积计算且具有深度结构的前馈神经网络(Feedforward Neural Networks),是深度学习(deep learning)的代表算法之一 。卷积神经网络具有表征学习(representation learning)能力,能够按其阶层结构对输入信息进行平移不变分类(shift-invariant classification),因此也被称为“平移不变人工神经网络(Shift-Invariant Artificial Neural Networks, SIANN)” 。
1.输入层。在处理图像的卷积神经网络中,他一般代表一张图片的像素矩阵。
2.卷积层。卷积层中的每个节点的输入只是上一层神经网络的一小块,大小通常为33或者55。卷积层将神经网络的没一小块进行更加深入的分析从而得到抽象程度更高的特征。
3.池化层。池化层神经网络不会该表三维矩阵的深度,但是它可以缩小矩阵的大小。池化操作可以认为是将一张分辨率较高的图片转化为分辨率较低的图片。通过池化层,可以进一步缩小最后全连接层中节点的个数,从而达到减少整个神经网络中参数的目的。
4.全连接层。一般有1到2层全连接层,完成分类任务。
5.Softmax层。通过Softmax可以得到当前样例属于不同种类的概率分布情况。
1.需要调用的库
import tensorflow as tf #用tensorflow搭建神经网络
import numpy as np #对数据进行处理
import random #对数据进行处理时需要用到随机函数
from six.moves import cPickle as pickle #读取数据文件
import os #读取文件时需要用到
import time #计算时间
对cifar10数据进行处理
在对数据进行处理之前,一定要确保自己的CIFAR10数据集是正确的数据集,我用了一个错误的数据集导致自己卡了半天。
这是用了错误的数据集报错的情况(UnpicklingError:invalid load key)
def load_CIFAR_batch(filename):
"""load single batch of cifar"""
with open(filename, 'rb') as f:
datadict = pickle.load(f, encoding='bytes') #读取文件,加载数据集
x = datadict[b'data'] # 加上b防止报错,如果不加b可能会报错(我没加b就报错了)
y = datadict[b'labels']
x = x.reshape(10000, 3, 32, 32).transpose(0, 2, 3, 1).astype("float")
y = np.array(y) #将得到的数据转化为ndarray数组,这样才能喂入神经网络
return x, y
def load_CIFAR10(ROOT):
"""load all of cifar"""
xs = []
ys = []
for b in range(1, 6): #cifar10数据集一共有5个训练数据
f = os.path.join(ROOT, 'data_batch_%d' % (b))
x, y = load_CIFAR_batch(f)
xs.append(x)
ys.append(y)
xtr = np.concatenate(xs)
ytr = np.concatenate(ys)
del x, y
xte, yte = load_CIFAR_batch(os.path.join(ROOT, 'test_batch')) #测试集有一个
ytr = ytr.reshape(50000, 1)
yte = yte.reshape(10000, 1)
return xtr, ytr, xte, yte #返回训练集和测试集的图像和标签,以ndarray数组的形式返回
def getbatch(batch_size, type='train'): #获得batch,因为训练数据过大,所以每次训练只能随机抽取数据进行训练
x_img_train, y_label_train, x_img_test, y_label_test = load_CIFAR10('C:\\Users\\10372\\Desktop\\cifar10') #通过路径获得数据
batch_img = []
batch_label = []
if (type == 'train'): #如果是训练集
for i in range(batch_size):
randnum = random.randint(0, x_img_train.shape[0] - 1)
batch_img.append(x_img_train[randnum])
temp = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] #将label中的数字转化为数组,对应神经网络的10个输出层,如4对应[0,0,0,0,1,0,0,0,0,0]
temp[int(y_label_train[randnum])] = 1
batch_label.append(temp)
batch_image = np.reshape(batch_img, [batch_size] + [32, 32, 3])
batch_label = np.array(batch_label)
return batch_image, batch_label
else: #如果是测试集
for i in range(batch_size):
randnum = random.randint(0, x_img_test.shape[0] - 1)
batch_img.append(x_img_test[randnum])
temp = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
temp[int(y_label_test[randnum])] = 1
batch_label.append(temp)
batch_image = np.reshape(batch_img, [batch_size] + [32, 32, 3])
batch_label = np.array(batch_label)
return batch_image, batch_label
2.搭建神经网络
def CNN():
def weight(shape):
return tf.Variable(tf.truncated_normal(shape,stddev=0.1),
name='w')
#定义bias函数,用于建立偏差张量
#输入shape,先以tf.constant建立常数(输入参数:1.0与shape),
#然后使用tf.Variable建立TensorFlow张量变量,并且返回计算结果
def bias(shape):
return tf.Variable(tf.constant(0.1,shape=shape)
,name='b')
#定义conv2d函数,用于进行卷积运算
def conv2d(x,w):
return tf.nn.conv2d(x,w,strides=[1,1,1,1],
padding='VALID')
#使用TensorFlow提供的tf.nn.conv2d进行卷积运算,并且返回运算结果
#x是输入的图像:后续我们会传入要处理的图像,必须是四维张量
#W是filter weight滤镜的权重
#strides:是步长,padding是补充0,VALID表示不使用全0填充,SAME表示使用全0填充
#出具max_pool_2x2函数,用于建立池化层
def max_pool_2x2(x):
return tf.nn.max_pool(x,ksize=[1,2,2,1],
strides=[1,2,2,1],
padding='SAME')
#ksize:缩减采集窗口的大小,设置为[1,2,2,1],其格式是[1,height,width,1]
#strides:缩减采集窗口的跨步,设置为[1,2,2,1],其格式为[1,strde,strde,1]
#建立模型
#1.输入层
#代码说明:
#placeholder是TensorFlow"计算图"的输入,参数设置如下
#"Float":数据类型
#shape=[None,1024]:第一维设置为None,因为后续我们训练时会传送很多数字图片
#项数不固定,所以设置为None,第二维是输入图片的像素
#tf.reshape:x原本为一维向量,因为后续卷积和池化的运算,所以必须转化为
#四维张量
#建立卷积层1
with tf.variable_scope('C1_Conv'):
w1 = weight([5,5,3,8])
b1=bias([8])
Conv1=conv2d(x,w1)+b1
C1_Conv = tf.nn.relu(Conv1)
#w1:建立w1权重,1,2维是5代表滤镜的大小是5*5,第三维是1代表图像是单色,3代表是RGB三色
# 第四维是8代表要产生8个图像
#b1:因为要产生8个图像,所以输入shape为[8]
#conv1:进行卷积运算
#C1_Conv = tf.nn.relu(Conb1):ReLu激活函数
#建立池化层1
#将原始图像由28*28缩小为14*14
with tf.name_scope('C1_Pool'):
C1_Pool=max_pool_2x2(C1_Conv)
#建立卷积层2
with tf.variable_scope('C2_Conv'):
w2 = weight([5,5,8,32])
b2=bias([32])
Conv2=conv2d(C1_Pool,w2)+b2
C2_Conv=tf.nn.relu(Conv2)
#建立池化层2
with tf.name_scope('C2_Pool'):
C2_Pool=max_pool_2x2(C2_Conv)
return C2_Pool
def forward_network(regularizer):
C2_Pool=CNN()
def weight(shape):
return tf.Variable(tf.truncated_normal(shape,stddev=0.1),
name='w')
def bias(shape):
return tf.Variable(tf.constant(0.1,shape=shape)
,name='b')
#建立平坦层
#将池化层2中32个5*5的图像转化为以为向量
with tf.name_scope('D_Flat'):
D_Flat = tf.reshape(C2_Pool,[-1,5*5*32])
#第一维是-1,因为后续会传入不限定项数的训练数据
#建立隐藏层
with tf.variable_scope('D_hidden_Layer'):
w3=weight([5*5*32,120])
if regularizer !=None:
tf.add_to_collection("losses",regularizer(w3))
b3=bias([120])
D_Hidden = tf.nn.relu(
tf.matmul(D_Flat,w3)+b3)
D_Hidden_Dropout = tf.nn.dropout(D_Hidden,
keep_prob=0.8)
#[600,120]:因为上一层有600个神经元,建立的隐藏层D_Hidden有120个神经元
#加入Dropout避免过拟合:D_Hidden是要执行dropout的神经网络层,keep_prob=0.8
# 是保留80%的神经元,随机去掉20%的神经元
#建立输出层
with tf.variable_scope('Output_layer'):
w4=weight([120,10])
if regularizer !=None:
tf.add_to_collection("losses",regularizer(w4))
b4=bias([10])
y_predict = tf.nn.softmax(
tf.matmul(D_Hidden_Dropout,
w4)+b4)
return y_predict
3.训练
#定义训练方法
with tf.name_scope("optimizer"):
y_label = tf.placeholder("float",shape=[None,10],
name="y_label")
#配置神经网络参数
BATCH_SIZE=100
LEARNING_RATE_BASE=0.005
LEARNING_RATE_DECAY=0.99
LERANING_RATE_DECAY_STEP=100
REGULARAZTION_RATE=0.0001
TRATNING_STEPS=20000
MOVING_AVERAGE_DECAY=0.99
REGULARAZTION_RATE=0.001
regularizer=tf.contrib.layers.l2_regularizer(REGULARAZTION_RATE)
#模板保存的路径和文件名
MODEL_SAVE_PATH='/path/to/model'
MODEL_NAME='model.ckpt'
x=tf.placeholder(tf.float32,[None,32,32,3],name='x-input')
x_=tf.placeholder(tf.float32,[None,32,32,3],name='test')
y_=tf.placeholder(tf.float32,[None,10],name='y-input')
y=forward_network(regularizer)
global_step=tf.Variable(0,trainable=False)
#定义损失函数,学习率,滑动平均操作以及训练过程
with tf.name_scope("optimizer"):
y_label = tf.placeholder("float",shape=[None,10],
name="y_label")
#定义评估模型准确率的方式
#计算每一项数据是否预测正确
correct_prediction=tf.equal(tf.argmax(y_label,1),
tf.argmax(y,1))
#tf.equal:判断下列真实值与预测值是否相等,如果相等返回1
#tf.argmax:转化为数字0-9,例如0,0,0,0,0,0,0,0,1,0,0等于7
#计算预测正确结果的平均值
accuracy=tf.reduce_mean(tf.cast(correct_prediction,"float"))
loss_function = tf.reduce_mean(
tf.nn.softmax_cross_entropy_with_logits(
logits=y,labels=y_label))
variable_averages=tf.train.ExponentialMovingAverage(
MOVING_AVERAGE_DECAY,global_step)
variable_averages_op=variable_averages.apply(
tf.trainable_variables())
cross_entropy=tf.nn.sparse_softmax_cross_entropy_with_logits(
logits=y,labels=tf.argmax(y_,1))
cross_entropy_mean=tf.reduce_mean(cross_entropy)
loss=cross_entropy_mean+tf.add_n(tf.get_collection('losses'))
learning_rate=tf.train.exponential_decay(
LEARNING_RATE_BASE,
global_step,
LERANING_RATE_DECAY_STEP,
LEARNING_RATE_DECAY)
train_step=tf.train.GradientDescentOptimizer(learning_rate)\
.minimize(loss,global_step=global_step)
with tf.control_dependencies([train_step,variable_averages_op]):
train_op=tf.no_op(name='train')
saver=tf.train.Saver()
with tf.Session() as sess:
tf.global_variables_initializer().run()
for i in range(TRATNING_STEPS):
xs,ys=getbatch(BATCH_SIZE)
xs=xs.astype('float32')/255.0
_,loss_value,step = sess.run([train_op,loss,global_step],
feed_dict={x:xs,y_:ys})
print(i)
if i % 50 == 0:
xt,yt=getbatch(BATCH_SIZE,type="test")
xt = xt.astype('float32') / 255.0
loss1,acc=sess.run([loss_function,accuracy],
feed_dict={x:xt,y_label:yt})
print("After %d training step(s),loss on training"
"batch is %g."%(step,loss_value))
print("Train Epoch:", '%02d' % (i + 1), "loss=", \
"{:.9f}".format(loss1), "Accuracy=", acc)
saver.save(sess,os.path.join(MODEL_SAVE_PATH,MODEL_NAME),
global_step=global_step)
目前存在的问题:
训练时间过长
本文中大量参看了书籍《TensorFlow+Keras深度学习人工智能实践应用》和《TensorFlow实战Google深度学习框架(第2版)》如果有需要该书籍的,可以找我发扫描版。