学习记录:自定义数据训练

感谢这位作者,以下记录是来自于https://blog.csdn.net/xinyu3307的几篇文章,我看到比较好,就转记录到自己的博客了,如果有侵权,立马删掉

这思维导图,可为是画的真的好,清楚明了,给他点赞。下面笔记开始。

这里写图片描述

数据集准备 
kaggle猫狗大战数据集(训练),微软的不需要翻墙

  • 12500张cat
  • 12500张dog

生成图片路径和标签的List

step1:获取D:/Study/Python/Projects/Cats_vs_Dogs/data/Cat下所有的猫图路径名,存放到cats中,同时贴上标签0,存放到label_cats中。狗图同理。

train_dir = 'D:/Study/Python/Projects/Cats_vs_Dogs/data'

def get_files(file_dir):
    for file in os.listdir(file_dir+'/Cat'):
            cats.append(file_dir +'/Cat'+'/'+ file) 
            label_cats.append(0)
    for file in os.listdir(file_dir+'/Dog'):
            dogs.append(file_dir +'/Dog'+'/'+file)
            label_dogs.append(1)

step2:对生成的图片路径和标签List做打乱处理

    #把cat和dog合起来组成一个list(img和lab)
    image_list = np.hstack((cats, dogs))
    label_list = np.hstack((label_cats, label_dogs))

    #利用shuffle打乱顺序
    temp = np.array([image_list, label_list])
    temp = temp.transpose()
    np.random.shuffle(temp)

    #从打乱的temp中再取出list(img和lab)
    image_list = list(temp[:, 0])
    label_list = list(temp[:, 1])
    label_list = [int(i) for i in label_list]

生成Batch

step1:将上面生成的List传入get_batch() ,转换类型,产生一个输入队列queue,因为img和lab是分开的,所以使用tf.train.slice_input_producer(),然后用tf.read_file()从队列中读取图像

  • image_W, image_H, :设置好固定的图像高度和宽度
  • 设置batch_size:每个batch要放多少张图片
  • capacity:一个队列最大多少
def get_batch(image, label, image_W, image_H, batch_size, capacity):
    #转换类型
    image = tf.cast(image, tf.string)
    label = tf.cast(label, tf.int32)

    # make an input queue
    input_queue = tf.train.slice_input_producer([image, label])

    label = input_queue[1]
    image_contents = tf.read_file(input_queue[0]) #read img from a queue

step2:将图像解码,不同类型的图像不能混在一起,要么只用jpeg,要么只用png等。

image = tf.image.decode_jpeg(image_contents, channels=3) 

step3:数据预处理,对图像进行旋转、缩放、裁剪、归一化等操作,让计算出的模型更健壮。


image = tf.image.resize_image_with_crop_or_pad(image, image_W, image_H)

image = tf.image.per_image_standardization(image)

step4:生成batch

  • image_batch: 4D tensor [batch_size, width, height, 3],dtype=tf.float32
  • label_batch: 1D tensor [batch_size], dtype=tf.int32
image_batch, label_batch = tf.train.batch([image, label],
                                                batch_size= batch_size,
                                                num_threads= 32, 
                                                capacity = capacity)
#重新排列label,行数为[batch_size]
label_batch = tf.reshape(label_batch, [batch_size])
image_batch = tf.cast(image_batch, tf.float32)

测试

step1:变量初始化,每批2张图,尺寸208x208,设置好自己的图像路径

BATCH_SIZE = 2
CAPACITY = 256
IMG_W = 208
IMG_H = 208

train_dir = 'D:/Study/Python/Projects/Cats_vs_Dogs/data'

step2:调用前面的两个函数,生成batch

image_list, label_list = get_files(train_dir)
image_batch, label_batch = get_batch(image_list, label_list, IMG_W, IMG_H, BATCH_SIZE, CAPACITY)

step3:开启会话session,利用tf.train.Coordinator()tf.train.start_queue_runners(coord=coord)来监控队列(这里有个问题:官网的start_queue_runners()是有两个参数的,sess和coord,但是在这里加上sess的话会报错)。 
利用try——except——finally结构来执行队列操作(官网推荐的方法),避免程序卡死什么的。i<2执行两次队列操作,每一次取出2张图放进batch里面,然后imshow出来看看效果。

with tf.Session() as sess:
    i = 0
    coord = tf.train.Coordinator()
    threads = tf.train.start_queue_runners(coord=coord)

    try:
        while not coord.should_stop() and i<2:

            img, label = sess.run([image_batch, label_batch])

            # just test one batch
            for j in np.arange(BATCH_SIZE):
                print('label: %d' %label[j])
                plt.imshow(img[j,:,:,:])
                plt.show()
            i+=1

    except tf.errors.OutOfRangeError:
        print('done!')
    finally:
        coord.request_stop()
    coord.join(threads)

