背景介绍
语音识别技术,也被称为自动语音识别(Automatic Speech Recognition,简称ASR),其目标是将人类的语音中的词汇内容转换为计算机可读的输入,例如按键、二进制编码或者字符序列。语音识别技术已经发展了几十年,直到2009年,Hinton把人工智能深度学习解决方案引入语音识别中,语音识别才取得了巨大突破。
Amazon Transcribe 是一项自动语音识别 (ASR) 服务,使开发人员能够轻松地为其应用程序添加语音转文本功能。自从在 re:Invent 2017 发布以来,越来越多的用户将语音识别功能添加到其应用程序和设备中。2019年8月,Amazon Transcribe推出对中文普通话的支持。更加另用户兴奋的是,在中国的北京区域(BJS)和宁夏区域(ZHY)也已支持该项服务。
在日常工作学习中,我们往往需要对一个视频文件增加字幕。传统的方法需要将视频中的对话用文字记录下来,通常采用记事本等工具保存文字记录,然后借助一些工具软件为文字加上时间轴,然后进行人工校对,整个过程需要耗费大量的时间和精力。是否有更快捷的方法呢?下面我们分享一个使用Amazon Transcribe为视频自动增加字幕的示例。
体系架构
示例的总体架构如下图所示:
用户上传视频文件到S3存储桶;
- 监测到S3存储桶中的文件变化,触发lambda函数;
- lambda函数调用Transcribe服务,生成视频对应的文本(json格式);
- 对文本进行格式转换,生成字幕文件格式(srt);
- 上传字幕文件到存储桶。
实现过程
1. 创建S3存储桶
首先在AWS管理控制台进入”S3“服务,点击“Create bucket”, 输入存储桶的名称,点击“Create”按钮创建一个s3存储桶。
在刚建立的存储桶中,点击“Create folder”按钮,输入文件目录名称“video”,然后点击“Save”按钮。然后进入到“video”目录,点击“Create folder”按钮,输入文件目录名称“output”,点击“Save”按钮。此时,您在存储桶中创建了“video”目录,后面的lambda函数将监测video目录中的文件变化。在“video”目录下的“output”目录用来存储生成的字幕文件。
2. 创建IAM角色
每个Lambda函数都有一个与之关联的IAM角色。此角色定义允许该功能与其进行交互的其他AWS服务。在本示例中,您需要创建一个IAM角色,授予您的Lambda函数权限,以便与Transcribe服务以及在上一步中创建的S3服务进行交互。
在AWS管理控制台中,单击“Services”,然后选择“IAM”。在左侧导航栏中选择“Role”,然后选择“Create new role”,依次选择“AWS Service”,“Lambda”作为角色类型,然后单击“Next:Permissions”按钮,在“Filter”文本框中键入“AWSLambdaBasicExecutionRole”,然后选中该角色旁边的复选框,然后在“”中输入“AmazonTranscribeFullAccess”,选中该角色旁边的复选框,点击“Next:Review”,中角色名称中输入“extractSubtitleRole”,点击“Create role”。
3. 创建Lambda函数
在AWS管理控制台进入“Lambda”服务,点击“Create Function”按钮。
在“Function name”中填写函数名称,在“Runtime”的选择框中选择“Python 2.7”,在“Permissions”中选择“Use an existing role”,然后选择刚刚创建的角色名称,点击“Create function”按钮完成函数的创建。在此示例中,我们选择了Python 2.7作为开发环境,并为该Lambda函数赋予了上一步创建的角色。
4. 配置触发条件
在Lambda的函数配置页面,点击“Add Trigger”按钮添加触发条件。
在触发条件配置页面,在“Bucket”下拉列表中选择刚刚创建的存储桶名称,在“Event”下拉列表中选择“Put”,在“Prefix”中输入“videos/”,在“Suffix”中输入“.mp4”,然后点击“add”按钮,完成触发条件的添加。该触发条件设置监视刚刚创建存储桶的video目录中扩展名为.mp4的文件,如果是put操作,将触发该lambda函数。
5. Lambda内存和超时配置
在刚创建的Lambda函数中,我们需要配置了内存的大小和执行超时。由于Lambda函数会调用Transcribe服务进行文字提取,因此不需要修改内容的大小,默认值为128MB。示例中我们采用的视频文件的时长均在一分钟内,Transcribe的处理时间通常不会超过一分钟,在这里我们设置超时时长“Timeout”为10分钟。
6. 导入Lambda函数
打开附件中的python文件,将其内容粘贴在Lambda函数实现的区域,点击右上角的“Save”按钮。
Lambda的实现主要包括以下几个步骤:
6.1. 参数获取
从event对象中和系统变量中获取相关参数信息。
- region:当前区域,示例中使用的是区域是us-east-1
- bucket_name:存储桶名称,您刚刚创建的存储桶名称
- sourceS3Key:视频文件的key值。示例中监测video目录下的mp4类型的文件,key值为video/sample.mp4
- fn:根据sourceS3Key提取文件名。示例中fn为mp4
- dir:根据sourceS3Key提取目录名。示例中dir为video
6.2. 调用Transcribe任务
- 为每个任务job_name创建唯一的标识
- 调用starttranscriptionjob,下面的代码中介绍了每个参数以及含义
- 由于调用的job是异步任务,我们通过轮训的方法检测job的返回结果
#生成转换任务的时间戳 now=int(time.time()) job_name = “conv-“ str(now)
”’ 启动转换任务 MediaFileUri:媒体路径,示例采用s3的路径 MediaFormat:媒体格式,目前支持mp3,mp4,wav,flac LanguageCode:媒体的语言编码,我们的视频是中文的,设置为zh-CN ”’
代码语言:javascript复制 transcribe = boto3.client('transcribe')
transcribe.start_transcription_job(
TranscriptionJobName=job_name,
Media={'MediaFileUri': job_uri},
MediaFormat='mp4',
LanguageCode='zh-CN'
)
#转换需要一定的时间,这里进行轮训检测处理结果。您也可以通过控制台查看任务状态。
代码语言:javascript复制 while True:
status = transcribe.get_transcription_job(TranscriptionJobName=job_name)
if status['TranscriptionJob']['TranscriptionJobStatus'] in ['COMPLETED', 'FAILED']:
break
print("Processing...")
time.sleep(5)
- job的返回结果
6.3. 生成srt字幕文件
我们可以看到,在json数组中,包含每个字(或者词语)的开始时间,结束时间,置信度等信息。下面我们需要把json数组转换成字幕文件。常见的字幕格式有srt, ssa, ass, idx sub,其中srt, ssa, ass是文本格式,idx sub是图形格式。本示例中,我们将使用srt格式。srt的格式非常简单:一句时间代码 一句字幕。
6.4. 转换为srt格式字幕
函数process()将上一步的json文件转换成srt格式的字幕文件,具体处理过程如下。
代码语言:javascript复制def process(items):
i=1
output=''
isStart=False
isEnd=False
start_time=0
end_time=0
msg=''
for index, item in enumerate(items):
if (not item.has_key('start_time')):
msg=msg item['alternatives'][0]['content']
else:
end_time=float(item['end_time'])
if (end_time-start_time>4.0 or index 1==len(items)):
isEnd=True
if (not isStart and item.has_key('start_time')):
isStart=True
start_time=float(item['start_time'])
msg=msg item['alternatives'][0]['content']
output=output str(i) 'n'
continue
if (isStart and not isEnd and item.has_key('start_time')):
msg=msg item['alternatives'][0]['content']
if (isStart and isEnd):
hour=int(start_time/60/60)
min=int(start_time/60)-hour*60
sec=int(start_time)-min*60-hour*60*60
msec=int((start_time-sec)*1000)
e_hour=int(end_time/60/60)
e_min=int(end_time/60)-e_hour*60
e_sec=int(end_time)-e_min*60-e_hour*60*60
e_msec=int((end_time-sec)*1000)
msg1='{}:{}:{},{} --> {}:{}:{},{}'.format(hour,min,sec,msec, e_hour,e_min,e_sec,e_msec) 'n'
output=output msg1 msg item['alternatives'][0]['content'] 'nn'
i=i 1
isStart=False
isEnd=False
start_time=end_time
msg=''
代码语言:javascript复制
6.5. 上传结果到S3
最后我们将srt文件上传到s3,本示例中,我们设置了video/output作为其输出的存储路径。
代码语言:javascript复制def uploadResult(region,bucket_name,fn,body):
s3 = boto3.client(service_name='s3',region_name=region)
s3.put_object(Bucket=bucket_name, Key=fn[0:-4] '.srt', Body=body)
7. 测试
在AWS管理控制台点击“S3”服务,打开刚创建的存储桶,进入“video”目录,点击“Upload”“Add files”从本地电脑里选择一个视频文件,点击“Upload”。此时就会触发我们刚刚创建的Lambda函数。我们可以在“Amazon Transcribe”观察job的执行情况。点击任何一个job的名称,可以显示job的详细信息。当job的状态显示为“Complete”,进入到S3存储桶的“output”目录,您会惊喜的发现,字幕文件已经生成了。注意,由于Lambda函数有600秒的执行超时限制,尽量不要处理时间超过15分钟的视频。
下面我们看一下效果吧。通过一些测试,语音的识别正确率还是比较高的,值得一提的是,Transcribe能够根据语音的停顿自动加上标点。但在人名的识别上,正确率还有待提高。
很多播放软件都支持自动加载字幕,需要把字幕文件和原始的视频文件放在同一目录。如果需要把字幕合成到视频中,可以使用ffmpeg为视频嵌入字幕,如果您使用的是Mac操作系统,也可以使用subler图形化工具把字幕文件嵌入到视频中。
8. 调试
在这里,一些读者一定会由于疏忽遗漏了上面的某些步骤,从而导致Lambda函数执行失败。在CloudWatch中,可以快速查询到Lambda函数的执行日志,方便读者进行调试。
成本分析
最后我们分析一下成本,以美东弗吉尼亚区域(us-east-1)为例:
Lambda实例采用128M内存,每月有3,200,000秒的免费用量,假设处理一段视频需要600秒,免费额度内您可以处理近5000个视频。
Memory (MB) | Free tier seconds per month | Price per 100ms ($) |
---|---|---|
128 | 3,200,000 | 0.000000208 |
假设采用S3标准存储,假设处理5000个视频文件,每个文件大小100M,大约需要500G的存储空间,大约需要12$(5000*100/1024*0.023)。字幕文件为文本格式,大小可以忽略。
Volume Size | Price |
---|---|
First 50 TB / Month | $0.023 per GB |
Next 450 TB / Month | $0.022 per GB |
Over 500 TB / Month | $0.021 per GB |
Amazon Transcribe API的计价方式是$0.0004/秒,按照上面的假设,每个视频长度为600秒,费用大约需要1200$(5000*600*0.0004)。
按照上面的假设,处理每个视频需要的费用仅仅需要0.24$ ((1200 12)/5000)),折算成人民币,成本不到2块钱。
总结
通过使用Amazon Transcribe,用户可以方便的集成在各种场景中。用户不需要购买服务器,不需要算法实现,仅通过Lambda或者API调用的方式,方便快速的构建自己的ASR应用。
参考文章
- https://aws.amazon.com/cn/blogs/china/amazon-transcribe-now-supports-mandarin-and-russian/
- https://docs.aws.amazon.com/zh_cn/transcribe/latest/dg/what-is-transcribe.html
- https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/transcribe.html
源代码
https://awschinablog.s3.cn-north-1.amazonaws.com.cn/appx/sourcecode.zip