语音识别与克隆算法

博主简介

博主是一名大二学生,主攻人工智能研究。感谢让我们在CSDN相遇,博主致力于在这里分享关于人工智能,c++,Python,爬虫等方面知识的分享。 如果有需要的小伙伴可以关注博主,博主会继续更新的,如果有错误之处,大家可以指正。

专栏简介:   本专栏主要研究python在人工智能方面的应用,涉及算法,案例实践。包括一些常用的数据处理算法,也会介绍很多的Python第三方库。如果需要,点击这里   订阅专栏

给大家分享一个我很喜欢的一句话:“每天多努力一点,不为别的,只为日后,能够多一些选择,选择舒心的日子,选择自己喜欢的人!”


目录

百度语音简介

获取Access Token

选择HTTP POST亲求格式

百度语音识别

百度语音识别Python SDK

基于语音识别的视频文本提取

基于音频指纹的音乐识别

音频信号采集与播放

 音频指纹生成

语音克隆技术简介

1.说话人语音编码器(Speaker Encoder)

2.序列合成器(Synthesizer)

3.声码器(Vocoder)


百度语音简介

百度语音是百度AI开放平台提供的一个在线识别语音引擎。和前面介绍的图形识别一样,都是通过对API的引用,利用百度AI提供的接口进行实现。目前支持的语音包括普通话,粤语,四川话和英语等。利用百度语音进行在线识别的时候,需要上传完整的录音文件,而且语音文件市场不得超过60s。

百度语音提供两种识别模型:搜索模型与输入法模型。搜索模型实现效果如同百度搜索的语音输入,适合短语识别场景,中间有逗号。在应用普通话搜索模型时,也可识别简单的常用英语语句。

百度语音适用于目前追u的多种操作系统和多种编程语言,只要可以对百度语音服务器发起HTTP请求,均可以使用接口。其所支持的语言格式包括:PCM(不压缩),WAV(不压缩,PCM编码),AMR(压缩)。由于百度语音底层识别使用的是PCM编码,因此“.pcm”文件。如果上传文件为其他格式,则会在服务器端被转码为PCM格式,调用接口的耗时会增加。

获取Access Token

使用语音识别及合成的REST API需要获取Access Token。Access Token是用户身份验证和授权的凭证。获取Access Token需要用户在应用管理界面中新建应用,然后在应用列表中即可查看。

语音识别采用的是Client Credentials 授权方式,即应用公钥,密钥获取Access Token,适用于任何带Server类型的应用。通过此授权方式获取Access Token仅可访问平台授权类的接口。

选择HTTP POST亲求格式

如果你的音频文件在本地,可以以JSON和RAW两种格式提交,需要将音频数据放在body中。这两种提交方式,均不属于浏览器表单的提交。

若以JSON格式上传本地文件,则读取Base64编码的二进制音频文件内容,放在speech参数内。使用RAW格式,header:Content-Length的值即音频文件的大小。由于使用RAW方式,采样率和文件格式需要填写在Content-Type中,例如,Content-Type:audio/pcm;rate=16000.

以上两种提交方式都返回统一的结果,并采用JSON格式进行封装。如果识别成功,则识别结果放在JSON的“result”字段中。如果使用(url,callback)方式进行POST请求,百度服务器会回调用户服务器的callback地址。

百度语音识别返回的结果参数
参数 数据类型 是否必填 描述
err_no int 错误码
err_msg String 错误码描述
sn String 语音数据唯一标识
result Array([String,String,...]) 识别结果数组,提供1~5个候选结果

百度语音识别

百度语音识别Python SDK

百度语音 识别Python SDK和REST API功能一致,需要联机在线调用HTTOP接口。前面我们已经介绍过如何创建应用,如何获取账号密钥,这里就不过多介绍了。下面我们介绍一下AipSpeech进行语音识别的示例代码:

from aip import AipSpeech
APP_ID='30847447'
APP_KEY='OEMasN3dTxtq2Pr55duK8qzw'
SECRET_KEY='n7gKdf7VMsz8QEfw0VBZCWG6xdX72qII'
client=AipSpeech(APP_ID,APP_KEY,SECRET_KEY)
def get_file_content(filepath):
    with open(filepath,'rb')as fp:
        return fp.read()
result=client.asr(get_file_content('./test.wav'),'wav',16000,{'dev_pid':1536})
print(result)

{'err_msg': 'request pv too much', 'err_no': 3305, 'sn': '204379690881677639467'}

该结果显示,示例语音识别成功。Python SDK语音识别函数原型为client.asr(speech,format,rate,cuid,dev_pid) ,其参数描述如下:

语音识别函数接口参数及其描述
参数 数据类型 是否必须 描述
speech buffer 建立包含语音类容的Buffer对象,语音文件的格式为.wav,.pcm,.AMR.不区分大小。
format string 语音文件的格式为.PCM,.WAV或者.AMR.不区分大小写。
rate int 采样率,16000,固定值
cuid string 用户唯一标识,用来区分用户,填写计算机MAC地址或IMEI码
dev_pid int 默认为1537(普通话)

dev_pid参数及其描述
dev_pid 语言 模型 是否有标点 备注
1536 普通话(支持简单的语音识别) 搜索模型 支持自定义词库
1537 普通话(纯中文识别) 输入法模型 不支持自定义词库
1637 粤语 不支持自定义词库
1737 英语 不支持自定义词库
1837 四川话 不支持自定义词库
1936 普通话远场 远场模型 不支持自定义词库

基于语音识别的视频文本提取

视频文本信息是视频内容的重要线索,他对视频分段,视频检索和信息摘要等视频自动化处理有着重要的意义。利用AipSpeech语音识别引擎,我们可以很方便地从一个给定的视频文件中提取出其中的语音信息并转化为对应的语言文本。对于音频格式,百度语音识别API对其参数,格式等几个方面有着明确的要求。

①参数:单声道,16000采样率,16bit深度。

②格式:PCM(不压缩),WAV(不压缩,PCM编码)以及AMR(压缩)。

③其他:完整语音文件,不得超过60秒。

视频文本的提取,主要包括视频转化为音频,音频切割分段,以及从音频中提取文本等几个主要步骤。

从视频转换为所需格式的音频可采用第三方软件来实现,例如,FFmpeg音视频转换软件。因百度API最多支持60s时常的语音识别,我们必须将时长为60s以上的音频文件进行分段,然后进行语音识别,在综合处理输出结果文本。其中,从音频中提取文本,可以利用AipSpeech语音识别引擎来实现。

在开始编写代码之前,我们需要安装准备好用于音视频转换以及音频分割以及音频分割等相关操作的辅助工具。FFmpeg工具。FFmpeg分为3个版本:Static,Shared和Dev。前两个版本可以直接在命令行中使用,包含3个可执行文件:ffmpeg.exe,ffplay.exe,ffprobe.exe。Static版本中的可执行文件较大,因为相关的动态链接库都已经编译进可执行文件中。Shared版本则小很多,因为在他们运行的时候,还需要相关的动态链接库中调用相应的功能。

下载过后,将其中的bin目录添加到系统变量中“Path”。然后打开控制台,输入ffmpeg命令来运行程序,若无出错信息,则表示配置成功。

那么在python中如何调用FFmpeg喃?

那就需要利用安装命令安装即可。

pip install ffmpy3

以下示例代码实现了从视频文件到指定格式音频文件的转换:

def Video2Audio(file):
    inputfile=file #输入的视频文件
    file_type=file.split('.')[-1]
    outputfile=inputfile.replace(file_type,'wav') #将原视频文件扩展为.wav作为文件名
    ff=FFmpeg(inputs={inputfile:None},global_options=['-y'], #全局参数,'-y'指的是允许覆盖已有文件
            outputs={outputfile:'-vn -ar 16000 -ac 1 -ab 192 -f wav'}  )
    ff.cmd  #打包FFmpeg命令
    ff.run() #执行FFmpeg命令
    return outputfile

获取指定格式的音频文件,需要对其进行音频分割以满足百度语音识别API的处理要求。音频分割的关键是找出每段音频的起始点和结束点。为此,我们需要先获取整个音频文件的总长度,然后以60s文件间隔进行切分,计算出每段音频开始和结束的秒数,并分割为不同的文件进行保存。

def AudioSplit(file):
    inputfile=file #输入文件
    path=os.path.dirname(file)+'./wavefiles/' #指定分割后音频文件的保存目录
    path='./wavefiles'
    print("Audio files segmented into",path)
    wav_len=int(float(mediainfo(inputfile)['duration'])) #获取音频文件时长
    wave=AudioSegment.from_mp3(inputfile)  #音频源文件加载
    seg_file_list=list()
    if wav_len>60:
        n=wav_len//60
        if n*60<wav_len:
            n+=1
    for i in range(n):
        start_time=i*60*1000+1
        END_TIME=(i+1)*60*1000
        if END_TIME>wav_len*1000:
            END_TIME=wav_len*1000
        seg=wave[start_time:END_TIME]
        seg_audio_filename='{}segaudio_{}.wav'.format(path,i)
        seg.export(seg_audio_filename,format='wav')
        seg_file_list.append(seg_audio_filename)
    return seg_file_list


