Auto-Encoder (什么是Auto-Encoder part1)

本文介绍了Auto-Encoder,它可视为Self-Supervised Learning的一种Pre-Train方法。Auto-Encoder通过Encoder和Decoder将图片压缩再重建,训练无需标注资料,可用于下游任务。还提到其原理、历史,以及变形De-Noising Auto-Encoder,指出BERT可看作此类模型。

在讲 Auto-Encoder 之前,其实 Auto-Encoder 也可以算是,Self-Supervised Learning 的一环,所以再让我们用非常短的时间,来看一下Self-Supervised Learning 的 Framework

 首先你有大量的没有标注的资料,用这些没有标注的资料,你可以去训练一个模型,你必须发明一些不需要标注资料的任务,比如说做填空题,比如说预测下一个 Token

这个不用标注资料的学习叫做,Self-Supervised Learning,或者是也有人叫 Pre-Training,那用这些不用标注资料的任务,学完一个模型以后,它本身没有什麽用,BERT 只能做填空题,GPT 只能够把一句话补完,但是你可以把它用在其他下游的任务裡面。

你可以把 Self-Supervised Learning 的 Model,做一点点的微微的调整,就可以用在下游的任务裡面。

在有 BERT 在有 GPT 之前,其实有一个更古老的任务,更古老的不需要用标注资料的任务,就叫做 Auto-Encoder,所以你也可以把 Auto-Encoder,看作是 Self-Supervised Learning 的,一种 Pre-Train 的方法

当然可能不是所有人都会同意这个观点,有人可能会说这个 Auto-Encoder,不算是 Self-Supervised
Learning,这个 Auto-Encoder 很早就有了嘛,2006 年 15 年前就有了嘛,然后 Self-Supervised Learning是,19 年才有这个词彙嘛,所以 Auto-Encoder,不算 Self-Supervised Learning 的一环
那这个都是见仁见智的问题,这种名词定义的问题,真的我们就不用太纠结在这个地方,从 Self-Supervised Learning,它是不需要用 Label Data 来训练,这个观点来看,Auto-Encoder 我认为它可以算是,Self-Supervised Learning 的其中的一种方法,它就跟填空 预测,接下来的 Token 是很类似的概念,只是用的是另外不一样的想法

Auto-encoder

Auto-Encoder 是怎麽运作的呢,那现在我们换成用影像来做例子

 假设你有非常大量的图片,在 Auto-Encoder 裡面你有两个 Network,一个叫做 Encoder,一个叫做
Decoder,他们就是两个 Network。


1.Encoder 把一张图片读进来,它把这张图片变成一个向量,就 Encoder 它可能是很多层的 CNN,把一张图片读进来,它的输出是一个向量,接下来这个向量会变成 Decoder 的输入
2.Decoder 会产生一张图片,所以 Decoder 的 Network 的架构,可能会像是 GAN 裡面的 Generator,
它是 11 个向量输出一张图片


训练的目标是希望,Encoder 的输入跟 Decoder 的输出,越接近越好,也就是两张图越接近越像就是很好。

假设你把图片看作是一个很长的向量的话,我们就希望这个向量跟 Decoder 的输出,这个向量,这两个向量
他们的距离越接近越好,也有人把这件事情叫做 Reconstruction,叫做重建
因为我们就是把一张图片,压缩成一个向量,接下来 Decoder 要根据这个向量,重建原来的图片,那我们希望 原输入的结果,跟重建后的结果越接近越好
讲到这边你可能会发现说,这个东西 这个概念似曾相似,没错 我们在讲 Cycle GAN 的时候,已经讲过了这个概念

我们说在做 Cycle GAN 的时候,我们会需要两个 Generator,第一个 Generator,把 X Domain 的图片转到Y Domain,另外一个 Generator,把 Y Domain 的图片转回来,希望最原先的图片,跟转完两次后的图片越接近越好
那这边 Encoder 和 Decoder,这个 Auto-Encoder 的概念,跟 Cycle GAN 其实是一模一样的,都是希望所有的图片经过两次转换以后,要跟原来的输出越接近越好,而这个训练的过程,完全不需要任何的标注资料,你只需要蒐集到大量的图片,你就可以做这个训练所以它是一个 Unsupervised Learning 的方法,跟 Self-Supervised 那一系列,Pre-Training 的做法一样,你完全不需要任何的标注资料 

 那像这样子这个 Encoder 的输出,有时候我们叫它 Embedding,我们在讲 BERT 的时候,也提过
