Keras深度学习框架第十八讲:使用 KerasCV 进行分类

80 篇文章 0 订阅
50 篇文章 3 订阅

1、绪论

1.1 使用 KerasCV 进行分类的概念

KerasCV 是一个用于构建和训练计算机视觉模型的库,它集成了 Keras 的高级 API 和计算机视觉中常用的工具和预处理层。虽然 KerasCV 主要被设计为处理目标检测任务,但它的一些组件和工具也可以用于其他计算机视觉任务,包括图像分类。

分类是为给定的输入图像预测类别标签的过程。尽管分类是计算机视觉中一个相对直接的任务,但现代方法仍然由几个复杂的组件构成。幸运的是,KerasCV 提供了用于构建常用组件的 API。

本文展示了 KerasCV 通过模块化方法解决图像分类问题的三个复杂度级别:

  1. 使用预训练分类器进行推理
  2. 微调预训练的骨干网络
  3. 从头开始训练图像分类器

KerasCV 使用 Keras 3 来与 TensorFlow、PyTorch 或 Jax 中的任何一个协同工作。在下面的讨论中,我们将使用 jax 后端。这个指南在 TensorFlow 或 PyTorch 后端下运行无需任何更改,只需更新下面的 KERAS_BACKEND 即可。

1.2 使用 KerasCV 进行图像的步骤

在使用 KerasCV 进行图像分类时,你通常会遵循以下步骤:

  1. 数据准备:准备你的图像数据集,并将其分为训练集、验证集(可选)和测试集。确保你的图像已经被适当地预处理和标签化。

  2. 构建模型:使用 KerasCV(或直接使用 Keras)构建你的图像分类模型。这可能包括使用卷积神经网络(CNN)架构,如 VGG、ResNet、MobileNet 等。

  3. 编译模型:配置模型的学习过程,包括选择优化器、损失函数和评估指标。对于分类任务,常见的损失函数是交叉熵损失(categorical crossentropy 或 sparse categorical crossentropy),而评估指标通常是准确率(accuracy)。

  4. 训练模型:使用训练数据对模型进行训练。你可以使用 Keras 的 fit() 方法来执行训练过程。

  5. 评估模型:在验证集(如果有的话)或测试集上评估模型的性能。

  6. 使用模型:一旦模型训练完成并经过验证,你就可以使用它来对新的图像进行分类了。

请注意,虽然 KerasCV 提供了许多有用的工具和层来处理目标检测任务中的边界框,但在图像分类任务中,你可能更多地依赖于 Keras 的核心功能和常见的 CNN 架构。

1.3 基础设置

!pip install -q --upgrade keras-cv
!pip install -q --upgrade keras  # Upgrade to Keras 3.
import os

os.environ["KERAS_BACKEND"] = "jax"  # @param ["tensorflow", "jax", "torch"]

import json
import math
import numpy as np

import keras
from keras import losses
from keras import ops
from keras import optimizers
from keras.optimizers import schedules
from keras import metrics

import keras_cv

# Import tensorflow for [`tf.data`](https://www.tensorflow.org/api_docs/python/tf/data) and its preprocessing functions
import tensorflow as tf
import tensorflow_datasets as tfds

2、使用kerasCV进行分类

2.1 使用预训练分类器进行推理

让我们从最简单的 KerasCV API 开始:一个预训练分类器。在这个例子中,我们将构建一个已经在 ImageNet 数据集上预训练的分类器。我们将使用这个模型来解决古老的“猫或狗”问题。

KerasCV 中的最高级别模块是任务(task)。一个任务是一个 keras.Model,它由一个(通常是预训练的)骨干模型和特定于任务的层组成。以下是一个使用 keras_cv.models.ImageClassifier 和 EfficientNetV2B0 骨干网络的例子。

EfficientNetV2B0 在构建图像分类管道时是一个很好的起点。这种架构能够在使用 7M 参数计数的同时实现高准确率。

classifier = keras_cv.models.ImageClassifier.from_preset(
    "efficientnetv2_b0_imagenet_classifier"
)

程序员可能会注意到,这与旧的 keras.applications API 有一些小的差异;在旧的 API 中,您会使用 EfficientNetV2B0(weights=“imagenet”) 来构造分类器。虽然旧的 API 在分类方面表现得很好,但它并不能有效地扩展到需要复杂架构的其他用例,如目标检测和语义分割。

现在我们已经构建了分类器,让我们将其应用于这张可爱的猫咪图片吧!