音频分割文件完成后,我们将进入文本提取这个重要环节。l利用AipSpeech语音识别引擎,可轻松实现对语音文件进行文本提取。示例代码如下:


'''
音频撰文本函数
通过Baidu AI提供的ASR SDK对音频文件进行语音识别,并返回识别的文本。
'''
def Audio2Text(wavfile):
    #定义一个用于读取本地音频文件的函数
    def get_file_content(filepath):
        with open(filepath,'rb') as fp:
            return fp.read()

    APP_ID='30847447'
    APP_KEY='OEMasN3dTxtq2Pr55duK8qzw'
    SECRET_KEY='n7gKdf7VMsz8QEfw0VBZCWG6xdX72qII'
    client=AipSpeech(APP_ID,APP_KEY,SECRET_KEY)
    result=client.asr(get_file_content(wavfile),'wav',16000,{'dev_pid':1737})
    return result

对多个音频文件进行文本提取后需要合并得到最终结果。


def TextMerging():
    seg_audio_file_dir="./wavefiles/"
    files=os.listdir(seg_audio_file_dir) #遍历目录下的所有文件
    content=""
    for file in files:
        segaudiofile=seg_audio_file_dir+file
        txt=Audio2Text(segaudiofile)
        content+=str(txt)
    return content

运行该程序,除了少数的文本与原视频不同,但是 大多数都很准确。由于对音频分割时,会存在某一个读音被切分在相邻两端音频中的情况,从而在音频到文字的转换阶段产生一定的误差。采取按照语音停顿方式进行分割。

from pydub.silence import split_on_silence

chunks=split_on_silence(sound,min_silence_len=700,silence_thresh=-70)

上述代码中的silence_thresh为语音停顿识别阈值。通过该设定的阈值,我们可以将小于-70dBFS的音频信号是为静音(Silence),而且,当小于-70dBFS的信号超过700ms,则进行语音分割

基于音频指纹的音乐识别

说到音乐识别,相信很多小伙伴都很熟悉,比如酷狗音乐,QQ音乐,网易音乐,他们都有很多的功能,其中就有一个功能就有音乐识别。本届我们就来了解一下基于“音频指纹”的音乐识别系统。

 

系统架构的核心模块包括信号采集,音频指纹(亦可称之为声纹)生成以及数据存储系统。其中,音频指纹生成苏算法的核心部分会采用傅里叶变换。

音频信号采集与播放

“听歌识曲”首先是“听”,然后才能“识”。“听”的过程,实际上就是一个音频采集(录音与采样)的过程。:识“的过程,是将采集到的音频片段与曲库中的歌曲数据进行比对来获取歌曲信息的过程。曲库中保存着大量的歌曲数据,包括歌曲名称,歌曲存储位置,歌曲声纹等信息。

在写代码之前,我们需要先进行安装模块pyaudio模块。


#音频信号采集与播放
import wave
import pyaudio
class SoundProcessing():
    def Record(self,CHUNK=44100,FORMAT=pyaudio.paInt16,CHANNELS=2,RATE=441100,
               RECORD_SECONDS=200,WAVE_OUTPUT_FILENAME="demoWave.wav"):
        p=pyaudio.PyAudio()
        stream=p.open(format=FORMAT,
                      channels=CHANNELS,
                      rate=RATE,
                      input=True,
                      frames_per_buffer=CHUNK)
        frames=[]
        for i in range(0,int(RATE/CHUNK*RECORD_SECONDS)):
            data=stream.read(CHUNK)
            frames.append(data)
        stream.stop_stream()
        stream.close()
        p.terminate()
        wf=wave.open(WAVE_OUTPUT_FILENAME,'wb')
        wf.setnchannels(CHANNELS)
        wf.setsampwidth(p.get_sample_size(FORMAT))
        wf.setframerate(RATE)
        wf.writeframes(b''.join(frames))
        wf.close()
    def Play(self,FILEPATH):
        chunk=1024
        wf=wave.open(FILEPATH,'rb')
        p=pyaudio.PyAudio()
        #打开声音输出流
        stream=p.open(format=p.get_format_from_width(wf.getsampwidth()),
                      channels=wf.getnchannels(),
                      raate=wf.getframerate(),
                      output=True)
        while True:
            data=wf.readframes(chunk)
            if data=="":
                break
            stream.write(data)
        stream.close()
        p.terminate()
