基于Paraformer的alpha-token强制对齐

news2024/11/23 15:19:54

1. 基本原理

img1

CIF 作为Parafoemr的核心模块,用于预测字数和生成声学向量,从而实现了单轮非自回归解码。其中字数的预测主要通过encoder输出系数alpha的累计得分,满足通关阈值β=1.0即可产生一个token,其中alpha曲线在一定程度上呈现着vad效果,或者依次进行断句。

2. alpha-token 强制对齐

cif的时间戳对齐采用peak(通关方式)得到,这里我们直接尝试alpha-token对齐方式,将识别的token在编码器输出上进行对齐,其中对齐算法采用动态规划。具体参考main.py中的maxSumSubarrayWithGaps()。

以10s窗长进行音频切块,下面展示alpha-token 的对齐效果:
img2

用户可以修改main.py 参数进行试验

3. code

github:https://github.com/coolEphemeroptera/funasr_alpha_token_alignment

import subprocess
from typing import List
import matplotlib.font_manager
import numpy as np 
from funasr_onnx import SeacoParaformer
import os 
import shutil
import matplotlib.pyplot as plt 
import matplotlib
zhfont1 = matplotlib.font_manager.FontProperties(fname="./SourceHanSansSC-Bold.otf")

class SeacoParaformerPlus(SeacoParaformer):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.SR = 16000
        self.SECONDS_PER_FRAME = 0.02
        self.UPSAMPLE_TIMES = 3

    def decode(self,am_scores, valid_token_lens):
        res = []
        for am_score, valid_token_len in zip(am_scores, valid_token_lens):
            token_ids = am_score.argmax(axis=-1)
            token_chs = self.converter.ids2tokens(token_ids)
            token_chs_valid = token_chs[:valid_token_len]
            res.append(token_chs_valid)
        return res

    def __call__(self, waveform_list: list, hotwords: str, imgDir = './display',**kwargs) -> List:

        # 加载热词编码
        hotwords, hotwords_length = self.proc_hotword(hotwords)
        [bias_embed] = self.eb_infer(hotwords, hotwords_length)
        bias_embed = bias_embed.transpose(1, 0, 2)
        _ind = np.arange(0, len(hotwords)).tolist()
        bias_embed = bias_embed[_ind, hotwords_length.tolist()]
        bias_embed = np.expand_dims(bias_embed, axis=0)

        # onnx推理
        waveform_nums = len(waveform_list)
        content = []
        id = 0
        duration = 0
        for beg_idx in range(0, waveform_nums, self.batch_size):
            end_idx = min(waveform_nums, beg_idx + self.batch_size)
            # 1.计算mel特征
            feats, feats_len = self.extract_feat(waveform_list[beg_idx:end_idx])
            # 2.热词编码同步复制
            bias_embed_ = np.repeat(bias_embed, feats.shape[0], axis=0)
            # 3. 解码
            am_scores, valid_token_lens,us_alphas, us_peaks = self.bb_infer(feats, feats_len, bias_embed_)
            # 4. 后处理
            res = self.decode(am_scores, valid_token_lens)
            for r,alpha,peak in zip(res,us_alphas,us_peaks):
                content.append({'id':id,
                                'range':[duration,duration+len(waveform_list[id])],
                                'tokens':r,
                                'alpha':alpha,
                                'peak':peak})
                duration += len(waveform_list[id])
                id += 1
        return content
    
    def align_with_alpha(self,asr_res,img_path="tmp.png"):
        id = asr_res['id']
        tokens = asr_res['tokens'][:-1]
        tokens_n = len(tokens)
        stime,etime = round(asr_res['range'][0]/self.SR,2),round(asr_res['range'][1]/self.SR,2)
        alpha = asr_res['alpha']
        peak = asr_res['peak']

        # alpha 对齐
        max_val,max_path = maxSumSubarrayWithGaps(alpha,tokens_n,3)
        AX,AY = [],[]
        for ft,i,score in max_path:
            AX.append(ft*self.SECONDS_PER_FRAME+stime)
            AY.append(alpha[ft])

        # 绘图
        plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
        plt.rcParams['axes.unicode_minus'] = False
        plt.figure(figsize=(20, 8))
        plt.xlabel('time/seconds')
        plt.ylabel('alpha')
        plt.ylim([0,0.4])
        plt.title("ALPHA-ALIGNMENT (id:%s, range:%s-%s seconds)"%(id,stime,etime))
        x = np.linspace(stime,etime,len(alpha))
        plt.plot(x,alpha)
        plt.plot(AX, AY, 'o',color='red')
        for i,ax in enumerate(AX):
            ay = AY[i] + 0.01
            token = tokens[i]
            plt.text(ax, ay, token, fontsize=10, color='black',ha='center',fontproperties=zhfont1)
        plt.savefig(img_path)
        plt.close()

