开发者社区> 游客su25awkxr62sa> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

TensorFlow2.0(10):加载自定义图片数据集到Dataset

简介: TensorFlow2.0(10):加载自定义图片数据集到Dataset
+关注继续查看

前面的推文中我们说过,在加载数据和预处理数据时使用tf.data.Dataset对象将极大将我们从建模前的数据清理工作中释放出来,那么,怎么将自定义的数据集加载为DataSet对象呢?这对很多新手来说都是一个难题,因为绝大多数案例教学都是以mnist数据集作为例子讲述如何将数据加载到Dataset中,而英文资料对这方面的介绍隐藏得有点深。本文就来捋一捋如何加载自定义的图片数据集实现图片分类,后续将继续介绍​如何加载自定义的text、mongodb等数据。


加载自定义图片数据集


如果你已有数据集,那么,请将所有数据存放在同一目录下,然后将不同类别的图片分门别类地存放在不同的子目录下,目录树如下所示:

$ tree flower_photos -L 1
flower_photos
├── daisy
├── dandelion
├── LICENSE.txt
├── roses
├── sunflowers
└── tulips


所有的数据都存放在flower_photos目录下,每一个子目录(daisy、dandelion等等)存放的都是一个类别的图片。如果你已有自己的数据集,那就按上面的结构来存放,如果没有,想操作学习一下,你可以通过下面代码下载上述图片数据集:



import tensorflow as tf
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)  # 打印出数据集所在目录


下载好后,建议将整个flower_photos目录移动到项目根目录下。


