首页 > 其他分享 >使用 ROCm 在 AMD GPU 上微调和测试前沿的语音模型

使用 ROCm 在 AMD GPU 上微调和测试前沿的语音模型

时间:2024-11-20 09:44:28浏览次数:3  
标签:self AMD dataset ROCm train import GPU audio 音频

Fine-tuning and Testing Cutting-Edge Speech Models using ROCm on AMD GPUs — ROCm Blogs

AI 语音代理或语音机器人是通过使用口头语言与人交流而设计的。语音机器人通常用于客户服务和个人助手应用,并有可能进入并革命性地改变人们与技术互动的几乎每个方面,这些方面可以从语音的使用中受益。自动语音识别(ASR)技术是将人类语音转换为文本的过程,是创建 AI 语音代理的基础。在这篇博客文章中,我们将为您介绍如何在 AMD GPU 上使用 ROCm 部署三种机器学习 ASR 模型的实践操作。

我们首先将介绍如何微调Wav2Vec 2.0 模型以进行西班牙语的自动语音识别 (ASR),强调这种方法在识别口语西班牙语方面的高效性。然后,我们将向您展示如何使用音频频谱变换器模型进行音频分类任务,即识别和分类不同类型的音频(例如语音、环境声音或音乐),并强调其在音频信号分类中的精确性和可靠性。最后,我们将讨论使用PyAnnote.Audio工具包进行说话人分离任务,即建模和识别音频流中的每个说话者,并实际展示该工具在区分不同说话者方面的有效性。

这篇博客中所展示的微调和测试过程突出了 AMD 产品和技术的实用性和可靠性,使 AMD GPU 和 ROCm 成为语音处理应用的理想选择。

您可以在这个GitHub 文件夹中找到与这篇博客文章相关的资源。

要求

运行本博客

  • 克隆仓库并进入博客目录:

    git clone https://github.com/ROCm/rocm-blogs.git
    cd rocm-blogs/blogs/artificial-intelligence/speech_models
    
  • 构建并启动容器。有关构建过程的详细信息,请参阅 speech_models/docker/Dockerfile.

    cd docker
    docker compose build
    docker compose up
    
  • 在浏览器中访问 http://localhost:8888/lab/tree/src/speech_models.ipynb并打开`speech_models.ipynb`笔记本。

您可以使用`speech_models.ipynb`笔记本按照本博客中的练习进行操作。

探索 google/fleurs 数据集

这篇博客使用 google/fleurs 数据集(可以在 Hugging Face 上找到 链接)对西班牙语自动语音识别(ASR)模型进行微调。`google/fleurs` 的少样本学习评估的通用语音表示基准数据集涵盖了 102 种语言,每种语言拥有大约 12 小时的监督语音数据。

首先导入任务所需的依赖库:

from transformers import Wav2Vec2CTCTokenizer, Wav2Vec2FeatureExtractor, Wav2Vec2Processor, TrainingArguments, Trainer, Wav2Vec2ForCTC, AutoFeatureExtractor, AutoModelForAudioClassification
from huggingface_hub import login
from unidecode import unidecode
import json
import re
import torch

import evaluate

from datasets import load_dataset, load_metric, DatasetDict
import numpy as np
import pandas as pd
import IPython.display as ipd

import random
from IPython.display import Audio, display

pd.set_option('display.max_columns', None)
pd.set_option('display.max_rows', None)
pd.set_option('display.max_colwidth', None)

然后加载并探索 google/fleurs 数据集:

# 加载数据集

dataset = load_dataset(
    "google/fleurs", 
    "es_419", 
    split={'train':'train', 'test':'test', 'validation':'validation'},
    trust_remote_code=True
)

'''
Google/fleurs 数据集根据选择的语言可能包含一些不一致的音频示例。 对于西班牙语,一种解决方法是通过观察波形的最大值约为 1e-4 来过滤无效记录。 更多信息请参见 Hugging Face 上的相关讨论:https://huggingface.co/datasets/google/fleurs/discussions/16
'''
dataset = dataset.filter(lambda example: example['audio']['array'].max()>1e-4)
dataset

DatasetDict({
    train: Dataset({
        features: ['id', 'num_samples', 'path', 'audio', 'transcription', 'raw_transcription', 'gender', 'lang_id', 'language', 'lang_group_id'],
        num_rows: 2306
    })
    test: Dataset({
        features: ['id', 'num_samples', 'path', 'audio', 'transcription', 'raw_transcription', 'gender', 'lang_id', 'language', 'lang_group_id'],
        num_rows: 908
    })
    validation: Dataset({
        features: ['id', 'num_samples', 'path', 'audio', 'transcription', 'raw_transcription', 'gender', 'lang_id', 'language', 'lang_group_id'],
        num_rows: 408
    })
})

