【机器学习】基于CTC模型的语音转换可编辑文本研究

1.引言

1.1语音识别技术的研究背景

1.1.1.语音识别技术的需求

语音识别技术的研究和发展,对于提升人类与机器的交互方式具有深远的影响。首先,它极大地提高了工作效率和便利性。通过语音指令控制设备,用户可以更快捷地完成任务,无需手动输入或操作。例如,在办公环境中,语音识别可以快速完成文档编辑、邮件发送等任务;在家庭中,智能家居设备响应语音指令,实现灯光、温度等的调节。这种交互方式不仅节省时间,也使得那些由于身体条件限制而难以使用传统输入方式的人群能够更轻松地使用技术。

其次,语音识别技术对于实现无障碍访问至关重要。它为视觉障碍人士提供了一种全新的与技术互动的方式,使他们能够独立完成日常任务,如阅读信息、上网浏览等。此外,多语言支持的语音识别技术也促进了全球化背景下的交流与合作,帮助不同语言背景的人们跨越语言障碍,更有效地沟通和使用技术。

最后,语音识别技术在教育、安全、紧急响应以及数据收集和分析等领域的应用,进一步扩展了其研究的价值。在教育领域,它可以帮助学生练习发音和语言技能,提供个性化的学习体验。在安全领域,语音识别可以用于身份验证,提高交易和通信的安全性。在紧急情况下,如医疗急救或灾难响应,快速准确的语音识别可以挽救生命。同时,自动转录的语音数据为市场研究、客户服务和产品开发等领域提供了宝贵的信息资源。

综上所述,语音识别技术的研究不仅推动了人工智能和机器学习领域的进步,而且为社会带来了更广泛的应用和便利,其重要性和影响力正日益增强。

1.1.2. 语音识别的挑战

当我们着手进行语音识别研究时,一个核心的挑战是音频信号与文本转录之间的对齐问题。尽管我们拥有音频片段和相应的文本记录,但音频中的声音与文本中的字符之间的精确对应关系往往是未知的。这种对齐的不确定性大大增加了训练一个高效语音识别系统的任务难度。

在没有精确对齐信息的情况下,采用简单的对应规则——比如假设每个字符对应固定数量的音频样本——是不可行的。由于说话人的语速、口音、情感表达等因素的差异,这种假设很快就会被现实情况所打破。例如,一个快速说话的人可能在很短的时间内说出许多字符,而一个慢速说话的人则可能在较长的时间段内只说出几个字符。

解决这一问题的一种方法是手动对齐,即将每个字符与音频中的特定位置进行匹配。虽然这种方法在理论上可以提供准确的模型训练数据,但它在实际操作中存在巨大的工作量,特别是对于大规模数据集而言,这种方法几乎是不可行的。这不仅需要耗费大量的人力和时间,而且很难保证一致性和准确性。

这种对齐问题并非语音识别领域所独有。在其他领域,如手写文字识别、视频分析等,我们也面临着类似的挑战。在手写文字识别中,需要确定笔划的顺序和结构,以正确识别单词和句子。而在视频分析中,动作识别和标注需要将视频中的连续帧与特定的动作或事件相对应。这些任务都需要精确的时间或空间对齐,以确保识别的准确性。

为了克服这些挑战,研究人员开发了各种算法和模型来自动学习数据中的对齐关系。例如,在语音识别中,可以使用深度学习技术,如循环神经网络(RNN)和长短期记忆网络(LSTM),它们能够捕捉音频信号中的时间依赖性,并学习字符与音频之间的复杂映射关系。在手写文字识别中,卷积神经网络(CNN)可以用于识别笔划模式和结构。而在视频分析中,两维和三维卷积网络可以用于捕捉视频中的空间和时间特征。

1.2. CTC模型简介

为了更正式地描述,让我们考虑将输入序列 𝑋 = [𝑥₁, 𝑥₂, …, 𝑥𝑇](如音频)映射到相应的输出序列 𝑌 = [𝑦₁, 𝑦₂, …, 𝑦𝑈](如转录文本)。我们想要找到从 𝑋 到 𝑌 的准确映射。

