1.代码
import dataset import tensorflow as tf import time from datetime import timedelta import math import random import numpy as np # conda install --channel https://conda.anaconda.org/menpo opencv3 #Adding Seed so that random initialization is consistent
# 随机初始化:每一次随机都是相同的结果 from numpy.random import seed seed(10) # 数值随意,不改变就行 from tensorflow import set_random_seed set_random_seed(20)
# 每次迭代送入32张图 batch_size = 28 # 指定标签:只有两种 classes = ['island','seaice'] # 一共有多少类别,最后训练需要 num_classes = len(classes)
# 1000张图中,20%为测试集 validation_size = 0.2 # 由于图片有大有小,这里我设置/截所有图像为64x64 img_size = 64 # 彩色图:3通量 num_channels = 3 # 所有图像所在位置:training_data文件夹 train_path='training_data'
# 调用dataset.py中的read_train_sets函数 # 目的:得到已处理好、分好的图片集 data = dataset.read_train_sets(train_path, img_size, classes, validation_size=validation_size)
print("图片预处理完毕,分组如下:") print("训练集张数:{}".format(len(data.train.labels))) print("测试集张数:{}".format(len(data.valid.labels)))
session = tf.Session() # 第一个参数是每次送入训练的张数;中间两个参数是图片的尺度:64x64;最后一个参数是3通量 x = tf.placeholder(tf.float32, shape=[None, img_size, img_size, num_channels], name='x')
# 标签数 y_true = tf.placeholder(tf.float32, shape=[None, num_classes], name='y_true') # argmax判断当前哪个值大,就是什么 y_true_cls = tf.argmax(y_true, dimension=1)#y_true中每行最大原素的列坐标
# 卷积网络结构设置 filter_size_conv1 = 3 # 卷积核1是3x3 num_filters_conv1 = 32
filter_size_conv2 = 3#第一部分是输入层。第二部分由n个卷积层和池化层的组合组成。第三部分由一个全连结的多层感知机分类器构成。 num_filters_conv2 = 32
filter_size_conv3 = 3 num_filters_conv3 = 64 # 全连接层:1024个特征 常见还有2048 4096等等 fc_layer_size = 1024
# 权重参数设置 def create_weights(shape):#创建w return tf.Variable(tf.truncated_normal(shape, stddev=0.05))#产生截断正态分布随机数,取值范围为 [ mean - 2 * stddev, mean + 2 * stddev ]。
def create_biases(size):#创建b return tf.Variable(tf.constant(0.05, shape=[size]))#创建常量,shape:表示张量的“形状”,即维数以及每一维的大小(猜测创建值为0.05的大小为size的一为张量)
# -------------------------------------------------------- # # 辅助函数1:卷积池化各层参数的设置与工作 def create_convolutional_layer(input, num_input_channels, #深度 conv_filter_size, num_filters): # 权重参数初始化:3 3 3 32 # 前两个参数是滑动窗尺寸3x3 第三个参数为3通量 第4个参数是这一层观察多少个特征 weights = create_weights(shape=[conv_filter_size, conv_filter_size, num_input_channels, num_filters])#将要创建的卷积核的大小,深度,个数都传递给crearte_weights函数生成随机权重 biases = create_biases(num_filters)#b的个数核卷积核的个数一致
# 执行一次卷积操作 layer = tf.nn.conv2d(input=input, filter=weights, strides=[1, 1, 1, 1], padding='SAME')#tf.nn.conv2d输入参数直接进行了卷积运算
layer += biases # relu激活函数:激活后的数值传给下一步 layer = tf.nn.relu(layer) # 池化操作:上一卷积层的输出就是这里的输入;池化窗尺寸为2x2 layer = tf.nn.max_pool(value=layer, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
# 一套卷积池化层工作完毕 return layer
# 辅助函数2:全连接层参数的设置 def create_flatten_layer(layer): # 把到最后一个卷积池化层的尺寸:[7,8,8,64]#如果这个地方是1那后面7全改一即可,应该是1 # 既然是全连接层,就要把它拉伸;即对这个全连接层的"输入"应有8x8x64=4096个 layer_shape = layer.get_shape()#layer_shape = [7,8,8,64]
# 计算得到那个4096的数值 num_features = layer_shape[1:4].num_elements()#shape[1:4]切片数组得到[8,8,64]数组,num_elements()返回一个变量[8,8,64]的规模,也就是该变量的所有元素的数量。
# 转换成数组/矩阵 layer = tf.reshape(layer, [-1, num_features])#-1是不确定值,通过7*8*8*64/8*8*64计算得出7#目前理解7是指七页
return layer
# 辅助函数3:全连接层创建与工作 def create_fc_layer(input,#7*4096 #7*1024 num_inputs,# 8*8*64 = 4096 #1024 num_outputs,#1024 #2 use_relu=True): # 全连接层的权重参数等的设置:前4096,后2048(自己之前设置过的) weights = create_weights(shape=[num_inputs, num_outputs])#4096*1024#1024*2 biases = create_biases(num_outputs)#1024#2
# 计算: layer = tf.matmul(input, weights) + biases#矩阵7*4096和4096*1024的到7*1024#7*1024和1024*2得到7*2(即七张图每张图俩类别的概率) # dropout解决过拟合,随机杀死30%个节点 layer=tf.nn.dropout(layer,keep_prob=0.7) # relu激活函数 if use_relu: layer = tf.nn.relu(layer) return layer # -------------------------------------------------------- #
# 调用辅助函数1:第一套 “卷积池化层” 工作完毕 layer_conv1 = create_convolutional_layer(input=x,#x第47行shape=NONE num_input_channels=num_channels, conv_filter_size=filter_size_conv1, num_filters=num_filters_conv1)
# 调用辅助函数1:第二套 “卷积池化层” 工作完毕 layer_conv2 = create_convolutional_layer(input=layer_conv1, num_input_channels=num_filters_conv1, conv_filter_size=filter_size_conv2, num_filters=num_filters_conv2) # 调用辅助函数1:第三套 “卷积池化层” 工作完毕 layer_conv3= create_convolutional_layer(input=layer_conv2, num_input_channels=num_filters_conv2, conv_filter_size=filter_size_conv3, num_filters=num_filters_conv3) # 调用辅助函数2:对下面的全连接层先设置相关的参数 layer_flat = create_flatten_layer(layer_conv3)
# 调用辅助函数3:全连接层1工作 layer_fc1 = create_fc_layer(input=layer_flat, num_inputs=layer_flat.get_shape()[1:4].num_elements(),# num_outputs=fc_layer_size, use_relu=True)
# 调用辅助函数3:全连接层2工作 layer_fc2 = create_fc_layer(input=layer_fc1, num_inputs=fc_layer_size,#1024 num_outputs=num_classes,#2 use_relu=False)
# 预测值:谁大选谁 y_pred = tf.nn.softmax(layer_fc2,name='y_pred') #softmax的输出向量,就是概率,该样本属于各个类的概率#softmax后为tensor y_pred_cls = tf.argmax(y_pred, dimension=1)#取行最大的 #这俩步作者为了打印与梯度下降操作无关
# 以下是常规操作: session.run(tf.global_variables_initializer())# 必须要使用global_variables_initializer的场合 # 含有tf.Variable的环境下,因为tf中建立的变量是没有初始化的,也就是在debug时还不是一个tensor量,而是一个Variable变量类型 #简单来说初始化所有张量 cross_entropy = tf.nn.softmax_cross_entropy_with_logits(logits=layer_fc2, labels=y_true)# #第一个参数logits:就是神经网络最后一层的输出,如果有batch的话,它的大小就是[batchsize,num_classes],单样本的话,大小就是num_classes #第二个参数labels:实际的标签,大小同上 #体的执行流程大概分为两步: #第一步是先对网络最后一层的输出做一个softmax, #这一步通常是求取输出属于某一类的概率,对于单样本而言,输出就是一个num_classes大小的向量([Y1,Y2,Y3...]其中Y1,Y2,Y3...分别代表了是属于该类的概率) #第二步是softmax的输出向量[Y1,Y2,Y3...]和样本的实际标签做一个交叉熵
cost = tf.reduce_mean(cross_entropy)#结合上一步求loss#求损失值 #前三步为了最后一步优化器 optimizer = tf.train.AdamOptimizer(learning_rate=1e-4).minimize(cost)#tf.train.AdamOptimizer()函数是Adam优化算法: #是一个寻找全局最优点的优化算法,引入了二次方梯度校正。#学习率1e-4# #梯度下降函数,优化器就会按照循环的次数一次次沿着loss最小值的方向优化参数了。 #train_step = tf.train.GradientDescentOptimizer(0.2).minimize(loss) #优化器# train_step = tf.train.AdamOptimizer(0.001) #收敛速度比较快# train_step = tf.train.AdamOptimizer(1e-3).minimize(loss) #10的-3次方,学习率, #此步骤定义好优化器 correct_prediction = tf.equal(y_pred_cls, y_true_cls)#判断预测和实际是否一致 accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))#tf.cast将预测结果转换为float32后的张量的平均值 #也可以看成准确率
session.run(tf.global_variables_initializer())
# 打印: def show_progress(epoch, feed_dict_train, feed_dict_validate, val_loss,i): acc = session.run(accuracy, feed_dict=feed_dict_train) val_acc = session.run(accuracy, feed_dict=feed_dict_validate) msg = "Training Epoch {0}--- iterations: {1}--- 训练集精度: {2:>6.1%}, 测试集精度: {3:>6.1%}, 测试集损失值: {4:.3f}" print(msg.format(epoch + 1,i, acc, val_acc, val_loss)) ftmp.write(msg.format(epoch + 1,i, acc, val_acc, val_loss)) ftmp.write('\n') ftmp.flush()
# 从第0次开始迭代 total_iterations = 0
# 跑模型 + 模型保存: ftmp = open('result.txt','w') saver = tf.train.Saver() def train(num_iteration): global total_iterations for i in range(total_iterations, total_iterations + num_iteration):
# 调用dataset.py文件中data类中的next_batch方法 x_batch, y_true_batch, _, cls_batch = data.train.next_batch(batch_size)#batch_size ==28 x_valid_batch, y_valid_batch, _, valid_cls_batch = data.valid.next_batch(batch_size)#每次迭代返回该段batch的 #images图片数据(矩阵) labels每张图片对应标签 img_names图片名字 cls每遍历一张图片就记录该图片类别的列表 # 做好每一个epoch feed_dict_tr = {x: x_batch, y_true: y_true_batch} feed_dict_val = {x: x_valid_batch, y_true: y_valid_batch}
# 开始运行训练 session.run(optimizer, feed_dict=feed_dict_tr)#我们在编写代码的时候,总是要先定义好整个图,然后才调用sess.run()。 #feed_dict参数的作用是替换图中的某个tensor的值或设置graph的输入值。 #相当于定义好了张量a和b以及操作(,这一步执行。 # 打印: if i % int(data.train.num_examples/batch_size) == 0: # 损失值 val_loss = session.run(cost, feed_dict=feed_dict_val) epoch = int(i / int(data.train.num_examples/batch_size)) show_progress(epoch, feed_dict_tr, feed_dict_val, val_loss,i) # 保存文件夹的地方 saver.save(session, './model/island-seaice.ckpt',global_step=i)
total_iterations += num_iteration
# 调用train函数:规定一共迭代4000次 train(num_iteration=4000)
2.详细流程图
源码:
链接:https://pan.baidu.com/s/1NyNoIqXJ7bg_X-ZW4UFhug 提取码:7krh 复制这段内容后打开百度网盘手机App,操作更方便哦