自编码器通过最小化重建误差来学习,方法是使用损失函数和梯度下降等优化技术。学习过程涉及数据通过前向传播和反向传播的流程,以及使用周期(epochs)和批次(batches)进行训练的结构。理解这些机制对于构建自编码器是必不可少的。然而,在查看代码之前,一些周密的准备工作非常重要。这就像烹饪前准备食材和工作区一样;充分的准备能让实际的烹饪过程更顺畅、更成功。
这个准备阶段包含若干步骤和考量,以确保您的自编码器项目能获得最大的成功机会。让我们逐一了解。
明确您的目标
首先,您希望自编码器达成什么?虽然基本目标始终是数据重建,但重建的目的可能不同。对于入门级自编码器,常见目标有:
- 高效数据表示(特征学习): 您可能希望学习数据的压缩且有意义的表示。瓶颈层会提供这些学习到的特征。
- 降维: 如果您的数据集拥有大量特征(高维度),您可以使用自编码器来减少特征数量,同时尽可能多地保留重要信息。
清晰地界定目标有助于指导后续决策,例如瓶颈层的大小以及如何评估您的模型。目前,我们的主要精力将放在精确重建上,这为其他这些应用提供了支持。
了解您的数据
数据是自编码器的命脉。在构建从数据中学习的网络之前,您需要充分了解它。请思考以下问题:
- 这是什么类型的数据? 是图像、数值传感器读数、文本特征,还是其他?数据类型决定了输入层的结构,并常会影响输出层激活函数的选择。
- 您的数据维度如何? 您有多少样本?每个样本有多少特征?了解特征数量非常重要,因为它直接决定了输入层(通常也是输出层)的神经元数量。
- 值的范围是什么? 您的所有特征都在相似的尺度上吗?例如,像素值是0到255,还是有些特征范围是0到1,有些是1到1000?尺度上的大差异会降低训练效率。这提示了数据预处理的必要性,我们接下来会讨论它。
- 数据是否干净? 是否存在缺失值或明显的异常点?虽然基本自编码器相对可靠,但显著的数据质量问题会阻碍学习。对于第一个自编码器,最好从相对干净的数据开始。
花少量时间了解数据集能省去后续大量麻烦。
数据预处理:为训练做准备
原始数据很少能直接用于神经网络。预处理是机器学习中将数据转换为更合适格式的标准步骤。对于自编码器,常见的预处理步骤有:
- 归一化或标准化: 这通常是非常重要的一步。当输入特征被缩放到一致范围时,大多数自编码器能更有效地训练。
- 归一化 通常将数据缩放到 [0, 1] 或 [-1, 1] 的范围。对于像素值在0到255之间的图像数据,除以255是一种常见的归一化技术,可将其带入 [0, 1] 范围。这与输出层中的 sigmoid 激活函数配合良好,因为 sigmoid 也会输出0到1之间的值。
- 标准化 将数据重新缩放,使其均值为0,标准差为1。
它们之间的选择取决于数据和所用的激活函数,但对于许多基本自编码器任务而言,归一化到 [0, 1] 是一个好的起点。
- 数据重塑: 神经网络常期望输入数据具有特定形状。例如,一个带有全连接层(我们首先构建的类型)的简单自编码器,期望每个输入样本都是一个扁平向量。如果您处理的是图像(例如 28x28 像素),您需要将每张图像展平为一个包含 784 像素(28 * 28 = 784)的向量。
- 数据分割: 正如我们讨论过拟合和欠拟合时简要提及的,将数据集分成至少两份,通常是三份,是标准做法:
- 训练集: 用于训练自编码器(即调整其权重)。
- 验证集: 用于调整超参数(如层数或瓶颈大小),并在训练期间监测过拟合。模型不直接从这些数据中学习,但它在此集上的表现会指导您的设计选择。
- 测试集: 用于最终、无偏地评估训练好的自编码器在未见过数据上的表现。
对于我们最初的自编码器,我们将侧重于归一化和重塑,并确保我们有办法评估模型未直接训练过的数据上的表现。
关于架构的初步思考
虽然自编码器模型的详细构建将在第5章讨论,但根据您的数据和目标,开始思考一些基本的架构方面是好的:
- 输入和输出层大小: 这很简单。输入层中的神经元数量必须与预处理后的输入数据中的特征数量相符。由于自编码器旨在重建其输入,输出层通常会与输入层具有相同数量的神经元。
- 瓶颈层大小: 这是一个重要的设计选择。瓶颈层比输入/输出层具有更少的神经元,这迫使自编码器学习压缩的表示。
- 如果瓶颈过大(神经元过多),自编码器可能会学习到一个“恒等函数”,仅仅将输入复制到输出,而没有学习到任何有意义的特征。这会导致较低的重建误差,但学习到的表示对于降维或特征学习不会很有用。
- 如果瓶颈过小(神经元过少),自编码器可能难以捕获足够的信息以准确重建输入,从而导致较高的重建误差。
找到一个合适的瓶颈大小通常需要一些尝试。
- 隐藏层和神经元的数量: 您可以在编码器和解码器中设置多个隐藏层。更深的架构(更多层)可能学习更复杂的映射,但它们也需要更多数据且更难训练。对于第一个自编码器,建议从简单架构开始(例如,编码器中一个隐藏层,解码器中一个,再加上瓶颈层)。
- 激活函数: 我们已经提及了这些。
- 对于编码器和解码器中的隐藏层,ReLU(修正线性单元)是常见且有效的选择。
- 对于输出层,如果您的数据已归一化到 [0, 1](例如图像),sigmoid 激活函数是合适的,因为它输出此范围的值。如果您的数据可以为负值或范围更广,输出层可能使用其他激活函数,例如线性激活(无激活)(尽管对于重建归一化的正值数据,sigmoid 是常见的)。
一个显示这些准备阶段的简单图表可能如下所示:
准备构建自编码器模型的典型流程。
选择您的工具
稍后,在第5章中,我们将动手构建一个自编码器。为此常用的工具包包括:
- 编程语言: Python 是深度学习的事实标准。
- 库: 我们将使用 TensorFlow 及其 Keras API。Keras 以其用户友好性而闻名,非常适合初学者定义和训练神经网络。其他流行的库包括 PyTorch。
- 计算资源: 对于我们最初的简单自编码器,您计算机上的标准 CPU 足以进行训练。更复杂的自编码器或更大的数据集可能需要 GPU(图形处理单元)来加速训练。
设定预期
构建和训练神经网络,包括自编码器,是一个迭代过程。很少能第一次就获得完美结果。预料会:
- 尝试: 您可能会尝试不同的瓶颈大小、层数,甚至预处理的变体。
- 监测训练: 关注损失函数。它是否在下降?是否过早地趋于平稳?
- 评估: 直观检查重建结果。它们表现良好吗?模型在哪里出错?
这种构建、训练、评估和改进的迭代循环是使用机器学习模型的核心部分。
通过思考这些点:您的目标、您的数据、必要的预处理以及初步的架构构思,您在开始编写代码时会更有把握。这种准备有助于您做出明智决策,并为开发自编码器提供更清晰的途径。在接下来的章节中,我们将开始将这些准备工作付诸实践,着手构建我们的第一个自编码器。