step4:查看结果,会出现4张图,resize的效果感觉不是很好,不知道是什么问题 
2017.7.10 图片不正常是因为生成batch的时候将image转成了浮点型,吧image_batch = tf.cast(image_batch, tf.float32)注释掉后就好了

这里写图片描述 
这里写图片描述

网络结构定义 
一个简单的卷积神经网络,卷积+池化层x2,全连接层x2,最后一个softmax层做分类。 
函数:def inference(images, batch_size, n_classes):

  • 输入参数: 
    images,image batch、4D tensor、tf.float32、[batch_size, width, height, channels]
  • 返回参数: 
    logits, float、 [batch_size, n_classes]

卷积层1 
16个3x3的卷积核(3通道),padding=’SAME’,表示padding后卷积的图与原图尺寸一致,激活函数relu()

with tf.variable_scope('conv1') as scope:
   weights = tf.get_variable('weights', 
                                  shape = [3,3,3, 16],
                                  dtype = tf.float32,                                   initializer=tf.truncated_normal_initializer(stddev=0.1,dtype=tf.float32))
   biases = tf.get_variable('biases', 
                                 shape=[16],
                                 dtype=tf.float32,
                                 initializer=tf.constant_initializer(0.1))
    conv = tf.nn.conv2d(images, weights, strides=[1,1,1,1], padding='SAME')
    pre_activation = tf.nn.bias_add(conv, biases)
    conv1 = tf.nn.relu(pre_activation, name= scope.name)

池化层1 
3x3最大池化,步长strides为2,池化后执行lrn()操作,局部响应归一化,对训练有利。


with tf.variable_scope('pooling1_lrn') as scope:
    pool1 = tf.nn.max_pool(conv1, ksize=[1,3,3,1],strides=[1,2,2,1],padding='SAME', name='pooling1')
    norm1 = tf.nn.lrn(pool1, depth_radius=4, bias=1.0, alpha=0.001/9.0,beta=0.75,name='norm1')

卷积层2 
16个3x3的卷积核(16通道),padding=’SAME’,表示padding后卷积的图与原图尺寸一致,激活函数relu()

with tf.variable_scope('conv2') as scope:
    weights = tf.get_variable('weights',
                              shape=[3,3,16,16],
                              dtype=tf.float32,
initializer=tf.truncated_normal_initializer(stddev=0.1,dtype=tf.float32))
    biases = tf.get_variable('biases',
                             shape=[16],                            
                             dtype=tf.float32,
initializer=tf.constant_initializer(0.1))
    conv = tf.nn.conv2d(norm1, weights, strides=[1,1,1,1],padding='SAME')
    pre_activation = tf.nn.bias_add(conv, biases)
    conv2 = tf.nn.relu(pre_activation, name='conv2')

池化层2 
3x3最大池化,步长strides为2,池化后执行lrn()操作,

#pool2 and norm2
with tf.variable_scope('pooling2_lrn') as scope:
    norm2 = tf.nn.lrn(conv2, depth_radius=4, bias=1.0, alpha=0.001/9.0,beta=0.75,name='norm2')
    pool2 = tf.nn.max_pool(norm2, ksize=[1,3,3,1], strides=[1,1,1,1],padding='SAME',name='pooling2')

全连接层3 
128个神经元,将之前pool层的输出reshape成一行,激活函数relu()

with tf.variable_scope('local3') as scope:
   reshape = tf.reshape(pool2, shape=[batch_size, -1])
   dim = reshape.get_shape()[1].value
   weights = tf.get_variable('weights',
                             shape=[dim,128],
                             dtype=tf.float32,          initializer=tf.truncated_normal_initializer(stddev=0.005,dtype=tf.float32))
    biases = tf.get_variable('biases',
                            shape=[128],
                            dtype=tf.float32, 
initializer=tf.constant_initializer(0.1))
   local3 = tf.nn.relu(tf.matmul(reshape, weights) + biases, name=scope.name)    

全连接层4 
128个神经元,激活函数relu()

#local4
with tf.variable_scope('local4') as scope:
    weights = tf.get_variable('weights',
                              shape=[128,128],
                              dtype=tf.float32, 
initializer=tf.truncated_normal_initializer(stddev=0.005,dtype=tf.float32))
    biases = tf.get_variable('biases',
                             shape=[128],
                             dtype=tf.float32,
initializer=tf.constant_initializer(0.1))
    local4 = tf.nn.relu(tf.matmul(local3, weights) + biases, name='local4')

Softmax回归层 
将前面的FC层输出,做一个线性回归,计算出每一类的得分,在这里是2类,所以这个层输出的是两个得分。

