使⽤TensorFlow训练模型的基本流程本⽂已在机器视觉与算法建模发布,转载请联系我。
使⽤TensorFlow的基本流程
本篇⽂章将介绍使⽤tensorflow的训练模型的基本流程,包括制作读取TFRecord,训练和保存模型,读取模型。
准备
语⾔:Python3
库:tensorflow、cv2、numpy、matplotlib
数据集:Chars74K dataset 的数字部分
⽹络:CNN
所有代码已经上传⾄github:
TFRecord
TensorFlow提供了⼀种统⼀的格式来存储数据,这个格式就是TFRecord.
message Example {
Features features = 1;
};
message Features{
map<string,Feature> featrue = 1;
};
message Feature{
oneof kind{
BytesList bytes_list = 1;
FloatList float_list = 2;
Int64List int64_list = 3;
}
};
从代码中我们可以看到, tf.train.Example 包含了⼀个字典,它的键是⼀个字符串,值为Feature,Feature可以取值为字符串(BytesList)、浮点数列表(FloatList)、整型数列表(Int64List)。
写⼊⼀个TFRecord⼀般分为三步:
读取需要转化的数据
将数据转化为Example Protocol Buffer,并写⼊这个数据结构
通过将数据转化为字符串后,通过TFRecordWriter写出
⽅法⼀
这次我们的数据是分别保存在多个⽂件夹下的,因此读取数据最直接的⽅法是遍历⽬录下所有⽂件,然后读⼊写出TFRecord⽂件。该⽅法对应⽂件MakeTFRecord.py,我们来看关键代码
filenameTrain = 'TFRecord/train.tfrecords'
filenameTest = 'TFRecord/test.tfrecords'
writerTrain = tf.python_io.TFRecordWriter(filenameTrain)
writerTest = tf.python_io.TFRecordWriter(filenameTest)
folders = os.listdir(HOME_PATH)
for subFoldersName in folders:
label = transform_label(subFoldersName)
path = os.path.join(HOME_PATH, subFoldersName) # ⽂件夹路径
subFoldersNameList = os.listdir(path)
i = 0
for imageName in subFoldersNameList:
imagePath = os.path.join(path, imageName)
images = cv2.imread(imagePath)
res = size(images, (128, 128), interpolation=cv2.INTER_CUBIC)
image_raw_data = string()
example = tf.train.Example(ain.Features(feature={
'label': _int64_feature(label),
'image_raw': _bytes_feature(image_raw_data)
}))
if i <= len(subFoldersNameList) * 3 / 4:
writerTrain.write(example.SerializeToString())
else:
writerTest.write(example.SerializeToString())
i += 1
在做数据的时候,我打算将3/4的数据⽤做训练集,剩下的1/4数据作为测试集,⽅便起见,将其保存为两个⽂件。
基本流程就是遍历Fnt⽬录下的所有⽂件夹,再进⼊⼦⽂件夹遍历其⽬录下的图⽚⽂件,然后⽤OpenCV的imread⽅法将其读⼊,再将图⽚数据转化为字符串。在TFRecord提供的数据结构中_bytes_feature'是存储字符串的。<br> 以上将图⽚成功读⼊并写⼊了TFRecord的数据结构中,那图⽚对应的标签怎么办呢? ``` Python def transform_label(folderName): label_dict = { 'Sample001': 0, 'Sample002': 1,
'Sample003': 2, 'Sample004': 3, 'Sample005': 4, 'Sample006': 5, 'Sample007': 6, 'Sample008': 7, 'Sample009': 8, 'Sample010': 9,
'Sample011': 10, } return label_dict[folderName] ``` 我建⽴了⼀个字典,由于⼀个⽂件下的图⽚都是同⼀类的,所以将图⽚对应的⽂件夹名字与它所对应的标签,产⽣映射关系。代码中label = transform_label(subFoldersName)`通过该⽅法获得,图⽚的标签。
⽅法⼆
在使⽤⽅法⼀产⽣的数据训练模型,会发现⾮常容易产⽣过拟合。因为我们在读数据的时候是将它打包成batch读⼊的,虽然可以使
⽤tf.train.shuffle_batch⽅法将队列中的数据打乱再读⼊,但是由于⼀个类中的数据过多,会导致即便打乱后也是同⼀个类中的数据。例如:数字0有1000个样本,假设你读取的队列长达1000个,这样即便打乱队列后读取的图⽚任然是0。这在训练时容易过拟合。为了避免这种情况发⽣,我的想法是在做数据时将图⽚打乱后写⼊。对应⽂件MakeTFRecord2.py,关键代码如下
folders = os.listdir(HOME_PATH)
for subFoldersName in folders:
path = os.path.join(HOME_PATH, subFoldersName) # ⽂件夹路径
subFoldersNameList = os.listdir(path)
for imageName in subFoldersNameList:
imagePath = os.path.join(path, imageName)
totalList.append(imagePath)
# 产⽣⼀个长度为图⽚总数的不重复随机数序列
dictlist = random.sample(range(0, len(totalList)), len(totalList))
print(totalList[0].split('\\')[1].split('-')[0]) # 这是图⽚对应的类别
i = 0
for path in totalList:
images = cv2.imread(totalList[dictlist[i]])
res = size(images, (128, 128), interpolation=cv2.INTER_CUBIC)
image_raw_data = string()
label = transform_label(totalList[dictlist[i]].split('\\')[1].split('-')[0])
print(label)
example = tf.train.Example(ain.Features(feature={
'label': _int64_feature(label),
'image_raw': _bytes_feature(image_raw_data)
}))
if i <= len(totalList) * 3 / 4:
writerTrain.write(example.SerializeToString())
else:
writerTest.write(example.SerializeToString())
i += 1
基本过程:遍历⽬录下所有的图⽚,将它的路径加⼊⼀个⼤的列表。通过⼀个不重复的随机数序列,来控制使⽤哪张图⽚。这就达到随机的⽬的。
怎么获取标签呢?图⽚⽂件都是类型-序号这个形式命名的,这⾥通过获取它的类型名,建⽴字典产⽣映射关系。
def transform_label(imgType):
label_dict = {
'img001': 0,
'img002': 1,
'img003': 2,
'img004': 3,
'img005': 4,
'img006': 5,
'img007': 6,
'img008': 7,
'img009': 8,
'img010': 9,
'img011': 10,
}
return label_dict[imgType]
原尺⼨图⽚CNN
对应CNN_train.py⽂件
训练的时候怎么读取TFRecord数据呢,参考以下代码
# 读训练集数据
def read_train_data():
reader = tf.TFRecordReader()
filename_train = tf.train.string_input_producer(["TFRecord128/train.tfrecords"])
_, serialized_example_test = ad(filename_train)
features = tf.parse_single_example(
serialized_example_test,
features={
'label': tf.FixedLenFeature([], tf.int64),
'image_raw': tf.FixedLenFeature([], tf.string),
}
python怎么读文件夹下的文件夹)
img_train = features['image_raw']
images_train = tf.decode_raw(img_train, tf.uint8)
images_train = tf.reshape(images_train, [128, 128, 3])
labels_train = tf.cast(features['label'], tf.int64)
labels_train = tf.cast(labels_train, tf.int64)
labels_train = tf.one_hot(labels_train, 10)
return images_train, labels_train
通过features[键名]的⽅式将存⼊的数据读取出来,键名和数据类型要与写⼊的保持⼀致。
关于这⾥的卷积神经⽹络,我是参考王学长培训时的代码写的。当然照搬肯定不⾏,会遇到loss NaN的情况,我解决的⽅法是仿照AlexNet中,在卷积后加⼊LRN层,进⾏局部响应归⼀化。在设置参数时,加⼊l2正则项。关键代码如下
def weights_with_loss(shape, stddev, wl):
var = tf.truncated_normal(stddev=stddev, shape=shape)
if wl is not None:
weight_loss = tf.l2_loss(var), wl, name='weight_loss')
tf.add_to_collection('losses', weight_loss)
return tf.Variable(var)
def net(image, drop_pro):
W_conv1 = weights_with_loss([5, 5, 3, 32], 5e-2, wl=0.0)
b_conv1 = biasses([32])
conv1 = lu(conv(image, W_conv1) + b_conv1)
pool1 = max_pool_2x2(conv1)
norm1 = tf.nn.lrn(pool1, 4, bias=1, alpha=0.001 / 9.0, beta=0.75)
W_conv2 = weights_with_loss([5, 5, 32, 64], stddev=5e-2, wl=0.0)
b_conv2 = biasses([64])
conv2 = lu(conv(norm1, W_conv2) + b_conv2)
norm2 = tf.nn.lrn(conv2, 4, bias=1, alpha=0.001 / 9.0, beta=0.75)
pool2 = max_pool_2x2(norm2)
W_conv3 = weights_with_loss([5, 5, 64, 128], stddev=0.04, wl=0.004)
b_conv3 = biasses([128])
conv3 = lu(conv(pool2, W_conv3) + b_conv3)
pool3 = max_pool_2x2(conv3)
W_conv4 = weights_with_loss([5, 5, 128, 256], stddev=1 / 128, wl=0.004)
b_conv4 = biasses([256])
conv4 = lu(conv(pool3, W_conv4) + b_conv4)
pool4 = max_pool_2x2(conv4)
image_raw = tf.reshape(pool4, shape=[-1, 8 * 8 * 256])
# 全连接层
fc_w1 = weights_with_loss(shape=[8 * 8 * 256, 1024], stddev=1 / 256, wl=0.0)
fc_b1 = biasses(shape=[1024])
fc_1 = lu(tf.matmul(image_raw, fc_w1) + fc_b1)
# drop-out层
drop_out = tf.nn.dropout(fc_1, drop_pro)
fc_2 = weights_with_loss([1024, 10], stddev=0.01, wl=0.0)
fc_b2 = biasses([10])
return tf.matmul(drop_out, fc_2) + fc_b2
128x128x3原图训练过程
在验证集上的正确率
这⾥使⽤的是1281283的图⽚,图⽚⽐较⼤,所以我产⽣了⼀个想法。在做TFRecord数据的时候,将图⽚尺⼨减半。所以就有了第⼆种⽅法。
图⽚尺⼨减半CNN
对应⽂件CNN_train2.py
与上⾯那种⽅法唯⼀的区别是将图⽚尺⼨128*128*3改成了64*64*3所以我这⾥就不重复说明了。
64x64x3图⽚训过程
在验证集上的正确率
保存模型
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论