深度学习架构师手册——深度神经架构搜索 (Deep Neural Architecture Search, DNAs)

378 阅读50分钟

前几章介绍并回顾了不同的神经网络(NN),它们被设计用来处理不同类型的数据。设计这些网络需要知识和直觉,而这些只有通过消化多年的领域研究才能获得。这些网络的大部分是由专家和研究人员手工设计的。这包括发明完全新的神经网络层,并通过组合和堆叠现有的神经网络层来构建一个实际可用的架构。两个任务都需要大量的迭代实验时间才能真正取得成功,创造出一个有用的网络。

现在,想象一个世界,我们可以专注于发明有用的新型层,而软件则负责自动化最终架构构建过程。自动化架构搜索方法正是通过简化设计最佳最终神经网络架构的任务来实现这一点,只要根据深厚的领域知识选择合适的搜索空间。在本章中,我们将重点讨论使用一种叫做神经架构搜索(NAS)的自动化架构创建过程,从现有的神经网络层构建一个实际可用的架构。通过理解不同类型的NAS,您将能够根据当前的模型构建设置选择最直接的自动化搜索优化方法,方法可以是从简单到高效复杂的。具体来说,本章将介绍以下内容:

  • 理解NAS的宏观概念
  • 理解基于超参数搜索的NAS
  • 理解基于强化学习(RL)的NAS
  • 理解非强化学习(RL)基础的NAS

技术要求

本章包括Python编程语言中的实际实现。这些简单的方法需要安装以下库:

  • numpy
  • pytorch
  • catalyst == 21.12
  • scikit-learn

您可以在GitHub上找到本章的代码文件,网址为:github.com/PacktPublis…

理解NAS的大局观

在深入探讨NAS方法的大局观细节之前,重要的是要注意,尽管NAS减少了塑造最终架构所需的人工努力,但它并不完全消除领域专业知识的需求。正如我们之前讨论的,深度学习(DL)的基础知识对于选择适当的搜索空间以及准确解读NAS的结果至关重要。搜索空间是指在搜索过程中可以探索的可能选项或配置集合。此外,NAS的性能在很大程度上依赖于训练数据的质量以及搜索空间与任务的相关性。因此,领域专业知识仍然是必不可少的,以确保最终架构不仅高效,而且准确且与所解决的问题相关。通过本节的学习,您将更好地理解如何利用您的领域专业知识来优化NAS的有效性。

前几章关于神经网络(NN)的内容仅介绍了少数几种显著的NN层类型,并且只是略微涉及了所有神经网络层的完整库。如今,NN层的变种太多,导致很难精确设计在架构中哪个点使用哪些层。主要问题在于,可能的NN架构空间是无限大的。此外,评估任何可能的架构设计在资源方面是缓慢且昂贵的。正因为如此,评估所有可能的NN架构是不可能的。以在ImageNet上训练卷积神经网络(CNN)ResNet50架构为例,让我们感受一下这有多么不可能。使用单个RTX 3080 Ti Nvidia GPU进行训练大约需要3到4天,这款GPU是为普通消费者设计的,市面上可以直接购买。而商业消费者通常会获得工业级GPU,其处理能力更强,能够将训练时间缩短到一天以内。

通常,研究人员会通过直觉手工设计架构,使用已有的NN层和操作。这种手工方法是一项一次性的工作,每当发明出新的、更好的核心NN层时,重复此过程是不可扩展的。这时,NAS就派上用场了。NAS利用已经发明的NN层和操作来构建更高效的NN架构。NAS的核心在于使用更智能的方式在不同架构之间进行概念搜索。NAS的搜索机制可以通过三种方式实现,分别是:一般超参数搜索优化、强化学习(RL)和不使用RL的NAS方法。

一般超参数搜索优化是指可以应用于任何机器学习(ML)算法超参数优化的方法。强化学习(RL)是另一种高级ML方法,与监督学习(SL)和无监督学习(UL)一起,RL处理的是在一个环境中优化所采取的动作,这些动作会产生具有可量化奖励或惩罚的状态。非RL基础的NAS方法可以进一步细分为三种不同类型:从小型架构基线逐渐增长的渐进架构、从复杂的完全定义架构图中逐步缩小的渐进架构以及进化算法。渐进架构增长方法包括所有将简单网络逐步增长为更大网络的方法,通过增加深度或宽度实现。相反,也有一些方法首先定义一个具有所有可能连接和操作的架构,并逐步去掉这些连接。最后,进化算法是一类基于生物现象(如变异和繁殖)的算法。在本章中,我们将仅介绍一些一般超参数搜索优化方法、RL方法、基于渐进增长的NAS的简单形式以及基于渐进缩小的NAS的竞争版本。渐进增长的NAS方法将提供技术实现,而其他更复杂的方法则将参考开源的实现。

在深入探讨上述任何NAS方法之前,您首先需要理解微架构和宏架构的概念。微架构是指在逻辑块中使用的层的具体组合。正如在第三章《理解卷积神经网络》中介绍的那样,这些逻辑块可以重复堆叠在一起,生成实际使用的架构。最终创建的架构中也可能有不同的逻辑块,它们具有不同的层配置。与之相比,宏架构是指不同块如何组合在一起形成最终神经网络架构的高层概述。NAS方法的核心思想总是围绕着基于已整理的知识减少搜索空间,而这些知识涉及哪些层或层配置是最有效的。本章将介绍的方法,要么保持宏架构设置固定,只在微架构空间中进行搜索,要么具有灵活性,可以通过创造性的技巧探索微架构和宏架构空间,从而使搜索成为可能。

首先,让我们从最简单的NAS方法——一般超参数搜索优化算法开始。

理解基于一般超参数搜索的NAS

在机器学习(ML)中,参数通常指的是模型在训练过程中学习到的权重和偏置,而超参数是在训练开始之前设置的,并影响模型学习方式的值。超参数的例子包括学习率和批量大小。一般超参数搜索优化算法是一种NAS方法,用于自动搜索构建给定神经网络架构所使用的最佳超参数。让我们回顾一下几种可能的超参数。在多层感知器(MLP)中,超参数可以是控制MLP深度的层数、每一层的宽度,以及所使用的中间层激活函数类型。在卷积神经网络(CNN)中,超参数可以是卷积层的滤波器大小、每层的步幅大小,以及每个卷积层后使用的中间层激活函数类型。

对于神经网络架构,可以配置的超参数类型在很大程度上依赖于用于创建和初始化神经网络的辅助工具和方法的能力。例如,考虑配置三个隐藏层大小的任务。如果有一种方法能够生成一个固定层数为三层的MLP,那么就可以只对隐藏层大小执行超参数搜索。通过简单地为函数添加三个超参数,可以分别设置这三个隐藏层的大小。然而,为了实现既能搜索层数又能搜索隐藏层大小的灵活性,必须构建一个可以动态应用这些超参数来创建MLP的辅助方法。