Embedding 这个词彙了,那有的人叫它 Representation,有的人叫它 Code,因为 Encoder 是一个编码嘛,所以这个有人把这个 Vector 叫做 Code,那其实指的都是同一件事情
怎麽把 Train 的 Auto-Encoder,用在 Downstream 的任务裡面呢
常见的用法就是,原来的图片,你也可以把它看作是一个很长的向量,但这个向量太长了 不好处理,那怎麽办呢
你把这个图片丢到 Encoder 以后,输出另外一个向量,这个向量你会让它比较短,比如说只有 10 维 ,只有100 维,那你拿这个新的向量来做你接下来的任务,也就是图片不再是一个很高维度的向量,它通过Encoder 的压缩以后,变成了一个低维度的向量,你再拿这个低维度的向量,来做接下来想做的事情,这就是常见的,Auto-Encoder用在 Downstream 的任务,用在下游任务的方法

当中这个VECTOR 可以叫做EMbedding,Representation,Code 

那因为通常 Encoder 的输入,是一个维度非常高的向量,而 Encoder 的输出,也就是我们的
Embedding,Representation 或者 Code,它是一个非常低维度的向量,比如说输入是 100×100 的图片,那100×100 那就是 1 万维的向量了,如果是 RGB 那就是 3 万维的向量.。

但是通常 Encoder 的 Output 你会设得很小,比如说 10,100 这样的等级,所以这个这边会有一个特别窄的地方,所以这个部分,这个 Encoder 的输出,有时候又叫做 Bottleneck,叫做瓶颈,就本来输入是很宽的,输出也是很宽的 中间特别窄,所以这一段就叫做 Bottleneck。但在其中会缺失掉很多被压缩的信息。

而 Encoder 做的事情,是把本来很高维度的东西,转成低维度的东西,把高维度的东西转成低维度的东西又叫做 Dimension Reduction

Why Auto-encoder?

好 我们来想一下,Auto-Encoder 这件事情它要做的,是把一张图片压缩又还原回来,但是还原这件事情为什麽能成功呢

 你想想看假设本来图片是 3×3,3×3 很小,但我们就假设 3×3 好了,本来的图片是 3×3,你要用 9 个数值来描
述一张 3×3 的图片,假设 Encoder 输出的这个向量是二维的,我们怎麽有可能从二维的向量,去还原 3×3 的图片,还原9个数值呢我们怎麽有办法把 9 个数值变成 2 个数值,又还原成 3,又还原回 9 个数值呢?

能够做到这件事情是因为,对于影像来说,并不是所有 3×3 的矩阵都是图片,图片的变化其实是有限的,你随
便 Sample 一个 Random 的 Noise,随便 Sample 一个矩阵,出来它通常都不是你会看到的图片
举例来说,假设图片是 3×3 的,那它的变化,虽然表面上应该要有 3×3 个数值,才能够描述 3×3 的图片,但是也许它的变化实际上是有限的也许你把图片蒐集起来发现说。

 它只有这样子的类型,跟这样子的类型,其他类型根本就不是,你一般在训练的时候会看到的状况,就是因为
说图片的变化还是有限的所以你在做这个 Encoder 的时候,Encoder 可以说,我就只用两个维度就可以描述一张图片,虽然图片是3×3,应该用 9 个数值才能够储存,但是实际上它的变化也许只有两种类型,那你就可以说看到这种类型,我就左边这个维度是 1 右边是 0,看到这种类型就左边这个维度是 0,右边这个维度是 1。所以说此时就能通过0和1来表示了

那所以对应到刚才这个樊一翁的例子

 就是这个鬍子是图片複杂的状态,是原来图片的 Pixel,是原来图片的像素
而 Encoder 做的事情就是化繁为简,本来比较複杂的东西,它只是表面上比较複杂,事实上它的变化其实是有限的,你只要找出它有限的变化,你就可以把本来複杂的东西,把它变得用比较简单的方法来表示它
如果我们可以把複杂的图片,用比较简单的方法来表示它,那我们就只需要比较少的训练资料,在下游的任务裡面,我们可能就只需要比较少的训练资料,就可以让机器学到,我们本来要它学的事情,这个就是 Auto-Encoder 的概念。

Auto-encoder is not a new idea

那 Auto-Encoder,它从来都不是一个新的想法,它真的是非常非常地有历史,举例来说在这个
Hinton,Hinton 就是 Deep Learning 之父。