filepath = keras.utils.get_file(origin="https://i.imgur.com/9i63gLN.jpg")
image = keras.utils.load_img(filepath)
image = np.array(image)
keras_cv.visualization.plot_image_gallery(
    np.array([image]), rows=1, cols=1, value_range=(0, 255), show=True, scale=4
)

在这里插入图片描述
接下来,让我们从分类器获取一些预测结果:

predictions = classifier.predict(np.expand_dims(image, axis=0))

预测结果以 softmax 类别排名的形式呈现。我们可以使用简单的 argsort 函数找到顶部类别的索引:

top_classes = predictions[0].argsort(axis=-1)

为了解码类别映射,我们可以构建一个从类别索引到 ImageNet 类别名称的映射。为了方便起见,我已经将 ImageNet 类别映射存储在一个 GitHub Gist 上。现在我们来下载并加载它。

classes = keras.utils.get_file(
    origin="https://gist.githubusercontent.com/LukeWood/62eebcd5c5c4a4d0e0b7845780f76d55/raw/fde63e5e4c09e2fa0a3436680f436bdcb8325aac/ImagenetClassnames.json"
)
with open(classes, "rb") as f:
    classes = json.load(f)

现在我们可以简单地通过索引查找类别名称:

top_two = [classes[str(i)] for i in top_classes[-2:]]
print("Top two classes are:", top_two)
Top two classes are: ['Egyptian cat', 'velvet']

2.2 微调预训练分类器

当针对我们任务的具体标记图像可用时,微调自定义分类器可以提高性能。如果我们想要训练一个猫狗分类器,使用明确标记的猫狗数据应该比通用分类器表现更好!对于许多任务,可能没有相关的预训练模型可用(例如,针对您应用程序的特定图像分类)。

首先,让我们从加载一些数据开始:

BATCH_SIZE = 32
IMAGE_SIZE = (224, 224)
AUTOTUNE = tf.data.AUTOTUNE
tfds.disable_progress_bar()

data, dataset_info = tfds.load("cats_vs_dogs", with_info=True, as_supervised=True)
train_steps_per_epoch = dataset_info.splits["train"].num_examples // BATCH_SIZE
train_dataset = data["train"]

num_classes = dataset_info.features["label"].num_classes

resizing = keras_cv.layers.Resizing(
    IMAGE_SIZE[0], IMAGE_SIZE[1], crop_to_aspect_ratio=True
)


def preprocess_inputs(image, label):
    image = tf.cast(image, tf.float32)
    # Staticly resize images as we only iterate the dataset once.
    return resizing(image), tf.one_hot(label, num_classes)


# Shuffle the dataset to increase diversity of batches.
# 10*BATCH_SIZE follows the assumption that bigger machines can handle bigger
# shuffle buffers.
train_dataset = train_dataset.shuffle(
    10 * BATCH_SIZE, reshuffle_each_iteration=True
).map(preprocess_inputs, num_parallel_calls=AUTOTUNE)
train_dataset = train_dataset.batch(BATCH_SIZE)

images = next(iter(train_dataset.take(1)))[0]
keras_cv.visualization.plot_image_gallery(images, value_range=(0, 255))

接下来构建我们的模型。预设名称中的“imagenet”表示骨干网络是在 ImageNet 数据集上进行预训练的。预训练的骨干网络通过利用从可能更大的数据集中提取的模式,从我们的标记样本中提取更多信息。

model = keras_cv.models.ImageClassifier.from_preset(
    "efficientnetv2_b0_imagenet", num_classes=2
)
model.compile(
    loss="categorical_crossentropy",
    optimizer=keras.optimizers.SGD(learning_rate=0.01),
    metrics=["accuracy"],
)

在这里调用 model.fit() 方法对keras.Sequential 模型分类器进行调整:

model.fit(train_dataset)

微调后的模型屏蔽了无关的要素

predictions = model.predict(np.expand_dims(image, axis=0))

classes = {0: "cat", 1: "dog"}
print("Top class is:", classes[predictions[0].argmax()])
1/1 ━━━━━━━━━━━━━━━━━━━━ 3s 3s/step
Top class is: cat

3、示例

通过前面的讨论,我们已经对分类有了一定的了解。本节让我们来执行一个示例:从头开始训练一个分类模型!图像分类的一个标准基准是 ImageNet 数据集,但由于许可限制,本教程将使用 CalTech 101 图像分类数据集。虽然本文中使用的是较为简单的 CalTech 101 数据集,但相同的训练模板也可以用于 ImageNet 以实现接近最先进水平的分数。