NAS的最简单形式利用这些工具,对已定义的超参数进行更智能的搜索。这里将介绍三种著名的超参数搜索变种:连续二分法、Hyperband和贝叶斯超参数优化。我们将通过一个来自pytorch的MLP来介绍这三种算法,因为它的实现足够简短,适合放在一章中。让我们从连续二分法开始。

使用连续二分法搜索神经架构

一种通过减少搜索空间来优化运行时间的最基本方法是随机抽样一些超参数配置,并仅对选定的配置执行完整的训练和评估。这种方法被称为随机搜索。如果我们知道某些配置在消耗了一定数量的资源后几乎肯定会表现不佳怎么办?

连续二分法是随机搜索的一种扩展,有助于在搜索最佳神经架构时节省资源。连续二分法的思想是在每个步骤中淘汰表现不佳的配置的一半,从而集中精力关注更有前景的配置。这样,我们就不会浪费时间在那些不太可能产生良好结果的配置上。

让我们通过一个简单的例子来解释这一概念。假设您正在尝试找到一个MLP的最佳配置,超参数包括层数和层大小。您首先随机抽样100种不同的配置。现在,您不需要对所有100个配置进行完整训练,而是应用连续二分法。您对每个配置进行短时间训练(例如,5个周期),然后评估它们在验证数据集上的表现。此时,您淘汰掉50个表现最差的配置,继续训练剩余的50个配置,再进行5个周期的训练。

经过第二轮训练后,您再次评估剩余配置的表现,淘汰掉25个表现最差的配置。然后,前25个配置将继续训练,直到收敛。通过应用连续二分法,您可以节省资源和时间,集中精力在最有前景的配置上,同时在早期就丢弃那些表现不佳的配置。这使得您能够更高效地搜索最佳的神经架构。

接下来,我们将深入探讨连续二分法的技术实现,并为接下来所有基于一般超参数调优的NAS方法奠定基础:

首先,我们导入相关的库并设置pytorch库的随机种子,以确保结果的可重复性:

import json
import os
import numpy as np
import torch
import torch.nn as nn
import torch.nn.functional as F
from catalyst import dl, utils
from catalyst.contrib.datasets import MNIST
from sklearn import datasets
from sklearn.metrics import log_loss
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import MinMaxScaler
from torch import nn as nn
from torch import optim
from torch.utils.data import DataLoader, TensorDataset
torch.manual_seed(0)

接下来,定义一个pytorch MLP类,根据隐藏层的数量和每层的隐藏大小动态构建MLP:

class MLP(nn.Module):
    def __init__(self, input_layer_size, output_layer_size, layer_configuration, activation_type='relu'):
        super(MLP, self).__init__()
        self.fully_connected_layers = nn.ModuleDict()
        self.activation_type = activation_type
        hidden_layer_number = 0
        for hidden_layer_idx in range(len(layer_configuration)):
            if hidden_layer_idx == 0:
                self.fully_connected_layers[
                    str(hidden_layer_number)
                ] = nn.Linear(
                    input_layer_size,
                    layer_configuration[hidden_layer_idx]
                )
                hidden_layer_number += 1
            if hidden_layer_idx == len(layer_configuration) - 1:
                self.fully_connected_layers[
                    str(hidden_layer_number)
                ] = nn.Linear(
                    layer_configuration[hidden_layer_idx],
                    output_layer_size
                )
            else:
                self.fully_connected_layers[
                    str(hidden_layer_number)
                ] = nn.Linear(
                    layer_configuration[hidden_layer_idx],
                    layer_configuration[hidden_layer_idx + 1]
                )
                hidden_layer_number += 1

    def forward(self, x):
        for fc_key in self.fully_connected_layers:
            x = self.fully_connected_layers[fc_key](x)
            if fc_key != str(len(self.fully_connected_layers) - 1):
                x = F.relu(x)
        return x

接下来,我们需要训练此MLP的逻辑,当提供特定的层配置列表时,使用pytorch抽象库Catalyst训练模型,并保存最佳和最后一个周期的模型:

def train_and_evaluate_mlp(
    trial_number, layer_configuration, epochs,
    input_layer_size, output_layer_size,
    load_on_stage_start=False, best_or_last='last',
    verbose=False
):
    criterion = nn.CrossEntropyLoss()
    runner = dl.SupervisedRunner(
        input_key="features", output_key="logits",
        target_key="targets", loss_key="loss"
    )
    model = MLP(
        input_layer_size=input_layer_size,
        layer_configuration=layer_configuration,
        output_layer_size=output_layer_size,
    )
    optimizer = optim.Adam(model.parameters(), lr=0.02)
    checkpoint_logdir = "logs/trial_{}".format(
        trial_number
    )
    runner.train(
        model=model, criterion=criterion,
        optimizer=optimizer, loaders=loaders,
        num_epochs=epochs,
        callbacks=[
            dl.CheckpointCallback(
                logdir=checkpoint_logdir,
                loader_key="valid",
                metric_key="loss",
                mode="all",
                load_on_stage_start="last_full" if load_on_stage_start else None,
            )
        ], logdir="./logs", valid_loader="valid",
        valid_metric="loss", minimize_valid_metric=True,
        verbose=verbose
    )
    with open(os.path.join(checkpoint_logdir, '_metrics.json'), 'r') as f:
        metrics = json.load(f)
        if best_or_last == 'last':
            valid_loss = metrics['last']['_score_']
        else:
            valid_loss = metrics['best']['valid']['loss']
    return valid_loss

接下来,我们需要一个生成随机超参数的函数,这里超参数结构为一个隐藏层大小规格的列表,列表中项目的数量决定了层数。我们将隐藏层数范围固定为1到6层,隐藏层大小范围为2到100:

def get_random_configurations(
    number_of_configurations, rng
):
    layer_configurations = []
    for _ in range(number_of_configurations):
        layer_configuration = []
        number_of_hidden_layers = rng.randint(
            low=1, high=6
        )
        for _ in range(number_of_hidden_layers):
            layer_configuration.append(
                rng.randint(low=2, high=100)
            )
        layer_configurations.append(layer_configuration)
    layer_configurations = np.array(
        layer_configurations
    )
    return layer_configurations

现在,随着辅助函数的定义完成,我们来设置数据集,应用MLP。这里我们将使用scikit-learn的鸢尾花数据集。我们将加载它、缩放数据、拆分为训练集和验证集,并准备好供Catalyst库使用。注意,到此为止的代码将在接下来的两个方法中重复使用:

iris = datasets.load_iris()
iris_input_dataset = iris['data']
target = torch.from_numpy(iris['target'])
scaler = MinMaxScaler()
scaler.fit(iris_input_dataset)
iris_input_dataset = torch.from_numpy(
    scaler.transform(iris_input_dataset)
).float()
(
    X_train, X_test, y_train, y_test
) = train_test_split(
    iris_input_dataset, target, test_size=0.33,
    random_state=42
)
training_dataset = TensorDataset(X_train, y_train)
validation_dataset =  TensorDataset(X_test, y_test)
train_loader = DataLoader(
    training_dataset, batch_size=10, num_workers=1
)
valid_loader = DataLoader(
    validation_dataset, batch_size=10, num_workers=1
)
loaders = {"train": train_loader, "valid": valid_loader}

接下来,我们将采取连续二分法的方式,使用训练周期作为资源组件,在每次迭代完成预定数量的周期后执行三次连续二分法。前两轮的表现最好的配置将继续训练。我们使用20个初始配置,并进行3轮,每轮5个周期的连续二分法。接下来,定义这些值以及控制生成配置的随机数生成器:

rng = np.random.RandomState(1234)
number_of_configurations = 20
layer_configurations = get_random_configurations(
    number_of_configurations, rng
)
successive_halving_epochs = [5, 5, 5]

最后,我们将定义连续二分法的执行逻辑。请注意,最后训练的周期权重将在下一轮使用,而不是使用验证得分最好的周期:

for succesive_idx, successive_halving_epoch in enumerate(successive_halving_epochs):
    valid_losses = []
    for idx, layer_configuration in enumerate(layer_configurations):
        trial_number = trial_numbers[idx]
        valid_loss = train_and_evaluate_mlp(
            trial_number, layer_configuration,
            epochs=successive_halving_epoch,
            load_on_stage_start=False if succesive_idx==0 else True
        )
        valid_losses.append(valid_loss)
        if succesive_idx != len(successive_halving_epochs) - 1:
            succesive_halved_configurations = np.argsort(
                valid_losses
            )[:int(len(valid_losses)/2)]
            layer_configurations = layer_configurations[
                succesive_halved_configurations
            ]
            trial_numbers = trial_numbers[
                succesive_halved_configurations
            ]

通过以下逻辑,最终可以找到表现最好的配置:

best_loss_idx = np.argmin(valid_losses)
best_layer_configuration = layer_configurations[best_loss_idx]
best_loss_trial_number = trial_numbers[best_loss_idx]

在连续二分法中,有些配置可能只有在训练过程的后期才会表现良好,而有些配置则可能在训练过程的早期就表现出色。选择较长或较短的等待时间会使某些模型处于不利地位,因此需要找到一个平衡点,但我们可能并不知道这个平衡点是什么。接下来将介绍的Hyperband方法正是尝试解决这个问题。

使用Hyperband搜索神经架构

Hyperband通过执行多个独立的端到端连续二分法迭代(称为“括号”)来改进连续二分法中的一些不足。每个连续的括号将有更小的原始样本配置,但会分配更多的资源。这个算法本质上允许一些随机采样的配置训练得更久,从而增加了展示良好性能的潜力,以便在后续括号中放弃这些配置时不会浪费资源。完整的算法如图7.1所示:

image.png

该算法需要两个用户输入配置:具体来说,R是训练和评估单个配置所需的最大资源量,η是一个划分数,用来决定在每次连续二分法迭代结束时保留多少个配置。总的括号数s_max、每个括号分配的总资源B、每个括号和迭代n及n_i的配置总数,以及每个括号分配的资源r_i,都是通过公式计算得出的。为了更容易理解,图7.2展示了当R = 81和η = 3时,每个括号中Hyperband算法结果配置的示例。

image.png

这些设置会产生总共5个括号,并最终生成10个模型。然后,从这10个模型中选出最佳模型,作为搜索操作生成的最终模型。

请注意,在这种方法中,专家知识可以通过例如固定模型的宏架构并仅搜索微架构逻辑块的超参数,显式地注入到两个搜索方法的过程中。让我们使用在连续二分法话题中定义的方法和数据集,来实现Hyperband:

首先,我们需要定义计算对数所需的额外库:

import math

接下来,我们将定义Hyperband实现所需的两个输入参数,即每个配置在训练中希望使用的最大资源量(以周期为单位),以及Hyperband算法中每次连续二分法操作后配置的除数N:

resource_per_conf = 30  # R
N = 3

现在,根据图7.1定义Hyperband的主要逻辑:

s_max = int(math.log(resource_per_conf, N))
bracket_resource = (s_max + 1) * resource_per_conf
bracket_best_valid_losses = []
bracket_best_layer_configuration = []

for s in range(s_max, -1, -1):
    number_of_configurations = int(
        (bracket_resource / resource_per_conf) *
        (N**s / (s+1))
    )
    r = resource_per_conf * N**-s
    layer_configurations = get_random_configurations(
        number_of_configurations, rng
    )
    trial_numbers = np.array(
        range(len(layer_configurations))
    )
    valid_losses = []

    for i in range(s+1):
        number_of_configurations_i = int(
            number_of_configurations * N**-i
        )
        r_i = int(r * N**i)
        valid_losses = []

        for idx, layer_configuration in enumerate(layer_configurations):
            trial_number = '{}_{}'.format(
                s, trial_numbers[idx]
            )
            valid_loss = train_and_evaluate_mlp(
                trial_number, layer_configuration,
                epochs=r_i, load_on_stage_start=False if s == s_max else True
            )
            valid_losses.append(valid_loss)
            if succesive_idx != len(successive_halving_epochs) - 1:
                succesive_halved_configurations = np.argsort(
                    valid_losses
                )[:int(number_of_configurations_i / N)]
                layer_configurations = layer_configurations[
                    succesive_halved_configurations
                ]
                trial_numbers = trial_numbers[
                    succesive_halved_configurations
                ]
                best_loss_idx = np.argmin(valid_losses)
                best_layer_configuration = layer_configurations[best_loss_idx]
                best_loss_trial_number = trial_numbers[
                    best_loss_idx
                ]
                bracket_best_valid_losses.append(
                    valid_losses[best_loss_idx]
                )
                bracket_best_layer_configuration.append(
                    best_layer_configuration
                )

这两种方法在很大程度上依赖于随机搜索,但在选择超参数配置时并没有非常智能。接下来,我们将探索一种搜索方法,它在一些初步搜索完成后,优化下一个超参数的选择。

使用贝叶斯超参数优化搜索神经架构

