构建人工智能模型基础:TFDS和Keras的完美搭配

上一篇:《数据工程师,转型人工智能岗位的理想时空通道》

**序言:**本节将带您深入探索 TensorFlow 提供的关键工具和方法,涵盖数据集管理和神经网络模型的构建与训练。在现代人工智能框架中,TensorFlow 的数据集接口 (TensorFlow Datasets, 简称 TFDS) 与 Keras 模型库为深度学习任务提供了极大的便利。本章将具体展示如何使用 TFDS 和 Keras 配合构建神经网络架构,以实现高效的数据处理和模型训练。通过本节的实践操作,您将掌握从数据加载、预处理到模型搭建的核心流程,为进一步的人工智能模型研发奠定坚实的基础。

使用TFDS与Keras模型

在上一节中,我们学到了如何使用TensorFlow和Keras创建一个简单的计算机视觉模型,使用Keras内置的数据集(包括Fashion MNIST),代码如下所示:

mnist = tf.keras.datasets.fashion_mnist

(training_images, training_labels), (test_images, test_labels) = mnist.load_data()

使用TFDS时,代码非常相似,但有一些小的变化。Keras的数据集直接给我们返回了可以在model.fit中原生使用的ndarray类型,但使用TFDS时,我们需要进行一些转换:

(training_images, training_labels), (test_images, test_labels) = tfds.as_numpy(tfds.load('fashion_mnist', split=['train', 'test'], batch_size=-1, as_supervised=True))

在这里,我们使用了tfds.load,将fashion_mnist作为所需的数据集传递给它。我们知道这个数据集有训练集和测试集的划分,所以在数组中传入这些划分项将返回包含图像和标签的适配器数组。使用tfds.as_numpy在调用tfds.load时会将数据返回为Numpy数组。指定batch_size=-1会让我们获取所有数据,而as_supervised=True则确保返回的格式为(输入,标签)元组。

完成这些操作后,我们基本上获得了与Keras数据集相同的数据格式,但有一个区别------在TFDS中,数据的形状是(28, 28, 1),而在Keras数据集中是(28, 28)。

这意味着代码需要做一些小的改动来指定输入数据的形状为(28, 28, 1),而不是(28, 28):

import tensorflow as tf

import tensorflow_datasets as tfds

(training_images, training_labels), (test_images, test_labels) = tfds.as_numpy(tfds.load('fashion_mnist', split=['train', 'test'], batch_size=-1, as_supervised=True))

training_images = training_images / 255.0

test_images = test_images / 255.0

model = tf.keras.models.Sequential([

tf.keras.layers.Flatten(input_shape=(28, 28, 1)),

tf.keras.layers.Dense(128, activation=tf.nn.relu),

tf.keras.layers.Dropout(0.2),

tf.keras.layers.Dense(10, activation=tf.nn.softmax)

])

model.compile(optimizer='adam',

loss='sparse_categorical_crossentropy',

metrics=['accuracy'])

model.fit(training_images, training_labels, epochs=5)

对于更复杂的示例,可以参考第3章中使用的"马或人"数据集,这个数据集在TFDS中也可以使用。以下是使用它来训练模型的完整代码:

import tensorflow as tf

import tensorflow_datasets as tfds

data = tfds.load('horses_or_humans', split='train', as_supervised=True)

train_batches = data.shuffle(100).batch(10)

model = tf.keras.models.Sequential([

tf.keras.layers.Conv2D(16, (3,3), activation='relu', input_shape=(300, 300, 3)),

tf.keras.layers.MaxPooling2D(2, 2),

tf.keras.layers.Conv2D(32, (3,3), activation='relu'),

tf.keras.layers.MaxPooling2D(2,2),

tf.keras.layers.Conv2D(64, (3,3), activation='relu'),

tf.keras.layers.MaxPooling2D(2,2),

tf.keras.layers.Conv2D(64, (3,3), activation='relu'),

tf.keras.layers.MaxPooling2D(2,2),

tf.keras.layers.Conv2D(64, (3,3), activation='relu'),

tf.keras.layers.MaxPooling2D(2,2),

tf.keras.layers.Flatten(),

tf.keras.layers.Dense(512, activation='relu'),

tf.keras.layers.Dense(1, activation='sigmoid')

])

model.compile(optimizer='Adam', loss='binary_crossentropy', metrics=['accuracy'])

history = model.fit(train_batches, epochs=10)

正如你所见,这相当直接:只需调用 tfds.load,传入你想要的分割(在本例中是训练集),然后在模型中使用它。数据被批处理并打乱顺序,以便更有效地进行训练。