上述输出展示了一个包含 train、`test` 和 validation 分割的 DatasetDict 对象。每个分割中的 num_rows 属性表示该分割包含的记录数量。

注意: 根据所选择的语言,`Google/fleurs` 数据集包含一些不一致的音频示例。对于西班牙语,一种解决方法是在波形的最大值约为 1e-4 时过滤无效记录。更多信息请参见 Hugging Face 上的相关 讨论

首先,探究一下 train 分割的第一个示例:

# 探究 train 分割中的第一个记录
dataset["train"][0]

{'id': 844,
 'num_samples': 92160,
 'path': '/root/.cache/huggingface/datasets/downloads/extracted/ceb7b7f0b52887eaab6f672ec380d2cb9d46b7b8423185434fb6b186f63d4b2b/10005668950815513748.wav',
 'audio': {'path': 'train/10005668950815513748.wav',
  'array': array([0., 0., 0., ..., 0., 0., 0.]),
  'sampling_rate': 16000},
 'transcription': 'los murales o garabatos indeseados reciben el nombre de grafiti',
 'raw_transcription': 'Los murales o garabatos indeseados reciben el nombre de grafiti.',
 'gender': 1,
 'lang_id': 20,
 'language': 'Spanish',
 'lang_group_id': 0}

train 分割中的第一个示例包含一个有 92160 个值的数组。该数组表示以每秒 16000 个值(16kHz)的采样率采样的实际音频波形数据。这导致总共 5.76 秒的音频数据。还可以看到该音频文件内容的文本转录,对应的是西班牙语的女性说话者。

在 notebook 中,你可以聆听 train 分割中的一些随机示例:

# 映射标签到 id 和相反的映射
labels = dataset["train"].features["gender"].names[:2] # Extract gender of person's speech
label2id, id2label = dict(), dict()
for i, label in enumerate(labels):
    label2id[label] = str(i)
    id2label[str(i)] = label


# 探索一些数据集示例
idx_list = []
num_examples = 5

for _ in range(num_examples):
    rand_idx = random.randint(0, len(dataset["train"])-1)
    example = dataset["train"][rand_idx] # select a random example
    audio = example["audio"] # extract waveform
    idx_list.append(rand_idx) 

    print(f'Item: {rand_idx} | Label: {id2label[str(example["gender"])]}={label2id[id2label[str(example["gender"])]]}')
    print(f'Shape: {audio["array"].shape}, sampling rate: {audio["sampling_rate"]}')
    display(Audio(audio["array"], rate=audio["sampling_rate"]))
    print()

注意: 你需要在 notebook 中运行代码以聆听音频记录的示例。

你还可以显示这些随机样本的原始转录文本:

# 显示每个音频记录对应的原始文本转录
pd.DataFrame({'sentence':dataset['train'][idx_list]['raw_transcription']})

Sentence

Content

1

La forma evidente de viajar en la primera clase o en la clase ejecutiva de un avión es gastar una fortuna por ese privilegio (o, lo que es mejor, hacer que su compañía pague por usted).

2

Desde entonces, el brasileño ha jugado para el equipo en 53 enfrentamientos, en todos los campeonatos, y ha convertido 24 veces.

3

«Actualmente, tenemos ratones de cuatro meses de edad que antes solían ser diabéticos y que ya no lo son», agregó.

4

Se llevaron a cabo manifestaciones a nivel mundial, se condujeron numerosos juicios criminales, y los jefes de estado tanto de Islandia como de Pakistán renunciaron.

5

Muchas personas comprobaron el hallazgo mediante el uso de varios tipos de hardware y software y a comienzos del mes de febrero y se dio a conocer el martes.

如上所示的文本转录包含西班牙语的词汇和字符。在将它们输入到模型之前,你需要对其进行预处理。

此外,你还可以探索 train 分割中各示例时长的分布。使用以下代码示例创建音频片段时长的柱状图:

# 柱状图:训练分割中音频记录的时长

sampling_rate = 16000

duration_in_seconds = pd.Series([len(k['audio']['array'])/sampling_rate for k in dataset['train']])

ax = duration_in_seconds.hist(rwidth = 0.8)
ax.set_xlabel('Duration in seconds')
ax.set_ylabel('Frequency')
ax.grid(False)
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.spines['left'].set_visible(False)
ax.set_title('Histogram of speech duration | Train split')

Figure1

这张柱状图显示了大多数音频文件的时长大约在10到15秒左右。

Fine-tuning 和 测试语音模型