贝叶斯超参数优化是一种利用替代性能估计模型来选择一组估计最佳的配置进行采样和评估的方法。采样配置以进行训练和评估的过程正式称为获取函数(acquisition function)。与随机采样并希望其表现良好不同,贝叶斯优化试图利用从初始随机配置采样和实际训练评估中获得的先验信息,找到估计上表现良好的新配置。贝叶斯优化包括以下步骤:

  1. 采样一组超参数配置。
  2. 使用这些配置进行完整的训练和评估,获得性能评分。
  3. 使用所有可用数据训练一个替代回归模型(通常使用高斯过程(GP)模型),基于超参数估计性能评分。
  4. 使用所有可能的超参数配置,或者随机采样一定数量的超参数配置,并使用替代模型预测性能评分。
  5. 获取替代模型中估计的最小性能评分的k个超参数配置。
  6. 重复步骤1到步骤5,直到达到预定的次数,或者直到获得足够好的结果,或者直到资源预算用尽。

该过程本质上试图通过估计将要产生的评分来加速实际的训练和评估过程,并且仅实际训练那些估计上表现最好的几个配置。优化只有在替代模型性能评分估计函数比实际训练和评估主模型的速度要快得多时才有效。请注意,标准的贝叶斯优化仅适用于连续空间,并不能很好地处理离散超参数。

让我们使用之前定义的方法和数据集,探讨基于贝叶斯优化的NAS的技术实现:

首先,我们导入贝叶斯优化方法背后的主要工具——来自scikit-learn的高斯过程回归器(GaussianProcessRegressor):

from sklearn.gaussian_process import GaussianProcessRegressor

接下来,我们定义生成结构化固定大小列的方法,列的大小为6,这是之前定义的最大可能层数。当层数少于6时,后续的列将只是作为特征的0层:

def get_bayesian_optimization_input_features(
    layer_configurations
):
    bo_input_features = []
    for layer_configuration in layer_configurations:
        bo_input_feature = layer_configuration + [0] * (6 - len(layer_configuration))
        bo_input_features.append(bo_input_feature)
    return bo_input_features

接下来,我们定义基于贝叶斯优化的NAS使用MLP时的三个重要参数。第一个参数是配置数量。我们在这里的做法是:在第一轮中初步训练100个配置,按照指定的每个配置的周期数进行训练。然后,构建一个高斯过程回归器来预测验证损失。之后,我们将在接下来的几轮中采样配置,并使用模型预测并挑选出前五个配置进行完整的训练。在每一轮中,都会使用所有可用的验证损失数据来训练一个新的回归模型:

number_of_configurations = [100, 2000]
epochs_per_conf = 15
topk_models = 5

最后,我们定义主要逻辑来实现一个基于贝叶斯优化的NAS版本,使用MLP:

Trial_numbers = np.array(
    range(len(layer_configurations))
)
trial_number = 0
model = None
best_valid_losses_per_iteration = []
best_configurations_per_iteration = []
overall_bo_input_features = []
overall_bo_valid_losses = []

for number_of_configuration in number_of_configurations:
    valid_losses = []
    layer_configurations = get_random_configurations(
        number_of_configuration, rng
    )
    if model:
        bo_input_features = get_bayesian_optimization_input_features(layer_configurations)
        predicted_valid_losses = model.predict(
            bo_input_features
        )
        top_k_idx = np.argsort(
            predicted_valid_losses
        )[:topk_models]
        layer_configurations = layer_configurations[
            top_k_idx
        ]
    
    for idx, layer_configuration in enumerate(layer_configurations):
        trial_identifier = 'bo_{}'.format(trial_number)
        valid_loss = train_and_evaluate_mlp(
            trial_number, layer_configuration,
            epochs=epochs_per_conf,
            load_on_stage_start=False, best_or_last='best'
        )
        valid_losses.append(valid_loss)
        trial_number += 1
    
    best_loss_idx = np.argmin(valid_losses)
    best_valid_losses_per_iteration.append(
        valid_losses[best_loss_idx]
    )
    best_configurations_per_iteration.append(
        layer_configurations[best_loss_idx]
    )
    bo_input_features = get_bayesian_optimization_input_features(layer_configurations)
    overall_bo_input_features.extend(bo_input_features)
    overall_bo_valid_losses.extend(valid_losses)
    model = GaussianProcessRegressor()
    model.fit(
        overall_bo_input_features,
        overall_bo_valid_losses
    )

到此为止,我们已经完成了基于贝叶斯优化的MLP超参数搜索!

除了本章讨论的基于超参数搜索的NAS方法之外,还值得提及其他三种方法:层次搜索、代理模型和进化算法:

  • 层次搜索:专注于在不同的粒度级别上优化架构,允许更高效地探索搜索空间。
  • 代理模型:作为目标模型的轻量级近似,减少在搜索过程中评估候选架构的计算成本。
  • 进化算法:受自然选择过程启发,可以应用于NAS问题,通过变异、交叉和选择操作探索和优化架构。

在选择基于超参数搜索的NAS技术时,这些方法也可以考虑。

基于一般超参数搜索的NAS方法提供了一种比单纯的随机搜索或蛮力搜索更智能的配置搜索方式。当您已经拥有基础设施来轻松选择不同的超参数,并且已经内嵌了领域专家知识时,它能提供最大的帮助。

然而,基于一般超参数搜索的NAS通常需要大量的算法外工具来构建模型,并将那些可以通过超参数可靠控制的辅助方法形式化。除此之外,仍然需要相当多的知识来决定使用哪些类型的层,并且需要在算法外进行NN模型的宏观和微观架构的构建。

在下一节中,我们将介绍一系列NAS方法,这些方法更广泛地涵盖了实现任何神经网络NAS所需的所有步骤,这被称为基于强化学习的NAS。

理解基于RL的NAS

强化学习(RL)是一类学习算法,涉及学习一种策略,允许代理在与环境中的状态互动时,连续地做出行动决策。图7.3展示了RL算法的一般概述:

image.png

这类算法最常用于为游戏创建智能机器人,使其能够充当离线玩家,与真实人类对战。在数字游戏的背景下,环境代表了代理操作的整个设置,包括游戏角色的位置和状态,以及游戏世界的条件。另一方面,状态是在给定时间对环境的快照,反映了当前的游戏条件。强化学习中的一个关键组成部分是环境反馈组件,它可以提供奖励或惩罚。在数字游戏中,奖励和惩罚的例子包括某些形式的竞争评分系统、游戏内现金、升级系统,或有时通过死亡进行负面反馈。

当将其应用于NAS领域时,状态将是生成的神经网络架构,环境将是对生成的神经网络配置的评估。奖励和惩罚将是训练和评估后,基于选定数据集的架构的延迟性能和指标性能。另一个关键组件是策略(policy),它负责基于状态生成行动。