"Horses or Humans"数据集被划分为训练集和测试集,因此如果你想在训练时验证模型,可以通过TFDS加载单独的验证集,方法如下:

val_data = tfds.load('horses_or_humans', split='test', as_supervised=True)

你需要像处理训练集一样批处理它。例如:

validation_batches = val_data.batch(32)

然后在训练时,指定这些批次作为验证数据。你还需要显式设置每个周期要使用的验证步数,否则TensorFlow会报错。如果不确定,设置为1即可,如下:

history = model.fit(train_batches, epochs=10, validation_data=validation_batches, validation_steps=1)

加载特定版本

所有在TFDS中存储的数据集都使用MAJOR.MINOR.PATCH编号系统。其保证如下:如果仅PATCH更新,则调用返回的数据相同,但底层组织可能发生变化。这种变化对开发者应是无感知的。如果MINOR更新,则数据保持不变,但可能会在每条记录中增加新的特性(非破坏性更改)。此外,对特定切片(参见第74页的"使用自定义切片")的数据不会重新排序。如果MAJOR更新,则记录格式及其位置可能会发生变化,因此特定切片可能会返回不同的值。

在检查数据集时,你会看到何时有不同版本可用------例如,cnn_dailymail数据集就是这样。如果你不想要默认版本(本文撰写时是3.0.0),而是希望使用早期版本,例如1.0.0,可以按以下方式加载:

data, info = tfds.load("cnn_dailymail:1.0.0", with_info=True)

请注意,如果你在Colab上使用TFDS,建议检查Colab使用的TFDS版本。本文撰写时,Colab预装的TFDS是2.0版,但其中存在一些加载数据集的bug(包括cnn_dailymail数据集),这些问题在TFDS 2.1及之后的版本中已修复,因此建议使用这些版本,或者至少在Colab中安装它们,而不是依赖内置的默认版本。

使用映射函数进行数据增强

在前面的章节中,你见到了使用ImageDataGenerator为模型提供训练数据时的一些有用增强工具。你可能想知道如何在使用TFDS时实现同样的功能,因为这时你不是从子目录流式读取图像。实现此功能的最佳方法(或任何其他形式的转换)是对数据适配器使用映射函数。让我们看看如何实现这一点。

之前,我们对Horses or Humans数据集的处理只是从TFDS中加载数据并为其创建批次,如下所示:

data = tfds.load('horses_or_humans', split='train', as_supervised=True)

train_batches = data.shuffle(100).batch(10)

要对数据进行变换并将其映射到数据集,你可以创建一个映射函数。这只是标准的Python代码。例如,假设你创建了一个名为augmentimages的函数,并让它进行一些图像增强,如下所示:

def augmentimages(image, label):

image = tf.cast(image, tf.float32)

image = (image/255)

image = tf.image.random_flip_left_right(image)

return image, label

然后你可以将其映射到数据上,创建一个名为train的新数据集:

train = data.map(augmentimages)

之后,在创建批次时,使用train而不是data,如下:

train_batches = train.shuffle(100).batch(32)

在augmentimages函数中,你可以看到使用tf.image.random_flip_left_right(image)对图像进行左右随机翻转。tf.image库中有很多可用于增强的函数;详细内容请参阅文档。

使用TensorFlow Addons

TensorFlow Addons库包含更多可用函数。ImageDataGenerator增强中的一些功能(如旋转)仅在此库中可用,因此建议查看它。

使用TensorFlow Addons非常简单------只需安装库即可:

pip install tensorflow-addons

安装完成后,可以将Addons混入到你的映射函数中。以下是将旋转Addons用于前面映射函数的示例:

import tensorflow_addons as tfa

def augmentimages(image, label):

image = tf.cast(image, tf.float32)

image = (image/255)

image = tf.image.random_flip_left_right(image)

image = tfa.image.rotate(image, 40, interpolation='NEAREST')

return image, label

使用自定义分割

到目前为止,你一直使用的是预先分割为训练集和测试集的数据集。例如,Fashion MNIST有60,000和10,000条记录,分别用于训练和测试。但如果你不想使用这些分割呢?如果你想根据自己的需求分割数据呢?TFDS的一个强大之处就在于------它提供了一个API,允许你精细地控制数据的分割方式。

实际上你已经见过这种方式了,例如像这样加载数据时:

data = tfds.load('cats_vs_dogs', split='train', as_supervised=True)

注意split参数是一个字符串,这里你请求了train分割,它恰好是整个数据集。如果你熟悉Python的切片符号,也可以使用它。这种符号可以总结为在方括号内定义你想要的切片,如下所示:[ : : ]。它是一种相当复杂的语法,赋予了很大的灵活性。