Hinton 在 06 年的 Science 的 Paper 裡面,就有提到 Auto-Encoder 这个概念,只是那个时候用的
Network,跟今天用的 Network,当然还是有很多不一样的地方,我们讲 2006 年是 15 年前,15 年前的
Auto-Encoder 长什麽样子

 那个时候人们不觉得,Deep 的 Network 是 Train 得起来的,那时候觉得说这个把 Network 叠很多很多层,然后每一层一起 Train 不太可能成功,所以那时候的信念是,每一层应该分开训练,所以 Hinton 用的是一个叫做,Restricted Boltzmann Machine 的技术,缩写是 RBM

(这个RBM现在已经没什么用了)
我们特别把 Hinton 15 年前的文章,把它的裡面的这个,Paper 裡面的图拿出来给大家看一下,过去 15 年前,人们是怎麽看待深度学习这个问题,那个时候觉得说,要 Train 一个这个很深的 Network 不太可能,每一层分开要 Train,虽然这个说很深也没有很深,只是三层,这个跟你作业 2 做得还要更shallow,但是在15年前这个已经是,哇 很深啊 它有三层太可怕了

De-noising Auto-encoder

那 Auto-Encoder 还有一个常见的变形,叫做 De-Noising 的 Auto-Encoder

 De-Noising 的 Auto-Encoder 是说,我们把原来要输进去给 Encoder 的图片,加上一些杂讯,就自己随便找一个杂讯把它加进去,(加入一个随机噪声)然后一样通过 Encoder,一样再通过 Decoder,试图还原原来的图片。

那我们现在还原的,不是 Encoder 的输入,Encoder 的输入的图片是有加杂讯的,我们要还原的不是
Encoder 的输入,我们要还原的是加入杂讯之前的结果

所以你会发现说,现在 Encoder 跟 Decoder,除了还原原来的图片这个任务以外,它还多了一个任务,这个任务是什麽,这个任务就是,它必须要自己学会把杂讯去掉

Encoder 看到的是没有杂讯的图片,但 Decode要还原的目标是,Encoder 看到的是有加杂讯的图片,但Decoder 要还原的目标是,没有加杂讯的图片,所以 Encoder 加 Decoder,他们合起来必须要联手能够把杂讯去掉,这样你才能够把,De-Noising 的 Auto-Encoder 训练起来

那说到 De-Noising 的 Auto-Encoder,有没有发现这个概念,其实也一点都不陌生呢,De-Noising 的 Auto-Encoder,也不算是太新的技术,至少在 2008 年的时候,就已经有相关的论文了

但是如果你看今天的 BERT 的话,其实你也可以把它看作就是一个,De-Noising 的 Auto-Encoder

 输入我们会加 Masking,那些 Masking 其实就是 Noise,BERT 的模型就是 Encoder,它的输出就是
Embedding

在讲 BERT 的技术的时候,我们就告诉你说这个输出就叫做 Embedding,接下来有一个 Linear 的模型,就是 Decoder,Decoder 要做的事情,就是还原原来的句子,也就是把填空题被盖住的地方,把它还原回来,所以我们可以说,BERT 其实就是一个,De-Noising 的 Auto-Encoder
有同学可能会问说,为什麽这个 Decoder 一定要 Linear 的呢,它不一定要是 Linear,它可以不是 Linear或者是我们换一个说法,这个 BERT 它有 12 层,最小的那个 BERT 有 12 层,比较大的有 24 层或者是 48 层,好 那最小的 BERT 是 12 层,如果我们说这个 12 层中间,第 6 层的输出是 Embedding,那你其实也可以说剩下的 6 层,就是 Decoder,你可以说 BERT,就假设你在用 BERT 的时候,你用的不是第 12 层的输出,而是第 6 层的输出,那你完全可以说,BERT 的前 6 层就是 Encoder,后面 6 层就是 Decoder,总之这个Decoder,没有一定要是 Linear