def rebuild_dir(dir):
    def delete_directory(directory):
        if os.path.exists(directory):shutil.rmtree(directory)
    delete_directory(dir)
    os.makedirs(dir)
    print(f"Success to create {dir}")

def audio_f2i(data,width=16):
    data = np.array(data)
    return np.int16(data*(2**(width-1)))

def audio_i2f(data,width=16):
    data = np.array(data)
    return np.float32(data/(2**(width-1)))

def read_audio_file(url):
        ffmpeg_cmd = [
                'ffmpeg',
                '-y',
                '-i', url,  
                '-vn',
                '-f', 's16le',
                '-acodec', 'pcm_s16le',
                '-ar', '16k',
                '-ac', '1',
                '-' ]
        with subprocess.Popen(ffmpeg_cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=False) as proc:
            stdout_data, stderr_data = proc.communicate()
        if stderr_data:
            audio_data = np.frombuffer(stdout_data,dtype=np.int16)
            audio_data = audio_i2f(audio_data)
        return audio_data

# 动态规划实现alpha-token强制对齐
def maxSumSubarrayWithGaps(NUMS,K,GAP):
    N = len(NUMS)
    # 初始化表单
    dp = [[-float('inf') for j in range(K+1)] for _ in range(N)]
    path = [[[] for j in range(K+1)] for _ in range(N)]
    # 初始化边界
    for i in range(N): # dp[:,0]
        dp[i][0] = 0
        path[i][0] = []
    for j in range(K+1): # dp[0,:]
        if j==0:
            dp[0][j] = 0
        elif j==1:
            dp[0][j] = NUMS[0]
        else: 
            dp[0][j] = -float('inf')

    # dp填表
    for i in range(1,N):
        for j in range(1,K+1):
            # 不满足G间隔
            if (j-1)*GAP+1>i+1:
                dp[i][j] = -float('inf')
                path[i][j] = []
            # 满足间隔
            else:
                for k in range(j-1,i-GAP+1):
                    # 更新最大值且区间内满足极差(停顿)要求
                    if dp[k][j-1]+NUMS[i]>dp[i][j] and max(NUMS[k:i+1])-min(NUMS[k+1:i])>0.02:
                        dp[i][j] = dp[k][j-1]+NUMS[i]
                        path[i][j] = [k,j-1,dp[k][j-1]]
    # 回溯
    max_i = np.argmax([dp[i][K] for i in range(N)])
    max_val = dp[max_i][K]
    max_path = []
    i,j,v = max_i,K,max_val
    max_path.append([i,j,v])
    while 1:
        if not path[i][j]:break
        i,j,v = path[i][j]
        if j>0:
            max_path.append([i,j,v])
        if j==1:break
    max_path.reverse()
    return max_val,max_path


if __name__ == '__main__':

    SR = 16000

    # 参数
    url = "/home/nvidia/funasr_alpha_token_alignment/funasr_models/iic/speech_seaco_paraformer_large_asr_nat-zh-cn-16k-common-vocab8404-pytorch/example/asr_example.wav"
    img_dir = 'alpha_align_plot'
    chunk_seconds = 10
    cache_dir='./funasr_models'
    model_name = 'iic/speech_seaco_paraformer_large_asr_nat-zh-cn-16k-common-vocab8404-pytorch'
    model_quant = True
    batch_size = 60
    

    # 1. 加载模型
    paraformer = SeacoParaformerPlus(model_dir=model_name,
                                    quantize=model_quant,
                                    batch_size=batch_size,
                                    cache_dir=cache_dir)

    # 2. 音频分块
    audio_data = read_audio_file(url)
    audio_length = len(audio_data)
    chunk_size = chunk_seconds*SR
    batch = []
    for i in range(0,audio_length,chunk_size):
        s,e = i,min(i+chunk_size,audio_length)
        chunk = audio_data[s:e]
        batch.append(chunk)

    # 3. ASR
    content = paraformer(batch,hotwords='')

    # 4. alpha对齐
    rebuild_dir(img_dir)
    for asr_res in content:
        id = asr_res['id']
        text = asr_res['tokens']
        print(id,text)
        paraformer.align_with_alpha(asr_res,img_path=f"{img_dir}/{id}.png")
        print("saved into:",f"{img_dir}/{id}.png")


     

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1714541.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