以下小节展示了如何对Wav2Vec 2.0模型进行微调,以实现西班牙语语音识别。Wav2Vec 2.0是一种自监督预训练的语音表征模型,能够仅通过原始音频学习特征。它可以被微调用于音频分类和自动语音识别等任务。此外,该博客还演示了如何使用Audio Spectrogram Transformer模型进行音频分类推理,以及如何使用PyAnnote工具包进行说话人分离。

微调 Wav2Vec 2.0 以实现西班牙语自动语音识别

Wav2Vec 2.0 模型由Facebook AI研究团队开发,是一种用于自动语音识别(ASR)的最先进框架。该模型使用卷积神经网络处理原始音频波形,从音频数据中提取有意义的特征。该模型的训练分为两个阶段。在第一阶段,通过自监督学习,模型通过预测输入音频中被掩盖的部分来学习通用的音频表示。在第二阶段,模型使用带标签的数据进行微调,用于特定的ASR任务。

Wav2Vec2-Large-XLSR-53 是 Wav2Vec 2.0 模型的一个变体,设计用于跨语言语音识别。该变体在包含53种语言的56,000小时的语音数据上进行了训练,旨在捕捉多种语言特性,从而在ASR任务中表现出色。

The process of fine-tuning Wav2Vec2-Large-XLSR-53 for the specific task of Spanish speech recognition on the google/fleurs dataset involves adapting the pre-trained model to the Spanish language by fine-tuning it with a relatively small amount of labeled data. This enables the model to recognize and transcribe Spanish speech more accurately.

用于西班牙语语音识别的Wav2Vec2-Large-XLSR-53 微调过程使用 google/fleurs 数据集,其目的是通过相对少量的带标签数据,使预训练模型适应西班牙语言。这使得模型能够更准确地识别和转录西班牙语语音。

微调过程通常包括将音频数据重新采样为16kHz,并处理文本标签以去除特殊字符并进行归一化。`google/fleurs` 数据集中的音频波形已经采样为16kHz,因此你可以专注于去除特殊字符并归一化标签值。

class DataCollatorCTCWithPadding:

    def __init__(self, processor, padding = True):
        self.processor = processor
        self.padding = padding

    def __call__(self, features):

        # 分离输入和标签。它们可能需要不同的填充方法
        input_features = [{"input_values": feature["input_values"]} for feature in features]
        label_features = [{"input_ids": feature["labels"]} for feature in features]

        # 填充输入特征
        batch = self.processor.pad(input_features, padding = self.padding, return_tensors = "pt")

        # 准备标签进行处理并使用处理器
        label_texts = [self.processor.decode(feature["input_ids"], skip_special_tokens = True) for feature in label_features]
        labels_batch = self.processor(text = label_texts, padding = self.padding, return_tensors = "pt")
        
        # 用 -100 替换填充,忽略
        labels = labels_batch["input_ids"].masked_fill(labels_batch.attention_mask.ne(1),-100)
        batch["labels"] = labels

        return batch

接下来,定义一个自定义 ASRFineTuner 类来协助微调任务:

自定义微调类 