3.1 数据加载

NUM_CLASSES = 101
# Change epochs to 100~ to fully train.
EPOCHS = 1


def package_inputs(image, label):
    return {"images": image, "labels": tf.one_hot(label, NUM_CLASSES)}


train_ds, eval_ds = tfds.load(
    "caltech101", split=["train", "test"], as_supervised="true"
)
train_ds = train_ds.map(package_inputs, num_parallel_calls=tf.data.AUTOTUNE)
eval_ds = eval_ds.map(package_inputs, num_parallel_calls=tf.data.AUTOTUNE)

train_ds = train_ds.shuffle(BATCH_SIZE * 16)

3.2数据整理

CalTech101 数据集中的每个图像大小都不同,因此我们使用 ragged_batch() API 来将它们组合成批次,同时保持每个单独图像的形状信息。

train_ds = train_ds.ragged_batch(BATCH_SIZE)
eval_ds = eval_ds.ragged_batch(BATCH_SIZE)

batch = next(iter(train_ds.take(1)))
image_batch = batch["images"]
label_batch = batch["labels"]

keras_cv.visualization.plot_image_gallery(
    image_batch.to_tensor(),
    rows=3,
    cols=3,
    value_range=(0, 255),
    show=True,
)

3.3数据增强

在我们之前的微调示例中,我们执行了静态调整大小操作,并没有使用任何图像增强技术。这是因为对训练集进行一次遍历就足以获得不错的结果。但是,当训练模型以解决更困难的任务时,您希望在数据管道中包含数据增强。

数据增强是一种技术,用于使模型对输入数据的变化(如光照、裁剪和方向)具有鲁棒性。KerasCV 在 keras_cv.layers API 中包含了一些最有用的增强方法。创建一个最佳的增强流程是一门艺术,但在本指南的这一部分中,我们将提供一些关于分类最佳实践的建议。

在使用图像数据增强时需要注意的一点是,您必须小心不要将增强后的数据分布与原始数据分布偏离太远。目标是防止过拟合并提高泛化能力,但完全脱离数据分布的样本只会给训练过程增加噪声。

我们将使用的第一个增强是 RandomFlip。这个增强的行为大致如您所期望:它要么翻转图像,要么不翻转。虽然这种增强在 CalTech101 和 ImageNet 中很有用,但应该注意的是,它不应该用于数据分布不是垂直镜像不变的任务。一个发生这种情况的数据集示例是 MNIST 手写数字数据集。将数字 6 沿垂直轴翻转会使数字看起来更像 7 而不是 6,但标签仍然会显示为 6。

random_flip = keras_cv.layers.RandomFlip()
augmenters = [random_flip]

image_batch = random_flip(image_batch)
keras_cv.visualization.plot_image_gallery(
    image_batch.to_tensor(),
    rows=3,
    cols=3,
    value_range=(0, 255),
    show=True,
)

通过操作一半的图像已经被翻转了。

接下来我们要使用的增强是 RandomCropAndResize。这个操作会随机选择图像的一个子集,然后将其调整到指定的目标大小。通过使用这种增强,我们强制我们的分类器变得空间不变。此外,这一层还接受一个 aspect_ratio_factor 参数,可以用来扭曲图像的纵横比。虽然这可以提高模型的性能,但应该谨慎使用。纵横比的扭曲很容易使样本偏离原始训练集的数据分布。请记住——数据增强的目标是产生更多与训练集数据分布一致的训练样本!

RandomCropAndResize 也可以处理 tf.RaggedTensor 输入。在 CalTech101 图像数据集中,图像的大小多种多样。因此,它们不能轻松地组合成一个密集的训练批次。幸运的是,RandomCropAndResize 为您处理了 Ragged -> Dense 的转换过程!

让我们在增强集合中添加一个 RandomCropAndResize:

crop_and_resize = keras_cv.layers.RandomCropAndResize(
    target_size=IMAGE_SIZE,
    crop_area_factor=(0.8, 1.0),
    aspect_ratio_factor=(0.9, 1.1),
)
augmenters += [crop_and_resize]

image_batch = crop_and_resize(image_batch)
keras_cv.visualization.plot_image_gallery(
    image_batch,
    rows=3,
    cols=3,
    value_range=(0, 255),
    show=True,
)

我们现在正在处理一批密集的图像。接下来,让我们在训练集中加入一些基于空间和颜色的抖动。这将使我们能够训练出一个对光照闪烁、阴影等更加鲁棒的分类器。