gitlab 创建 ssh 和 token

文章目录 一、创建ssh key二、将密钥内容复制到gitlab三、创建token 一、创建ssh key 打开控制台cmd,执行命令 ssh-keygen -t rsa -C xxxxx xxxxx是你自己的邮箱 C:\Users\xx\.ssh 目录下会创建一个名为id_rsa.pub的文件,用记事本打开,并…

哪些公司防泄密软件最受欢迎?2024年防泄密软件排行榜 |

在数字化时代,数据的安全性和保密性已成为企业运营和发展的关键要素。随着技术的不断进步,防泄密软件逐渐成为了企业保护核心数据和知识产权的重要工具。在2024年,市场上涌现出了众多防泄密软件,它们各具特色,为企业的…

Scikit-Learn随机森林回归

Scikit-Learn随机森林回归 1、随机森林1.1、集成学习1.2、Bagging方法1.3、随机森林算法1.4、随机森林的优缺点2、Scikit-Learn随机森林回归2.1、Scikit-Learn随机森林回归API2.2、随机森林回归实践(加州房价预测)1、随机森林 随机森林是一种由决策树构成的集成算法,它在大多…

JAVA-->方法的使用详解

JAVA–>方法的使用详解 1.方法的概念及使用 1.1 什么是方法 : 方法就是一个代码片段. 类似于 C 语言中的 “函数”。 1.2 方法定义 / 方法定义 修饰符 返回值类型 方法名称([参数类型 形参 ...]){方法体代码;[return 返回值]; }判断是否为闰年 public class Method{ //…

为什么工控现场会用到Profinet转Modbus网关设备

一、背景: 工控现场之所以需要使用Profinet转Modbus网关,是因为工控系统中常常存在不同厂家设备之间通讯协议不一致的问题。而Modbus和Profinet分别代表着两种不同的通信协议,Profinet通常用于较新的设备,而Modbus则是比较老的通…

medsam ,数入xml +img, 根据检测框,原图显示分割效果,加上点的减少处理

1、输入每张图片的多个检测框,得到这张图片的sam 分割结果 import numpy as np import matplotlib.pyplot as plt import osjoin os.path.join import torch from segment_anything import sam_model_registry from skimage import io, transform import torch.nn…

透视AI技术:探索折射技术在去衣应用中的奥秘

引言: 随着人工智能技术的飞速发展,其在图像处理和计算机视觉领域的应用日益广泛。其中,AI去衣技术作为一种颇具争议的应用,引发了广泛的讨论和关注。本文将深入探讨折射技术在AI去衣中的应用及其背后的原理。 一、AI去衣技术简介…

AI Agent智能体概述及原理

AI Agent概述 AI Agent旨在理解、分析和响应人类输入,像人类一样执行任务、做出决策并与环境互动。它们可以是遵循预定义规则的简单系统,也可以是根据经验学习和适应的复杂、自主的实体;可以是基于软件的实体,也可以是物理实体。…

深入理解统计学中的最大值与最小值

新书上架~👇全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我👆,收藏下次不迷路┗|`O′|┛ 嗷~~ 目录 一、统计学中的基础概念:最大值与最小值 1. 创建数组与数据导入 2. 求解整体数…

重磅发布,2024精选《制造业商业智能BI最佳实践合集 》

在数字时代,中国制造业正面临着前所未有的深刻变革。 商业环境的复杂性与多变性、全球化竞争的激烈程度、消费需求的快速演变,以及新技术的持续进步等多种因素共同推动着制造企业积极加入数字化转型的潮流。 在这个转型的过程中,转型的速度…

yq—2024/5/29—零钱兑换

代码实现&#xff1a; #define min(a, b) ((a) > (b) ? (b) : (a))int coinChange(int *coins, int coinsSize, int amount) {int dp[amount 1];// 初始化for (int i 0; i < amount 1; i) {dp[i] INT32_MAX;}dp[0] 0;// 01背包 -----先遍历物品&#xff0c;再遍历背…

oracle数据回显时候递归实战

太简单的两篇递归循环 orcale 在项目里递归循环实战 先看资产表T_ATOM_ASSET结构 看业务类别表T_ATOM_BUSI_CATEGORY结构 问题出现 页面显示 实际对应的归属业务分类 涉及到oracle递归实战(这里不会如何直接在atomAsset的seelct里面处理递归回显) 直接在实现层看atomAs…

CTF_RE典例

PZCTF Xor 分组异或 0&#xff0c;1&#xff0c;2&#xff0c;3 不变, 4 , 5 &#xff0c;6&#xff0c;7只异或Str[0], 8,9,10,11要先后异或Str[0],Str[1] s [0x50, 0x5a, 0x43, 0x54, 0x16, 0x2b, 0x11, 0xf, 0x3b, 0x63,0x7e, 0x7e, 0x78, 0x2c, 0x16, 0x3a, 0x71, 0x2e…

The First项目报告:一场由社区驱动的去中心化加密冒险—Turbo

2023年3月14日&#xff0c;由OpenAI公司开发自回归语言模型GPT-4发布上线&#xff0c;一时之间引发AI智能领域的轩然大波&#xff0c;同时受到影响的还有加密行业&#xff0c;一众AI代币纷纷出现大幅度拉升。与此同时&#xff0c;一款名为Turbo的Meme代币出现在市场中&#xff…

DNSlog环境搭建

阿里云域名公网VPS地址 购买阿里云域名后设置“自定义DNSHOST” DNS服务器填写ns1和ns2 如&#xff1a;ns1.aaa.com IP地址填写你的VPS地址 如&#xff1a;1.1.1.1 填写解析记录&#xff0c;一个A记录、一个NS记录 NS记录就是*.域名指向记录值ns1.域名 如&#xff1a;*.aaa…

计算机图形学入门03:二维基本变换

变换(Transformation)可分为模型(Model)变换和视图(Viewing)变换。在3D虚拟场景中相机的移动和旋转&#xff0c;角色人物动画都需要变换&#xff0c;用来描述物体运动。将三维世界投影变换到2D屏幕上成像出来&#xff0c;也需要变换。 1.缩放变换 如上图所示&#xff0c;把一个…

社区供稿丨GPT-4o 对实时互动与 RTC 的影响

以下文章来源于共识粉碎机 &#xff0c;作者AI芋圆子 前面的话&#xff1a; GPT-4o 发布当周&#xff0c;我们的社区伙伴「共识粉碎机」就主办了一场主题为「GPT-4o 对实时互动与 RTC 的影响」讨论会。涉及的话题包括&#xff1a; GPT-4o 如何降低延迟&#xff08;VAD 模块可…

图片怎样在线改像素大小?电脑快速修改图片大小的方法

在设计图片的时候下载的图片尺寸一般会比较大&#xff0c;在网上使用经常会因为尺寸的问题导致无法正常上传&#xff0c;那么如何快速在线改图片大小呢&#xff1f;想要修改图片尺寸可以在直接选择网上的图片改大小工具的功能来快速完成修改&#xff0c;操作简单方便使用&#…

M功能-支付平台(六)

target&#xff1a;离开柬埔寨倒计时-217day 今天突然发现我在csdn居然把我ip属地搞出来了&#xff0c;之前都没注意到&#xff0c;哎 前言 M功能演示版本做到后期(也就是第二周的后面3天)真的很心酸&#xff0c;这边安排的4后端后面都放弃了&#xff0c;觉得做不出来&#…

python Z-score标准化

python Z-score标准化 Zscore标准化sklearn库实现Z-score标准化手动实现Z-score标准化 Zscore标准化 Z-score标准化&#xff08;也称为标准差标准化&#xff09;是一种常见的数据标准化方法&#xff0c;它将数据集中的每个特征的值转换为一个新的尺度&#xff0c;使得转化后的…