我正在尝试使用slim tensorflow库微调inceptionv3模型。 在为其编写代码时,我无法理解某些事情。我试图阅读源代码(没有适当的文档)并找出一些东西,我能够微调它并保存检查点。以下是我遵循的步骤 1.我为我的训练数据创建了一个tf.record,这很好,现在我正在使用下面的代码读取数据。
import tensorflow as tf
import tensorflow.contrib.slim.nets as nets
import tensorflow.contrib.slim as slim
import matplotlib.pyplot as plt
import numpy as np
# get the data and labels here
data_path = '/home/sfarkya/nvidia_challenge/datasets/detrac/train1.tfrecords'
# Training setting
num_epochs = 100
initial_learning_rate = 0.0002
learning_rate_decay_factor = 0.7
num_epochs_before_decay = 5
num_classes = 5980
# load the checkpoint
model_path = '/home/sfarkya/nvidia_challenge/datasets/detrac/inception_v3.ckpt'
# log directory
log_dir = '/home/sfarkya/nvidia_challenge/datasets/detrac/fine_tuned_model'
with tf.Session() as sess:
feature = {'train/image': tf.FixedLenFeature([], tf.string),
'train/label': tf.FixedLenFeature([], tf.int64)}
# Create a list of filenames and pass it to a queue
filename_queue = tf.train.string_input_producer([data_path], num_epochs=1)
# Define a reader and read the next record
reader = tf.TFRecordReader()
_, serialized_example = reader.read(filename_queue)
# Decode the record read by the reader
features = tf.parse_single_example(serialized_example, features=feature)
# Convert the image data from string back to the numbers
image = tf.decode_raw(features['train/image'], tf.float32)
# Cast label data into int32
label = tf.cast(features['train/label'], tf.int32)
# Reshape image data into the original shape
image = tf.reshape(image, [128, 128, 3])
# Creates batches by randomly shuffling tensors
images, labels = tf.train.shuffle_batch([image, label], batch_size=64, capacity=128, num_threads=2,
min_after_dequeue=64)
现在我使用slim来调整模型,这就是代码。
init_op = tf.group(tf.global_variables_initializer(), tf.local_variables_initializer())
sess.run(init_op)
# Create a coordinator and run all QueueRunner objects
coord = tf.train.Coordinator()
threads = tf.train.start_queue_runners(coord=coord)
# load model
# load the inception model from the slim library - we are using inception v3
#inputL = tf.placeholder(tf.float32, (64, 128, 128, 3))
img, lbl = sess.run([images, labels])
one_hot_labels = slim.one_hot_encoding(lbl, num_classes)
with slim.arg_scope(slim.nets.inception.inception_v3_arg_scope()):
logits, inceptionv3 = nets.inception.inception_v3(inputs=img, num_classes=5980, is_training=True,
dropout_keep_prob=.6)
# Restore convolutional layers:
variables_to_restore = slim.get_variables_to_restore(exclude=['InceptionV3/Logits', 'InceptionV3/AuxLogits'])
init_fn = slim.assign_from_checkpoint_fn(model_path, variables_to_restore)
# loss function
loss = tf.losses.softmax_cross_entropy(onehot_labels=one_hot_labels, logits = logits)
total_loss = tf.losses.get_total_loss()
# train operation
train_op = slim.learning.create_train_op(total_loss + loss, optimizer= tf.train.AdamOptimizer(learning_rate=1e-4))
print('Im here')
# Start training.
slim.learning.train(train_op, log_dir, init_fn=init_fn, save_interval_secs=20, number_of_steps= 10)
现在我对代码的问题很少,我无法弄清楚。一旦,代码达到 slim.learning.train 我看不到任何打印,但它是训练,我可以在日志中看到。现在, 1.如何给代码提供时代数?现在它一步一步地运行,每一步都有batch_size = 64 2.如何确保在代码 tf.train.shuffle_batch 中我不重复我的图像并且我正在训练整个数据集? 3.如何在培训期间打印损失值?
答案 0 :(得分:1)
以下是您的问题的答案。
您无法直接向slim.learning.train
提供纪元。相反,您将批次数作为参数。它被称为number_of_steps
。它用于在line 709上设置名为should_stop_op
的操作。我假设您知道如何将时期数转换为批次。
我不认为shuffle_batch
函数会重复图像,因为它在内部使用RandomShuffleQueue。根据{{3}},RandomShuffleQueue
使用后台线程将元素排队为:
size(queue) < capacity
时:
它将元素列为:
number of elements dequeued < batch_size
:
size(queue) >= min_after_dequeue + 1
元素。所以在我看来,元素重复的可能性很小,因为在dequeuing
操作中,所选元素将从队列中删除。因此无需更换即可提取样品。
是否会为每个纪元创建一个新队列?
输入tf.train.shuffle_batch
的张量为image
和label
,最终来自filename_queue
。如果该队列无限期地生成TFRecord文件名,那么我不认为shuffle_batch
将创建一个新队列。您还可以创建像this answer这样的玩具代码,以了解shuffle_batch
的工作原理。
接下来,如何训练整个数据集?在您的代码中,以下行获取TFRecord文件名列表。
filename_queue = tf.train.string_input_producer([data_path], num_epochs=1)
如果filename_queue
涵盖了您拥有的所有TFRecords,那么您肯定会对整个数据集进行培训。现在,如何改变整个数据集是另一个问题。正如@mrry提到的this,没有支持(但是,AFAIK)来重新排列内存不足的数据集。因此,最好的方法是准备数据集的许多分片,使每个分片包含大约1024个示例。将TFRecord文件名列表随机播放为:
filename_queue = tf.train.string_input_producer([data_path], shuffle=True, capacity=1000)
请注意,我删除了num_epochs = 1
参数并设置了shuffle=True
。这样它将无限期地生成TFRecord文件名的 shuffled 列表。现在,在每个文件上,如果使用tf.train.shuffle_batch
,您将获得接近统一的随机播放。基本上,由于每个分片中的示例数量趋向于1,因此您的随机播放将变得越来越均匀。我不想设置num_epochs
,而是使用前面提到的number_of_steps
参数终止训练。
logging.info('total loss = %f', total_loss)
。我不知道是否有更简单的方法。另一种不更改代码的方法是在Tensorboard中查看摘要。有关如何在Tensorboard中查看摘要的非常有用的文章,包括本答案末尾的链接。通常,您需要执行以下操作。
summary
对象。summary
。summary
操作现在,如果您使用slim.learning.train
,则已自动完成步骤5和6。
对于前4个步骤,您可以检查文件training.py
。第472行显示了如何创建summaries
对象。第490,512和536行将相关变量写入summaries
。第549行合并所有摘要,第553行创建操作。您可以将此操作传递给slim.learning.train
,还可以指定编写摘要的频率。在我看来,除了你想要进行特定的调试之外,不要将损失,total_loss,准确度和学习率之外的任何内容写入摘要中。如果你写直方图,那么对于像ResNet-50这样的网络来说,张量板文件可能需要几十个小时才能加载(我的张量板文件曾经是28 GB,这需要12个小时来加载6天的进度!)。顺便说一句,你实际上可以使用train_image_classifier.py
文件进行微调,你将跳过上面的大部分步骤。但是,我更喜欢这个,因为你要学到很多东西。
请参阅train_image_classifier.py
部分,了解如何在浏览器中查看进度。
补充说明:
您可以执行以下操作,而不是最小化total_loss + loss
:
loss = tf.losses.softmax_cross_entropy(onehot_labels=one_hot_labels, logits = logits)
tf.losses.add_loss(loss)
total_loss = tf.losses.get_total_loss()
train_op = slim.learning.create_train_op(total_loss, optimizer=tf.train.AdamOptimizer(learning_rate=1e-4))
我在学习Tensorflow时发现launching tensorboard帖子非常有用。