例如,如果你希望train的前10,000条记录作为训练数据,可以省略 ,直接调用train[:10000](一个有用的记忆技巧是将前导冒号读作"前",所以这将读作"train前10,000条记录"):

data = tfds.load('cats_vs_dogs', split='train[:10000]', as_supervised=True)

你还可以使用%来指定分割。例如,如果你希望前20%的记录用于训练,可以像这样使用:20%:

data = tfds.load('cats_vs_dogs', split='train[:20%]', as_supervised=True)

你甚至可以更进一步,组合多个分割。也就是说,如果你希望训练数据是前1000条记录和最后1000条记录的组合,可以这样做(-1000:表示"最后1000条记录",":1000"表示"前1000条记录"):

data = tfds.load('cats_vs_dogs', split='train[-1000:]+train[:1000]', as_supervised=True)

Dogs vs. Cats数据集没有固定的训练、测试和验证分割,但使用TFDS,创建自定义分割非常简单。假设你希望分割为80%、10%、10%。可以这样创建三个数据集:

train_data = tfds.load('cats_vs_dogs', split='train[:80%]', as_supervised=True)

validation_data = tfds.load('cats_vs_dogs', split='train[80%:90%]', as_supervised=True)

test_data = tfds.load('cats_vs_dogs', split='train[-10%:]', as_supervised=True)

一旦你有了它们,就可以像使用任何命名分割一样使用它们。

需要注意的是,由于返回的数据集无法被探测其长度,因此通常很难确认你是否正确地分割了原始数据集。要查看你在某个分割中的记录数量,你必须遍历整个数据集并一条条计数。以下是对你刚创建的训练集进行计数的代码:

train_length = [i for i, _ in enumerate(train_data)][-1] + 1

print(train_length)

这可能是一个较慢的过程,因此请确保仅在调试时使用它。

本节总结: 本章介绍了如何使用 TensorFlow Datasets(TFDS)和 Keras 搭建神经网络模型,并探索了数据增强、分割和预处理等关键操作。通过将 TFDS 数据集与 Keras 模型结合,您学会了如何高效加载和转换数据,为神经网络模型的构建和训练做好准备。此外,我们还介绍了如何灵活地自定义数据分割和应用数据增强,为模型提供更加多样化的训练数据。掌握了这些技能后,您将能够更自如地应用 TensorFlow 和 Keras 进行各种深度学习项目的开发,为复杂模型的搭建奠定坚实的基础。下一节我们将会为大家介绍从TFDS中下载出来的数据集是以什么形式保存下来的---TFRecord!

相关推荐
果冻人工智能19 小时前
创建用于预测序列的人工智能模型,设计数据集。
#人工智能·#ai代理·#ai应用·#ai员工·#神经网络·#ai
果冻人工智能5 天前
预测大师的秘籍:揭开时间序列的真相
#人工智能·#ai代理·#ai应用·#ai员工·#cnn·#chatgpt·#神经网络·#ai
果冻人工智能8 天前
人工智能规模法则的起源、分析、内幕以及对齐方法
#人工智能·#ai代理·#ai应用·#ai员工·#cnn·#神经网络·#ai
果冻人工智能10 天前
规模法则(Scaling Law)与参数效率的提高,
#人工智能·#ai代理·#ai应用·#ai员工·#cnn·#chatgpt·#神经网络·#ai
果冻人工智能11 天前
人工智能大语言模型起源篇(二),从通用语言微调到驾驭LLM
#人工智能·#ai代理·#ai应用·#ai员工·#cnn·#chatgpt·#神经网络·#ai
果冻人工智能12 天前
人工智能大语言模型起源篇(一),从哪里开始
#人工智能·#ai代理·#豆包·#ai应用·#ai员工·#cnn·#chatgpt·#神经网络·#ai
果冻人工智能13 天前
用人工智能模型预测股市和加密货币的K线图
#人工智能·#ai代理·#ai应用·#ai员工·#cnn·#chatgpt·#神经网络·#ai
果冻人工智能14 天前
2024年发布的多模态大语言模型和它们采用的设计方法
#人工智能·#ai员工·#ai
果冻人工智能16 天前
搭建人工智能多模态大语言模型的通用方法
#人工智能·#ai代理·#豆包·#ai应用·#ai员工·#cnn·#chatgpt·#神经网络·#ai
果冻人工智能17 天前
再用RNN神经网络架构设计生成式语言模型
#人工智能·#ai代理·#豆包·#ai应用·#ai员工·#cnn·#chatgpt·#神经网络·#ai