
动手学PyTorch建模与应用:从深度学习到大模型DeepSeek教程-PyTorch音频建模技术
随着音频技术的发展,人们对高质量音频的需求越来越强烈,而多声道音频可以满足人们的这种需求。本节介绍基于PyTorch的音频建模技术。
随着音频技术的发展,人们对高质量音频的需求越来越强烈,而多声道音频可以满足人们的这种需求。本节介绍基于PyTorch的音频建模技术。
9.3.1 加载音频数据源
加载音频数据,需要安装PyTorch的torchaudio库和soundfile库,在torchaudio中加载文件时,可以选择指定后端以通过torchaudio.set_audio_backend使用sox_io或SoundFile,其中Windows系统中使用SoundFile,Linux/macOS系统中使用sox_io。
导入相关库,代码如下:
# 导入相关库
import torch
import torchaudio
import soundfile
import matplotlib.pyplot as plt
torchaudio.set_audio_backend("soundfile")
torchaudio支持以WAV和MP3格式加载声音文件。我们称波形为原始音频信号。代码如下:
# 定义文件名
filename = "恭喜发财.mp3"
# 加载音频文件并获取波形和采样率
waveform, sample_rate = torchaudio.load(filename)
# 打印波形的形状
print("波形形状:{}".format(waveform.size()))
# 打印波形的采样率
print("波形采样率:{}".format(sample_rate))
# 创建一个图形
plt.figure()
# 绘制波形的时间序列
plt.plot(waveform.t().numpy())
# 显示图形
plt.show()
上述代码的主要目的是加载一个音频文件,并将其波形显示出来。
首先,定义了一个文件名filename,它指定了要加载的音频文件。然后,使用torchaudio.load函数加载音频文件,并获取波形数据waveform和采样率sample_rate。
其次,使用print函数打印出波形的形状和采样率。waveform.size表示波形数据的形状,即波形的维度。
然后,使用plt.figure创建一个图形窗口。使用plt.plot函数绘制波形的时间序列,这里使用waveform.t().numpy()来获取波形的时间序列数据。
最后,使用plt.show显示绘制的波形图形。这样,就可以直观地看到音频文件的波形。
输出的原始音频信号的参数如下:
波形形状:torch.Size([2, 8935836])
波形采样率:44100
输出的原始音频信号如图9-2所示。
图9-2 原始音频信号
9.3.2 波形变换的类型
目前,torchaudio库支持的波形转换类型如下。
- 重采样:将波形重采样为其他采样率。
- 频谱图:从波形创建频谱图。
- GriffinLim:使用Griffin-Lim转换从线性比例幅度谱图计算波形。
- ComputeDeltas:计算张量(通常是声谱图)的增量系数。
- ComplexNorm:计算复数张量的范数。
- MelScale:使用转换矩阵将正常STFT转换为Mel频率STFT。
- AmplitudeToDB:将频谱图从功率/振幅标度变为分贝标度。
- MFCC:根据波形创建梅尔频率倒谱系数。
- MelSpectrogram:使用PyTorch中的STFT功能从波形创建MEL频谱图。
- MuLawEncoding:基于mu-law压扩对波形进行编码。
- MuLawDecoding:解码mu-law编码的波形。
- TimeStretch:在不更改给定速率的音高的情况下,及时拉伸频谱图。
- FrequencyMasking:在频域中屏蔽频谱图应用。
- TimeMasking:在时域中屏蔽频谱图应用。
由于所有变换都是nn.Modules或jit.ScriptModules,它们可以用作神经网络的一部分。
9.3.3 绘制波形频谱图
首先,以对数刻度查看频谱图的对数,代码如下:
# 使用 Spectrogram 函数对波形数据进行处理,得到频谱图数据
specgram = torchaudio.transforms.Spectrogram()(waveform)
# 打印频谱图的形状,即频谱图的尺寸
print("频谱图形状:{}".format(specgram.size()))
# 创建一个新的图形窗口
plt.figure()
# 显示频谱图的对数变换结果。specgram.log2()[0,:,:].numpy()表示取频谱图的对数变换结果,并将其转换为 NumPy 数组;cmap='gray' 用于指定颜色映射为灰度色;aspect="auto" 表示自动调整图像的纵横比
plt.imshow(specgram.log2()[0,:,:].numpy(), cmap='gray', aspect="auto")
#显示绘制的图形窗口
plt.show()
上述代码首先使用torchaudio库中的Spectrogram函数将波形数据转换为频谱图。然后打印出频谱图的形状,并使用Matplotlib库绘制并显示频谱图。通过观察频谱图,可以了解信号在不同频率上的能量分布情况。
运行上述代码,输出如图9-3所示。
以对数刻度查看梅尔频谱图,代码如下:
# 使用 torchaudio.transforms.MelSpectrogram()函数对波形进行梅尔频谱图变换
specgram = torchaudio.transforms.MelSpectrogram()(waveform)
# 打印梅尔频谱图的形状
print("梅尔频谱图形状:{}".format(specgram.size()))
# 创建一个新的图形
plt.figure()
# 显示梅尔频谱图的对数变换结果
p = plt.imshow(specgram.log2()[0,:,:].detach().numpy(), cmap='viridis', aspect="auto")
# 显示图形
plt.show()
这段代码的目的是将波形数据转换为梅尔频谱图,并将其可视化显示出来,以便观察信号在梅尔频率尺度上的能量分布情况。与之前的代码类似,但是使用了MelSpectrogram函数而不是Spectrogram函数来生成梅尔频谱图。梅尔频谱图是一种特殊的频谱表示,它基于梅尔频率尺度,常用于语音处理等领域。
运行上述代码,输出如图9-4所示。
图9-3 以对数刻度查看频谱图 图9-4 以对数刻度查看梅尔频谱图
我们可以重新采样波形,一次一个通道,代码如下:
# 计算新的采样率,将原始采样率除以15
new_sample_rate = sample_rate / 15
#选择要处理的通道,这里设置为 0
channel = 0
#使用 Resample 函数对波形进行重新采样。将原始采样率和新的采样率作为参数传递给函数,并将波形数据的指定通道转换为一维张量
transformed = torchaudio.transforms.Resample(sample_rate, new_sample_rate)(waveform[channel, :].view(1, -1))
# 打印变换后波形的形状,即尺寸信息
print("变换后波形形状:{}".format(transformed.size()))
# 创建一个新的图形窗口
plt.figure()
#绘制变换后的波形。transformed[0, :] 表示取变换后波形的第一个样本,并将其转换为 NumPy 数组进行绘图
plt.plot(transformed[0, :].numpy())
#显示绘制的图形
plt.show()
通过上述代码可以观察到重采样后波形的形状和变化。重采样操作常用于改变波形的采样率,以适应不同的需求或处理。
运行上述代码,输出如图9-5所示。
图9-5 重新采样波形
9.3.4 波形Mu-Law编码
下面介绍音频处理时的Mu-Law与反Mu-Law变换。可以基于Mu-Law编码对信号进行编码,但是要做到这一点,需要信号在-1和1之间。由于张量只是一个常规的PyTorch张量,因此我们可以在其上应用标准运算符,代码如下:
print("波形最小值:{}\n波形最大值:{}\n波形平均值:{}".format(waveform.min(), waveform.max(),waveform.mean()))
输出如下:
波形最小值:-1.0179462432861328
波形最大值:0.9967185854911804
波形平均值:-1.855347363743931e-05
由于波形不在-1和1之间,因此我们不需要对其进行归一化,代码如下:
# 定义一个名为 normalize 的函数,接受一个张量作为参数
def normalize(tensor):
"""
对输入的张量进行归一化处理
参数:
tensor (Tensor):需要进行归一化的张量
返回:
normalized_tensor (Tensor):归一化后的张量
"""
tensor_minusmean = tensor - tensor.mean() # 从张量中减去其均值
# 将减去均值后的张量除以其绝对值的最大值
return tensor_minusmean / tensor_minusmean.abs().max()
# 对 waveform 进行归一化处理,并将结果存储在 waveform_ 中
waveform_ = normalize(waveform)
应用编码波形,代码如下:
#使用torchaudio库中的MuLawEncoding变换函数对waveform_进行处理
transformed = torchaudio.transforms.MuLawEncoding()(waveform_)
#打印变换后波形的形状,即尺寸信息
print("变换后波形形状: {}".format(transformed.size()))
#创建一个新的图形对象
plt.figure()
#使用 plot 函数绘制变换后波形的曲线,这里取了第一个样本
plt.plot(transformed[0,:].numpy())
#显示绘制的图形
plt.show()
通过上述代码可以观察到经过Mu-Law编码变换后波形的形状和特征。绘制波形图可以帮助用户直观地理解变换后的波形特征。运行上述代码,输出如图9-6所示。
图9-6 波形Mu-Law编码
现在解码,代码如下:
#使用torchaudio库中的MuLawDecoding解码函数对变换后的波形 transformed进行解码操作
reconstructed = torchaudio.transforms.MuLawDecoding()(transformed)
#打印解码后新波形的形状,即尺寸信息
print("新波形形状: {}".format(reconstructed.size()))
#创建一个新的图形对象
plt.figure()
#使用 plot 函数绘制解码后的新波形曲线,这里取了第一个样本
plt.plot(reconstructed[0,:].numpy())
#显示绘制的图形
plt.show()
通过这段代码可以观察到解码后新波形的形状和特征。Mu-Law编码是Mu-Law编码的逆操作,用于将编码后的波形还原为原始波形的近似。绘制波形图可以帮助用户直观地理解解码后的波形 特征。
运行上述代码,输出如图9-7所示。
图9-7 波形Mu-Law解码
9.3.5 变换前后波形的比较
为了分析波形变换前后是否存在较大差异,可以将原始波形与归一化和Mu-Law变换后的波形进行比较,代码如下:
# 计算原始波形和重构波形之间的差异
err = ((waveform - reconstructed).abs() / waveform.abs()).mean()
# 打印原始信号和重构信号之间的差异,保留两位小数
print("原始信号和重构信号之间的差异: {:.2%}".format(err))
上述代码用于评估原始波形和重构波形之间的相似度或差异程度,通过计算差异的均值并以百分比形式显示,可以更直观地了解两者之间的差异情况。
首先,通过abs()函数取两个波形的绝对值,然后相减得到差异值。
其次,将差异值除以原始波形的绝对值,得到一个相对差异的度量。
然后,对这个相对差异值进行均值计算,得到平均差异。
最后,使用格式化字符串打印平均差异,:.2%表示将差异值显示为带有两位小数的百分比形式。
运行上述代码,输出如下:
原始信号和重构信号之间的差异: 41.18%
可以看出,经过归一化和Mu-Law变换后的波形与原始波形存在较大的差异,平均差异达到了41.18%。
更多推荐
所有评论(0)