通过改变颜色和空间特征来增强图像的方法有无数种,但可能最经过考验的技术是 RandAugment。RandAugment 实际上是一组 10 种不同的增强方法:AutoContrast、Equalize、Solarize、RandomColorJitter、RandomContrast、RandomBrightness、ShearX、ShearY、TranslateX 和 TranslateY。在推理时,每个图像都会随机选择 num_augmentations 个增强器,并为每个增强器随机选择幅度因子。然后这些增强器会按顺序应用。

KerasCV 使用 augmentations_per_image 和 magnitude 参数来轻松调整这些参数!让我们来试试看:

rand_augment = keras_cv.layers.RandAugment(
    augmentations_per_image=3,
    value_range=(0, 255),
    magnitude=0.3,
    magnitude_stddev=0.2,
    rate=1.0,
)
augmenters += [rand_augment]

image_batch = rand_augment(image_batch)
keras_cv.visualization.plot_image_gallery(
    image_batch,
    rows=3,
    cols=3,
    value_range=(0, 255),
    show=True,
)

如果一张图像缺少某一类别的关键特征怎么办?例如,如果一片叶子挡住了猫的耳朵的视线,但我们的分类器仅仅通过观察猫的耳朵来学习分类猫怎么办?

一种简单的解决方法是使用 RandomCutout,它随机地移除图像的一部分:

random_cutout = keras_cv.layers.RandomCutout(width_factor=0.4, height_factor=0.4)
keras_cv.visualization.plot_image_gallery(
    random_cutout(image_batch),
    rows=3,
    cols=3,
    value_range=(0, 255),
    show=True,
)

虽然 RandomCutout 可以较好地解决这个问题,但它可能会导致分类器对由切除产生的特征边界和黑色像素区域产生反应。

CutMix 通过使用一种更复杂(也更有效)的技术来解决同样的问题。CutMix 不是用黑色像素替换被切除的区域,而是用从训练集中采样的其他图像的区域来替换这些区域!替换后,图像的分类标签会更新为原始图像和混合图像的类别标签的混合。

cut_mix = keras_cv.layers.CutMix()
# CutMix needs to modify both images and labels
inputs = {"images": image_batch, "labels": label_batch}

keras_cv.visualization.plot_image_gallery(
    cut_mix(inputs)["images"],
    rows=3,
    cols=3,
    value_range=(0, 255),
    show=True,
)

接下来,让我们看看 MixUp()。不幸的是,虽然 MixUp() 在实践中被证明可以显著提高训练模型的鲁棒性和泛化能力,但为什么会出现这种改进还不太清楚……但一点小魔法从未伤害过任何人!

MixUp() 的工作原理是从一批图像中采样两个图像,然后将它们的像素强度和分类标签混合在一起。

mix_up = keras_cv.layers.MixUp()
# MixUp needs to modify both images and labels
inputs = {"images": image_batch, "labels": label_batch}

keras_cv.visualization.plot_image_gallery(
    mix_up(inputs)["images"],
    rows=3,
    cols=3,
    value_range=(0, 255),
    show=True,
)

如果你仔细观察会看到图像已经被混合在一起了。

我们不会将 CutMix() 和 MixUp() 应用到每一张图像上,而是选择其中一个应用到每一批图像上。这可以通过使用 keras_cv.layers.RandomChoice() 来实现。

cut_mix_or_mix_up = keras_cv.layers.RandomChoice([cut_mix, mix_up], batchwise=True)
augmenters += [cut_mix_or_mix_up]

现在让我们将最终的增强器应用到训练数据上:

def create_augmenter_fn(augmenters):
    def augmenter_fn(inputs):
        for augmenter in augmenters:
            inputs = augmenter(inputs)
        return inputs

    return augmenter_fn


augmenter_fn = create_augmenter_fn(augmenters)
train_ds = train_ds.map(augmenter_fn, num_parallel_calls=tf.data.AUTOTUNE)

image_batch = next(iter(train_ds.take(1)))["images"]
keras_cv.visualization.plot_image_gallery(
    image_batch,
    rows=3,
    cols=3,
    value_range=(0, 255),
    show=True,
)

此时还需要调整评估集的大小,以获取模型期望的图像大小的密集批次。在这种情况下,程序员使用确定性的 keras_cv.layers.Resizing 来避免给评估指标增加噪声。

