tensorflow从0开始(7)——利用tensorflow进行开发的准备工作(续1)

tensorflow开发流程——表情分析(前期准备)

Cifar10程序分析

为什么要做这个解读,个人看来,Cifar是一个图像多分类的经典案例。学习tensorflow以来,还没有任何实质性的进展。个人认为把Cifar问题的输入,换成其它的分类图像数据,应该也可以训练出来不同的分类模型,来对不同的图像数据集进行分类,所以先要搞清楚Cifar Demo的整个过程(关于此观点是否成立,待弄懂之后,导入自己的数据集,简单测试下,再做修改)。下面只做其中关于train部分代码的解读。 
cifar10_train的流程如下:

  • 下载提取数据(如果数据不存在)(cifar10_input.py)
  • 读取数据(cifar10_input.py)
  • 创建模型CNN并初始化参数(cifar10.py)
  • 利用模型来预测数据
  • 将数据的预测值和真实值进行比对,进行loss运算,并通过梯度下降原则,不断调整模型的参数

整个Cifar10相关的代码位于路径下,~/libsource/tensorflow/为你自己的tensorflow源码路径:

~/libsource/tensorflow/tensorflow/tensorflow/models/image/cifar10

Cifar10数据下载

Cifar10的官方例子中,已经提供了数据的下载代码,如下:

tf.app.flags.DEFINE_string('data_dir', '/tmp/cifar10_data',"""Path to the CIFAR-10 data directory.""")

DATA_URL = 'http://www.cs.toronto.edu/~kriz/cifar-10-binary.tar.gz'

def maybe_download_and_extract():
  """Download and extract the tarball from Alex's website."""C
  dest_directory = FLAGS.data_dir
  if not os.path.exists(dest_directory):
    os.makedirs(dest_directory)
  filename = DATA_URL.split('/')[-1]
  filepath = os.path.join(dest_directory, filename)
  if not os.path.exists(filepath):
    def _progress(count, block_size, total_size):
      sys.stdout.write('\r>> Downloading %s %.1f%%' % (filename,
          float(count * block_size) / float(total_size) * 100.0))
      sys.stdout.flush()
    filepath, _ = urllib.request.urlretrieve(DATA_URL, filepath, _progress)
    print()
    statinfo = os.stat(filepath)
    print('Successfully downloaded', filename, statinfo.st_size, 'bytes.')
    tarfile.open(filepath, 'r:gz').extractall(dest_directory)

代码中:urllib.request.urlretrieve用来下载数据,过程中会毁掉_progress函数,对下载进度进行显示。_progress(count, block_size, total_size)的三个参数分别指下载的数据块数目,一个数据块的大小,服务器端的总的数据大小。 
下载完成后利用tarfile进行解压。 
tarfile.open(filepath, ‘r:gz’).extractall(dest_directory),open返回一个tarfile对象,调用tarfile的extreactall方法将压缩文件解压到目标目录。 
https://docs.python.org/2/library/tarfile.html

Cifar数据读入

我本来的想法是把这部分,改为opencv的读入。但是读到这一部分的实现时,我还是有点搞不清楚的。 
整个过程中,查阅了官网提供的很多资料,但还是不能很好的理解,但是认识还是加深不少。以下是我觉得可能会有帮助的几个官网的链接: 
关于线程和队列的: 
https://www.tensorflow.org/versions/r0.9/how_tos/threading_and_queues/index.html 
关于tensorflow中读入数据的集中方式: 
https://www.tensorflow.org/versions/r0.9/how_tos/reading_data/index.html 
关于输入和读入器的: 
https://www.tensorflow.org/versions/r0.9/api_docs/python/io_ops.html#batching-at-the-end-of-an-input-pipeline

关于读入数据,我自己写的验证代码如下:

#first we summary the input image by queue

#first file path
file_path='/tmp/cifar10_data/cifar-10-batches-bin/data_batch_1.bin'
data_dir='/tmp/cifar10_data/cifar-10-batches-bin'
summary_dir='/tmp/tf_summary'

#import lib
import tensorflow as tf


IMAGE_SIZE=24
NUM_CLASSES=10
NUM_EXAMPLES_PER_EPOCH_FOR_TRAIN = 50000

#define input image format
class CifarData(object):
    pass

img=CifarData()
img.height = 32
img.width = 32
img.depth = 3

img_bytes=img.height * img.width * img.depth

label_bytes=1

record_bytes=label_bytes+img_bytes

#define filequeue
file_queue=tf.train.string_input_producer([file_path])