# softmax
with tf.variable_scope('softmax_linear') as scope:
    weights = tf.get_variable('softmax_linear',
                              shape=[128, n_classes],
                              dtype=tf.float32,
initializer=tf.truncated_normal_initializer(stddev=0.005,dtype=tf.float32))
    biases = tf.get_variable('biases', 
                             shape=[n_classes],
                             dtype=tf.float32, 
initializer=tf.constant_initializer(0.1))
    softmax_linear = tf.add(tf.matmul(local4, weights), biases, name='softmax_linear')

return softmax_linear

loss计算 
将网络计算得出的每类得分与真实值进行比较,得出一个loss损失值,这个值代表了计算值与期望值的差距。这里使用的loss函数是交叉熵。一批loss取平均数。最后调用了summary.scalar()记录下这个标量数据,在TensorBoard中进行可视化。 
函数:def losses(logits, labels):

  • 传入参数:logits,网络计算输出值。labels,真实值,在这里是0或者1
  • 返回参数:loss,损失值
with tf.variable_scope('loss') as scope:
    cross_entropy =tf.nn.sparse_softmax_cross_entropy_with_logits\
                    (logits=logits, labels=labels, name='xentropy_per_example')
    loss = tf.reduce_mean(cross_entropy, name='loss')
    tf.summary.scalar(scope.name+'/loss', loss)
return loss
  • loss损失值优化 

目的就是让loss越小越好,使用的是AdamOptimizer优化器 
函数:def trainning(loss, learning_rate):

  • 输入参数:loss。learning_rate,学习速率。
  • 返回参数:train_op,训练op,这个参数要输入sess.run中让模型去训练。

with tf.name_scope('optimizer'):
    optimizer = tf.train.AdamOptimizer(learning_rate= learning_rate)
    global_step = tf.Variable(0, name='global_step', trainable=False)
    train_op = optimizer.minimize(loss, global_step= global_step)
return train_op

评价/准确率计算 
计算出平均准确率来评价这个模型,在训练过程中按批次计算(每隔N步计算一次),可以看到准确率的变换情况。 
函数:def evaluation(logits, labels):

  • 输入参数:logits,网络计算值。labels,标签,也就是真实值,在这里是0或者1。
  • 返回参数:accuracy,当前step的平均准确率,也就是在这些batch中多少张图片被正确分类了。
with tf.variable_scope('accuracy') as scope:
    correct = tf.nn.in_top_k(logits, labels, 1)
    correct = tf.cast(correct, tf.float16)
    accuracy = tf.reduce_mean(correct)
    tf.summary.scalar(scope.name+'/accuracy', accuracy)
return accuracy

文件training.py

导入文件


import os
import numpy as np
import tensorflow as tf
import input_data
import model
  • 变量声明
N_CLASSES = 2 #猫和狗
IMG_W = 208  # resize图像,太大的话训练时间久
IMG_H = 208
BATCH_SIZE = 16
CAPACITY = 2000
MAX_STEP = 10000 # 一般大于10K
learning_rate = 0.0001 # 一般小于0.0001
  • 获取批次batch
train_dir = '/home/kevin/tensorflow/cats_vs_dogs/data/train/'
logs_train_dir = '/home/kevin/tensorflow/cats_vs_dogs/logs/train/'

train, train_label = input_data.get_files(train_dir)
train_batch,train_label_batch=input_data.get_batch(train,
                                train_label,
                                IMG_W,
                                IMG_H,
                                BATCH_SIZE, 
                                CAPACITY)      

操作定义

train_logits = model.inference(train_batch, BATCH_SIZE, N_CLASSES)
train_loss = model.losses(train_logits, train_label_batch)        
train_op = model.trainning(train_loss, learning_rate)
train__acc = model.evaluation(train_logits, train_label_batch)
summary_op = tf.summary.merge_all() #这个是log汇总记录

#产生一个会话
sess = tf.Session()  
#产生一个writer来写log文件
train_writer = tf.summary.FileWriter(logs_train_dir, sess.graph) 
 #产生一个saver来存储训练好的模型
saver = tf.train.Saver()
#所有节点初始化
sess.run(tf.global_variables_initializer()) 

#队列监控
coord = tf.train.Coordinator()
threads = tf.train.start_queue_runners(sess=sess, coord=coord)

进行batch的训练

try:
    #执行MAX_STEP步的训练,一步一个batch
    for step in np.arange(MAX_STEP):
        if coord.should_stop():
                break
        #启动以下操作节点,有个疑问,为什么train_logits在这里没有开启?
        _, tra_loss, tra_acc = sess.run([train_op, train_loss, train__acc])
        #每隔50步打印一次当前的loss以及acc,同时记录log,写入writer   
        if step % 50 == 0:
            print('Step %d, train loss = %.2f, train accuracy = %.2f%%' %(step, tra_loss, tra_acc*100.0))
            summary_str = sess.run(summary_op)
            train_writer.add_summary(summary_str, step)
        #每隔2000步,保存一次训练好的模型
        if step % 2000 == 0 or (step + 1) == MAX_STEP:
            checkpoint_path = os.path.join(logs_train_dir, 'model.ckpt')
            saver.save(sess, checkpoint_path, global_step=step)

