TensorFlow实现对花朵数据集的图片分类
共 5127字,需浏览 11分钟
·
2022-05-19 12:23
点击下方卡片,关注“新机器视觉”公众号
重磅干货,第一时间送达
转载自:古月居
转载自:古月居
前言
利用TensorFlow实现对花朵数据集的图片分类
提示:以下是本篇文章正文内容,下面案例可供参考
一、数据集
数据集是五个分别存放着对应类别花朵图片的五个文件夹,包括daisy(雏菊)633张;dandelion(蒲公英)898张,rose(玫瑰)641张,sunflower(向日葵)699张,tulips(郁金香)799张。
二、代码
1、下载数据集
import tensorflow as tf
AUTOTUNE = tf.data.experimental.AUTOTUNE
import pathlib
data_root_orig = tf.keras.utils.get_file(origin='https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz', fname='flower_photos', untar=True)
data_root = pathlib.Path(data_root_orig)
print(data_root)
for item in data_root.iterdir():
print(item)
打印下载后的文件路径和文件成员:
output:
C:\Users\Administrator.keras\datasets\flower_photos
C:\Users\Administrator.keras\datasets\flower_photos\daisy
C:\Users\Administrator.keras\datasets\flower_photos\dandelion
C:\Users\Administrator.keras\datasets\flower_photos\LICENSE.txt
C:\Users\Administrator.keras\datasets\flower_photos\roses
C:\Users\Administrator.keras\datasets\flower_photos\sunflowers
C:\Users\Administrator.keras\datasets\flower_photos\tulips
2、统计并观察数据
#获取五个文件夹的名字
label_names = sorted(item.name for item in data_root.glob('*/') if item.is_dir())
label_names
output:[‘daisy’, ‘dandelion’, ‘roses’, ‘sunflowers’, ‘tulips’]
#将文件夹的名字(即花的分类)标上序号
label_to_index = dict((name, index) for index, name in enumerate(label_names))
label_to_index
{‘daisy’: 0, ‘dandelion’: 1, ‘roses’: 2, ‘sunflowers’: 3, ‘tulips’: 4}
#获取所以图片的标签(0,1,2,3,4)
import random
all_image_paths = list(data_root.glob('*/*'))
all_image_paths = [str(path) for path in all_image_paths]
random.shuffle(all_image_paths)
image_count = len(all_image_paths)
image_count
all_image_labels = [label_to_index[pathlib.Path(path).parent.name]for path in all_image_paths]
print("First 10 labels indices: ", all_image_labels[:10])
3670
First 10 labels indices: [0, 2, 3, 4, 2, 1, 4, 1, 4, 0]
下面我们先来观察一张图片
#观察第一张图片
img_path = all_image_paths[0]
img_path
‘C:\Users\Administrator\.keras\datasets\flower_photos\daisy\11124324295_503f3a0804.jpg’
#读取原图
img_raw = tf.io.read_file(img_path)
#转换成TensorFlow可以使用的tensor类型
img_tensor = tf.image.decode_image(img_raw)
print(img_tensor.shape)
print(img_tensor.dtype)
(309, 500, 3)
#对图片按要求进行转换,这里将size规定到【192,192】;值域映射到【0,1】
img_final = tf.image.resize(img_tensor, [192, 192])
img_final = img_final/255.0
print(img_final.shape)
print(img_final.numpy().min())
print(img_final.numpy().max())
(192, 192, 3)
0.0
0.99984366
定义预处理和加载函数
def preprocess_image(image):
image = tf.image.decode_jpeg(image, channels=3)
image = tf.image.resize(image, [192, 192])
image /= 255.0
return image
def load_and_preprocess_image(path):
image = tf.io.read_file(path)
return preprocess_image(image)
导入matpoltlib进行画图(导入失败的解决方案见我的另一篇博文)
import matplotlib.pyplot as plt
image_path = all_image_paths[0]
label = all_image_labels[0]
print (load_and_preprocess_image(img_path))
plt.imshow(load_and_preprocess_image(img_path))
plt.grid(False)
3、构建数据集
![](https://filescdn.proginn.com/bf22152f4c547cc686d04ffe0e4886fe/17fceb61a2aeb0d9b17abaa58afd7a7d.webp)
使用tf.data.Dataset来构建规范的数据集
#“from_tensor_slices ”方法使用张量的切片元素构建图片路径的数据集
path_ds = tf.data.Dataset.from_tensor_slices(all_image_paths)
#同理,构建标签数据集,并用tf.cast转换成int64数据类型
label_ds = tf.data.Dataset.from_tensor_slices(tf.cast(all_image_labels, tf.int64))
#根据路径获取图片,并经过加载和预处理得到图片数据集
image_ds = path_ds.map(load_and_preprocess_image )
image_ds
将image_ds和label_ds打包成新的数据集
image_label_ds = tf.data.Dataset.zip((image_ds, label_ds))
print(image_label_ds)
画图查看我们构造完成的新数据
plt.figure(figsize=(8,8))
for n,image_label in enumerate(image_label_ds.take(4)):
plt.subplot(2,2,n+1)
plt.imshow(image_label[0])
plt.grid(False)
![](https://filescdn.proginn.com/a5da4e48972ca4b96f0c43029f6f133c/5fc7f8030b9f7ccf6e35013d8130b8e0.webp)
4、迁移学习进行分类
接下来用创建的数据集训练一个分类模型,简单起见,直接用tf.keras.applications包中训练好的模型,并将其迁移到我们的图片分类问题上来。这里使用的模型是MobileNetV2模型
#迁移MobileNetV2模型,并且不加载顶层
base_model=tf.keras.applications.mobilenet_v2.MobileNetV2(include_top=False,weights='imagenet',input_shape=(192,192,3))
inputs=tf.keras.layers.Input(shape=(192,192,3))
#模型可视化1,使用model.summary()方法
base_model.summary()
接下来,我们打乱一下数据集,并定义好训练过程中每个批次(Batch)数据的大小
#使用shuffle方法打乱数据集
image_count = len(all_image_paths)
ds = image_label_ds.shuffle(buffer_size = image_count)
#让数据集重复多次
ds = ds.repeat()
#设置每个批次的大小
BATCH_SIZE = 32
ds = ds.batch(BATCH_SIZE)
#通过prefetch方法让模型的训练和每个批次数据的加载并行
ds = ds.prefetch(buffer_size = AUTOTUNE)
然后,针对MobileNetV2改变一样数据集的取值范围,因为MobileNetV2接受输入的数据值域是【-1,1】,而我们之前的预处理函数将图片的像素值映射到【0,1】
def change_range(image,label):
return 2*image-1,label
keras_ds = ds.map(change_range)
接下来定义模型,由于预训练好的MobileNetV2返回的数据维度是(32,6,6,128),其中32是一个批次Batch的大小,“6,6”是输出的特征的大小为6*6,1280代表该层使用的1280个卷积核。为了使用花朵分类问题,需要做一下调整
model = tf.keras.Sequential([
base_model,
tf.keras.layers.GlobalAveragePooling2D(),
tf.keras.layers.Dense(len(label_names),activation="softmax")
])
如上代码,我们用Sequentail建立我们的网络结构,base_model是迁移过来的模型,我们添加了全局评价池化层GlobalAveragePooling,经过此操作6*6的特征被降维,变为(32,1280)。
最后,由于该分类问题有五个结果,我们增加一个全连接层(Dense)将维度变为(32,5)。
最后,编译一下模型,同时制定使用的优化器,损失函数和评价标准
model.compile(optimizer = tf.keras.optimizers.Adam(),
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
model.summary()
![](https://filescdn.proginn.com/2496af283f5e548090bc616ee2675e19/f67aac2cb20edd7ec8858ef5d3eb475b.webp)
使用model.fit训练模型,epochs是训练的回合数,step_per_epoch代表每个回合要去多少个批次数据。通常等于我们数据集大小除以批次大小后取证(3670/32≈10)
model.fit(ds,epochs=10,steps_per_epoch=100)
![](https://filescdn.proginn.com/7e278ad220386cd3b3d5989d52bd6742/6ce71f3cec4539b584ba1e2c7ee4542c.webp)
虽然没有跑完整个代码,但是已经能看出来准确度达到一个很高的程度,并在逐步上升。
本文仅做学术分享,如有侵权,请联系删文。