#read data from queue
reader = tf.FixedLengthRecordReader(record_bytes=record_bytes)
img.key,value = reader.read(file_queue)
num_recs = reader.num_records_produced
record_bytes=tf.decode_raw(value,tf.uint8)
img.label=tf.cast(tf.slice(record_bytes,[0],[label_bytes]),tf.int32)
depth_major=tf.reshape(tf.slice(record_bytes,[label_bytes],[img_bytes]),[img.depth,img.height,img.width])
img.unit8image=tf.transpose(depth_major,[1,2,0])

img_summary=tf.reshape(img.unit8image, [-1,32,32,3])
tf.image_summary('img',img_summary)

reshaped_img=tf.cast(img.unit8image, tf.float32)
height = IMAGE_SIZE
width=IMAGE_SIZE

distorted_img=tf.random_crop(reshaped_img,[height,width,3])
distorted_img=tf.image.random_flip_left_right(distorted_img)
distorted_img=tf.image.random_brightness(distorted_img,max_delta=63)
distorted_img=tf.image.random_contrast(distorted_img,lower=0.2,upper=1.8)
float_img= tf.image.per_image_whitening(distorted_img)
min_queue_examples=20000

num_preprocess_threads = 16

images=tf.train.shuffle_batch([float_img],128,num_threads=num_preprocess_threads,capacity=min_queue_examples+3*128,min_after_dequeue=min_queue_examples)

tf.image_summary('images',images,100)

distorted_img_summary=tf.reshape(distorted_img,[-1, height,width,3])
tf.image_summary('img1',distorted_img_summary,100)

sess = tf.InteractiveSession()

tf.initialize_all_variables().run()

merged=tf.merge_all_summaries()

print('begin to start queue')
tf.train.start_queue_runners(sess=sess)
print('queue has been started')

writer=tf.train.SummaryWriter(summary_dir,sess.graph)


for i in range(1000):
    summary, img_, key_ = sess.run([merged,value,img.key])
    print("step%d: %s"%(i,key_))
    writer.add_summary(summary,i)

输出结果如下,说明利用上述的queue的读入方式,程序每次自动的更新了数据:

begin to start queue
queue has been started
step0: /tmp/cifar10_data/cifar-10-batches-bin/data_batch_1.bin:332
step1: /tmp/cifar10_data/cifar-10-batches-bin/data_batch_1.bin:456
step2: /tmp/cifar10_data/cifar-10-batches-bin/data_batch_1.bin:492
step3: /tmp/cifar10_data/cifar-10-batches-bin/data_batch_1.bin:818
step4: /tmp/cifar10_data/cifar-10-batches-bin/data_batch_1.bin:910
step5: /tmp/cifar10_data/cifar-10-batches-bin/data_batch_1.bin:994
step6: /tmp/cifar10_data/cifar-10-batches-bin/data_batch_1.bin:1174
step7: /tmp/cifar10_data/cifar-10-batches-bin/data_batch_1.bin:1302
step8: /tmp/cifar10_data/cifar-10-batches-bin/data_batch_1.bin:1529
step9: /tmp/cifar10_data/cifar-10-batches-bin/data_batch_1.bin:1561

tensorboard的输出图像如下: 


queue_input_summary.png 
上述图像说明一次reader的操作,能够将一个文件里的图像读出,并进行batch,但是这一步是怎么做到的,还不清楚。这个要后续在来研究。。。。。。。。。。。。。。。。。 
下面这段代码,是如何做到读出一系列数据的,不理解。。。。。。。。。。。。。暂且跳过。

img.key,value = reader.read(file_queue)

Cifar10的Model

例子中的代码,模型会对神经网络的各个参数给一个初始值,利用初始的神经网络,对图片进行推断,会得出一个分类。然后根据这个分类与正确的分类的比对,不断地调整CNN的参数,使得分类结果越来越准确,训练得出最终的模型。