except tf.errors.OutOfRangeError:
    print('Done training -- epoch limit reached')
finally:
    coord.request_stop()

测试图片

函数:def evaluate_one_image():


with tf.Graph().as_default():
       BATCH_SIZE = 1
       N_CLASSES = 2

       image = tf.cast(image_array, tf.float32)
       image = tf.image.per_image_standardization(image)
       image = tf.reshape(image, [1, 208, 208, 3])

       logit = model.inference(image, BATCH_SIZE, N_CLASSES)

       logit = tf.nn.softmax(logit)

       x = tf.placeholder(tf.float32, shape=[208, 208, 3])

       # you need to change the directories to yours.
       logs_train_dir = 'D:/Study/Python/Projects/Cats_vs_Dogs/Logs/train'


       saver = tf.train.Saver()

       with tf.Session() as sess:

           print("Reading checkpoints...")
           ckpt = tf.train.get_checkpoint_state(logs_train_dir)
           if ckpt and ckpt.model_checkpoint_path:
               global_step = ckpt.model_checkpoint_path.split('/')[-1].split('-')[-1]
               saver.restore(sess, ckpt.model_checkpoint_path)
               print('Loading success, global_step is %s' % global_step)
           else:
               print('No checkpoint file found')

           prediction = sess.run(logit, feed_dict={x: image_array})
           max_index = np.argmax(prediction)
           if max_index==0:
               print('This is a cat with possibility %.6f' %prediction[:, 0])
           else:
               print('This is a dog with possibility %.6f' %prediction[:, 1])

训练过程中按步骤测试图片

在获取文件时,取出训练图片的20%作为测试数据

函数:def get_files(file_dir, ratio):中修改

#所有的img和lab的list
all_image_list = temp[:, 0]
all_label_list = temp[:, 1]

#将所得List分为两部分,一部分用来训练tra,一部分用来测试val
#ratio是测试集的比例
n_sample = len(all_label_list)
n_val = math.ceil(n_sample*ratio) #测试样本数
n_train = n_sample - n_val # 训练样本数

tra_images = all_image_list[0:n_train]
tra_labels = all_label_list[0:n_train]
tra_labels = [int(float(i)) for i in tra_labels]
val_images = all_image_list[n_train:-1]
val_labels = all_label_list[n_train:-1]
val_labels = [int(float(i)) for i in val_labels]

return tra_images,tra_labels,val_images,val_labels

函数:def get_files(file_dir, ratio):中修改

获取train和validation的batch
train_batch, train_label_batch = input_train_val_split.get_batch(train,
                                                  train_label,
                                                  IMG_W,
                                                  IMG_H,
                                                  BATCH_SIZE, 
                                                  CAPACITY)
    val_batch, val_label_batch = input_train_val_split.get_batch(val,
                                                  val_label,
                                                  IMG_W,
                                                  IMG_H,
                                                  BATCH_SIZE, 
                                                  CAPACITY)
每隔200步,测试一批,同时记录log
if step % 200 == 0 or (step + 1) == MAX_STEP:
    val_images, val_labels = sess.run([val_batch, val_label_batch])
    val_loss, val_acc = sess.run([loss, acc], 
                                 feed_dict={x:val_images, y_:val_labels})
    print('**  Step %d, val loss = %.2f, val accuracy = %.2f%%  **' %(step, val_loss, val_acc*100.0))
    summary_str = sess.run(summary_op)
    val_writer.add_summary(summary_str, step)  

结果 
这张图片是猫的概率为0.987972,所用模型的训练步骤是6000步 
这里写图片描述

模型的评估主要有几个指标:平均准确率、识别的时间、loss下降变化等。Tensorflow提供了一个log可视化的工具tensroboard。要看到log就必须在训练时用summary去记录想要显示的东西,包括acc\loss甚至image。


Tensorboard的使用 
windows下,在CMD命令行或者shell界面下输入(在存放log文件的目录打开才有效,不然在chrome浏览器无法看见图):

tensorboard --logdir=D:\Study\Python\Projects\Cats_vs_Dogs\Logs\train
  • 1

然后打开浏览器输入返回的值:

127.0.0.1:6006
  • 1

进入tensorboard,查看各种log

这里写图片描述

这里写图片描述


这里写图片描述


这里写图片描述


这个不知道干嘛的

这里写图片描述



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值