TensorFlow实现对花朵数据集的图片分类

新机器视觉

共 5127字,需浏览 11分钟

 ·

2022-05-19 12:23

点击下方卡片,关注“新机器视觉”公众号

重磅干货,第一时间送达

转载自:古月居

前言



利用TensorFlow实现对花朵数据集的图片分类


提示:以下是本篇文章正文内容,下面案例可供参考



一、数据集


数据集是五个分别存放着对应类别花朵图片的五个文件夹,包括daisy(雏菊)633张;dandelion(蒲公英)898张,rose(玫瑰)641张,sunflower(向日葵)699张,tulips(郁金香)799张。



二、代码


1、下载数据集


import tensorflow as tfAUTOTUNE = tf.data.experimental.AUTOTUNEimport pathlibdata_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,12,34import randomall_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,1img_final = tf.image.resize(img_tensor, [192, 192])img_final = img_final/255.0print(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  # normalize to [0,1] range  return image    return imagedef load_and_preprocess_image(path):      image = tf.io.read_file(path)      return preprocess_image(image)


导入matpoltlib进行画图(导入失败的解决方案见我的另一篇博文)


import matplotlib.pyplot as pltimage_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、构建数据集



使用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)


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 = 32ds = 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,labelkeras_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()


使用model.fit训练模型,epochs是训练的回合数,step_per_epoch代表每个回合要去多少个批次数据。通常等于我们数据集大小除以批次大小后取证(3670/32≈10)


model.fit(ds,epochs=10,steps_per_epoch=100)


虽然没有跑完整个代码,但是已经能看出来准确度达到一个很高的程度,并在逐步上升。



本文仅做学术分享,如有侵权,请联系删文。

—THE END—
浏览 53
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报