inference_resizing = keras_cv.layers.Resizing(
    IMAGE_SIZE[0], IMAGE_SIZE[1], crop_to_aspect_ratio=True
)
eval_ds = eval_ds.map(inference_resizing, num_parallel_calls=tf.data.AUTOTUNE)

image_batch = next(iter(eval_ds.take(1)))["images"]
keras_cv.visualization.plot_image_gallery(
    image_batch,
    rows=3,
    cols=3,
    value_range=(0, 255),
    show=True,
)

解包我们的数据集,并准备将它们传递给 model.fit(),该函数接受一个 (images, labels) 的元组。

def unpackage_dict(inputs):
    return inputs["images"], inputs["labels"]


train_ds = train_ds.map(unpackage_dict, num_parallel_calls=tf.data.AUTOTUNE)
eval_ds = eval_ds.map(unpackage_dict, num_parallel_calls=tf.data.AUTOTUNE)

3.4 数据优化

为了达到最佳性能,我们需要使用学习率调度器而不是单一的学习率。虽然这里不会详细介绍带有预热(warmup)的余弦衰减(Cosine decay)调度器,但你可以在这里了解更多关于它的信息。

学习率调度器在训练过程中动态地改变学习率,以适应不同的训练阶段。例如,在训练的早期阶段,可能需要一个较高的学习率来快速减少损失,而随着训练的深入,学习率逐渐减小,以进行更精细的调整。

带有预热(warmup)的余弦衰减(Cosine decay)是一种常用的学习率调度策略。在预热阶段,学习率从较小的值开始,并逐渐增加到基础学习率,这有助于模型在训练的早期阶段稳定下来。然后,学习率按照余弦函数进行衰减,直到训练结束。

使用这种策略,可以更有效地训练模型,通常可以获得更好的性能。但是,具体的参数设置(如预热阶段的长度、基础学习率等)可能需要根据你的数据集和模型进行调整。

def lr_warmup_cosine_decay(
    global_step,
    warmup_steps,
    hold=0,
    total_steps=0,
    start_lr=0.0,
    target_lr=1e-2,
):
    # Cosine decay
    learning_rate = (
        0.5
        * target_lr
        * (
            1
            + ops.cos(
                math.pi
                * ops.convert_to_tensor(
                    global_step - warmup_steps - hold, dtype="float32"
                )
                / ops.convert_to_tensor(
                    total_steps - warmup_steps - hold, dtype="float32"
                )
            )
        )
    )

    warmup_lr = target_lr * (global_step / warmup_steps)

    if hold > 0:
        learning_rate = ops.where(
            global_step > warmup_steps + hold, learning_rate, target_lr
        )

    learning_rate = ops.where(global_step < warmup_steps, warmup_lr, learning_rate)
    return learning_rate


class WarmUpCosineDecay(schedules.LearningRateSchedule):
    def __init__(self, warmup_steps, total_steps, hold, start_lr=0.0, target_lr=1e-2):
        super().__init__()
        self.start_lr = start_lr
        self.target_lr = target_lr
        self.warmup_steps = warmup_steps
        self.total_steps = total_steps
        self.hold = hold

    def __call__(self, step):
        lr = lr_warmup_cosine_decay(
            global_step=step,
            total_steps=self.total_steps,
            warmup_steps=self.warmup_steps,
            start_lr=self.start_lr,
            target_lr=self.target_lr,
            hold=self.hold,
        )

        return ops.where(step > self.total_steps, 0.0, lr)

构建优化器