然而,使用更简单的监督学习算法会面临一些挑战,特别是:

  1. 𝑋 和 𝑌 的长度都可能变化。
  2. 𝑋 和 𝑌 长度的比例也可能变化。
  3. 我们没有 𝑋 和 𝑌 元素之间的准确对齐(对应)。

CTC 算法克服了这些挑战。对于给定的 𝑋,它给出了所有可能 𝑌 的输出分布。我们可以使用这个分布来推断可能的输出或评估给定输出的概率。

并非所有计算损失函数和执行推理的方法都是可行的。我们需要 CTC 高效地执行这两项任务。

损失函数:对于给定的输入,我们希望训练模型以最大化其对正确答案的分配概率。为此,我们需要有效地计算条件概率 𝑝(𝑌|𝑋)。函数 𝑝(𝑌|𝑋) 也必须是可微的,以便我们可以使用梯度下降。

推理:自然地,在训练模型之后,我们想要使用它来在给定的 𝑋 下推断可能的 𝑌。这意味着解决 𝑌∗ = argmax𝑌 𝑝(𝑌|𝑋) 的问题。理想情况下,可以高效地找到 𝑌∗。使用 CTC,我们将寻求一个不太昂贵且易于找到的近似解。

1.3.研究内容

语音识别技术,作为人工智能领域内的一个重要分支,是计算机科学与计算语言学相互交融的产物。它的目标是使计算机能够理解并转换人类的语音为可编辑的文本。这项技术常被称为自动语音识别(ASR)、计算机语音识别或语音到文本(STT)。它综合了计算机科学、语言学和计算机工程等多个学科的研究成果,为人工智能的进步和人机交互的优化提供了坚实的基础。

本文将深入探讨如何利用二维卷积神经网络(2D CNN)、循环神经网络(RNN)以及连接时序分类(CTC)损失函数,构建一个高效的自动语音识别系统。CTC算法在解决序列预测问题,尤其是处理音频信号与字符之间的对齐问题时,显示出了其卓越的能力。

在构建该系统的过程中,我们将采用LJSpeech数据集,这是一个源自LibriVox项目的开源资源。该数据集包含了由单一说话者朗读的短音频片段,这些片段均选自7本非小说类书籍。使用此数据集,我们可以训练出一个能够理解不同语境下语音信号的模型。

为了评估模型的性能,我们将采用词错误率(WER)作为主要的评价指标。WER是衡量语音识别准确性的一种标准方法,它通过计算识别结果中替换、插入和删除错误的数量,并与原始文本中的单词总数进行比较来得出。这一指标能够全面反映模型在语音识别任务中的准确性和稳定性。我们将使用jiwer这个开源Python库来计算WER,它提供了一套便捷的工具,以便于评估ASR系统的性能。

接下来,本文将详细阐述构建基于CTC的ASR模型的各个环节,包括数据预处理、模型架构设计、训练策略以及性能评估等。通过这些内容,读者不仅能够深入理解ASR系统的构建原理和关键技术,而且能够获得宝贵的知识和经验,为未来的研究和实践打下坚实的基础。

2. 语音识别实现过程

2.1. 软件包安装和设置

安装jiwer软件包

pip install jiwer

设置

# 导入 pandas 库,用于数据处理  
import pandas as pd  
  
# 导入 numpy 库,用于数值计算  
import numpy as np  
  
# 导入 tensorflow 库,用于深度学习模型构建  
import tensorflow as tf  
  
# 从 tensorflow 中导入 keras 模块,用于构建和训练深度学习模型  
from tensorflow import keras  
  
# 从 keras 中导入 layers 模块,包含各种神经网络层  
from tensorflow.keras import layers  
  
# 导入 matplotlib.pyplot 库,用于绘图  
import matplotlib.pyplot as plt  
  
# 导入 IPython.display 模块,用于在 Jupyter 环境中显示图像等  
from IPython import display  
  
# 导入 jiwer 库,用于计算词错误率(WER)  
from jiwer import wer  

2.2.加载数据集

本文使用LJSpeech数据集作为研究的数据资源。