if __name__=='__main__':
    snd=SoundProcessing() #类的实例化
    #录音并将其存储为demoWave.wav文件
    snd.Record(RECORD_SECONDS=30,WAVE_OUTPUT_FILENAME='demoWave.wav')
    snd.Play('demoWave.wav')

 音频指纹生成

音频文件有很多格式,注入MP3,WAV,PCM等。其中,WAV格式是Microsoft公司研发的一种音频格式文件,它符合资源交换文件格式(Resource Interchange File Format,RIFF)规范,用于保存Windows操作系统的音频信息资源,beiWindows操作系统及其应用程序广泛支持。标准化的WAV文件采用44100采样率,16bit深度编码。WAV文件分为两个部分,第一个部分是WAV头文件,第二个部分是利用脉冲编码调制(Pulse Code Modulation,PCM)方式进行编码的音频数据。我们将以常见的WAV格式为例,来阐述如何生成音乐的音频指纹(声纹)。

从本质上来看,声音就是一种波。

我们用一个音频文件来描述其波形:



import wave
import matplotlib.pyplot as plt
import numpy as np
import os
waveFile=wave.open('./test.wav','rb')
params=waveFile.getparams()
nchannels,sampwidth,framerate,nframes=params[:4]
strData=waveFile.readframes(nframes)#读取音频文件并转为字符串格式
waveData=np.fromstring(strData,dtype=np.int16) #将字符串格式转化为int类型
waveData=waveData*1.0/(max(abs(waveData))) #wave幅值归一化
#音频波形可视化
time=np.arange(0,nframes)*(1.0/framerate)
waveData=np.arange(453632)
plt.plot(time,waveData)
plt.xlabel("Time(X)")
plt.ylabel("Amplitude(Y)")
plt.title("Single Channel Wave")
plt.grid("on")
plt.show()

音频波形文件是连续的模拟信号,经过采样可形成数字信号。对于一个单声道音频文件而言,经采样后,实际上就产生一个二维数组,每个元素是对应采样点的数值。对于我们普通人来说,我们该如何去实现听歌识曲?那就是背歌词,只要听到某一句或者多句歌词,就会记起来,但是对于像博主我记忆力不好的人而言,记住很多歌曲是不现实的,所以,我们就要采用其他的方式。那就是利用计算机来记住音频信号序列。声音属于时域信号,我们需要将其转化为频域信号以便后续的信号处理。以下示例代码,通过傅里叶变换将音频时域信号转换为频域信号。


import wave
import matplotlib.pyplot as plt
import numpy as np
import os
waveFile=wave.open('./test.wav','rb')
params=waveFile.getparams()
nchannels,sampwidth,framerate,nframes=params[:4]
strData=waveFile.readframes(nframes)#读取音频文件并转为字符串格式
waveData=np.fromstring(strData,dtype=np.int16) #将字符串格式转化为int类型
waveData=waveData*1.0/(max(abs(waveData))) #wave幅值归一化
#音频波形可视化
time=np.arange(0,nframes)*(1.0/framerate)
#waveData=np.arange(453632)
df=1
freq=[df*n for n in range(0,len(waveData))]
c=np.fft.fft(waveData)
plt.plot(freq,abs(c),color='blue')
plt.xlabel("Frequency(Hz)")
plt.ylabel("Amplitude(Y)")
plt.title("Frequency Domain Signal")
plt.grid(True)
plt.show()

音频信号经傅里叶变换之后,原本x,y轴分别为时间和波幅,现在则是频率以及频率幅值,与此同时,也改变了我们对音频构成的理解。

对每一帧音频信号进行傅里叶变换后,就可以开始构造声纹了,这就是整个系统中最核心的部分。构造声纹的最大挑战就是在于如何从众多的频率中选出区分都最大的频率分量。直观上看,选择具有最大幅值的频率(峰值)较为可靠。由于一首音乐的频率分布跨度太大,所以分析的时候会存在难以选择,为了避免分析整个频谱,我们通常将频谱分成多个子带,从每个子带中选择一个频率峰值。低子音带为30Hz~40Hz,40~80Hz和80~120Hz,中音和高音子带分别为120Hz~180Hz和180Hz~300Hz(人声和大部分乐器的基频出现在这俩个子带)。每个子带的最大频率就构成了这一帧信号的签名,这也就是我们最核心的“音频指纹”。

音频文件载入,音频指纹生成功能的实现示例代码:


import numpy as np
import os
import wave
class SoundProcessing():
    SongName=""
    document=[] #存放歌曲指纹列表
    def DataLoad(self,FILEPATH):
        filename_list=os.listdir(FILEPATH)
        for filename in filename_list:
            if filename.endswith('wav'):  #检查文件是否是wav格式
                SoundProcessing.SongName=filename
                f=wave.open(FILEPATH+"\\"+filename,'rb')
                params=f.getparams()
                self.nchannels,self.sampwidth,self.framerate,self.nframes=params[:4]
                str_data=f.readframes(self.nframes)
                self.wave_data=np.fromstring(str_data,dtype=np.short)
                self.wave_data.shape=-1,self.sampwidth
                self.wave_data=self.wave_data.T
                self.GenerateFingerPrint()
                self.name=os.path.basename('./test1.wav')
                return True
        f.close()
    def GenerateFingerPrint(self,frames=40):
        block=[]
        fft_blocks=[]
        self.high_point=[]  #用于保存生成的音频指纹
        blocks_size=self.framerate//frames
        blocks_num=self.nframes/blocks_size
        for i in range(0,len(self.wave_data[0])-blocks_size,blocks_size):
            block.append(self.wave_data[0][i:i+blocks_size])
            fft_blocks.append(np.abs(np.fft.fft(self.wave_data[0][i:i+blocks_size])))
        self.high_point.append((np.argmax(fft_blocks[-1][0:40]),np.argmax(fft_blocks[-1][40:80])+40,
                                np.argmax(fft_blocks[-1][80:120])+40,
                                np.argmax(fft_blocks[-1][120:180])+120,))
        song_fp="{'songname'"+":'"+SoundProcessing.SongName+"','fingerprint'"+":"+str(self.high_point[20:25])+"}"
        song_fp=eval(song_fp)
        SoundProcessing.document.append(song_fp)
        print (SoundProcessing.document)
if __name__=="__main__":
    a=SoundProcessing()
    a.DataLoad('F:\人工智能算法')
    a.GenerateFingerPrint(frames=40)

结果展示:

[{'songname': 'test.wav', 'fingerprint': []}] [{'songname': 'test.wav', 'fingerprint': []}, {'songname': 'test.wav', 'fingerprint': []}]

在构造指纹的时候,我们需要注意的是,用户所除的环境的复杂,所以录制的音乐可能会有所杂音,于是,我建议在使用音频指纹的时候引入模糊化操作等手段来提高算法的抗噪能力。否则会影响最终检索质量。

语音克隆技术简介

语音合成,是指文本到音频的人工转换,或给定一段文字让计算机自动生成对应的人类读音。通过AI语音技术,在极短的时间内“克隆”出目标人物的声音。相信喜欢看碟战片的小伙伴比较了解,里面各个国家的特工,利用语音合成,模仿别人的声音,获取情报。在计算机技术发展迅速的今天,这些都已经能够实现。

合成自然语音,需要对大量高质量的语音转录进行训练。若要支持多人语音通常需要对每个人的语音数据集进行数十分钟的训练,而为多人记录大量高质量的数据不太现实。该项目所采用的方法是,通过独立训练一个捕捉说话人特征空间(Space of Speaker Characterstics)语音识别嵌入网络(Speaker-Descriminative Embedding Network),并在一个较小的数据集上训练一个高质量的TTS模型,从而将说话人建模与语音合成分离。解耦合网络使他们能够在独立的数据上进行训练,从而减少获得高质量多峰训练数据的需要。

该语音克隆系统由3个独立训练的神经网络组成。如图:

1.说话人语音编码器(Speaker Encoder)

它先从说话人那里获取一段参考语音信号(Speaker Reference Waveform),亦即说话人的音频小样本,然后从中计算出一个固定维矢量(Fixed Dimensional Vector)。

2.序列合成器(Synthesizer)

它基于说话人嵌入矢量,根据一系列字素(Grapheme)或音素输入,预测出一个对数梅尔频谱(Log-Mel Spectrum)。也就是给定一段文本,将其编码为向量表示,然后,将语音与文本这两个向量结合起来解码成声谱图(Spectrogram)。

3.声码器(Vocoder)

它将对数梅尔频谱转换成时域波形(Waveform)。也就是将声谱图转换成我们可以听到的音频波形。

由于博主对机器学习知识还不掌握,这里只能稍做介绍。语音篇的学习就到此结束了,后面就是自然语言处理技术的分享。期待大家的关注,点赞,收藏。

拜了个拜!!!

猜你喜欢

转载自blog.csdn.net/qq_59931372/article/details/129274591