total_images = 9000
total_steps = (total_images // BATCH_SIZE) * EPOCHS
warmup_steps = int(0.1 * total_steps)
hold_steps = int(0.45 * total_steps)
schedule = WarmUpCosineDecay(
    start_lr=0.05,
    target_lr=1e-2,
    warmup_steps=warmup_steps,
    total_steps=total_steps,
    hold=hold_steps,
)
optimizer = optimizers.SGD(
    weight_decay=5e-4,
    learning_rate=schedule,
    momentum=0.9,
)

最后,我们现在可以构建我们的模型并调用 fit() 方法了!keras_cv.models.EfficientNetV2B0Backbone()keras_cv.models.EfficientNetV2Backbone.from_preset('efficientnetv2_b0') 的一个便利别名。请注意,这个预设并没有附带任何预训练的权重。

backbone = keras_cv.models.EfficientNetV2B0Backbone()
model = keras.Sequential(
    [
        backbone,
        keras.layers.GlobalMaxPooling2D(),
        keras.layers.Dropout(rate=0.5),
        keras.layers.Dense(101, activation="softmax"),
    ]
)

由于 MixUp() 和 CutMix() 产生的标签是有些人为的,我们采用标签平滑(label smoothing)来防止模型过度拟合这些增强过程产生的伪影。

loss = losses.CategoricalCrossentropy(label_smoothing=0.1)

编译模型

model.compile(
    loss=loss,
    optimizer=optimizer,
    metrics=[
        metrics.CategoricalAccuracy(),
        metrics.TopKCategoricalAccuracy(k=5),
    ],
)

调用fit()

model.fit(
    train_ds,
    epochs=EPOCHS,
    validation_data=eval_ds,
)

你现在已经知道如何在 KerasCV 中从头开始训练一个强大的图像分类器了。根据你的应用可用的标记数据的数量,从头开始训练可能不一定比使用迁移学习(加上上面讨论的数据增强)更强大。对于较小的数据集,预训练模型通常能产生较高的准确率和更快的收敛速度。

迁移学习是一种强大的技术,它允许你将从一个任务中学到的知识应用到另一个任务中,特别是在标记数据有限的情况下。通过使用预训练的模型作为起点,并利用大量的未标记或标记的数据进行微调(fine-tuning),你可以在不牺牲太多性能的情况下,从较小的数据集中受益。

然而,对于非常大的数据集或特定于任务的数据集,从头开始训练模型可能会更好,因为它可以学习到针对该任务特有的特征。在这种情况下,数据增强和其他正则化技术(如 Dropout、Batch Normalization 等)可以帮助防止过拟合,并提高模型的泛化能力。

总之,选择从头开始训练还是使用迁移学习,取决于你的具体需求、可用的数据量和计算资源。

4、总结

KerasCV 是一个专注于计算机视觉任务的库,它基于 Keras 框架,为图像分类、目标检测、图像分割等任务提供了丰富的模块化组件。

  1. 模块化设计

    • KerasCV 采用了模块化的设计,使得开发者可以轻松地组合和重用各种组件,如模型、层、指标、回调等。这种设计使得图像分类任务的开发更加灵活和高效。
  2. 与主流框架的兼容性

    • KerasCV 支持 TensorFlow、JAX 和 PyTorch 等主流深度学习框架,使得开发者可以在自己熟悉的框架上进行开发。同时,这也意味着 KerasCV 可以充分利用这些框架提供的最新功能和优化。
  3. 预训练模型与迁移学习

    • KerasCV 提供了多种预训练的图像分类模型,如 EfficientNet、ResNet 等。这些模型已经在大型数据集(如 ImageNet)上进行了训练,并具有良好的泛化能力。开发者可以通过迁移学习的方式,利用这些预训练模型在自己的数据集上进行微调,从而快速构建出高效的图像分类系统。
  4. 数据增强与正则化

    • KerasCV 提供了丰富的数据增强和正则化技术,如随机裁剪、旋转、翻转、颜色抖动等。这些技术可以增加模型的鲁棒性,防止过拟合,并提高模型的泛化能力。同时,KerasCV 还提供了灵活的回调机制,使得开发者可以在训练过程中动态地调整数据增强策略。
  5. 模型训练与评估

    • KerasCV 提供了简单易用的 API,用于模型的训练、验证和评估。开发者可以轻松地定义损失函数、优化器、评价指标等,并通过 Keras 的回调机制对训练过程进行监控和管理。此外,KerasCV 还支持多GPU训练和分布式训练,以加快训练速度和提高资源利用率。
  6. 生产级部署

    • KerasCV 的组件可以在任何框架中进行训练和序列化,并在另一个框架中重复使用,而无需进行昂贵的迁移。这使得 KerasCV 的模型可以轻松地从研究阶段过渡到生产阶段,并在不同的应用场景中进行部署和扩展。
  7. 持续更新与优化

    • KerasCV 是一个持续更新和优化的库,不断引入新的算法、模型和组件,以满足计算机视觉领域的最新需求。同时,KerasCV 还与 TensorFlow 和其他深度学习社区保持紧密的合作和交流,以共享最新的研究成果和技术进展。

综上所述,KerasCV 在图像分类方面提供了强大的支持,其模块化设计、与主流框架的兼容性、预训练模型与迁移学习、数据增强与正则化、模型训练与评估以及生产级部署等特性使得开发者可以更加高效地进行图像分类任务的开发和部署。

  • 36
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MUKAMO

你的鼓励是我们创作最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值