2.2.1.LJSpeech数据集简介

LJSpeech数据集是一个为文本到语音合成(TTS)任务设计的公共数据集,由一位女性演讲者朗读7本非小说类书籍的段落录制而成。该数据集包含13,100个简短的音频剪辑,每个音频剪辑都是单通道16位PCM WAV格式,采样率为22050 Hz。音频剪辑的长度从1秒到10秒不等,总长度约为24小时。

数据集附带有元数据文件(通常为CSV格式),其中包含每个音频文件的ID、转录(Transcription)和规范化转录(Normalized transcription)。ID对应.wav文件的名称,转录列显示了读者说出的原始单词,而规范化转录则将数字、序数和货币单位等展开为完整的单词。这一特性使得LJSpeech数据集在文本到语音合成的研究和开发中特别有用,因为它可以帮助模型更好地学习特定说话者的语音特征和表达方式。

2.2.2. 加载数据集步骤

要加载LJSpeech数据集,您可以按照以下步骤进行:

  1. 下载数据集

    • 您可以通过直接链接下载LJSpeech数据集:http://data.keithito.com/data/speech/LJSpeech-1.1.tar.bz2
    • 或者,您可以使用百度网盘链接下载,链接为:链接,提取码为:7o1a
  2. 解压数据集

    • 下载完成后,您会得到一个名为LJSpeech-1.1.tar.bz2的压缩包。
    • 在Linux系统中,您可以使用以下命令解压:tar -jxvf LJSpeech-1.1.tar.bz2
  3. 了解数据集结构

    • 解压后,您会发现数据集包含两个主要部分:音频文件和元数据。
    • 音频文件位于/wavs/文件夹中,每个文件都是一个单通道16位PCM WAV,采样率为22,050 Hz。
    • 元数据存储在metadata.csv文件中,该文件包含每个音频文件的标签(转录)信息。
  4. 处理元数据

    • metadata.csv文件包含以下字段:
      • ID:这是对应.wav文件的名称
      • Transcription:读者说出的单词(UTF-8)
      • Normalized transcription:使用数字、序数和货币单位进行转录并扩展为完整单词(UTF-8)
    • 在本演示中,我们将使用“Normalized transcription”字段作为标签。
  5. 加载数据

    • 根据您的应用程序或框架,您可能需要编写代码来遍历/wavs/文件夹中的音频文件,并使用metadata.csv中的相应“Normalized transcription”作为标签。
    • 如果您正在使用Python,并希望利用现有的数据处理库(如pandas),您可以先加载metadata.csv文件到一个DataFrame中,然后按照需要进行处理。
# 导入所需的库  
import pandas as pd  
import tensorflow as tf  
from tensorflow.keras import utils  
  
# 数据集的下载链接  
data_url = "https://data.keithito.com/data/speech/LJSpeech-1.1.tar.bz2"  
  
# 使用keras的utils.get_file函数下载并解压数据集  
# 如果数据集已经下载过,则不会重复下载  
data_path = utils.get_file("LJSpeech-1.1", data_url, untar=True)  
  
# 设置音频文件和元数据文件的路径  
wavs_path = data_path + "/wavs/"  
metadata_path = data_path + "/metadata.csv"  
  
# 读取元数据文件并解析  
# 注意:原始数据可能使用“|”作为分隔符,但具体应查看文件确认  
metadata_df = pd.read_csv(metadata_path, sep="|", header=None, quoting=3, encoding='utf-8')  
  
# 为DataFrame设置列名  
metadata_df.columns = ["file_name", "transcription", "normalized_transcription"]  
  
# 保留需要的列:文件名和规范化转录  
metadata_df = metadata_df[["file_name", "normalized_transcription"]]  
  
# 如果需要对数据集进行随机排序,可以使用sample方法  
# 这里设置frac=1表示保留全部数据,但进行随机排序  
# 如果不需要随机排序,可以省略这行代码  
metadata_df = metadata_df.sample(frac=1).reset_index(drop=True)  
  
# 显示前3行数据  
print(metadata_df.head(3))

