2021SC@SDUSC
目标检测是计算机视觉中的一项重要任务。使用深度学习进行对象检测可以产生高度准确的模型,但开发人员也可能遇到一些挑战。首先,深度学习模型的训练成本非常高——即使使用 GPU,现代对象检测模型也可能需要数小时的计算才能从头开始训练。管理这些 GPU 并在多个 GPU 上并行运行工作负载很快就会变得复杂。其次,对象检测模型通常具有许多超参数。虽然存在自动调整超参数的算法,但在实践中应用这些算法需要运行数百或数千个训练作业并比较所有这些模型的性能。说复杂!
确定使训练深度学习模型和调整超参数变得更加容易。它可以自动将作业调度到一组 GPU(本地或云端)上,并包括用于高效超参数调整的最先进算法。它提供了一个实时仪表板来跟踪和可视化结果,使您能够实时清楚地了解模型的表现——作为模型开发人员,您可以快速开始训练工作或 HP 搜索,和决心会照顾其余的。
确定还可以轻松地同时使用多个 GPU,这意味着您可以更快地训练单个模型(使用分布式训练)或在更短的时间内搜索大量超参数空间 - 无需修改代码或手动管理 GPU。确定让您专注于模型开发,因此您可以更快地将想法转化为生产中的工作模型。
要了解确定的其他功能,请查看文档
在本博客中,将首先在 AWS 上安装Determined,然后修改现成的 tf.keras 对象检测模型以与Determined一起工作。 接下来,将在单个 GPU 上训练模型,最后进行超参数搜索。
所使用的模型基于使用 RetinaNet 进行对象检测。
RetinaNet 是一个两阶段检测器——它既定位又检测图像中存在的对象。 它使用特征金字塔网络来检测多个尺度的对象,并引入了一种新的损失,即焦点损失函数,以缓解极端前景-背景类不平衡的问题。 要深入了解模型,可以参考原始论文 Focal Loss for Dense Object Detection。
可以使用 GCP 或您选择的本地 Linux 实例。 master运行的实例至少要有200GB的磁盘空间; 每个代理实例应该有 50GB 的磁盘空间。 我将使用单个代理并将主实例和代理部署到同一个 AWS 实例。
要在单个 AWS 实例上安装确定,按照下列步骤操作:
每个步骤都附有与 Amazon Linux/RHEL/CentOS Linux 实例兼容的代码。
步骤 1:设置Linux 实例 — AWS、GCP 或本地。
第 2 步:确保 Linux 实例上安装了 Python3 和 Docker。
sudo yum install python3 docker
第三步:启动docker服务。
sudo service docker start
第 4 步:为 docker 套接字分配全局读、写和执行权限。
sudo chmod 777 /var/run/docker.sock
第五步:使用pip安装det-deploy,这个工具我们将用来安装确定系统的其余部分。
sudo pip3 install determined-deploy
步骤 6:使用 pip 安装确定的 CLI。 CLI 用于提交新的深度学习工作负载以供确定系统的其余部分执行。
sudo pip3 install determined-cli
第七步:设置DET_MASTER环境变量; 这会告诉 CLI 运行确定主服务器的 IP 地址或主机名。 在这种情况下,我们将 master 部署到安装了 det-deploy 的同一个实例,因此我们可以使用“localhost”。
export DET_MASTER=<master-hostip>
第 8 步:调出确定的主和代理。
如果您的系统有 GPU,请确保已安装 NVIDIA 驱动程序以及 NVIDIA 容器工具包。
如果您使用带有 GPU 的 AWS 实例,请运行以下命令:
det-deploy local cluster-up
如果使用的是没有 GPU 的 AWS 实例,请运行以下命令:
det-deploy local cluster-up --no-gpu
现在在工作区中设置了一个确定的集群。
上述过程不是安装确定的唯一方法; 对于生产部署,在单个实例(不带 GPU)上运行主实例,并配置“确定”以在提交新的深度学习工作负载时自动配置称为“动态代理”的配备 GPU 的实例。
将模型移植到Determined的涉及使模型与确定的 API 兼容。有关调整现有模型代码以使用确定的更多信息,请查看确定的 tf.keras 教程。
一旦我们的模型代码适应了确定的工作,我们将训练模型的单个实例并执行超参数搜索 - 无需更改我们的模型代码!
可以在此处下载模型源代码。
概述
将模型移植到确定的 API 通常很简单;如果我们有一个现有的训练脚本,大部分代码可以保持不变,我们只需要“重构”它以适应四个不同的步骤:
初始化你的模型
定义你的模型
加载训练数据集
加载验证数据集
首先必须初始化一个模型。此步骤涉及定义训练模型时可能需要的所有超参数。
接下来,定义模型的层,以及使用的优化器和损失。
分别加载训练和验证模型所需的训练和验证数据。
然后将这四个方法排列在一个基于 TensorFlow 的 Trial 类——一个继承自determined.keras.TFKerasTrial 类的Python 类中,如下所示:
import keras
from determined.keras import TFKerasTrial, TFKerasTrialContext
class ObjectDetectionTrial(TFKerasTrial):
def __init__(self, context: TFKerasTrialContext):
# Initialize the trial class.
pass
def build_model(self):
# Define and compile the model graph.
pass
def build_training_data_loader(self):
# Create the training data loader. This should return a
# keras.Sequence, a tf.data.Dataset, or NumPy arrays.
pass
def build_validation_data_loader(self):
# Create the validation data loader. This should return a
# keras.Sequence, a tf.data.Dataset, or NumPy arrays.
pass
这个试用类定义了模型的原型。
深度学习算法建模通常涉及的实际训练和测试程序如何?
确定提供了一个内置的训练循环,在加载训练数据后会自动调用。 它会记录训练和验证指标并定期检查模型的状态。
原型设计到位后,定义每个试用类方法。
这一步涉及我们在 Python 类中看到的典型 init() 方法。 确定将参数 TrialContext 传递给此方法,该方法包含有关训练时使用的超参数以及其他有用数据的信息。
对于当前的对象检测模型,将上下文存储到实例变量中。
def __init__(self, context: TFKerasTrialContext):
self.context = context
创建一个名为 startup-hook.sh 的文件,内容如下所示。 一个启动钩子是一个特殊的文件,在每个试用容器的启动过程中,在调用用户的模型代码之前,它会被确定执行。 它对于自定义容器环境(例如,设置环境变量)和安装其他依赖项很有用。 在这种情况下,我们将使用启动钩子来安装 tensorflow_datasets 库:
pip install -q -U tensorflow-datasets==4.1.0
此步骤涉及定义模型的架构。 build_model() 方法,如 Trial 类中所见,返回一个已编译的 tf.keras.Model 对象。 在这种方法中,模型必须在编译之前通过调用 self.context.wrap_model() 进行包装,并且优化器需要通过调用 self.context.wrap_optimizer() 进行包装。
def build_model(self):
resnet50_backbone = get_backbone()
loss_fn = RetinaNetLoss(self.context.get_hparam("num_classes"))
model = RetinaNet(self.context.get_hparam("num_classes"), resnet50_backbone)
model = self.context.wrap_model(model)
learning_rate_fn = tf.optimizers.schedules.PiecewiseConstantDecay(
boundaries=[125, 250, 500, 240000, 360000],
values=self.context.get_hparam("learning_rate")
)
optimizer = tf.optimizers.SGD(learning_rate=learning_rate_fn, momentum=0.9)
optimizer = self.context.wrap_optimizer(optimizer)
model.compile(loss=loss_fn, optimizer=optimizer)
return model
接下来,分别使用 build_training_data_loader() 和 build_testing_data_loader() 方法加载训练和测试数据集。 确定支持多个用于将数据加载到 tf.keras 模型的 API,包括 tf.keras.Sequence、tf.data.Dataset,甚至是一对 NumPy 数组(用于小数据集或测试运行)。
现在,将对象检测数据加载到 tf.data.Dataset 对象中。
def build_training_data_loader(self):
label_encoder = LabelEncoder()
train, dataset_info = tfds.load(
"coco/2017", split="train[:5%]", with_info=True
)
autotune = tf.data.experimental.AUTOTUNE
train = train.map(preprocess_data, num_parallel_calls=autotune)
train = self.context.wrap_dataset(train)
train_dataset = train.cache().shuffle(8 * self.context.get_hparam("batch_size"))
train_dataset = train_dataset.padded_batch(
batch_size=self.context.get_hparam("batch_size"),
padding_values=(0.0, 1e-8, -1),
drop_remainder=True
)
train_dataset = train_dataset.map(
label_encoder.encode_batch, num_parallel_calls=autotune
)
train_dataset = train_dataset.apply(tf.data.experimental.ignore_errors())
train_dataset = train_dataset.prefetch(autotune)
return train_dataset
同样,使用 tf.data.Dataset 对象加载测试数据。
def build_validation_data_loader(self):
label_encoder = LabelEncoder()
test, dataset_info = tfds.load(
"coco/2017", split="validation", with_info=True
)
autotune = tf.data.experimental.AUTOTUNE
test = test.map(preprocess_data, num_parallel_calls=autotune)
test = self.context.wrap_dataset(test)
test_dataset = test.padded_batch(
batch_size=1, padding_values=(0.0, 1e-8, -1), drop_remainder=True
)
test_dataset = test_dataset.map(label_encoder.encode_batch, num_parallel_calls=autotune)
test_dataset = test_dataset.apply(tf.data.experimental.ignore_errors())
test_dataset = test_dataset.prefetch(autotune)
return test_dataset
确保还包括运行模型所需的杂项功能。 可以在此处找到模型的完整源代码。
在接下来一篇博客中将继续学习介绍训练模型、运行实验、评估模型、调整超参数等内容