为特征向量数据(1D数组)叠加噪声实现数据增强
日期 | 作者 | 版本 | 备注 |
---|---|---|---|
2023.09.11 | Dog Tao | V1.0 | 完成文档的初始版本。 |
文章目录
- 为特征向量数据(1D数组)叠加噪声实现数据增强
- 背景介绍
- 叠加噪声的主要方法
- 高斯噪声(Gaussian Noise)
- 均匀噪声(Uniform Noise)
- 盐与胡椒噪声(Salt and Pepper Noise)
- 随机遮挡噪声(Random Occlusion Noise)
- 数据裁剪
- 函数封装
背景介绍
数据增强(Data Augmentation)是一种在训练机器学习和深度学习模型时使用的技术,旨在通过对原始数据进行小的、随机的修改,来增加训练集的大小和多样性。这种增强的方法可以帮助模型学到更多的数据变化,从而增强模型的泛化能力,并减少过拟合。
根据数据的类型和特点,存在各种不同的数据增强技术。以下是针对不同类型数据的一些常见的数据增强方法:
-
图像数据:
- 旋转、缩放、剪切
- 色彩抖动(亮度、对比度、饱和度、色调变化)
- 噪声注入(盐与胡椒噪声、高斯噪声)
- 水平和垂直翻转
- 仿射变换
- 随机遮挡或模糊
-
时序数据/1D信号:
- 噪声注入
- 时间拉伸或压缩
- 随机遮挡
- 滑动窗口平均
- 高频和低频滤波
-
文本数据:
- 同义词替换
- 随机删除、插入或交换单词
- 句子重组
- 回译(将文本翻译成另一种语言,然后再翻译回原语言)
-
音频数据:
- 噪声注入(背景噪声、白噪声)
- 变速不变调
- 音高调整
- 时间拉伸或压缩
- 混响或其他音效添加
-
表格数据:
- 抖动(对值进行轻微调整)
- 特征交叉(组合两个或更多的特征)
- 数据插补(使用统计方法或模型预测缺失值)
-
视频数据:
- 与图像数据增强相似的技术,但在时间维度上应用
- 帧间隔调整
- 视频裁剪或切片
当考虑数据增强技术时,重要的是确保增强方法不会破坏数据的原始语义或特征。此外,应始终在一个验证集上评估模型,该验证集没有应用相同的增强方法,以确保模型的泛化能力。
叠加噪声的主要方法
一般情况下,在机器学习中一个特征数据的表示形式为一个高维向量(例如时序数据、传感器数据或任何非结构化的一维数据)。为一个高维向量增加噪声以实现数据增强,可以考虑以下几种方法:
高斯噪声(Gaussian Noise)
高斯噪声是最常用的噪声类型,它的值是根据正态分布(高斯分布)来生成的。以下提供基于numpy.Array
类型与torch.tensor
类型的实现示例:
- 基于
numpy.Array
类型
import numpy as np
def add_gaussian_noise_np(np_array, mean=0, std=1):
"""
向numpy数组添加高斯噪声。
参数:
np_array (np.Array): 输入数组。
mean (float): 高斯噪声的平均值。
std (float): 高斯噪声的标准差。
返回:
np.Array: 添加了噪声的数组。
"""
noise = np.random.normal(mean, std, np_array.shape)
return np_array + noise
- 基于
torch.tensor
类型
import torch
def add_gaussian_noise_torch(tensor, mean=0, std=1):
"""
向torch.tensor添加高斯噪声。
参数:
tensor (torch.Tensor): 输入张量。
mean (float): 高斯噪声的平均值。
std (float): 高斯噪声的标准差。
返回:
torch.Tensor: 添加了噪声的张量。
"""
noise = torch.normal(mean, std, size=tensor.shape)
return tensor + noise
均匀噪声(Uniform Noise)
与高斯噪声不同,均匀噪声的值是从一个均匀分布中随机选取的。以下提供基于numpy.Array
类型与torch.tensor
类型的实现示例:
- 基于
numpy.Array
类型
import numpy as np
def add_uniform_noise_np(array, low=-1, high=1):
"""
向numpy数组添加均匀噪声。
参数:
array (np.Array): 输入数组。
low (float): 均匀噪声的最小值。
high (float): 均匀噪声的最大值。
返回:
np.Array: 添加了噪声的数组。
"""
noise = np.random.uniform(low, high, array.shape)
return array + noise
- 基于
torch.tensor
类型
import torch
def add_uniform_noise_torch(tensor, low=-1, high=1):
"""
向torch.tensor添加均匀噪声。
参数:
tensor (torch.Tensor): 输入张量。
low (float): 均匀噪声的最小值。
high (float): 均匀噪声的最大值。
返回:
torch.Tensor: 添加了噪声的张量。
"""
noise = torch.FloatTensor(tensor.size()).uniform_(low, high)
return tensor + noise
盐与胡椒噪声(Salt and Pepper Noise)
这种噪声会将向量中的某些元素设置为最大值(例如1)或最小值(例如0),模拟真实世界中的“损坏”数据。以下提供基于numpy.Array
类型与torch.tensor
类型的实现示例:
- 基于
numpy.Array
类型
import numpy as np
def add_salt_pepper_noise_np(array, salt_prob=0.05, pepper_prob=0.05):
"""
向numpy数组添加盐和胡椒噪声。
参数:
array (np.Array): 输入数组。
salt_prob (float): 盐噪声的概率。
pepper_prob (float): 胡椒噪声的概率。
返回:
np.Array: 添加了噪声的数组。
"""
noise = np.random.choice([0, 1, 2], size=array.shape, p=[pepper_prob, salt_prob, 1 - salt_prob - pepper_prob])
array[noise == 0] = 0
array[noise == 1] = 1
return array
- 基于
torch.tensor
类型
import torch
def add_salt_pepper_noise_torch(tensor, salt_prob=0.05, pepper_prob=0.05):
"""
向torch.tensor添加盐和胡椒噪声。
参数:
tensor (torch.Tensor): 输入张量。
salt_prob (float): 盐噪声的概率。
pepper_prob (float): 胡椒噪声的概率。
返回:
torch.Tensor: 添加了噪声的张量。
"""
noise = torch.multinomial(torch.tensor([pepper_prob, salt_prob, 1 - salt_prob - pepper_prob]), num_samples=tensor.numel(), replacement=True)
tensor[noise == 0] = 0
tensor[noise == 1] = 1
return tensor
随机遮挡噪声(Random Occlusion Noise)
随机遮挡噪声模拟真实情况中可能出现的部分损坏或遮挡的数据,以提高模型的泛化能力。以下提供基于numpy.Array
类型与torch.tensor
类型的实现示例:
- 基于
numpy.Array
类型
import numpy as np
def add_random_block_noise_np(array, block_size=5):
"""
向numpy数组添加随机遮挡噪声。
参数:
array (np.Array): 输入数组。
block_size (int): 遮挡区域的长度。
返回:
np.Array: 添加了噪声的数组。
"""
# 确定开始点,确保有足够的空间添加遮挡
start_idx = np.random.randint(0, array.shape[0] - block_size)
# 将遮挡区域设置为0
array[start_idx:start_idx+block_size] = 0
return array
- 基于
torch.tensor
类型
import torch
def add_random_block_noise_torch(tensor, block_size=5):
"""
向torch.tensor添加随机遮挡噪声。
参数:
tensor (torch.Tensor): 输入张量。
block_size (int): 遮挡区域的长度。
返回:
torch.Tensor: 添加了噪声的张量。
"""
# 确定开始点,确保有足够的空间添加遮挡
start_idx = torch.randint(0, tensor.size(0) - block_size, (1,)).item()
# 将遮挡区域设置为0
tensor[start_idx:start_idx+block_size] = 0
return tensor
在这些函数中,我们选择了一个随机的开始点,并从该点开始将一维数组或张量中的连续数据设置为0,直到达到指定的block_size。
数据裁剪
当我们向向量添加噪声后,可能需要考虑是否需要对结果进行裁剪或归一化,以确保它们仍然在一个合理的范围内。例如,如果向量值的范围是[0, 1],那么在添加噪声后,可能需要执行以下操作来确保噪声后的向量仍然在这个范围内:
noisy_vector = np.clip(noisy_vector, 0, 1)
函数封装
我们设计一个函数来为特征数据叠加噪声,实现数据增强。将设计的函数命名为data_augmentation
,该函数会接受以下参数:
x
和y
:分别对应样本数据和标签数据。augment_factor
:增强数量,例如你想为每一组样本和标签生成10组样本和标签,那么这个值应设为10。sigma
:高斯噪声的标准偏差。noise_range
:均匀噪声的范围。prob
:盐与胡椒噪声的概率。
函数会为每一组输入样本生成augment_factor
个增强样本,并返回增强后的样本和标签集。例如令augment_factor=10
,对于每个输入样本和标签,我们将获得30倍(3种噪声类型 ✖ augment_factor
)的增强样本和标签。我们可以根据需要调整增强的数量和程度。
import torch
def add_gaussian_noise(tensor, sigma):
"""
为给定的tensor添加高斯噪声。
参数:
tensor: torch.Tensor - 输入的张量。
sigma: float - 高斯噪声的标准偏差。
返回:
torch.Tensor - 添加了高斯噪声的张量。
"""
noise = torch.normal(mean=0., std=sigma, size=tensor.size())
return tensor + noise
def add_uniform_noise(tensor, noise_range):
"""
为给定的tensor添加均匀噪声。
参数:
tensor: torch.Tensor - 输入的张量。
noise_range: float - 均匀噪声的范围,噪声值将从[-noise_range, noise_range]选择。
返回:
torch.Tensor - 添加了均匀噪声的张量。
"""
noise = torch.FloatTensor(tensor.size()).uniform_(-noise_range, noise_range)
return tensor + noise
def add_salt_and_pepper_noise(tensor, prob):
"""
为给定的tensor添加盐与胡椒噪声。
参数:
tensor: torch.Tensor - 输入的张量。
prob: float - 添加盐或胡椒的概率。
返回:
torch.Tensor - 添加了盐与胡椒噪声的张量。
"""
noise = torch.FloatTensor(tensor.size()).uniform_(0, 1)
salt_and_pepper = torch.where(noise < prob/2, torch.ones_like(tensor), torch.where(noise < prob, torch.zeros_like(tensor)-1, torch.zeros_like(tensor)))
return tensor + salt_and_pepper
def data_augmentation(x, y, augment_factor=10, sigma=0.1, noise_range=0.05, prob=0.01):
"""
对给定的样本和标签进行数据增强。
参数:
x: torch.Tensor - 输入样本张量。
y: torch.Tensor - 标签张量。
augment_factor: int - 每种噪声类型的增强数量。
sigma: float - 高斯噪声的标准偏差。
noise_range: float - 均匀噪声的范围。
prob: float - 盐与胡椒噪声的概率。
返回:
torch.Tensor, torch.Tensor - 增强后的样本和标签张量。
"""
augmented_x, augmented_y = [], []
# 为每个输入样本添加高斯噪声
for _ in range(augment_factor):
augmented_x.append(add_gaussian_noise(x, sigma))
augmented_y.append(y) # 噪声仅影响输入数据,不影响标签
# 为每个输入样本添加均匀噪声
for _ in range(augment_factor):
augmented_x.append(add_uniform_noise(x, noise_range))
augmented_y.append(y)
# 为每个输入样本添加盐与胡椒噪声
for _ in range(augment_factor):
augmented_x.append(add_salt_and_pepper_noise(x, prob))
augmented_y.append(y)
# 返回堆叠后的增强样本和标签
return torch.stack(augmented_x), torch.stack(augmented_y)
if __name__ == "__main__":
# 使用示例
x = torch.rand((1024,))
y = torch.tensor([1]) # 假设这是一个标签
augmented_x, augmented_y = data_augmentation(x, y, augment_factor=10, sigma=0.1, noise_range=0.05, prob=0.01)