class ASRFineTuner:

    def __init__(self, pretrained_model_tag, dataset_name, output_dir, num_train_epochs = 5, learning_rate=3e-4, batch_size = 16):
        
        self.pretrained_model_tag = pretrained_model_tag
        self.dataset_name = dataset_name
        self.output_dir = output_dir
        self.num_train_epochs = num_train_epochs
        self.learning_rate = learning_rate
        self.batch_size = batch_size
        
        # Load and preprocess dataset
        self.dataset = load_dataset(self.dataset_name, "es_419", split={'train':'train', 'test':'test', 'validation':'validation'}, trust_remote_code=True)
        self.dataset = self.dataset.filter(lambda example: example['audio']['array'].max()>1e-4) #remove invalid examples
        
        self.tokenized_dataset =  self.dataset.map(self._remove_special_characters)
        self._create_vocabulary_json() # Create vocabulary tokens file
        
        self.vocab_dict = None # contains the vocabulary letters. For display only

        # Load tokenizer, feature extractor, processor
        self.tokenizer = Wav2Vec2CTCTokenizer("./vocab.json", unk_token="[UNK]", pad_token="[PAD]", word_delimiter_token="|",)
        self.feature_extractor = Wav2Vec2FeatureExtractor(feature_size=1, sampling_rate=16000, padding_value=0.0, do_normalize=True, return_attention_mask=True)
        self.processor = Wav2Vec2Processor(feature_extractor = self.feature_extractor, tokenizer = self.tokenizer)

        # Tokenize dataset
        self.tokenized_dataset = self.tokenized_dataset.map(self._prepare_dataset, num_proc=4, remove_columns=self.dataset.column_names["train"]) 
        self.train_dataset = self.tokenized_dataset['train']
        self.test_dataset = self.tokenized_dataset['test']
        self.validation_dataset = self.tokenized_dataset['validation']        

        # Instantiate data collator
        self.data_collator = DataCollatorCTCWithPadding(processor=self.processor, padding=True)

        # Load the model
        self.model = Wav2Vec2ForCTC.from_pretrained(
            self.pretrained_model_tag, 
            attention_dropout=0.1,
            hidden_dropout=0.1,
            feat_proj_dropout=0.0,
            mask_time_prob=0.05,
            layerdrop=0.1,
            ctc_loss_reduction="mean", 
            pad_token_id = self.processor.tokenizer.pad_token_id,
            vocab_size = len(self.processor.tokenizer)
        ).to("cuda")
        
        # Wav2Vec2 layers are used to extract acoustic features from the raw speech signal. 
        # thus the feaure extraction part of the model has been sufficiently trained and does not need additional fine-tune
        self.model.freeze_feature_encoder() 

        # Gradient checkpointing reduces memory footprint during training  by storing
        # only a subset of intermediate activations and recomputing the rest during backward pass
        self.model.gradient_checkpointing_enable()
        
        
        # Training arguments
        self.training_args = TrainingArguments(
            output_dir = self.output_dir,
            group_by_length = True,
            per_device_train_batch_size = 4,
            per_device_eval_batch_size= 4,
            eval_strategy = "epoch",
            num_train_epochs=self.num_train_epochs,
            fp16=True, #enabled mixed precision
            save_steps = 100,
            eval_steps = 100,
            logging_steps = 10,
            learning_rate = self.learning_rate,
            warmup_steps = 50,
            save_total_limit = 2,
            push_to_hub = False
        )

    
        # Trainer
        self.trainer = Trainer(
            model = self.model,
            data_collator = self.data_collator,
            args = self.training_args,
            compute_metrics = self._compute_metrics,
            train_dataset = self.train_dataset,
            eval_dataset = self.validation_dataset,
            tokenizer = self.processor.feature_extractor,
        )

        # Inference results
        self.results = None
        

    # -- Helper methods --

    def _prepare_dataset(self, batch):
        audio = batch["audio"]
        
        # batched input_values and labels
        batch["input_values"] = self.processor(audio["array"], sampling_rate=16000).input_values[0]
        batch["labels"] = self.processor(text = batch['raw_transcription']).input_ids
        
        return batch

    def _remove_special_characters(self,batch):
        chars_to_ignore_regex =  "[.,?!;:'-=@$#<>\[\]_{}|&`~'*\/()+%0-9']"
        batch["raw_transcription"] = re.sub(chars_to_ignore_regex, "",unidecode(batch["raw_transcription"])).lower() + " "
        
        return batch

    def _extract_all_chars(self,batch):
      all_text = " ".join(batch["raw_transcription"])
      vocab = list(set(all_text))
        
      return {"vocab": [vocab], "all_text": [all_text]}

    def _create_vocabulary_json(self):
        # Aggreagates all the transcription text
        vocabs = self.tokenized_dataset.map(
            self._extract_all_chars, 
            batched=True, 
            batch_size=-1,
            keep_in_memory=True,
            remove_columns=self.dataset.column_names["train"]
        )

        # Create a vocabulary (letters) dictionary
        vocab_list = list(set(vocabs["train"]["vocab"][0]) | set(vocabs["test"]["vocab"][0]) | set(vocabs["validation"]["vocab"][0]))
        vocab_dict = {v: k for k, v in enumerate(vocab_list)}
        vocab_dict["|"] = vocab_dict[" "]
        del vocab_dict[" "]
        vocab_dict["[UNK]"] = len(vocab_dict)
        vocab_dict["[PAD]"] = len(vocab_dict)

        # Save the vocabulary as json for Wav2Vec2CTCTokenizer
        with open('vocab.json', 'w') as vocab_file:
            json.dump(vocab_dict, vocab_file)

        self.vocab_dict = vocab_dict

    def _compute_metrics(self, pred):
        pred_logits = pred.predictions
        pred_ids = np.argmax(pred_logits, axis=-1)
    
        pred.label_ids[pred.label_ids == -100] = self.processor.tokenizer.pad_token_id
    
        pred_str = self.processor.batch_decode(pred_ids) #predicted string
        label_str = self.processor.batch_decode(pred.label_ids, group_tokens=False) 

        wer_metric = evaluate.load("wer", trust_remote_code=True) #Word Error Rate metric
        wer = wer_metric.compute(predictions=pred_str, references=label_str)
        
        return {"wer": wer}

    def _map_to_result(self,batch):        
        with torch.no_grad():
            input_values = torch.tensor(batch["input_values"], device="cuda").unsqueeze(0)
            logits = self.model(input_values).logits
        
        pred_ids = torch.argmax(logits, dim=-1)
        batch["pred_str"] = self.processor.batch_decode(pred_ids)[0]
        batch["text"] = self.processor.decode(batch["labels"], group_tokens=False)        
        
        return batch


    # -- Class methods --
    def train(self):
        self.trainer.train()

    def predict_test_set(self):
        results = self.test_dataset.map(self._map_to_result, remove_columns = self.test_dataset.column_names)
        
        return results

