赞
踩
本教程提供了使用深度学习框架tensorflow/models中的slim实现图像的分类问题,包括数据处理、网络训练、测试以及实时显示等。
运行环境:
Ubuntu18.04
cuda:10.0
cudnn: 7.6.5
Tensorflow:1.14
models: 1.13.0
环境的配置可参考我的另一篇博客:使用Tensorflow object detection API训练自己的数据教程中的环境配置教程。
在slim文件夹下建立一个classification_test的文件夹,用来放置本教程中需要用到的文件。
这里以官网提供的Flowers为例,对数据集进行下载。
在classification_test文件夹下建立data文件夹,用来存放数据。
cd slim/classification_test/data
wget http://download.tensorflow.org/example_images/flower_photos.tgz
tar zxf flower_photos.tgz
数据结构如下:
flower_photos
├── daisy
│ ├── 100080576_f52e8ee070_n.jpg
│ └── …
├── dandelion
├── LICENSE.txt
├── roses
├── sunflowers
└── tulips
数据集中共包含5种不同的花,每种文件夹都包含相应花的图片,如daisy文件夹下的图像如下:
由于实际情况中我们自己的数据集并不一定把图片按类别放在不同的文件夹里,故我们生成list.txt来表示图片路径与标签的关系。
编写create_list.py文件如下:
import os
class_names_to_ids = {'daisy': 0, 'dandelion': 1, 'roses': 2, 'sunflowers': 3, 'tulips': 4}
data_dir = 'flower_photos/'
output_path = 'list.txt'
fd = open(output_path, 'w')
for class_name in class_names_to_ids.keys():
images_list = os.listdir(data_dir + class_name)
for image_name in images_list:
fd.write('{}/{} {}\n'.format(class_name, image_name, class_names_to_ids[class_name]))
fd.close()
data_dir = 'flower_photos/'对应实际的数据集文件夹路径。
运行生成 list.txt 文件。
为了方便后期查看label标签,也可以定义labels.txt:
daisy
dandelion
roses
sunflowers
tulips
编写 create_train_val_list.py 文件,随机生成训练集与验证集:
import random _NUM_VALIDATION = 350 _RANDOM_SEED = 0 list_path = 'list.txt' train_list_path = 'list_train.txt' val_list_path = 'list_val.txt' fd = open(list_path) lines = fd.readlines() fd.close() random.seed(_RANDOM_SEED) random.shuffle(lines) fd = open(train_list_path, 'w') for line in lines[_NUM_VALIDATION:]: fd.write(line) fd.close() fd = open(val_list_path, 'w') for line in lines[:_NUM_VALIDATION]: fd.write(line) fd.close()
_NUM_VALIDATION = 350为随机生成的验证数据集的数量。
运行生成list_train.txt和list_val.txt两个文件。
编写文件 create_TFRecord.py 如下:
import sys sys.path.insert(0, '../models/slim/') from datasets import dataset_utils import math import os import tensorflow as tf def convert_dataset(list_path, data_dir, output_dir, _NUM_SHARDS=5): fd = open(list_path) lines = [line.split() for line in fd] fd.close() num_per_shard = int(math.ceil(len(lines) / float(_NUM_SHARDS))) with tf.Graph().as_default(): decode_jpeg_data = tf.placeholder(dtype=tf.string) decode_jpeg = tf.image.decode_jpeg(decode_jpeg_data, channels=3) with tf.Session('') as sess: for shard_id in range(_NUM_SHARDS): output_path = os.path.join(output_dir, 'data_{:05}-of-{:05}.tfrecord'.format(shard_id, _NUM_SHARDS)) tfrecord_writer = tf.python_io.TFRecordWriter(output_path) start_ndx = shard_id * num_per_shard end_ndx = min((shard_id + 1) * num_per_shard, len(lines)) for i in range(start_ndx, end_ndx): sys.stdout.write('\r>> Converting image {}/{} shard {}'.format( i + 1, len(lines), shard_id)) sys.stdout.flush() image_data = tf.gfile.FastGFile(os.path.join(data_dir, lines[i][0]), 'rb').read() image = sess.run(decode_jpeg, feed_dict={decode_jpeg_data: image_data}) height, width = image.shape[0], image.shape[1] example = dataset_utils.image_to_tfexample( image_data, b'jpg', height, width, int(lines[i][1])) tfrecord_writer.write(example.SerializeToString()) tfrecord_writer.close() sys.stdout.write('\n') sys.stdout.flush() os.system('mkdir -p train') convert_dataset('list_train.txt', 'flower_photos', 'train/') os.system('mkdir -p val') convert_dataset('list_val.txt', 'flower_photos', 'val/')
所有slim图像分类模型下载网址
在classification_test文件夹下建立checkpoints文件夹,存放预训练文件,下载并解压模型。
wget http://download.tensorflow.org/models/inception_resnet_v2_2016_08_30.tar.gz
tar zxf inception_resnet_v2_2016_08_30.tar.gz
官方提供了读入Flowers数据集的代码models/slim/datasets/flowers.py,将其修改成能读入上面定义的通用数据集。
在classification_test文件夹下建立并编写dataset_classification.py文件:
import os import tensorflow as tf slim = tf.contrib.slim def get_dataset(dataset_dir, num_samples, num_classes, labels_to_names_path=None, file_pattern='*.tfrecord'): file_pattern = os.path.join(dataset_dir, file_pattern) keys_to_features = { 'image/encoded': tf.FixedLenFeature((), tf.string, default_value=''), 'image/format': tf.FixedLenFeature((), tf.string, default_value='jpg'), 'image/class/label': tf.FixedLenFeature( [], tf.int64, default_value=tf.zeros([], dtype=tf.int64)), } items_to_handlers = { 'image': slim.tfexample_decoder.Image(), 'label': slim.tfexample_decoder.Tensor('image/class/label'), } decoder = slim.tfexample_decoder.TFExampleDecoder(keys_to_features, items_to_handlers) items_to_descriptions = { 'image': 'A color image of varying size.', 'label': 'A single integer between 0 and ' + str(num_classes - 1), } labels_to_names = None if labels_to_names_path is not None: fd = open(labels_to_names_path) labels_to_names = {i : line.strip() for i, line in enumerate(fd)} fd.close() return slim.dataset.Dataset( data_sources=file_pattern, reader=tf.TFRecordReader, decoder=decoder, num_samples=num_samples, items_to_descriptions=items_to_descriptions, num_classes=num_classes, labels_to_names=labels_to_names)
官方提供了训练脚本:train_image_classifier.py
将其修改以适应自己的数据集,修改内容如下:
from datasets import dataset_factory
修改成
import dataset_classification
dataset = dataset_factory.get_dataset(
FLAGS.dataset_name, FLAGS.dataset_split_name, FLAGS.dataset_dir)
修改成
dataset = dataset_classification.get_dataset(
FLAGS.dataset_dir, FLAGS.num_samples, FLAGS.num_classes, FLAGS.labels_to_names_path)
tf.app.flags.DEFINE_string(
'dataset_dir', None, 'The directory where the dataset files are stored.')
后面加入:
tf.app.flags.DEFINE_integer(
'num_samples', 3320, 'Number of samples.')
tf.app.flags.DEFINE_integer(
'num_classes', 5, 'Number of classes.')
tf.app.flags.DEFINE_string(
'labels_to_names_path', None, 'Label names file path.')
tf.app.flags.DEFINE_float('learning_rate', 0.01, 'Initial learning rate.') tf.app.flags.DEFINE_float( 'end_learning_rate', 0.0001, 'The minimal end learning rate used by a polynomial decay learning rate.') tf.app.flags.DEFINE_float( 'label_smoothing', 0.0, 'The amount of label smoothing.') tf.app.flags.DEFINE_float( 'learning_rate_decay_factor', 0.94, 'Learning rate decay factor.') tf.app.flags.DEFINE_integer( # batch_size 'batch_size', 32, 'The number of samples in each batch.') tf.app.flags.DEFINE_integer( 'train_image_size', None, 'Train image size') tf.app.flags.DEFINE_integer('max_number_of_steps', 300000, # max_steps 'The maximum number of training steps.')
python train_image_classifier.py \
--train_dir=train_logs \
--dataset_dir=./data/train \
--num_samples=3320 \
--num_classes=5 \
--labels_to_names_path=./data/labels.txt \
--model_name=inception_resnet_v2 \
--checkpoint_path=./checkpoints/inception_resnet_v2_2016_08_30.ckpt \
--checkpoint_exclude_scopes=InceptionResnetV2/Logits,InceptionResnetV2/AuxLogits \
--trainable_scopes=InceptionResnetV2/Logits,InceptionResnetV2/AuxLogits
bash train.sh
开始训练!!!
官方提供了验证脚本:eval_image_classifier.py
将其修改以适应自己的数据集,修改内容如下:
from datasets import dataset_factory
修改为:
from datasets import dataset_classification
dataset = dataset_factory.get_dataset(
FLAGS.dataset_name, FLAGS.dataset_split_name, FLAGS.dataset_dir)
修改为:
dataset = dataset_classification.get_dataset(
FLAGS.dataset_dir, FLAGS.num_samples, FLAGS.num_classes, FLAGS.labels_to_names_path)
tf.app.flags.DEFINE_string(
'dataset_dir', None, 'The directory where the dataset files are stored.')
后面加入:
tf.app.flags.DEFINE_integer(
'num_samples', 350, 'Number of samples.')
tf.app.flags.DEFINE_integer(
'num_classes', 5, 'Number of classes.')
tf.app.flags.DEFINE_string(
'labels_to_names_path', None, 'Label names file path.')
python eval_image_classifier.py \
--checkpoint_path=train_logs \
--eval_dir=eval_logs \
--dataset_dir=./data/val \
--num_samples=350 \
--num_classes=5 \
--model_name=inception_resnet_v2
bash eval.sh
开始验证!!!
运行
tensorboard --logdir train_logs/ --port 6007
tensorboard --logdir eval_logs/ --port 6007
分别可视化训练和验证的结果。
在训练完成后,在train_log文件夹内会生成 .data .index 和 .meta三个文件,需要将其导出转化成 .pb文件,方便后续的调用。
建立export_inference_graph.sh文件,调用export_inference_graph.py文件对网络模型体系进行导出到output_model_pb文件夹内。
python export_inference_graph.py \
--alsologtostderr \
--model_name=inception_resnet_v2 \
--output_file=./output_model_pb/inception_resnet_v2_inf_graph.pb \
--dataset_name flowers
tensorflow在训练过程中,通常不会将权重数据保存的格式文件里,反而是分开保存在一个叫checkpoint的检查点文件里,当初始化时,再通过模型文件里的变量Op节点来从checkoupoint文件读取数据并初始化变量。这种模型和权重数据分开保存的情况,使得发布产品时不是那么方便,所以便有了freeze_graph.py脚本文件用来将这两文件整合合并成一个文件。
python3 -m tensorflow.python.tools.freeze_graph \
--input_graph output_model_pb/inception_resnet_v2_inf_graph.pb \
--input_checkpoint ./train_logs/model.ckpt-306187 \
--input_binary true \
--output_node_names InceptionResnetV2/Logits/Predictions \
--output_graph ./output_model_pb/frozen_graph.pb
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。