既然我们已经了解自编码器的主要工作是重建其输入,并且我们使用损失函数来衡量其表现,那么现在我们来看看数据是如何实际通过自编码器移动以产生该重建结果的。这种从输入到输出的单向数据流动被称为前向传播。想象一下你正在发送一条消息 ($X$),它先通过一系列的翻译器和摘要器处理,然后再通过扩展器和翻译器返回,目的是取回原始消息 ($X'$)。前向传播就是这种完整的发送和接收过程。以下是数据流动的一个分步说明:进入输入层: 你的数据,无论是图像、一组数字还是传感器读数,首先进入输入层。这一层不进行任何计算;它只是将原始数据传递给自编码器的第一部分,即编码器。我们将输入数据称为 $X$。编码器的运作: 数据随后通过编码器。编码器通常由一个或多个“隐藏层”构成。每个层都包含处理单元(通常称为神经元)。当数据进入一个神经元时,它会被权重相乘。可以把权重看作是控制每条输入信息强度或重要性的旋钮。然后添加一个偏置项。偏置就像一个小而恒定的调整,有助于微调神经元的输出。这些计算(输入加偏置的加权和)的结果随后通过一个激活函数。这个函数决定神经元的最终输出是什么,通常将值转换为特定范围或判断神经元是否应该“激活”。 编码器的作用是压缩输入数据。因此,通常编码器中每个后续层将比前一个层拥有更少的神经元,逐步将信息压缩成更紧凑的形式。到达瓶颈层(潜在空间): 在通过所有编码器层后,数据到达瓶颈层,也称为潜在空间。这一层在自编码器中拥有最少的神经元数量。这一层的输出是输入数据的压缩表示,通常表示为 $z$。这个 $z$ 是一个紧凑的概要,在较低维空间中捕捉了输入最重要的特点。通过解码器扩展: 压缩表示 $z$ 随后被输入到解码器中。解码器的结构通常是编码器的镜像。它接收来自瓶颈的紧凑信息,并开始将其扩展回原始数据的形状。类似于编码器,解码器有带有神经元、权重、偏置和激活函数的隐藏层。然而,在解码器中,层的大小通常会增加,逐步“解压”压缩后的信息。产生输出层: 最后,数据通过解码器的最后一层,称为输出层。这一层的输出是自编码器对原始输入数据的重建。我们可以将这种重建数据称为 $X'$。输出层中的神经元数量必须与原始输入层中的特点数量(例如,图像中的像素,数据集中的列)匹配。从 $X$ 到 $X'$ 的整个过程,是一个“前向传递”或“前向传播”。自编码器接收输入,将其通过其层和计算网络传递,并产生一个输出。digraph G { rankdir=TB; graph [fontname="Arial", fontsize=10, label="自编码器中的数据流(前向传播)", labelloc=t, labeljust=c]; node [shape=box, style="filled,rounded", fontname="Arial", margin="0.25,0.15", width=2, height=0.6]; edge [fontname="Arial", fontsize=9]; input_data [label="输入数据\n(X)", fillcolor="#a5d8ff", shape=cylinder, width=1.5]; subgraph cluster_encoder { label = "编码器网络"; style="filled,rounded"; color="#ced4da"; bgcolor="#e9ecef"; node [fillcolor="#74c0fc"]; enc_layer1 [label="隐藏层 1\n(输入转换)"]; enc_layer_dots [label="...", shape=plaintext, fontsize=24, fontcolor="#495057", height=0.3, width=0.5]; enc_layerN [label="最终编码器层\n(压缩)"]; } bottleneck [label="瓶颈 (z)\n(潜在空间\n表示)", fillcolor="#4c6ef5", fontcolor="#ffffff", shape=ellipse, width=1.8, height=0.8]; subgraph cluster_decoder { label = "解码器网络"; style="filled,rounded"; color="#ced4da"; bgcolor="#e9ecef"; node [fillcolor="#74c0fc"]; dec_layer1 [label="隐藏层 1\n(潜在扩展)"]; dec_layer_dots [label="...", shape=plaintext, fontsize=24, fontcolor="#495057", height=0.3, width=0.5]; dec_layerN [label="最终解码器层\n(重建)"]; } output_data [label="重建数据\n(X')", fillcolor="#a5d8ff", shape=cylinder, width=1.5]; input_data -> enc_layer1 [label=" 输入编码器 ", minlen=1.5]; enc_layer1 -> enc_layer_dots [arrowhead=none, style=dashed]; enc_layer_dots -> enc_layerN; enc_layerN -> bottleneck [label=" 编码为 z ", minlen=1.5]; bottleneck -> dec_layer1 [label=" 从 z 解码 ", minlen=1.5]; dec_layer1 -> dec_layer_dots [arrowhead=none, style=dashed]; dec_layer_dots -> dec_layerN; dec_layerN -> output_data [label=" 输出 X' ", minlen=1.5]; }该图显示了数据在前向传播过程中所经过的路径。它以输入 ($X$) 开始,通过编码器在瓶颈处压缩成潜在表示 ($z$),然后解码器试图从这种表示中重建原始数据 ($X'$)。通过这种前向传播生成的输出 $X'$,是我们随后与原始输入 $X$ 进行比较的对象。它们之间的差异,正如我们讨论损失函数时所说,告诉我们自编码器在重建任务中的表现如何。这种误差衡量随后被用于下一步——反向传播,来调整自编码器的权重和偏置,这将在后续内容中说明。