TorchAudio 2.0.1学习

对于函数而言,在将张量参数传递给函数之前,请将其移到CUDA设备上。

例如:

cuda = torch.device("cuda")

waveform = waveform.to(cuda)

spectrogram = torchaudio.functional.spectrogram(waveform)

支持CUDA的类是通过torch.nn.Module()实现的。在传递CUDA张量之前,也需要将实例移动到CUDA设备上。

例如:

cuda = torch.device("cuda")

resampler = torchaudio.transforms.Resample(8000, 16000)

resampler.to(cuda)

waveform.to(cuda)

resampled = resampler(waveform)

 

神经网络的训练分为两个步骤:

前向传播:在前向传播中,神经网络对于正确的输出进行最佳猜测。它通过将输入数据通过每个函数来运行,从而进行这个猜测。

反向传播:在反向传播中,神经网络根据其猜测的误差调整其参数。它通过从输出开始向后遍历,收集误差对于函数参数的导数(梯度),并使用梯度下降来优化参数。

 

在PyTorch中的使用

我们加载一个预训练的resnet18模型(来自torchvision)。

我们创建一个随机数据张量,表示一个拥有3个通道、高度和宽度为64的单个图像,以及相应的标签,初始值为一些随机值。预训练模型中的标签形状为(1,1000)。

注意:

这个教程只在CPU上工作,在GPU设备上不工作(即使张量被移动到CUDA)。

import torch

from torchvision.models import resnet18, ResNet18_Weights

model = resnet18(weights=ResNet18_Weights.DEFAULT)

data = torch.rand(1, 3, 64, 64)

labels = torch.rand(1, 1000)

 

接下来,我们将输入数据通过模型的每个层进行运算,以进行预测。这称为前向传播。

prediction = model(data) # 前向传播

我们使用模型的预测结果和相应的标签来计算误差(损失)。

下一步是将此误差通过网络进行反向传播。

当我们在误差张量上调用 .backward() 时,反向传播开始。

然后Autograd计算并存储每个模型参数的梯度在参数的 .grad 属性中。

loss = (prediction - labels).sum()

loss.backward() # 反向传播

接下来,我们加载一个优化器,本例中使用学习率为0.01和动量为0.9的SGD。我们在优化器中注册模型的所有参数。

optim = torch.optim.SGD(model.parameters(), lr=1e-2, momentum=0.9)

最后,我们调用 .step() 来启动梯度下降。优化器通过其在 .grad 中存储的梯度来调整每个参数。

optim.step() #梯度下降

此时,你已经拥有训练神经网络所需的一切。

torch.autograd跟踪所有requires_grad标志设置为True的张量的操作。对于不需要梯度的张量,将该属性设置为False将其排除在梯度计算DAG之外。

即使只有一个输入张量的requires_grad=True,操作的输出张量也将需要梯度。

x = torch.rand(5, 5)

y = torch.rand((5, 5), requires_grad=True)

在神经网络中,不计算梯度的参数通常被称为冻结参数。如果事先知道不需要这些参数的梯度,将其部分“冻结”在模型中是很有用的(这样可以通过减少自动求导计算来提高性能)。

在微调中,我们通常冻结大部分模型,只修改分类器层以便对新标签进行预测。我们加载一个预训练的resnet18模型,并将所有参数冻结。

from torch import nn, optim

model = resnet18(weights=ResNet18_Weights.DEFAULT)

#冻结网络中的所有参数

for param in model.parameters():

param.requires_grad = False

假设我们想在一个有10个标签的新数据集上微调模型。在resnet中,分类器是最后一个线性层model.fc。

我们可以简单地用一个新的线性层(默认情况下未冻结)替换它,作为我们的分类器。

model.fc = nn.Linear(512, 10)

现在,模型中除了model.fc的参数之外,所有参数都被冻结。只有模型的权重和偏置需要计算梯度。

# 只优化分类器

optimizer = optim.SGD(model.parameters(), lr=1e-2, momentum=0.9) 请注意,尽管我们将所有参数都注册到了优化器中,但只有分类器的权重和偏置会计算梯度(因此在梯度下降中更新)。