上述代码的主要功能如下:

  1. 下载和解压数据集
    - 使用 TensorFlow(通过其 Keras API)的 utils.get_file 函数从指定的 URL 下载 LJSpeech 数据集(一个 tar.bz2 压缩包)。
    - 如果数据集已经下载过,则不会重复下载。
    - 解压下载的压缩包到指定的路径。

  2. 设置文件路径
    - 定义音频文件(wav 文件)所在的路径 wavs_path
    - 定义元数据文件(CSV 文件)所在的路径 metadata_path

  3. 读取元数据文件
    - 使用 pandas 的 read_csv 函数读取元数据 CSV 文件。
    - 假设 CSV 文件的字段之间使用 “|” 作为分隔符(但实际中需要根据文件内容来确定分隔符)。
    - 读取文件时指定了 header=None,因为 CSV 文件可能没有明确的标题行。
    - 读取时使用了 quoting=3,它告诉 pandas 如何处理引号内的字段(具体行为取决于 pandas 的实现和 CSV 文件的具体内容)。
    - 设置了文件的编码为 ‘utf-8’,以确保能够正确读取 UTF-8 编码的文本。

  4. 处理元数据
    - 为读取的 DataFrame 设置列名:file_name(音频文件名)、transcription(原始转录)和 normalized_transcription(规范化转录)。
    - 保留需要的列:file_namenormalized_transcription,因为在这个示例中我们只关心文件名和规范化后的转录文本。
    - 如果需要,可以对 DataFrame 进行随机排序(通过 sample(frac=1)),然后重置索引(通过 reset_index(drop=True))。这在某些情况下可能是有用的,比如当你想要打乱数据集的顺序时。

  5. 显示部分数据
    - 使用 print(metadata_df.head(3)) 显示元数据 DataFrame 的前 3 行。这有助于验证数据是否已成功加载并处理。

2.2.3.划分数据集

我们现在将数据分割成训练集和验证集。

# 计算分割点,用于将数据集分为90%的训练集和10%的验证集
split = int(len(metadata_df) * 0.90)

# 根据计算出的分割点,将数据集分割为训练集和验证集
df_train = metadata_df[:split]  # 训练集为前90%的数据
df_val = metadata_df[split:]   # 验证集为剩余10%的数据

# 打印训练集的大小
print(f"训练集大小: {
     len(df_train)}")

# 打印验证集的大小
print(f"验证集大小: {
     len(df_val)}")

2.3.数据预处理

2.3.1.准备词汇表
# 定义接受的字符集合,用于转录文本
characters = [x for x in "abcdefghijklmnopqrstuvwxyz'?! "]

# 将字符映射到整数,用于模型的输入
# 使用keras的StringLookup层,设置词汇表为characters,并且定义一个未登录词(OOV)的标记
char_to_num = keras.layers.StringLookup(vocabulary=characters, oov_token="")

# 将整数映射回原始字符,用于模型的输出
# 使用keras的StringLookup层,词汇表为char_to_num的词汇表反转,同样定义OOV标记
num_to_char = keras.layers.StringLookup(
    vocabulary=char_to_num.get_vocabulary(), oov_token="", invert=True
)

# 打印词汇表和它的大小
print(
    f"词汇表是: {
     char_to_num.get_vocabulary()} "
    f"(大小 = {
     char_to_num.vocabulary_size()})"
)

这段代码的主要功能是为自动语音识别(ASR)系统或任何需要文本转录的任务准备字符编码映射。具体来说,它包括以下几个步骤:

  1. 定义字符集:创建一个包含所有接受字符的列表,这些字符将用于文本转录。在这个例子中,字符集包括小写英文字母、一些标点符号以及空格。

  2. 字符到数字的映射:使用keras.layers.StringLookup层来将字符映射到整数。这个映射过程对于将文本数据转换为模型可以处理的数值型数据是必要的。vocabulary参数指定了所有可能的字符,oov_token参数定义了一个特殊的标记,用于表示词汇表之外的字符(在这个例子中没有使用OOV标记,所以设置为空字符串)。

  3. 数字到字符的映射:再次使用keras.layers.StringLookup层,但是这次设置invert=True,创建一个从整数映射回原始字符的反向映射。这样,模型的输出可以被转换回原始文本形式。

  4. 打印词汇表和大小:打印出创建的词汇表和它的大小。词汇表大小是指映射中包含的唯一字符数量。