def inference(images):
  """Build the CIFAR-10 model.

  Args:
    images: Images returned from distorted_inputs() or inputs().

  Returns:
    Logits.
  """
  # We instantiate all variables using tf.get_variable() instead of
  # tf.Variable() in order to share variables across multiple GPU training runs.
  # If we only ran this model on a single GPU, we could simplify this function
  # by replacing all instances of tf.get_variable() with tf.Variable().
  #
  # conv1
  with tf.variable_scope('conv1') as scope:
    kernel = _variable_with_weight_decay('weights', shape=[5, 5, 3, 64],
                                         stddev=1e-4, wd=0.0)
    conv = tf.nn.conv2d(images, kernel, [1, 1, 1, 1], padding='SAME')
    biases = _variable_on_cpu('biases', [64], tf.constant_initializer(0.0))
    bias = tf.nn.bias_add(conv, biases)
    conv1 = tf.nn.relu(bias, name=scope.name)
    _activation_summary(conv1)

  # pool1
  pool1 = tf.nn.max_pool(conv1, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1],
                         padding='SAME', name='pool1')
  # norm1
  norm1 = tf.nn.lrn(pool1, 4, bias=1.0, alpha=0.001 / 9.0, beta=0.75,
                    name='norm1')

  # conv2
  with tf.variable_scope('conv2') as scope:
    kernel = _variable_with_weight_decay('weights', shape=[5, 5, 64, 64],
                                         stddev=1e-4, wd=0.0)
    conv = tf.nn.conv2d(norm1, kernel, [1, 1, 1, 1], padding='SAME')
    biases = _variable_on_cpu('biases', [64], tf.constant_initializer(0.1))
    bias = tf.nn.bias_add(conv, biases)
    conv2 = tf.nn.relu(bias, name=scope.name)
    _activation_summary(conv2)

  # norm2
  norm2 = tf.nn.lrn(conv2, 4, bias=1.0, alpha=0.001 / 9.0, beta=0.75,
                    name='norm2')
  # pool2
  pool2 = tf.nn.max_pool(norm2, ksize=[1, 3, 3, 1],
                         strides=[1, 2, 2, 1], padding='SAME', name='pool2')

  # local3
  with tf.variable_scope('local3') as scope:
    # Move everything into depth so we can perform a single matrix multiply.
    reshape = tf.reshape(pool2, [FLAGS.batch_size, -1])
    dim = reshape.get_shape()[1].value
    weights = _variable_with_weight_decay('weights', shape=[dim, 384],
                                          stddev=0.04, wd=0.004)
    biases = _variable_on_cpu('biases', [384], tf.constant_initializer(0.1))
    local3 = tf.nn.relu(tf.matmul(reshape, weights) + biases, name=scope.name)
    _activation_summary(local3)

  # local4
  with tf.variable_scope('local4') as scope:
    weights = _variable_with_weight_decay('weights', shape=[384, 192],
                                          stddev=0.04, wd=0.004)
    biases = _variable_on_cpu('biases', [192], tf.constant_initializer(0.1))
    local4 = tf.nn.relu(tf.matmul(local3, weights) + biases, name=scope.name)
    _activation_summary(local4)

  # softmax, i.e. softmax(WX + b)
  with tf.variable_scope('softmax_linear') as scope:
    weights = _variable_with_weight_decay('weights', [192, NUM_CLASSES],
                                          stddev=1/192.0, wd=0.0)
    biases = _variable_on_cpu('biases', [NUM_CLASSES],
                              tf.constant_initializer(0.0))
    softmax_linear = tf.add(tf.matmul(local4, weights), biases, name=scope.name)
    _activation_summary(softmax_linear)

  return softmax_linear

根据loss不断修正CNN模型参数

利用给出的模型推测结果:

    # Build a Graph that computes the logits predictions from the
    # inference model.
    logits = cifar10.inference(images)

将推测结果与图片的真实分类进行比对

    # Calculate loss.
    loss = cifar10.loss(logits, labels)

loss函数的代码:

def loss(logits, labels):
  """Add L2Loss to all the trainable variables.

  Add summary for "Loss" and "Loss/avg".
  Args:
    logits: Logits from inference().
    labels: Labels from distorted_inputs or inputs(). 1-D tensor
            of shape [batch_size]

  Returns:
    Loss tensor of type float.
  """
  # Calculate the average cross entropy loss across the batch.
  labels = tf.cast(labels, tf.int64)
  cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(
      logits, labels, name='cross_entropy_per_example')
  cross_entropy_mean = tf.reduce_mean(cross_entropy, name='cross_entropy')
  tf.add_to_collection('losses', cross_entropy_mean)

  # The total loss is defined as the cross entropy loss plus all of the weight
  # decay terms (L2 loss).
  return tf.add_n(tf.get_collection('losses'), name='total_loss')

loss函数中主要是计算了推测分类结果与实际分类结果的交叉熵,交叉熵越小,证明模型越好。 
根据交叉熵,利用梯度下降原则,迭代计算,不断寻找loss的全局最小值,完成训练。代码如下:

def train(total_loss, global_step):
  """Train CIFAR-10 model.

  Create an optimizer and apply to all trainable variables. Add moving
  average for all trainable variables.

  Args:
    total_loss: Total loss from loss().
    global_step: Integer Variable counting the number of training steps
      processed.
  Returns:
    train_op: op for training.
  """
  # Variables that affect learning rate.
  num_batches_per_epoch = NUM_EXAMPLES_PER_EPOCH_FOR_TRAIN / FLAGS.batch_size
  decay_steps = int(num_batches_per_epoch * NUM_EPOCHS_PER_DECAY)

  # Decay the learning rate exponentially based on the number of steps.
  lr = tf.train.exponential_decay(INITIAL_LEARNING_RATE,
                                  global_step,
                                  decay_steps,
                                  LEARNING_RATE_DECAY_FACTOR,
                                  staircase=True)
  tf.scalar_summary('learning_rate', lr)

  # Generate moving averages of all losses and associated summaries.
  loss_averages_op = _add_loss_summaries(total_loss)

  # Compute gradients.
  with tf.control_dependencies([loss_averages_op]):
    opt = tf.train.GradientDescentOptimizer(lr)
    grads = opt.compute_gradients(total_loss)

  # Apply gradients.
  apply_gradient_op = opt.apply_gradients(grads, global_step=global_step)

  # Add histograms for trainable variables.
  for var in tf.trainable_variables():
    tf.histogram_summary(var.op.name, var)

  # Add histograms for gradients.
  for grad, var in grads:
    if grad is not None:
      tf.histogram_summary(var.op.name + '/gradients', grad)

  # Track the moving averages of all trainable variables.
  variable_averages = tf.train.ExponentialMovingAverage(
      MOVING_AVERAGE_DECAY, global_step)
  variables_averages_op = variable_averages.apply(tf.trainable_variables())

  with tf.control_dependencies([apply_gradient_op, variables_averages_op]):
    train_op = tf.no_op(name='train')

  return train_op

其中根据学习率(learning rate)得出一个梯度下降的优化器(GradientDescentOptimizer),然后计算出一个下降的梯度值,并将此梯度作用在模型上,优化模型。

整个训练过程:

整个训练过程的代码如下:

def train():
  """Train CIFAR-10 for a number of steps."""
  with tf.Graph().as_default():
    global_step = tf.Variable(0, trainable=False)

    # Get images and labels for CIFAR-10.
    images, labels = cifar10.distorted_inputs()

    # Build a Graph that computes the logits predictions from the
    # inference model.
    logits = cifar10.inference(images)

    # Calculate loss.
    loss = cifar10.loss(logits, labels)

    # Build a Graph that trains the model with one batch of examples and
    # updates the model parameters.
    train_op = cifar10.train(loss, global_step)

    # Create a saver.
    saver = tf.train.Saver(tf.all_variables())

    # Build the summary operation based on the TF collection of Summaries.
    summary_op = tf.merge_all_summaries()

    # Build an initialization operation to run below.
    init = tf.initialize_all_variables()

    # Start running operations on the Graph.
    sess = tf.Session(config=tf.ConfigProto(
        log_device_placement=FLAGS.log_device_placement))
    sess.run(init)

    # Start the queue runners.
    tf.train.start_queue_runners(sess=sess)

    summary_writer = tf.train.SummaryWriter(FLAGS.train_dir, sess.graph)

    for step in xrange(FLAGS.max_steps):
      start_time = time.time()
      _, loss_value = sess.run([train_op, loss])
      duration = time.time() - start_time

      assert not np.isnan(loss_value), 'Model diverged with loss = NaN'

      if step % 10 == 0:
        num_examples_per_step = FLAGS.batch_size
        examples_per_sec = num_examples_per_step / duration
        sec_per_batch = float(duration)

        format_str = ('%s: step %d, loss = %.2f (%.1f examples/sec; %.3f '
                      'sec/batch)')
        print (format_str % (datetime.now(), step, loss_value,
                             examples_per_sec, sec_per_batch))

      if step % 100 == 0:
        summary_str = sess.run(summary_op)
        summary_writer.add_summary(summary_str, step)

      # Save the model checkpoint periodically.
      if step % 1000 == 0 or (step + 1) == FLAGS.max_steps:
        checkpoint_path = os.path.join(FLAGS.train_dir, 'model.ckpt')
        saver.save(sess, checkpoint_path, global_step=step)

train过程如下图: 


待续。。。。。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值