回顾一下在基于一般超参数搜索的NAS中,神经网络配置样本的采集是基于随机采样的。在基于强化学习的NAS方法中,目标不仅是优化搜索过程,还要优化生成神经网络配置的采集过程,这个过程是基于先前的经验来生成的。然而,不同的基于强化学习的NAS方法中,配置是如何生成的,方法是不同的。

在本节中,我们将深入探讨几种特定于NAS的强化学习方法:

  • 基于强化学习的创始NAS方法
  • 通过参数共享实现的高效NAS(ENAS)
  • 移动NAS(MNAS)

让我们从第一个基于强化学习的创始NAS方法开始。

理解基于RL的创始NAS

强化学习可以与神经网络结合使用,在NAS的应用中,使用递归神经网络(RNN)作为生成主神经网络配置所需的缺失部分,从而在测试时以概率的方式生成配置。图7.4大致展示了基于强化学习方法的创始NAS的架构概览:

image.png

RNN是策略,它根据之前与环境的交互学习步骤确定状态。在NAS的情况下,动作等同于状态。回顾一下,RNN由多个顺序递归单元组成,每个单元能够生成一个中间的顺序输出。在NAS中,这些中间的顺序输出用于预测主神经网络的特定配置。然后,这些预测结果作为输入传递给下一个RNN单元。考虑到NAS任务是在图像领域搜索最佳CNN架构。图7.5展示了使用基于RNN的神经网络配置预测来完成此任务的结构:

image.png

卷积层有一些需要决定的规格:即卷积滤波器的数量、卷积滤波器的大小和步幅的大小。图7.5展示了单个CNN层的预测。对于后续的CNN层,相同的长短期记忆(LSTM)单元会在顺序中重复预测,最后一个LSTM单元的状态和单元输出作为输入。对于一个四层的CNN,LSTM将自回归地执行四次,以获得所有所需的配置预测。

至于如何更新LSTM的参数,将使用一种叫做策略梯度(policy gradient)的方法。策略梯度是一组使用梯度来更新策略的方法。具体来说,这里使用的是强化规则(reinforce rule),用于计算更新参数的梯度。用更通俗易懂的术语来说,以下公式展示了梯度的计算方式:

gradients = 对所有采样架构的(交叉熵损失 × (奖励 − 前奖励的移动平均))求平均

这里的交叉熵损失特别用于强调配置预测任务被框架化为多类分类问题,以便将搜索参数的数量限制在较小的范围内,同时确保设置了边界。例如,您不会希望为单个CNN层使用一百万个滤波器,或者在MLP中使用一百万神经元大小的全连接层。

这里的强化学习过程受到探索与利用(exploration vs exploitation)概念的指导。如果我们继续只使用RNN预测的状态,并将其作为计算交叉熵损失的标签,策略将变得越来越偏向其自身的参数。将RNN的预测作为标签使用被称为利用过程(exploitation process),其思路是让RNN对其自身的预测变得更有信心。这个过程使得模型在当前的智能上加深,而不是朝着可以通过外部数据探索获得的智能发展。探索(exploration)则是当网络配置被随机采样作为每个RNN单元交叉熵损失的标签时。这里的想法是从大量的探索开始,并在策略学习的后期阶段逐渐减少探索,更依赖于利用。

直到现在,这些步骤仅允许一个相对简单的CNN形式,但可以对RNN代理进行修改,以适应更复杂的CNN结构,例如并行连接或ResNet或DenseNet中的跳跃连接。在原始方法中,尝试通过在图7.5所示的五个顺序RNN单元末尾添加一个额外的单元来增加跳跃连接的复杂性,作为所谓的“锚点”处理。卷积层的锚点与参考卷积层之前每个卷积层的锚点单独结合,应用tanh激活函数,乘以一个可学习的权重,最后应用sigmoid激活函数,将输出值限制在0到1之间。这里的关键信息是,sigmoid函数提供了一个概率值,使得“是否添加跳跃连接”的二分类任务能够执行。可以使用0.5值来确定输出是1还是0。然而,一个问题是,不同层之间的输出大小可能不兼容。为了解决这种不兼容,采用了一种技巧,通过将较小的输出特征图用零填充,确保两个特征图的大小相同。

这种方法使得在NAS中可以动态地为CNN添加跳跃连接。图7.6展示了使用CIFAR-10图像数据集,通过这种NAS方法得到的最终架构:

image.png

该架构虽然简单,但能够决定实现良好结果所需的最佳跳跃连接。这个结果架构展示了架构的复杂性,并显示了没有适当的搜索算法,人工设计出这样的结果将有多么困难。再次强调,任何复杂性和修改都可以添加到RNN策略中,以考虑额外的组件,如学习率、池化方法、归一化方法或激活方法,这突出了该思想的灵活性。此外,NAS方法也可以应用于搜索MLP或RNN主神经网络。然而,这些额外的适应性和复杂性在这里不做详细讨论。

请注意,这项技术固定了微架构结构,因为使用了标准的卷积层。然而,该技术通过允许跳跃连接实现了某种形式的宏架构设计。这种基础技术的主要问题之一是评估随机生成或预测架构配置所需的时间。接下来,我们将探讨一种方法,试图最小化这个问题。

理解ENAS

ENAS是通过提高生成架构评估的效率,扩展基础NAS与强化学习(RL)方法的一种方法。此外,ENAS提供了两种不同的方法,允许搜索宏架构或微架构。参数共享是一个与迁移学习(TL)相关的概念,即从一个任务中学到的内容可以转移到另一个任务,并为该后续任务进行微调,以获得更好的结果。通过这种方式训练和评估主子架构提供了一种显而易见的加速过程的方法。然而,它在很大程度上依赖于从先前架构预训练的权重,并且即使最终架构表现良好,它也未能提供对最终搜索架构的无偏评估。尽管如此,这种方法仍然在与新的搜索空间结合时证明了它的价值。

ENAS同样使用RNN来应用RL,但它采用了完全不同的搜索方向,并用其RNN预测不同的组件。ENAS使用的搜索空间是通过一个单一的有向无环图(DAG),其中节点的数量决定了子架构的层数。图7.7展示了一个四节点DAG的示例:

image.png

RNN将充当控制器,预测任何架构类型的两个组件:即,连接到哪些前一个节点和使用哪种计算操作。在这种情况下,RNN将自回归地预测这两个组件四次,以适应四个节点。图7.7中的红线显示了预测的前一个节点的连接方式。每个节点将有固定数量的计算操作可以选择。为了确保轨迹无偏,计算操作程序将进行随机采样,且程序将基于相同的搜索空间。参数共享方法应用于这些节点的计算操作组件。在每次训练迭代后,每个层中每个计算操作的权重将被保存,以便将来在参数共享时使用。参数共享的工作方式是,每个节点编号的计算操作将在每次在相同层和相同计算操作时被重新加载时,作为标识符来保存和重新加载权重。