注: 上面的代码通过在实例化 TrainingArguments 类时设置 fp16=True 来启用混合精度。混合精度指的是同时使用 16 位和 32 位浮点类型,以提高训练速度并减少内存使用。更多关于混合精度训练的信息,请参阅以下博客: [使用 AMD GPU 在 PyTorch 中自动混合精度](Automatic mixed precision in PyTorch using AMD GPUs — ROCm Blogs) 和 [优化 RoBERTa:使用混合精度在 AMD 上进行微调](Optimizing RoBERTa: Fine-Tuning with Mixed Precision on AMD — ROCm Blogs).

I实例化 ASRFineTuner 类并调用其 train 方法:

spanish_ASR = ASRFineTuner(
    pretrained_model_tag = "facebook/wav2vec2-large-xlsr-53", 
    dataset_name = "google/fleurs",
    output_dir = './spanish_asr_out',
    num_train_epochs = 5
)        

# 微调模型
spanish_ASR.train()

训练过程中,你会看到类似下面的输出:

Epoch

Training Loss

Validation Loss

Wer

1

2.807

2.823586

0.982931

2

1.4859

1.254473

0.999501

3

0.4344

0.297086

0.330006

4

0.2789

0.194332

0.227491

5

0.2667

0.184779

0.21092

这个表格显示了训练损失(Training Loss)和验证损失(Validation Loss)正在减小。同样,词错误率(WER)指标也在减小。

词错误率(WER)是评估语音识别系统性能的常用指标。它通过计算将转录文本转换为参考文本所需的替换、插入和删除的总和来衡量转录文本与参考文本之间的差异。较低的WER表示语音识别系统更加准确。

训练完成后,通过调用 predict_test_set 方法来评估测试集结果:

# 进行推理
results = spanish_ASR.predict_test_set()

你可以通过显示转录文本和参考文本相互比较来检查输出。为此,定义一个函数来可视化预测文本和原始文本:

import random
import pandas as pd
from IPython.display import display, HTML


def show_random_elements(dataset, num_examples=50):

    # 显示50个例子    
    assert num_examples <= len(dataset), "Not enough elements in the dataset."
    picks = []
    for _ in range(num_examples):
        pick = random.randint(0, len(dataset)-1)
        while pick in picks:
            pick = random.randint(0, len(dataset)-1)
        picks.append(pick)
    
    df = pd.DataFrame(dataset[picks])
    display(HTML(df.to_html()))


show_random_elements(results)

predicted_text

text

pasado siminutos del inicio del espectaculo se desato un viento que aproximabamente un minuto despues habia alcanzado los kmphluego lego ala luvia pero tan fuerte tan densa que poerforaba tupiel como una uja a continuacion cayo gran izo del cielo nla gente aterorizada gritaba y coria por encima de otros

pasados cinco minutos del inicio del espectaculo se desato un viento que aproximadamente un minuto despues habia alcanzado los kilometros por hora luego llego la lluvia pero tan fuerte y tan densa que perforaba tu piel como una aguja a continuacion cayo granizo del cielo la gente aterrorizada gritaba y corria por encima de otros

el vale de cochamo es el destino para escalar mas popular de chile ya es conocido como el yosimite de sudamerica con variedad de extensos muros y riscos de granito

el valle de cochamo es el destino para escalar mas popular de chile y es conocido como el yosemite de sudamerica con variedad de extensos muros y riscos de granito

la mayor parte de las islas mas pequenas constituyen estados independientes o asociadas con francia y son populares por sus playas y complejos turisticos de lujo

la mayor parte de las islas mas pequenas constituyen estados independientes o asociadas con francia y son populares por sus playas y complejos turisticos de lujo

esto parece tener sentido ya que en la tiera no se percidibe su movimiento cierto

esto parece tener sentido ya que en la tierra no se percibe su movimiento cierto

这些结果表明,经过微调的模型能够识别每个音频文件中大部分的语音内容。为了获得更准确的转录结果,可以训练模型更多的轮次。

虽然自动语音识别(ASR)主要集中在转录口语上,但音频领域的另一个重要应用是音频分类,它对不同类型的声音进行分类。 