2.3.2.定义转化函数

在文本到语音(TTS)或自然语言处理(NLP)等任务中,预处理是一个关键步骤,它涉及到将原始数据转换为模型可以处理的格式。一旦我们准备好了词汇表(例如,在TTS中,这可能是字符或音素列表),下一步通常是定义一个函数来执行数据集的预处理和转换。

例如,在TTS中,预处理可能包括以下几个步骤:

  1. 文本清洗:删除不必要的字符、标点符号、特殊符号等。
  2. 文本归一化:将所有文本转换为小写(如果需要的话),并执行其他任何必要的文本转换。
  3. 词汇映射:使用前面准备好的词汇表,将文本转换为模型可以理解的格式,例如将字符或单词映射到唯一的索引或编码。
  4. 数据增强(可选):根据任务需求,可能还需要对数据进行增强,例如添加噪声、改变语速等。

为了实现这些转换,我们可以编写一个预处理函数,该函数接受原始文本作为输入,并返回经过转换的数据。这个函数将使用我们前面准备的词汇表和其他任何必要的转换逻辑。

# 定义音频处理的参数
# 帧长度,即STFT窗口中的样本数
frame_length = 256
# 帧步长,连续STFT窗口之间的样本数
frame_step = 160
# FFT大小,如果不指定,则使用大于等于frame_length的最小2的幂
fft_length = 384

def encode_single_sample(wav_file, label):
    ###########################################
    ## 音频处理
    ###########################################
    # 1. 读取wav文件
    file = tf.io.read_file(wavs_path + wav_file + ".wav")
    # 2. 解码wav文件,获取音频数据和采样率
    audio, _ = tf.audio.decode_wav(file)
    # 3. 去除音频数据的维度,只保留一维数据
    audio = tf.squeeze(audio, axis=-1)
    # 4. 将音频数据类型转换为浮点数
    audio = tf.cast(audio, tf.float32)
    # 5. 计算频谱图,使用STFT
    spectrogram = tf.signal.stft(
        audio, frame_length=frame_length, frame_step=frame_step, fft_length=fft_length
    )
    # 6. 取频谱图的幅度,即实部和虚部的模
    spectrogram = tf.abs(spectrogram)
    # 7. 对频谱图进行开平方操作
    spectrogram = tf.math.pow(spectrogram, 0.5)
    # 8. 对频谱图进行归一化处理
    means = tf.math.reduce_mean(spectrogram, 1, keepdims=True)
    stddevs = tf.math.reduce_std(spectrogram, 1, keepdims=True)
    spectrogram = (spectrogram - means) / (stddevs + 1e-10)

    ###########################################
    ## 文本标签处理
    ###########################################
    # 9. 将标签转换为小写
    label = tf.strings.lower(label)
    # 10. 将标签字符串分割成字符序列
    label = tf.strings.unicode_split(label, input_encoding="UTF-8")
    # 11. 将字符序列映射到整数序列
    label = char_to_num(label)

    # 返回包含频谱图和标签映射的字典
    return {
   "spectrogram": spectrogram, "label": label}

这段代码定义了一个函数encode_single_sample,它用于处理单个音频样本并将其转换为模型训练所需的格式。以下是代码的主要功能步骤:

  1. 定义帧长度、帧步长和FFT大小
    - frame_length:窗口长度,用于STFT(短时傅里叶变换)的样本数。
    - frame_step:帧步长,连续STFT窗口之间的样本数。
    - fft_length:应用FFT的大小,如果没有提供,则使用比frame_length大的最小2的幂。

  2. 读取和解码音频文件
    - 读取指定路径下的WAV文件。
    - 使用tf.audio.decode_wav解码WAV文件,获取音频数据和采样率。

  3. 转换音频数据类型

    • 将音频数据从原始类型转换为tf.float32<
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MUKAMO

你的鼓励是我们创作最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值