torch.no_grad()也提供了同样的排除功能,可以作为上下文管理器使用。

 

###################################################################################################

import torch

import torchaudio

from torchaudio.utils import download_asset

SAMPLE_WAV = download_asset("tutorial-assets/Lab41-SRI-VOiCES-src-sp0307-ch127535-sg0042.wav")

# 查询音频元数据

metadata = torchaudio.info(SAMPLE_WAV) print(metadata)

# 查询类似文件的对象

url = "https://download.pytorch.org/torchaudio/tutorial-assets/steam-train-whistle-daniel_simon.wav"

with requests.get(url, stream=True) as response:

  metadata = torchaudio.info(response.raw)

   print(metadata)

加载音频数据:要加载音频数据,可以使用torchaudio.load()函数。该函数接受类似路径的对象或类似文件的对象作为输入。

返回的值是一个元组,包含波形(Tensor)和采样率(int)。默认情况下,返回的Tensor对象的dtype是torch.float32,数值范围是[-1.0, 1.0]。

import matplotlib.pyplot as plt

waveform, sample_rate = torchaudio.load(SAMPLE_WAV)

def plot_waveform(waveform, sample_rate):

   waveform = waveform.numpy()

  num_channels, num_frames = waveform.shape
  time_axis = torch.arange(0, num_frames) / sample_rate # 一维张量

  figure, axes = plt.subplots(num_channels, 1) #num_channels*1的图
  if num_channels == 1:   
    axes = [axes]   
  for c in range(num_channels):   
    axes[c].plot(time_axis, waveform[c], linewidth=1)   
    axes[c].grid(True)   
    if num_channels > 1:   
      axes[c].set_ylabel(f"Channel {c+1}")   
  figure.suptitle("waveform")   
  plt.show(block=False)

plot_waveform(waveform, sample_rate)

def plot_specgram(waveform, sample_rate, title="Spectrogram"):

  waveform = waveform.numpy()

 num_channels, num_frames = waveform.shape

 figure, axes = plt.subplots(num_channels, 1)
 if num_channels == 1:
    axes = [axes]
 for c in range(num_channels):
    axes[c].specgram(waveform[c], Fs=sample_rate)
    if num_channels > 1:
        axes[c].set_ylabel(f"Channel {c+1}")
 figure.suptitle(title)
 plt.show(block=False)

plot_specgram(waveform, sample_rate)

# 切片

方法一

waveform1 = waveform1[:, frame_offset : frame_offset + num_frames]

print(f" - 已获取 {response.raw.tell()} 字节")

方法二

waveform2, sample_rate2 = torchaudio.load(response.raw, frame_offset=frame_offset, num_frames=num_frames)

print(f" - 已获取 {response.raw.tell()} 字节")

print("检查生成的波形数据 ... ", end="")

assert (waveform1 == waveform2).all()

print("匹配!")

要将音频数据保存为常见应用程序可读取的格式,您可以使用torchaudio.save()函数。

###################################################################################################

要获取音频信号随时间变化的频谱图,可以使用 torchaudio.transforms.Spectrogram() 函数。

SPEECH_WAVEFORM, SAMPLE_RATE = torchaudio.load(SAMPLE_SPEECH)
n_fft = 1024
win_length = None
hop_length = 512

# Define transform
spectrogram = T.Spectrogram(
    n_fft=n_fft,
    win_length=win_length,
    hop_length=hop_length,
    center=True,
    pad_mode="reflect",
    power=2.0,
)
# Perform transform
spec = spectrogram(SPEECH_WAVEFORM)

要从频谱图恢复出波形信号,可以使用 Griffin-Lim 算法(GriffinLim)

torch.random.manual_seed(0)

n_fft = 1024
win_length = None
hop_length = 512

spec = T.Spectrogram(
    n_fft=n_fft,
    win_length=win_length,
    hop_length=hop_length,
)(SPEECH_WAVEFORM)
griffin_lim = T.GriffinLim(
    n_fft=n_fft,
    win_length=win_length,
    hop_length=hop_length,
)
reconstructed_waveform = griffin_lim(spec)