使用音频频谱 Transformer (AST) 进行音频分类

音频频谱 Transformer (AST) 是一种专为音频分类任务设计的模型。AST 利用了注意力机制,而不是传统的卷积神经网络 (CNN)。注意力机制允许模型动态地调整输入数据(频谱)的不同部分的重要性。这意味着 AST 可以比 CNN 更有效地捕捉长距离依赖和全局上下文。AST 首先将输入音频波形转换为频谱图,然后将其划分为重叠的补丁。每个补丁都被转换为嵌入向量,然后输入到 Transformer 模型中。

对于音频分类任务,本文使用微调模型 MIT/ast-finetuned-audioset-10-10-0.4593 对一小部分来自 Google 的 AudioSet 音频记录进行分类。AudioSet 数据集是一个大规模的人类标注的 10 秒声段集合,取自 YouTube 视频,其中人类标注者验证了音频片段中声音的存在。该数据集包含约 200 万条记录,包含 527 个标签, 可从 agkphysics/AudioSet on Hugging Face 获得。

开始测试这个模型,首先导入所需模块:

from transformers import ASTFeatureExtractor
from datasets import load_dataset, Audio, DatasetDict, Dataset
from transformers import AutoModelForAudioClassification
import torchaudio
import torch
import numpy as np
import random
import IPython

接下来,加载数据集并从测试集中随机选择几个示例:

# 选择几个示例准备数据集

audio_dataset = load_dataset("agkphysics/AudioSet",
                             trust_remote_code=True,
                             split = "test",
                             streaming = True
                            )

audio_dataset_sample = [next(iter(audio_dataset)) for _ in range(50)] # select 50 examples
audio_dataset_sample = Dataset.from_list(random.sample(audio_dataset_sample,5)) # dataset with 5 random examples from the 50 before
audio_dataset_sample = DatasetDict({'test':audio_dataset_sample}) # transform to datasetdict object
audio_dataset_sample

然后,探索数据集中的第一个示例:

# 探索第一个示例
audio_dataset_sample['test']['audio'][0]

{'array': [0.09896022081375122,
  0.16452562808990479,
  0.18296313285827637,
  ...],
 'path': 'audio/eval/-1PZQg5Gi8A.flac',
 'sampling_rate': 48000}    

输出显示采样率为 48kHz。要使用音频频谱 Transformer 进行推理,必须将数据重新采样到 16kHz:

# 重采样波形到 16kHz
sampling_rate = 16000
audio_dataset_sample = audio_dataset_sample.cast_column('audio', Audio(sampling_rate = sampling_rate))

您可以收听训练集中的一些示例:

# 探索音频示例
num_examples = 5
for k in range(num_examples):
    example = audio_dataset_sample['test'][k]
    actual_label = example['human_labels']
    print(f'True labels: {actual_label}')
    display(IPython.display.Audio(data = np.asarray(example['audio']['array']),rate = sampling_rate, autoplay=False) )

注:您必须运行 notebook 才能收听音频示例。

最后,您可以通过运行以下代码测试您创建的示例集的音频分类:

# 聚合波形到一个列表中
waveforms  = [np.asarray(k['audio']['array']) for k in audio_dataset_sample['test']] 

# 对波形应用特征提取器
feature_extractor = ASTFeatureExtractor()
inputs = feature_extractor(waveforms, sampling_rate=sampling_rate, padding="max_length", return_tensors="pt")
input_values = inputs.input_values

# 实例化模型进行推理
model = AutoModelForAudioClassification.from_pretrained("MIT/ast-finetuned-audioset-10-10-0.4593")

# 设置为推理模式
with torch.no_grad():
  outputs = model(input_values)

# 预测标签
predicted_class_ids = outputs.logits.argmax(-1)

for id in predicted_class_ids:
    print("Predicted class:", model.config.id2label[id.item()])

预测结果如下:

Predicted class: Speech
Predicted class: Tools
Predicted class: Speech
Predicted class: Smoke detector, smoke alarm
Predicted class: Rumble

音频分析的另一个重要方面是识别和分割录音中的不同说话者。

使用PyAnnote.Audio进行说话人时序分割

PyAnnote 是一个用Python编写的开源工具包,用于说话人时序分割。PyAnnote建立在PyTorch之上,利用深度学习模型准确识别和区分音频录音中的不同说话人。PyAnnote时序分割可以自动检测对话中说话人变化的时刻,并将每个片段分配给特定的说话人。

为了演示说话人时序分割,这篇博文将PyAnnote工具包应用到talkbank/callhome 数据集。该数据集是一个包含中文、英文、德文、日文和西班牙语母语者之间非脚本化电话对话的集合。