ENAS可以应用于搜索RNN架构、CNN架构和MLP架构,并且通常可以扩展到任何其他架构类型。我们以搜索CNN架构为例。对于CNN,ENAS引入了两种搜索方法;第一种是进行宏架构搜索,第二种是进行微架构搜索。对于宏架构搜索,提出了六种操作,其中包括3 x 3和5 x 5的卷积滤波器、3 x 3和5 x 5的深度可分卷积,以及3 x 3大小的最大池化和平均池化。这组操作使得架构具有更多的多样性,而不仅仅是普通的卷积层,但与其允许卷积层配置的更多动态值,实际上这些配置被设置为固定值。另一个实现细节是,当选择多个前一个节点进行连接时,前一个节点层的输出会沿深度维度进行拼接,然后发送到当前节点的层。图7.8展示了使用CIFAR-10数据集进行宏架构搜索的结果:

image.png

这个结果是使用一块过时的NVIDIA GTX 1080 Ti GPU,仅用了0.32天的时间实现的,尽管使用的是CIFAR-10数据集而非ImageNet,但在CIFAR-10验证数据集上只取得了3.87的错误率。

至于微架构搜索,思想是构建低级逻辑块并重复使用相同的逻辑块,这样架构可以轻松扩展。ENAS中搜索了两种不同的逻辑块:一种是由主要卷积操作组成的逻辑块,另一种是旨在减少维度的降维逻辑块。图7.9展示了ENAS中用于扩展微架构决策的最终架构的宏架构:

image.png

N是一个固定的数字,在整个搜索过程中保持不变。由于这是微架构,架构构建过程被设计成允许层之间更复杂的交互,特别是将操作添加到前一个节点的输出中,以形成跳跃连接。由于这个原因,对于卷积逻辑块,RNN经过调整,固定了前两个RNN单元,以指定要连接的前两个节点的索引,后续的RNN单元则用于预测为这两个选定的前节点索引分别应用的计算操作。至于降维逻辑块,主要思想是选择任意操作,并使用步幅为2,这样就能有效地将输入的空间维度缩小为原来的二分之一。降维逻辑块可以与卷积逻辑块一起预测,使用相同数量的节点和相同的RNN。微架构中的参数共享方法与通用情况下的参数共享方法等效,通过类似地使用层号和计算类型作为标识符来保存和加载训练好的子架构权重。图7.10展示了在ENAS中使用微架构搜索策略的结果:

image.png

这个结果仅用了0.45天,使用过时的NVIDIA GTX 1080Ti GPU实现,尽管使用的是CIFAR-10数据集而非ImageNet,但在CIFAR-10验证数据集上只达到了2.89的错误率。

接下来,我们将介绍最后一种基于强化学习的NAS方法,称为MNAS。

理解MNAS

MNAS是用于创建CNN架构MnasNet的搜索方法,MnasNet是一种基于CNN的架构。后来,MNAS被用于构建在第3章《理解卷积神经网络》中介绍的EfficientNet架构系列。然而,这种方法仍然可以用于生成其他架构类型,如RNN或MLP。MNAS的主要目标是考虑延迟组件,这对于旨在边缘设备或移动设备上运行的架构来说是主要关注点,正如其名称所示。MNAS扩展了基于强化学习的NAS概念,并引入了比ENAS中的微架构搜索更灵活的搜索空间,允许在不同的模块中创建更多种类的层,尽管宏架构是固定的。图7.11展示了一个MNAS固定宏架构布局,包含七个模块,同时允许每个模块中有不同类型的配置和不同的层。这个七模块结构是从MobileNetV2架构中改编而来的:

image.png

这里使用RNN作为控制网络,预测每个CNN模块的以下配置:

  • 卷积操作:标准卷积层、深度可分卷积层和MobileNet中的MBConv层。
  • 卷积滤波器大小:3x3和5x5。
  • 挤压与激励比例:0、0.25。
  • 跳跃连接操作:池化、恒等残差或没有跳跃连接。
  • 每个模块的层数:0、+1、-1。这一设置是参考MobileNetV2中相同模块的层数。
  • 每层的输出滤波器大小:0.75、1.0、1.25。这一设置也是参考MobileNetV2中相同位置的卷积层滤波器大小。

引入的搜索空间对于实现更高效的网络和更强大的性能容量是至关重要的,从而获得更好的指标表现。例如,在CNN中,大部分计算集中在较早的层,因为特征图的尺寸较大,相比于后续层,需要更高效的层来处理。

关于延迟的一个重大问题是,它是一个依赖于软件和硬件环境的组件。例如,假设架构A在硬件和软件C中比架构B更快。当在另一种硬件和软件D上测试时,架构B可能比架构A更快。此外,架构的参数数量和每秒浮动操作数(FLOPs)规范也是实际延迟的代理,这也依赖于架构的并行度和硬件的计算核心。基于这些原因,MobileNet通过在移动电话的软件和硬件环境中对延迟进行客观评估,将延迟组件添加到奖励计算中,结合了指标计算和延迟。

图7.12展示了整个MNAS过程的概览:

image.png

延迟可以在实际目标软件和硬件环境中计算,并不限于仅使用手机。奖励是使用以下公式计算的,可以输入所需的目标延迟(以秒为单位):

reward = accuracy x [latency - target latency] ^ w

MnasNet的另一个关键细节是,OpenAI提出的另一种策略梯度方法,称为近端策略优化(PPO),被用来训练RNN策略网络,而不是强化学习方法(reinforce)。PPO方法相较于标准的强化学习策略梯度,完成了两件事:

  1. 对策略进行较小的梯度更新,使得策略能够以更稳定的方式学习,从而实现更高效的收敛。
  2. 使用生成的概率本身作为随机样本生成的采样概率,从而自动平衡探索与利用。

第一点通过两种方式实现:

  • 使用当前演员网络的概率与更新前的演员网络生成的旧概率加权损失。
  • 将概率裁剪到区间[1 - ϵ , 1 + ϵ],其中ϵ可以变化,但使用的值为0.2。

该方法通过两个网络而非一个网络执行,称为演员网络(actor-network)和评论员网络(critic network)。评论员网络被设计为预测一个不受约束的单一值,该值作为生成架构评估逻辑的一部分,与通过测量指标性能获得的奖励一起使用。另一方面,演员网络是我们所知道的主要网络,负责生成理想的网络架构配置。两个网络都可以通过RNN实现。图7.12很好地展示了这一点。两个网络的参数在每个批次中共同更新。演员网络的损失可以通过以下公式计算:

Loss = current predicted configuration probability / old predicted configuration probability x Advantage

然后,将使用此损失的最小值和另一版本的裁剪概率损失作为最终损失。裁剪损失定义如下:

clipped loss = (current predicted configuration probability / old predicted configuration probability, 1 - ϵ, 1 + ϵ) x Advantage

这里的优势(advantage)是一个自定义的损失逻辑,它为采样的子架构提供了一个量化的评估值,结合了奖励(使用指标性能)和评论员网络预测的单一值。在强化学习方法中,使用了前奖励的指数加权移动平均(EMA)。类似地,这里使用一种EMA形式来减少在不同时间步的优势。这个逻辑略微更加科学,但对于那些想了解更多的人,它可以通过以下公式计算:

Advantage = discount DISTANCE FROM FIRST TIMESTEP x critic and reward evaluation discount = λγ
critic and reward evaluation = (reward + γ(critic prediction value at t + 1) − critic prediction value at t)

其中,λ(lambda)和γ(gamma)是常数,取值在0到1之间。它们分别控制在每个时间步前进时优势折扣的权重衰减程度。此外,γ还控制未来时间步评论员预测值的贡献。至于评论员网络的损失,它可以使用以下公式定义:

critic loss = (advantage + future critic values − current critic value)²

最终的总损失将是评论员损失和演员损失的总和。PPO在效率和收敛性方面通常比标准强化学习策略梯度表现更好。这总结了PPO的逻辑,并以更直观的方式展示了它。

这里的RL搜索空间并不高效,在ImageNet上直接训练大约需要4.5天,使用了大量的64个TPUv2设备。然而,最终得到的子架构MnasNet在相同精度下比MobileNetV2更高效,或者在相同延迟下比MobileNetV2更准确,经过ImageNet基准测试后。最终,这些相同的MNAS方法被应用于EfficientNet,而EfficientNet已经成为今天最高效的CNN模型系列之一。

总结基于RL的NAS方法

强化学习(RL)为我们提供了一种智能学习最优神经网络架构的方式,通过采样、训练和评估神经架构,并应用所学的经验来预测性地生成最有效的神经架构配置。简单来说,基于RL的NAS训练一个神经网络来生成最佳的神经网络架构!基于RL的NAS最大的问题仍然是所需的计算时间非常昂贵。为了规避这个问题,几种不同的方法采取了一些技巧,列举如下:

  • 在较小但仍具代表性的数据集上作为代理任务训练RL的NAS,并在最终获得的神经架构上进行训练和评估,使用主数据集进行最终测试。
  • 通过独特的层编号和计算类型进行参数共享,幸运的是,这种方法可以通用地适用于ENAS中的其他方法。
  • 平衡宏架构和微架构搜索的灵活性,缩小搜索空间,同时确保它足够灵活,能够在网络的不同阶段利用所需的关键差异,以实现效率和良好的指标性能。
  • 将目标延迟和实际延迟直接嵌入奖励结构的一部分,结果是只搜索与指定延迟相关的大多数架构。

需要注意的是,这里介绍的方法并未提供RL及其潜力的详尽概述。

尽管RL为实现NAS提供了一个具体的方式,但它并非严格必要。在下一节中,我们将介绍不使用RL的NAS特定方法类别的例子。

理解非基于RL的NAS

NAS的核心是通过基于先前搜索经验做出决策,以智能地搜索不同的子架构配置,从而以非随机和非蛮力的方式找到最佳子架构。另一方面,RL的核心涉及使用基于控制器的系统来实现这种智能。智能化的NAS可以在不使用RL的情况下实现,在本节中,我们将介绍一种简化版本的从头开始的渐进增长式NAS方法(没有控制器),以及另一种来自复杂的完全定义的神经网络宏架构和微架构的竞争版本的淘汰方法。

理解基于路径淘汰的NAS

首先,差异化架构搜索(DARTS)是一种方法,通过去除RL控制器组件,扩展了ENAS中定义的DAG搜索空间。与选择连接的前一个节点和为节点选择要使用的操作不同,所有操作都通过相同的DAG系统在训练过程中包含在一个过度参数化的架构中。一个大小为操作总数的可学习权重向量用于在训练过程中对节点之间的所有操作进行加权加法。这个权重向量在加权加法过程之前会应用软最大(softmax)激活。在测试期间,选择前k条路径或操作作为实际网络,而其他路径则被修剪掉。然而,当权重向量被更新时,子架构本质上发生了变化。与训练和评估这个新的子架构以获取在数据集的保留或验证分区上的新指标性能不同,整个架构只使用一个训练周期来估算最佳验证性能,并使用训练损失来获得估算。这一估算将通过梯度下降用于更新过度参数化架构的参数。

Proxyless NAS进一步扩展了DARTS算法,并进行了一些附加。第一个附加是添加一个层,使用二值化权重表示权重向量,称为BinaryConnect。这些二值化权重充当门控,只有在启用时才允许数据通过。这一附加帮助解决了任何过度参数化架构的最大问题:需要加载定义架构的参数的GPU内存大小。第二个附加是将延迟组件添加到整体损失中,这是确保搜索考虑延迟并且不会仅仅为了获得更好的指标性能而尝试使用更多路径的关键。

让我们通过逐步描述Proxyless NAS中使用的整体训练方法,详细揭示这些细节:

  1. 仅基于每个节点的一个随机采样路径训练BinaryConnect权重向量,使用由软最大条件权重向量指定的概率,使用训练数据集的损失。通过冻结架构的其余部分的参数并使用标准的交叉熵损失来实现。

  2. 仅基于每个节点的两个随机采样路径训练架构参数,使用由软最大条件权重向量指定的概率,使用验证数据集的损失。通过冻结权重向量的参数,并使用近似梯度公式计算架构参数的梯度:

    gradient of parameters through path 1 = gradient of binary weight 2 x path 2 probability x (− path 1 probability) + gradient of binary weight 1 x path 1 probability x (1path 2 probability)
    gradient of parameters through path 2 = gradient of binary weight 1 x path 1 probability x (− path 2 probability) + gradient of binary weight 2 x path 2 probability x (1path 1 probability)
    

    该公式计算路径1和路径2的梯度。所使用的损失是交叉熵损失,合并了修剪路径后的预测延迟,类似于DARTS。延迟是通过外部ML模型预测的,训练该模型以根据架构的参数预测延迟,因为延迟评估需要大量时间,通常需要多次运行的平均值才能得到可靠的估算。任何ML模型都可以用来构建延迟预测模型,这个过程是在开始NAS过程之前进行的一次性过程。

  3. 重复步骤1-2,直到收敛,预定义的迭代次数,或在预定义的周期内验证损失没有改进时提前停止。