<think>我们使用一个简单的自编码器来实现信号调制。自编码器通常包括编码器(调制器)和解码器(解调器)两部分。编码器将输入数据(例如比特流)映射到星座点(复数形式),然后通过一个信道模型(例如添加高斯噪声),最后由解码器尝试恢复原始数据。 我们将实现以下步骤: 1. 构建自编码器模型(使用PyTorch) 2. 生成训练数据(随机的比特流) 3. 定义训练循环,并记录训练损失 4. 可视化星座点(在训练的不同阶段) 5. 绘制训练损失曲线 注意:为了模拟真实通信,我们会在编码器输出后添加高斯噪声(作为信道)。 模型结构: - 编码器:将输入比特流(例如,每个符号k个比特)映射为2个实数(即复数的实部和虚部) - 解码器:将接收到的2个实数(经过信道噪声)映射回k个比特(用sigmoid激活,然后进行二值化或使用BCE损失) 假设调制阶数为M,则每个符号有k=log2(M)个比特。 这里我们以16-QAM为例(M=16, k=4)。 我们将使用以下参数: - 批量大小(batch_size)= 256 - 训练周期(epochs)= 100 - 学习率(lr)= 0.001 - 信噪比(SNR)范围:在训练时随机变化以增强鲁棒性 注意:在可视化星座图时,我们会在无噪声的情况下通过编码器传递数据,以查看纯净的星座点。 我们将按照以下方式组织代码: 1. 导入必要的库 2. 定义自编码器模型 3. 生成训练数据 4. 训练模型并记录损失 5. 可视化星座图和损失曲线 由于我们之前已经定义了可视化函数,这里将直接使用它们。 代码实现如下:</think>下面我将基于自编码器实现信号调制功能,并添加星座点可视化和训练损失曲线可视化功能。完整代码如下: ```python import torch import torch.nn as nn import torch.optim as optim import numpy as np import matplotlib.pyplot as plt from sklearn.model_selection import train_test_split # 定义自编码器模型 class ModulationAutoencoder(nn.Module): def __init__(self, input_dim, latent_dim): super(ModulationAutoencoder, self).__init__() # 编码器(调制器) self.encoder = nn.Sequential( nn.Linear(input_dim, 128), nn.ReLU(), nn.Linear(128, 64), nn.ReLU(), nn.Linear(64, latent_dim * 2) # 输出实部和虚部 ) # 解码器(解调器) self.decoder = nn.Sequential( nn.Linear(latent_dim * 2, 64), nn.ReLU(), nn.Linear(64, 128), nn.ReLU(), nn.Linear(128, input_dim), nn.Sigmoid() # 输出概率值 ) def forward(self, x): # 编码为复数信号 complex_vec = self.encoder(x) # 将输出分为实部和虚部 real_part = complex_vec[:, 0] imag_part = complex_vec[:, 1] # 解码恢复原始信号 decoded = self.decoder(complex_vec) return real_part, imag_part, decoded def get_constellation(self, data): """获取星座点""" with torch.no_grad(): real_part, imag_part, _ = self.forward(data) return torch.stack((real_part, imag_part), dim=1).cpu().numpy() # 生成训练数据 def generate_data(num_samples, bits_per_symbol): """生成随机比特流数据""" # 生成随机比特 (0或1) data = np.random.randint(0, 2, size=(num_samples, bits_per_symbol)) return torch.tensor(data, dtype=torch.float32) # 可视化星座图 def plot_constellation(symbols, title="Constellation Diagram", epoch=None): """ 绘制星座图 :param symbols: 星座点数组,形状为(N, 2) :param title: 图表标题 :param epoch: 训练周期 """ plt.figure(figsize=(8, 8)) plt.scatter(symbols[:, 0], symbols[:, 1], alpha=0.6, c='blue') # 添加参考线和标注 plt.axhline(0, color='grey', lw=0.5) plt.axvline(0, color='grey', lw=0.5) plt.grid(True, linestyle='--', alpha=0.7) plt.xlabel('In-phase (I)') plt.ylabel('Quadrature (Q)') if epoch is not None: plt.title(f"{title} - Epoch {epoch}") plt.savefig(f"constellation_epoch_{epoch}.png", dpi=300) else: plt.title(title) plt.savefig(f"constellation_{title.replace(' ', '_')}.png", dpi=300) plt.show() # 可视化训练损失曲线 def plot_training_loss(train_losses, val_losses=None, title="Training Loss Curve"): """ 绘制训练损失曲线 :param train_losses: 训练损失列表 :param val_losses: 验证损失列表(可选) :param title: 图表标题 """ plt.figure(figsize=(10, 6)) # 绘制训练损失 epochs = range(1, len(train_losses) + 1) plt.plot(epochs, train_losses, 'b-o', label='Training Loss') # 绘制验证损失(如果存在) if val_losses is not None: plt.plot(epochs, val_losses, 'r-s', label='Validation Loss') # 添加标注 plt.title(title) plt.xlabel('Epoch') plt.ylabel('Loss') plt.grid(True, linestyle='--', alpha=0.7) plt.legend() # 保存图像 plt.savefig(f"loss_curve_{title.replace(' ', '_')}.png", dpi=300) plt.show() # 主训练函数 def train_modulation_autoencoder(): # 超参数设置 num_epochs = 100 batch_size = 256 learning_rate = 0.001 bits_per_symbol = 4 # 16-QAM调制 latent_dim = 1 # 复数维度 # 生成数据 num_samples = 10000 data = generate_data(num_samples, bits_per_symbol) # 划分训练集和验证集 train_data, val_data = train_test_split(data, test_size=0.2, random_state=42) # 创建数据加载器 train_loader = torch.utils.data.DataLoader(train_data, batch_size=batch_size, shuffle=True) val_loader = torch.utils.data.DataLoader(val_data, batch_size=batch_size, shuffle=False) # 初始化模型和优化器 device = torch.device("cuda" if torch.cuda.is_available() else "cpu") model = ModulationAutoencoder(bits_per_symbol, latent_dim).to(device) criterion = nn.BCELoss() # 二值交叉熵损失 optimizer = optim.Adam(model.parameters(), lr=learning_rate) # 训练记录 train_losses = [] val_losses = [] # 训练循环 for epoch in range(num_epochs): # 训练阶段 model.train() epoch_train_loss = 0.0 for batch in train_loader: batch = batch.to(device) # 前向传播 _, _, decoded = model(batch) # 计算损失 loss = criterion(decoded, batch) # 反向传播和优化 optimizer.zero_grad() loss.backward() optimizer.step() epoch_train_loss += loss.item() # 计算平均训练损失 avg_train_loss = epoch_train_loss / len(train_loader) train_losses.append(avg_train_loss) # 验证阶段 model.eval() epoch_val_loss = 0.0 with torch.no_grad(): for batch in val_loader: batch = batch.to(device) _, _, decoded = model(batch) loss = criterion(decoded, batch) epoch_val_loss += loss.item() # 计算平均验证损失 avg_val_loss = epoch_val_loss / len(val_loader) val_losses.append(avg_val_loss) # 每10个epoch打印一次结果 if (epoch + 1) % 10 == 0: print(f'Epoch [{epoch+1}/{num_epochs}], Train Loss: {avg_train_loss:.6f}, Val Loss: {avg_val_loss:.6f}') # 每20个epoch可视化一次星座图 if (epoch + 1) % 20 == 0 or epoch == 0 or epoch == num_epochs - 1: # 获取星座点 constellation_points = model.get_constellation(train_data[:1000].to(device)) plot_constellation(constellation_points, "Signal Modulation", epoch=epoch+1) # 训练完成后绘制损失曲线 plot_training_loss(train_losses, val_losses, "Modulation Autoencoder Training") # 返回最终星座图 final_constellation = model.get_constellation(train_data[:1000].to(device)) plot_constellation(final_constellation, "Final Constellation") return model, train_losses, val_losses # 运行训练 if __name__ == "__main__": model, train_losses, val_losses = train_modulation_autoencoder() ``` ### 关键功能说明: 1. **自编码器结构**: - **编码器**:将输入比特流映射为复数信号(实部和虚部) - **解码器**:从复数信号恢复原始比特流 - 使用BCELoss作为损失函数,适合二进制分类问题 2. **星座图可视化**: - 在I-Q平面上展示信号点的分布 - 每20个epoch保存一次可视化结果 - 添加网格线和坐标轴增强可读性 3. **训练损失曲线**: - 同时记录训练损失和验证损失 - 使用不同颜色区分曲线 - 添加图例和网格线增强可读性 4. **训练过程**: - 使用Adam优化器进行训练 -10个epoch打印一次训练进度 - 支持GPU加速训练 ### 数学模型基础: 自编码器通过学习最小化重建误差来学习高效的数据表示: $$ \mathcal{L}(\theta) = \frac{1}{N} \sum_{i=1}^{N} \| \mathbf{x}^{(i)} - \text{decoder}(\text{encoder}(\mathbf{x}^{(i)})) \|^2 $$ 在信号调制场景中,编码器输出可视为星座点: $$ \mathbf{z} = \text{encoder}(\mathbf{x}) = [I, Q] $$ 其中$I$和$Q$分别表示同相和正交分量,构成复平面上的点。 ### 相关问题 1. 如何调整自编码器结构以适应更高阶调制(如64-QAM或256-QAM)? 2. 在信号调制自编码器中,如何添加信道噪声模型以提高鲁棒性? 3. 除了星座图,还有哪些可视化方法可以评估调制性能? 4. 如何将元学习技术应用于信号调制自编码器以实现快速适应新调制方案?[^1] 5. 在自编码器结构中,如何平衡星座点间距和信号功率约束?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

就随便学学哈

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

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

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

打赏作者

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

抵扣说明:

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

余额充值