注意: PyAnnote 和 talkbank/callhome 在Hugging Face上分别作为受限模型和受限数据集提供。你必须申请访问这些资源并且拥有Hugging Face的访问令牌

运行这部分博文需要Hugging Face的访问令牌。

你可以使用下面的PyAnnote工具包对西班牙语母语者之间的电话对话进行说话人时序分割。首先,导入以下模块:

from transformers import ASTFeatureExtractor
from datasets import load_dataset, Audio, DatasetDict, Dataset
from transformers import AutoModelForAudioClassification
from pyannote.audio import Pipeline
import torch
import torchaudio
import numpy as np
import random

import IPython

接下来,加载数据集,随机选择一些样本,并将这些样本聚合成一个DatasetDict对象:

hf_token = "Your_Hugging_Face_Token"

audio_dataset = load_dataset("talkbank/callhome", 
                             "spa", 
                             trust_remote_code=True, 
                             split = "data", 
                             streaming = True, 
                             token= hf_token
                            )

data_iter = iter(audio_dataset)
audio_dataset_sample = [next(data_iter) for _ in range(30)]
audio_dataset_sample = Dataset.from_list(random.sample(audio_dataset_sample,3))
audio_dataset_sample = DatasetDict({'test':audio_dataset_sample})
audio_dataset_sample

浏览数据集中的第一个样本:

# 浏览第一个样本
audio_dataset_sample['test']['audio'][0]
{'array': [-0.003448486328125,
  -0.00347900390625,
  -0.003631591796875,
...],
 'path': None,
 'sampling_rate': 16000}

该数据集的采样率为16kHz。

现在你可以听取数据集中每个电话对话的最后15秒:

# 通过限制为15秒的音频举例电话对话

secs = 15
sampling_rate = 16000
num_examples = audio_dataset_sample['test'].num_rows

for k in range(num_examples):
    example = audio_dataset_sample['test'][k]
    
    print(f'Telephone conversations: {k+1} of {num_examples}')
    conversation_snippet = np.asarray(example['audio']['array'][-secs*sampling_rate:]) #选择最后15秒的音频
    display(IPython.display.Audio(data = conversation_snippet,rate = sampling_rate, autoplay=False) )

注意:你必须运行笔记本才能听到音频样本。

最后,你可以在第一个电话对话中测试说话人时序分割模型。

hf_token = "Your_Hugging_Face_Token"

# 加载模型
pipeline = Pipeline.from_pretrained("pyannote/speaker-diarization-3.1", use_auth_token = hf_token)
pipeline.to(torch.device("cuda"))

# 在第一个电话对话音频样本上进行推理
example = audio_dataset_sample['test'][0]
waveform_snippet = example['audio']['array'][-secs*sampling_rate:] #slice for the last 15 seconds
waveform_snippet = torch.tensor(waveform_snippet, device = 'cuda').unsqueeze(0)

# 应用预训练管道
diarization = pipeline({"waveform":waveform_snippet, "sample_rate":sampling_rate})

# 打印结果
for turn, _, speaker in diarization.itertracks(yield_label=True):
    print(f"start={turn.start:.1f}s stop={turn.end:.1f}s speaker_{speaker}")

模型的输出结果是:

start=0.0s stop=1.0s speaker_SPEAKER_00
start=1.4s stop=3.7s speaker_SPEAKER_00
start=2.0s stop=3.3s speaker_SPEAKER_01
start=3.7s stop=3.7s speaker_SPEAKER_01
start=4.0s stop=5.5s speaker_SPEAKER_00
start=4.1s stop=4.4s speaker_SPEAKER_01
start=6.1s stop=6.9s speaker_SPEAKER_00
start=6.1s stop=6.9s speaker_SPEAKER_01
start=7.4s stop=7.4s speaker_SPEAKER_01
start=7.4s stop=7.8s speaker_SPEAKER_00
start=7.8s stop=11.9s speaker_SPEAKER_01
start=12.3s stop=15.0s speaker_SPEAKER_01

输出显示了一系列片段,包括每个片段的时间间隔和识别出的讲话者。结构包含开始时间、结束时间以及关联讲话者的标签。

总结

在这篇博客文章中,我们一步一步地展示了如何在AMD硬件上使用ROCm,微调和测试三种最先进的机器学习自动语音识别(ASR)模型。我们首先介绍了Wav2Vec 2.0模型,该模型已经过微调,用于西班牙语的自动语音识别。接着,我们研究了如何使用音频频谱变换器进行音频分类。最后,我们重点介绍了如何使用PyAnnote.Audio进行讲话者区分。每个模型的微调和推理过程都强调了ROCm在AMD GPU上处理复杂语音处理任务时的稳健性和能力。