请记住,BinaryConnect用于实现作为门控的二值权重。一个细节是,标准的非约束非二值权重向量本身仍然存在,但应用了二值化操作。二值化过程通过以下步骤执行:

  1. 将所有二值权重设置为0。
  2. 使用软最大条件权重向量作为概率,采样所需数量的路径。
  3. 将所选择路径的二值权重设置为1。

BinaryConnect通过只加载非零路径到内存来节省内存。

PNAS成功地在ImageNet上达到了85.1的Top-1准确率,且没有使用像CIFAR-10这样的代理数据集,仅使用8.3天的时间,在NVIDIA GTX 1080 Ti GPU上完成搜索。

接下来,我们将介绍一种简单的渐进增长式NAS方法作为引入。

理解基于渐进增长的NAS

基于渐进增长的NAS方法的关键特点是,该方法可以在宏架构和微架构中都具有无限制的结构。 本章介绍的大多数技术都在一般结构上融入了大量领域知识,这些结构被认为是有用的。基于增长的NAS在搜索空间上自然是非有限的,并且有可能帮助发现新的有效宏架构结构。这一类NAS将继续发展,达到一个可以与其他NAS方法竞争的阶段,但在本书中,我们将仅介绍一种用于搜索子架构微架构结构的方法,称为渐进NAS(PNAS),作为引入。

PNAS通过简单地使用本章之前介绍的贝叶斯优化中定义的概念,并在微架构层面进行搜索,同时固定宏架构结构,类似于ENAS的微架构搜索方法,从而采用基于渐进增长的方法。宏架构结构根据数据集的大小进行调整,CIFAR-10使用较小的结构,ImageNet使用更深的结构。图7.13展示了这些结构:

image.png

该方法可以通过以下步骤完成,并且从零个块开始,定义一个初始预定义的最大块数:

  1. 从第一个块开始,迭代构建完整的CNN并评估所有的CNN。
  2. 训练一个RNN替代模型,使用单元配置来预测指标性能。
  3. 扩展到下一个块,并使用所有已选择和评估的前一个块变体,预测下一个块的可能单元选项组合的指标性能。
  4. 选择下一个块的两个最佳指标性能单元选项,使用这两个单元选项训练和评估完整构建的CNN。
  5. 使用第4步中获得的额外两个数据点来微调RNN替代模型。
  6. 重复步骤3至步骤5,直到总块数达到最大块数,或直到指标性能不再提高。

每个单元中的块将有一个配置,由五个变量定义,类似于ENAS:即第一个输入、第二个输入、对第一个输入的操作、对第二个输入的操作,以及组合第一个输入操作和第二个输入操作输出的方法。可能的输入集包括所有前一个块、前一个单元的输出和前两个单元的输出。这意味着单元可以与其他单元进行交互。所有可能的输入组合、操作类型和组合方法都在每个渐进块步骤中列出,并馈送给RNN模型以预测指标性能。

PNAS成功地在ImageNet上达到了84.2的Top-1准确率,但使用了225个GPU天,采用的是NVIDIA GTX 1080 GPU。

基于渐进增长的NAS方法线已经发展到一个阶段,使用一种称为高效前向架构搜索(efficient forward architecture search)的方法,只需5天的搜索就能实现84%的Top-1准确率,但这超出了本书的范围。

在本章的最后,图7.14展示了针对图像领域介绍的所有方法的性能比较,排除了通用超参数搜索方法:

方法参数数量(百万)搜索时间(天)CIFAR-10 测试错误率ImageNet 测试错误率
Vanilla RL NAS4.216804.47N/A
ENAS宏架构21.30.324.23N/A
ENAS微架构4.60.452.89N/A
DARTS3.442.8326.9
Proxyless NAS7.18.3N/A24.9
PNAS5.12253.4125.8

图7.14 – 所有介绍的NAS方法的性能比较,排除通用超参数搜索方法

此表格包括每个NAS方法在CIFAR-10和ImageNet数据集上的参数数量、搜索时间和测试错误率。每种NAS方法在延迟、复杂性和准确性方面都有其优缺点。特别是ENAS微架构方法,在参数数量较少、搜索时间短、CIFAR-10测试错误率低的情况下表现突出。它可能是图像领域神经架构搜索的推荐选择。然而,具体选择还取决于项目的需求和约束,如可用的计算资源和所需的准确性。

总结

NAS是一种适用于任何类型神经网络(NN)的方法,它可以实现自动化创建新的和先进的神经网络,而不需要手动设计神经架构。正如你所猜测的,NAS在基于图像的神经网络领域占据主导地位。EfficientNet模型系列 exemplifies了NAS对图像领域神经网络的影响。这是因为CNN组件种类繁多,使得相比简单的MLP,设计更为复杂。对于序列或时间序列数据的处理,RNN单元的变种较少,因此NAS在RNN上的主要工作集中在设计自定义的递归单元。尽管如此,还可以做更多的工作以适应transformers,因为它是当前的技术前沿,能够适应多种数据模式。

NAS主要由研究人员或大型机构的从业人员采用。当从业人员尝试为其用例训练更好的模型时,他们想要的一个关键特性是快速得到最终结果。NAS本身仍然是一个需要数天才能完成的过程,如果应用于大型数据集,可能需要几个月。这使得大多数从业人员不愿直接使用NAS。相反,他们通常使用已发布的开源实现中的现有架构。与使用手动定义的架构相比,使用现有架构在速度上没有区别,因此这给从业人员带来了使用现有架构的动力。也广为人知,预训练有助于提升模型的性能,因此直接使用NAS意味着你必须自己在大型通用数据集上预训练生成的架构,这进一步延长了完成NAS过程所需的时间。机器学习的用例通常需要大量时间来探索问题设置,并找出可从现有数据集实现的潜在性能。因此,模型实验之间的快速迭代对项目的成功至关重要。缓慢的实验会拖慢识别成功的时间。这些原因是NAS主要被大型机构的从业人员或那些愿意花时间设计可跨不同领域应用的通用自定义神经架构的研究人员所采用,而不是为特定用例构建定制架构。

然而,只要时间不成问题,NAS仍然无疑提供了一种独特的方式,帮助你为用例找到独特的自定义架构,目标可以是最大化在特定延迟下的性能,或者不考虑延迟的情况下获得最佳性能的模型。

在下一章中,我们将详细探讨监督学习(SL)中的不同问题类型,并提供监督深度学习(SDL)的一些通用技巧和方法。