Augment
Data Augmentation for Deep Learning-Based Radio Modulation Classification这篇文章写得不错,总结了三种常用的信号数据的扩增方式。文章中实验证明旋转优于翻转优于加噪。但我们的实验结果说明翻转优于旋转优于加噪,且加噪效果很差。这可能由于数据集的不同。另外从理论上而言,翻转不会引入噪声,而旋转会引入相位噪声,所以理论上翻转应该优于旋转。若有不同理解欢迎讨论。
flip
分别对应原始样本,竖直翻转,水平反转,竖直和水平反转。
rotation
分别对应旋转0°,旋转90°,旋转180°,旋转270°。
add guassian noise
加入零均值,方差分别为: σ = 0 \sigma=0 σ=0, σ = 0.05 \sigma=0.05 σ=0.05, σ = 0.1 \sigma=0.1 σ=0.1, σ = 0.2 \sigma=0.2 σ=0.2的噪声。此处方差选择应该根据信号的幅度大小实验选择。
flip and rotation
flip和rotation联合扩增中,可以看到红色框和蓝色框重复,所以只能扩充到原始样本的6倍大小。
在我们的实验中,得到了与文章不同的实验结果:
Method | flip | rotation | noise | f+r |
---|---|---|---|---|
Average acc | 95.037 | 94.7545 | 82.251 | 96.43 |
Method | flip | rotation | noise | f+r |
---|---|---|---|---|
Average acc | 72.7880 | 72.69 | 64.064 | 73.444 |
加高斯噪声差很多;flip应该略好于rotation,物理意义上flip并没有改变原本信号,而rotation加入了相位噪声。flip+rotation确实优于任意一种单独扩增。
实现代码
此处输入信号的维度为[batch, dim, length],即IQ通道在第二维度。例如一个1024采样点的IQ信号size为[1, 2, 1024]。函数都可以实现batch处理。
flip
输入信号和标签完成4倍扩充。
def flip(inputs, label):
flip_v = torch.zeros_like(inputs)
flip_h = torch.zeros_like(inputs)
flip_v_h = torch.zeros_like(inputs)
flip_v[:, 0, :] = inputs[:, 0, :]
flip_v[:, 1, :] = -inputs[:, 1, :]
flip_h[:, 0, :] = -inputs[:, 0, :]
flip_h[:, 1, :] = inputs[:, 1, :]
flip_v_h[:, 0, :] = -inputs[:, 0, :]
flip_v_h[:, 1, :] = -inputs[:, 1, :]
return torch.cat([inputs, flip_v, flip_h, flip_v_h], dim=0), torch.cat([label, label, label, label], dim=0)
rotation
输入信号和标签,还要输入旋转的角度(type为list),例如theta=[0, pi/2, pi, 3*pi/2],扩充为原来的4倍。
def rotation(inputs, label, theta: list):
out = []
label_list = []
for r in theta:
i_data = inputs[:, 0, :]
q_data = inputs[:, 1, :]
i_data_gen = math.cos(r)*i_data-math.sin(r)*q_data
q_data_gen = math.sin(r)*i_data+math.cos(r)*q_data
out.append(torch.cat([i_data_gen.unsqueeze(1), q_data_gen.unsqueeze(1)], dim=1))
label_list.append(label)
return torch.cat(out, dim=0), torch.cat(label_list, dim=0)
add guassian noise
用法同上,输入信号和标签及高斯噪声的方差list,注意是方差,不是标准差。扩充为原来的4倍。
def addguassiannoise(inputs, label, theta_2_all: list):
data_gen = []
label_gen = []
for theta_2 in theta_2_all:
noise = torch.normal(mean=0, std=theta_2, size=inputs.shape).cuda()
data_gen.append(inputs+noise)
label_gen.append(label)
return torch.cat(data_gen, dim=0), torch.cat(label_gen, dim=0)
flip and rotation
调用flip和rotation两个方法,并且因为rotation 0°和180°与flip中重复,是冗余的扩增,所以只翻转90°和270°,扩充为原来的6倍。
def rotation_flip(inputs, label):
flip_data, flip_label = flip(inputs, label)
r_data, r_label = rotation(inputs, label, [math.pi/2, 3/2*math.pi])
return torch.cat([flip_data, r_data], dim=0), torch.cat([flip_label, r_label], dim=0)