import tensorflow as tf
import random
import pathlib
data_path = pathlib.Path('./data/flower_photos')
all_image_paths = list(data_path.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


3670


查看一下前5张:


all_image_paths[:5]


['data/flower_photos/sunflowers/9448615838_04078d09bf_n.jpg',
 'data/flower_photos/roses/15222804561_0fde5eb4ae_n.jpg',
 'data/flower_photos/daisy/18622672908_eab6dc9140_n.jpg',
 'data/flower_photos/roses/459042023_6273adc312_n.jpg',
 'data/flower_photos/roses/16149016979_23ef42b642_m.jpg']


读取图片的同时,我们也不能忘记图片与标签的对应,要创建一个对应的列表来存放图片标签,不过,这里所说的标签不是daisy、dandelion这些具体分类名,而是整型的索引,毕竟在建模的时候y值一般都是整型数据,所以要创建一个字典来建立分类名与标签的对应关系:


label_names = sorted(item.name for item in data_path.glob('*/') if item.is_dir())label_names


['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}


all_image_labels = [label_to_index[pathlib.Path(path).parent.name] for path in all_image_paths]


for image, label in zip(all_image_paths[:5], all_image_labels[:5]):    print(image, ' --->  ', label)


data/flower_photos/sunflowers/9448615838_04078d09bf_n.jpg  --->   3
data/flower_photos/roses/15222804561_0fde5eb4ae_n.jpg  --->   2
data/flower_photos/daisy/18622672908_eab6dc9140_n.jpg  --->   0
data/flower_photos/roses/459042023_6273adc312_n.jpg  --->   2
data/flower_photos/roses/16149016979_23ef42b642_m.jpg  --->   2


好了,现在我们可以创建一个Dataset了:


ds = tf.data.Dataset.from_tensor_slices((all_image_paths, all_image_labels))


不过,这个ds可不是我们想要的,毕竟,里面的元素只是图片路径,所以我们要进一步处理。这个处理包含读取图片、重新设置图片大小、归一化、转换类型等操作,我们将这些操作统统定义到一个方法里:


def load_and_preprocess_from_path_label(path, label):
    image = tf.io.read_file(path)  # 读取图片
    image = tf.image.decode_jpeg(image, channels=3)
    image = tf.image.resize(image, [192, 192])  # 原始图片大小为(266, 320, 3),重设为(192, 192)
    image /= 255.0  # 归一化到[0,1]范围
    return image, label


image_label_ds  = ds.map(load_and_preprocess_from_path_label)


image_label_ds


<MapDataset shapes: ((192, 192, 3), ()), types: (tf.float32, tf.int32)>


这时候,其实就已经将自定义的图片数据集加载到了Dataset对象中,不过,我们还能秀,可以继续shuffle随机打散、分割成batch、数据repeat操作。这些操作有几点需要注意:


(1)先shuffle、repeat、batch三种操作顺序有讲究:

  • 在repeat之后shuffle,会在epoch之间数据随机(当有些数据出现两次的时候,其他数据还没有出现过)
  • 在batch之后shuffle,会打乱batch的顺序,但是不会在batch之间打乱数据。

(2)shuffle操作时,buffer_size越大,打乱效果越好,但消耗内存越大,可能造成延迟。

推荐通过使用 tf.data.Dataset.apply 方法和融合过的 tf.data.experimental.shuffle_and_repeat 函数来执行这些操作:



ds = image_label_ds.apply(tf.data.experimental.shuffle_and_repeat(buffer_size=image_count))
BATCH_SIZE = 32
ds = ds.batch(BATCH_SIZE)


好了,至此,本文内容其实就结束了,因为已经将自定义的图片数据集加载到了Dataset中。


下面的内容作为扩展阅读。


扩展


上面的方法是简单的在每次epoch迭代中单独读取每个文件,在本地使用 CPU 训练时这个方法是可行的,但是可能不足以进行GPU训练并且完全不适合任何形式的分布式训练。


可以使用tf.data.Dataset.cache在epoch迭代过程间缓存计算结果。这能极大提升程序效率,特别是当内存能容纳全部数据时。


在被预处理之后(解码和调整大小),图片就被缓存了:


ds = image_label_ds.cache()  # 缓存
ds = ds.apply(tf.data.experimental.shuffle_and_repeat(buffer_size=image_count))

使用内存缓存的一个缺点是必须在每次运行时重建缓存,这使得每次启动数据集时有相同的启动延迟。如果内存不够容纳数据,使用一个缓存文件:


ds = image_label_ds.cache(filename='./cache.tf-data')
ds = ds.apply(tf.data.experimental.shuffle_and_repeat(buffer_size=image_count))

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
pytorch中自定义数据集加载对象重写Dataset
pytorch中自定义数据集加载对象重写Dataset
0 0
TensorFlow加载cifar10数据集
TensorFlow加载cifar10数据集
0 0
Caffe:使用 classify.py 批量对图片分类
一般使用 Caffe 训练完网络后,会用 `test.bin` 来测试一下网络的精度,然后还能用 `classification.bin` 来用网络对图片进行单张的分类,但是一张一张的分,效率很低,所以我改写了 `classify.py` 文件,使其读取 test.txt 文件批量分类,输出具体哪一张图片分错了。
0 0
Tensorflow加载预训练模型和保存模型
Tensorflow加载预训练模型和保存模型
0 0
Tensorflow将模型导出为一个文件及接口设置
Tensorflow将模型导出为一个文件及接口设置
0 0
Tensorflow加载预训练模型的特殊操作
Tensorflow加载预训练模型的特殊操作
0 0
详解上采样的两种常用方法(附以TensorFlow 2.x实现的小demo)
详解上采样的两种常用方法(附以TensorFlow 2.x实现的小demo)
0 0
pytorch保存模型、加载模型的两种方式
pytorch保存模型、加载模型的两种方式
0 0
Dataset之COCO数据集:COCO数据集的简介、下载、使用方法之详细攻略
Dataset之COCO数据集:COCO数据集的简介、下载、使用方法之详细攻略
0 0
文章
问答
文章排行榜
最热
最新
相关电子书
更多
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载
冬季实战营第三期:MySQL数据库进阶实战
立即下载