标签:self,AMD,dataset,ROCm,train,import,GPU,audio,音频
From: https://blog.csdn.net/eidolon_foot/article/details/143832655

相关文章

  • Server2025 和 GPU-P(GPU Partitioning,GPU 分区技术)的正式支持,  GPU-P 是一种将物理 G
     Server2025和GPU-P(GPUPartitioning,GPU分区技术)的正式支持, WindowsServer2025系统将全面支持GPU-P技术。然而,GPU-P是一种将物理GPU划分为多个虚拟GPU(vGPU)并分配给不同虚拟机或容器的技术。如果你是在询问WindowsServer或MicrosoftHyper-V是否已经正式支持......
  • Ziya-LLaMA-13B 模型在GPU 上部署
    Ziya-LLaMA-13B模型在GPU上部署Ziya-LLaMA-13B是IDEA-CCNL基于LLaMa的130亿参数的大规模预训练模型,具备翻译,编程,文本分类,信息抽取,摘要,文案生成,常识问答和数学计算等能力。目前姜子牙通用大模型已完成大规模预训练、多任务有监督微调和人类反馈学习三阶段的训练过程。1.部署......
  • ubuntu2004 上安装与使用NVIDIA GPU A100
    ubuntu2004上安装与使用NVIDIAGPUA100先安装显卡驱动https://blog.csdn.net/qq_36999834/article/details/107589779用容器的方式安装cuda ##创建并启动容器,启动gpudocker要加上--gpusall选项,-i表示交互,-t表示分配一个伪终端, ##--rm自动删除停止运......
  • GPU A10 driver, CUDA 安装
    GPUA10driver,CUDA安装环境HOST:ubuntu804LTSGUST:通过PCIE透卡,KVM虚拟机:ubuntu1804LTS在gust里面安装GPUdriverdriver安装步骤NVIDIATelsaGPU的Linux驱动在安装过程中需要编译kernelmodule,系统需提前安装gcc和编译LinuxKernelModule所依赖的包......
  • NVIDIA(Hopper)H100 Tensor Core GPU 架构
    NVIDIA(Hopper)H100TensorCoreGPU架构AI赋能个体创业致力于降低直播成本服务于商家和个人​关注他  NVIDIAH100TensorCoreGPU是NVIDIA最新的(2022年发布)通用可编程流式GPU,适用于HPC、AI、科学模拟和数据分析。H100GPU主要用于执行A......
  • 配置NVIDIA Container Runtime和容器运行GPUStack教程
    GPUStack是一个设计用于运行大模型的开源GPU集群管理器,提供私有部署的大模型服务,支持大语言模型、Embedding文本嵌入模型、Reranker重排序模型、Vision多模态模型等各种模型。它可以聚合不同平台(如AppleMacbook、WindowsPC和Linux服务器)的GPU,构建一个统一的异构GPU......
  • 配置NVIDIA Container Runtime和容器运行GPUStack教程
    GPUStack是一个设计用于运行大模型的开源GPU集群管理器,提供私有部署的大模型服务,支持大语言模型、Embedding文本嵌入模型、Reranker重排序模型、Vision多模态模型等各种模型。它可以聚合不同平台(如AppleMacbook、WindowsPC和Linux服务器)的GPU,构建一个统一的异构GPU......
  • 在Unity实现《Farcry5》 GPU地形
    【USparkle专栏】如果你深怀绝技,爱“搞点研究”,乐于分享也博采众长,我们期待你的加入,让智慧的火花碰撞交织,让知识的传递生生不息!一、需求背景开放大世界渲染中,地形的渲染占比较重,包括开发投入、表现效果及性能开销等。而地形Shader部分的性能优化已经做过多版了,但Mesh的部分还......
  • GPU渲染一文详解,设置、优势和技巧
    在3D渲染领域,速度和效率至关重要,而GPU渲染已成为游戏规则的改变者,这是不争的事实。本文将介绍有关GPU渲染的所有信息,从设置硬件到探索其优势,以及优化工作流程的一些有用技巧。我们希望本指南能帮助您更好地了解GPU为您提供了哪些功能,以实现更快、更高效的渲染。什么是GPU渲染?......
  • 分享一个可以白嫖GPU算力的平台,需要的快到碗里来!
    想做深度学习训练,在哪做呢?有两个选择,本地or上云!本地部署做产品,成本比较高,但是自由度更高,毕竟是自己的设备,想怎么造都行,但如果本地没有什么算力资源的,那只能上云来跑了!今天我们挑一个可以白嫖的方案,大家跟着操作。首先我们进入骋风算力平台,注册个人账号,该平台目前正在做启......