Mel频谱图的生成涉及到生成频谱图并进行Mel标度转换。在torchaudio中,torchaudio.transforms.MelSpectrogram()提供了这个功能。

n_fft = 1024
win_length = None
hop_length = 512
n_mels = 128

mel_spectrogram = T.MelSpectrogram(
    sample_rate=sample_rate,
    n_fft=n_fft,
    win_length=win_length,
    hop_length=hop_length,
    center=True,
    pad_mode="reflect",
    power=2.0,
    norm="slaney",
    onesided=True,
    n_mels=n_mels,
    mel_scale="htk",
)

melspec = mel_spectrogram(SPEECH_WAVEFORM)

MFCC:

n_fft = 2048
win_length = None
hop_length = 512
n_mels = 256
n_mfcc = 256

mfcc_transform = T.MFCC(
    sample_rate=sample_rate,
    n_mfcc=n_mfcc,
    melkwargs={
        "n_fft": n_fft,
        "n_mels": n_mels,
        "hop_length": hop_length,
        "mel_scale": "htk",
    },
)

mfcc = mfcc_transform(SPEECH_WAVEFORM)

LFCC:

n_fft = 2048
win_length = None
hop_length = 512
n_lfcc = 256

lfcc_transform = T.LFCC(
    sample_rate=sample_rate,
    n_lfcc=n_lfcc,
    speckwargs={
        "n_fft": n_fft,
        "win_length": win_length,
        "hop_length": hop_length,
    },
)

lfcc = lfcc_transform(SPEECH_WAVEFORM)

Pitch:音高

pitch = F.detect_pitch_frequency(SPEECH_WAVEFORM, SAMPLE_RATE)

音频特征增强:

import torchaudio.transforms as T

SpecAugment是一种常用的频谱增强技术(改变速度、)

torchaudio实现了torchaudio.transforms.TimeStretch()、torchaudio.transforms.TimeMasking()和torchaudio.transforms.FrequencyMasking()。

spec = get_spectrogram(power=None)
stretch = T.TimeStretch()

rate = 1.2
spec_ = stretch(spec, rate)

时间掩码:

torch.random.manual_seed(4)

spec = get_spectrogram()
masking = T.TimeMasking(time_mask_param=80)
spec = masking(spec)

频域掩码:

torch.random.manual_seed(4)

spec = get_spectrogram()
masking = T.FrequencyMasking(freq_mask_param=80)
spec = masking(spec)

使用wav2vec2提取声学特征:在torchaudio.pipelines中有多个预训练模型可用。

bundle = torchaudio.pipelines.WAV2VEC2_ASR_BASE_960H #(960小时)
model = bundle.get_model().to(device)
waveform, sample_rate = torchaudio.load(SPEECH_FILE)
waveform = waveform.to(device)

if sample_rate != bundle.sample_rate:
    waveform = torchaudio.functional.resample(waveform, sample_rate, bundle.sample_rate)
with torch.inference_mode():
    features, _ = model.extract_features(waveform)

Wav2Vec2模型提供了一步完成特征提取和分类的方法。

使用torch.inference_mode():

  emission, _ = model(waveform)

emission[0].T,此时的横轴为帧,纵轴为类别

 

============================================================================

spectrogram(从原始音频信号创建一个或一批频谱图)

inverse_spectrogram(从所提供的复值频谱图创建一个或一批反频谱图)

griffinlim(使用 Griffin-Lim 变换从线性幅度谱图计算波形)

phase_vocoder(给定一个 STFT 张量,通过一个速度因子在时间上加速而不改变音高)

pitch_shift(将波形的音高调整 n_steps 步)

compute_deltas(计算张量(通常为频谱图)的增量系数)

detect_pitch_frequency(检测音高频率)

sliding_window_cmn(对每个utterance应用滑动窗口倒谱均值(和可选的方差)归一化)

compute_kaldi_pitch(提取音高)

spectral_centroid(计算每个通道沿时间轴的频谱中心)

 

posted @ 2023-09-23 12:53  永振  阅读(234)  评论(0编辑  收藏  举报