国内Ubuntu环境Docker部署 SenseVoice

国内Ubuntu环境Docker部署 SenseVoice


趁热搞定了 docker 部署 SenseVoice。在这里记录一下相关的文件。
SenseVoice是一个大模型语音识别库, 支持多种语言识别,速度快,准确率高,详细介绍请参考GitHub官网:
https://github.com/FunAudioLLM/SenseVoice

本笔记主要记录使用 docker 进行部署的相关文件,文件内容放在最后。

  • Dockerfile
  • compose.yaml
  • requirements.txt
  • start.sh
  • webui.py
  • model_download.py
部署过程
1. 下载必要的模型

model_download.py

import os
import argparse


parser = argparse.ArgumentParser(description='modelscope模型下载')

parser.add_argument('--model_name', type=str, help='the model name from modelscope, example AI-ModelScope/stable-diffusion-2-1', required=True)
parser.add_argument('--local_dir', type=str, help='the model cache path.', default=os.getcwd(), required=True)


if __name__ == '__main__':
    args = parser.parse_args()

    print(f"current workspace is {os.getcwd()}")
    print(f"the model_name is {args.local_dir}/{args.model_name}")
    print(f"the local_dir is {args.local_dir}")

    try:
        from modelscope import snapshot_download
        model_dir = snapshot_download(args.model_name, local_dir=args.local_dir)
    except ImportError:
        print("modelscope was not installed! try to install...")
        os.system("pip install modelscope")
    except Exception as e:
        print(f"An error occurred: {e}")

SenseVoice项目的根目录下创建一个 download_model.py 文件,并将上述内容写入。

执行以下命令分别下载 SenseVoiceSmall speech_fsmn_vad_zh-cn-16k-common-pytorch 模型。

python3 model_download.py --model_name=iic/SenseVoiceSmall --local_dir=models/iic/SenseVoiceSmall
python3 model_download.py --model_name=iic/speech_fsmn_vad_zh-cn-16k-common-pytorch --local_dir=models/iic/speech_fsmn_vad_zh-cn-16k-common-pytorch

2、docker部署
  • Dockerfile
  • compose.yaml
  • requirements.txt
  • start.sh
  • webui.py

请在 SenseVoice项目的根目录下创建一个 docker 文件夹,并将上述文件放入 docker 文件夹内。

修改 webui.py 文件18行的 model 变量为 models/iic/SenseVoiceSmall (上述1下载模型设置的本地路径); 20行的vad_model参数修改为 models/iic/speech_fsmn_vad_zh-cn-16k-common-pytorch
在这里插入图片描述
webui.py

# coding=utf-8

import os
import librosa
import base64
import io
import gradio as gr
import re

import numpy as np
import torch
import torchaudio
from argparse import ArgumentParser


from funasr import AutoModel

model = "models/iic/SenseVoiceSmall"
model = AutoModel(model=model,
				  vad_model="models/iic/speech_fsmn_vad_zh-cn-16k-common-pytorch",
				  vad_kwargs={"max_single_segment_time": 30000},
				  trust_remote_code=True,
				  )

import re

emo_dict = {
	"<|HAPPY|>": "😊",
	"<|SAD|>": "😔",
	"<|ANGRY|>": "😡",
	"<|NEUTRAL|>": "",
	"<|FEARFUL|>": "😰",
	"<|DISGUSTED|>": "🤢",
	"<|SURPRISED|>": "😮",
}

event_dict = {
	"<|BGM|>": "🎼",
	"<|Speech|>": "",
	"<|Applause|>": "👏",
	"<|Laughter|>": "😀",
	"<|Cry|>": "😭",
	"<|Sneeze|>": "🤧",
	"<|Breath|>": "",
	"<|Cough|>": "🤧",
}

emoji_dict = {
	"<|nospeech|><|Event_UNK|>": "❓",
	"<|zh|>": "",
	"<|en|>": "",
	"<|yue|>": "",
	"<|ja|>": "",
	"<|ko|>": "",
	"<|nospeech|>": "",
	"<|HAPPY|>": "😊",
	"<|SAD|>": "😔",
	"<|ANGRY|>": "😡",
	"<|NEUTRAL|>": "",
	"<|BGM|>": "🎼",
	"<|Speech|>": "",
	"<|Applause|>": "👏",
	"<|Laughter|>": "😀",
	"<|FEARFUL|>": "😰",
	"<|DISGUSTED|>": "🤢",
	"<|SURPRISED|>": "😮",
	"<|Cry|>": "😭",
	"<|EMO_UNKNOWN|>": "",
	"<|Sneeze|>": "🤧",
	"<|Breath|>": "",
	"<|Cough|>": "😷",
	"<|Sing|>": "",
	"<|Speech_Noise|>": "",
	"<|withitn|>": "",
	"<|woitn|>": "",
	"<|GBG|>": "",
	"<|Event_UNK|>": "",
}

lang_dict =  {
    "<|zh|>": "<|lang|>",
    "<|en|>": "<|lang|>",
    "<|yue|>": "<|lang|>",
    "<|ja|>": "<|lang|>",
    "<|ko|>": "<|lang|>",
    "<|nospeech|>": "<|lang|>",
}

emo_set = {"😊", "😔", "😡", "😰", "🤢", "😮"}
event_set = {"🎼", "👏", "😀", "😭", "🤧", "😷",}

def format_str(s):
	for sptk in emoji_dict:
		s = s.replace(sptk, emoji_dict[sptk])
	return s


def format_str_v2(s):
	sptk_dict = {}
	for sptk in emoji_dict:
		sptk_dict[sptk] = s.count(sptk)
		s = s.replace(sptk, "")
	emo = "<|NEUTRAL|>"
	for e in emo_dict:
		if sptk_dict[e] > sptk_dict[emo]:
			emo = e
	for e in event_dict:
		if sptk_dict[e] > 0:
			s = event_dict[e] + s
	s = s + emo_dict[emo]

	for emoji in emo_set.union(event_set):
		s = s.replace(" " + emoji, emoji)
		s = s.replace(emoji + " ", emoji)
	return s.strip()

def format_str_v3(s):
	def get_emo(s):
		return s[-1] if s[-1] in emo_set else None
	def get_event(s):
		return s[0] if s[0] in event_set else None

	s = s.replace("<|nospeech|><|Event_UNK|>", "❓")
	for lang in lang_dict:
		s = s.replace(lang, "<|lang|>")
	s_list = [format_str_v2(s_i).strip(" ") for s_i in s.split("<|lang|>")]
	new_s = " " + s_list[0]
	cur_ent_event = get_event(new_s)
	for i in range(1, len(s_list)):
		if len(s_list[i]) == 0:
			continue
		if get_event(s_list[i]) == cur_ent_event and get_event(s_list[i]) != None:
			s_list[i] = s_list[i][1:]
		#else:
		cur_ent_event = get_event(s_list[i])
		if get_emo(s_list[i]) != None and get_emo(s_list[i]) == get_emo(new_s):
			new_s = new_s[:-1]
		new_s += s_list[i].strip().lstrip()
	new_s = new_s.replace("The.", " ")
	return new_s.strip()

def model_inference(input_wav, language, fs=16000):
	# task_abbr = {"Speech Recognition": "ASR", "Rich Text Transcription": ("ASR", "AED", "SER")}
	language_abbr = {"auto": "auto", "zh": "zh", "en": "en", "yue": "yue", "ja": "ja", "ko": "ko",
					 "nospeech": "nospeech"}
	
	# task = "Speech Recognition" if task is None else task
	language = "auto" if len(language) < 1 else language
	selected_language = language_abbr[language]
	# selected_task = task_abbr.get(task)
	
	# print(f"input_wav: {type(input_wav)}, {input_wav[1].shape}, {input_wav}")
	
	if isinstance(input_wav, tuple):
		fs, input_wav = input_wav
		input_wav = input_wav.astype(np.float32) / np.iinfo(np.int16).max
		if len(input_wav.shape) > 1:
			input_wav = input_wav.mean(-1)
		if fs != 16000:
			print(f"audio_fs: {fs}")
			resampler = torchaudio.transforms.Resample(fs, 16000)
			input_wav_t = torch.from_numpy(input_wav).to(torch.float32)
			input_wav = resampler(input_wav_t[None, :])[0, :].numpy()
	
	
	merge_vad = True #False if selected_task == "ASR" else True
	print(f"language: {language}, merge_vad: {merge_vad}")
	text = model.generate(input=input_wav,
						  cache={},
						  language=language,
						  use_itn=True,
						  batch_size_s=60, merge_vad=merge_vad)
	
	print(text)
	text = text[0]["text"]
	text = format_str_v3(text)
	
	print(text)
	
	return text


audio_examples = [
    ["example/zh.mp3", "zh"],
    ["example/yue.mp3", "yue"],
    ["example/en.mp3", "en"],
    ["example/ja.mp3", "ja"],
    ["example/ko.mp3", "ko"],
    ["example/emo_1.wav", "auto"],
    ["example/emo_2.wav", "auto"],
    ["example/emo_3.wav", "auto"],
    #["example/emo_4.wav", "auto"],
    #["example/event_1.wav", "auto"],
    #["example/event_2.wav", "auto"],
    #["example/event_3.wav", "auto"],
    ["example/rich_1.wav", "auto"],
    ["example/rich_2.wav", "auto"],
    #["example/rich_3.wav", "auto"],
    ["example/longwav_1.wav", "auto"],
    ["example/longwav_2.wav", "auto"],
    ["example/longwav_3.wav", "auto"],
    #["example/longwav_4.wav", "auto"],
]



html_content = """
<div>
    <h2 style="font-size: 22px;margin-left: 0px;">Voice Understanding Model: SenseVoice-Small</h2>
    <p style="font-size: 18px;margin-left: 20px;">SenseVoice-Small is an encoder-only speech foundation model designed for rapid voice understanding. It encompasses a variety of features including automatic speech recognition (ASR), spoken language identification (LID), speech emotion recognition (SER), and acoustic event detection (AED). SenseVoice-Small supports multilingual recognition for Chinese, English, Cantonese, Japanese, and Korean. Additionally, it offers exceptionally low inference latency, performing 7 times faster than Whisper-small and 17 times faster than Whisper-large.</p>
    <h2 style="font-size: 22px;margin-left: 0px;">Usage</h2> <p style="font-size: 18px;margin-left: 20px;">Upload an audio file or input through a microphone, then select the task and language. the audio is transcribed into corresponding text along with associated emotions (😊 happy, 😡 angry/exicting, 😔 sad) and types of sound events (😀 laughter, 🎼 music, 👏 applause, 🤧 cough&sneeze, 😭 cry). The event labels are placed in the front of the text and the emotion are in the back of the text.</p>
	<p style="font-size: 18px;margin-left: 20px;">Recommended audio input duration is below 30 seconds. For audio longer than 30 seconds, local deployment is recommended.</p>
	<h2 style="font-size: 22px;margin-left: 0px;">Repo</h2>
	<p style="font-size: 18px;margin-left: 20px;"><a href="https://github.com/FunAudioLLM/SenseVoice" target="_blank">SenseVoice</a>: multilingual speech understanding model</p>
	<p style="font-size: 18px;margin-left: 20px;"><a href="https://github.com/modelscope/FunASR" target="_blank">FunASR</a>: fundamental speech recognition toolkit</p>
	<p style="font-size: 18px;margin-left: 20px;"><a href="https://github.com/FunAudioLLM/CosyVoice" target="_blank">CosyVoice</a>: high-quality multilingual TTS model</p>
</div>
"""


def launch(host, port):
	with gr.Blocks(theme=gr.themes.Soft()) as demo:
		# gr.Markdown(description)
		gr.HTML(html_content)
		with gr.Row():
			with gr.Column():
				audio_inputs = gr.Audio(label="Upload audio or use the microphone")
				
				with gr.Accordion("Configuration"):
					language_inputs = gr.Dropdown(choices=["auto", "zh", "en", "yue", "ja", "ko", "nospeech"],
												  value="auto",
												  label="Language")
				fn_button = gr.Button("Start", variant="primary")
				text_outputs = gr.Textbox(label="Results")
			gr.Examples(examples=audio_examples, inputs=[audio_inputs, language_inputs], examples_per_page=20)
		
		fn_button.click(model_inference, inputs=[audio_inputs, language_inputs], outputs=text_outputs)

	# demo.launch()
	demo.launch(server_name=host, server_port=port)


if __name__ == "__main__":
	# iface.launch()
	parser = ArgumentParser()
	parser.add_argument('--host', default="0.0.0.0", type=str, help='Server bound address')
	parser.add_argument('--port', default=5306, type=int, help='Port number')
	args = parser.parse_args()
	launch(args.host, args.port)

然后执行 cd docker && docker compose -f compose.yaml up。访问 5306端口,出现以下界面即部署成功。
在这里插入图片描述
最后附上docker相关文件的内容:

Dockerfile

FROM nvidia/cuda:11.8.0-cudnn8-devel-ubuntu22.04

ENV LANG=C.UTF-8 LC_ALL=C.UTF-8

ENV DEBIAN_FRONTEN=noninteractive
SHELL ["/bin/bash", "-c"]

RUN apt-get update -y
RUN apt-get install -y libgl1-mesa-glx libglib2.0-0 gcc g++
RUN apt-get install -y net-tools wget curl git

RUN apt-get install -y make build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev libffi-dev liblzma-dev

# 从国内镜像源下载安装python
# wget https://www.python.org/ftp/python/3.10.13/Python-3.10.13.tar.xz && tar Jxf Python-3.10.13.tar.xz 
RUN wget https://mirrors.huaweicloud.com/python/3.10.13/Python-3.10.13.tar.xz && tar Jxf Python-3.10.13.tar.xz
RUN cd Python-3.10.13 && ./configure --with-system-ffi --enable-shared --enable-optimizations && make && make install && echo "/usr/local/lib" | tee /etc/ld.so.conf.d/python3.conf && ldconfig
RUN python3 -V && pip3 -V

# 设置国内镜像源
RUN pip3 config set global.index-url https://mirrors.aliyun.com/pypi/simple/ && pip3 config set install.trusted-host mirrors.aliyun.com

WORKDIR /workspace
COPY ./requirements.txt ./

RUN pip3 install -r requirements.txt
RUN apt-get install -y ffmpeg

compose.yaml

services:
  sense-voice:
    container_name: sense-voice
    image: sense-voice:1.0
    restart: always
    ports:
      - 5306:5306
    environment:
      - TZ=Asia/Tokyo
      - NVIDIA_VISIBLE_DEVICES=all
    volumes:
      - ../../SenseVoice:/workspace/SenseVoice
    # command: tail -f /dev/null
    command: sh -c "sh /workspace/SenseVoice/docker/start.sh"
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              capabilities: [gpu]

requirements.txt

--extra-index-url https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/pytorch/wheel/cu121/
# torch<=2.3
# torchaudio
torch==2.1.2
torchaudio==2.1.2
torchvision==0.16.2
modelscope
huggingface
huggingface_hub
funasr>=1.1.3
numpy<=1.26.4
gradio
fastapi>=0.111.1

start.sh

#! /bin/bash
cd SenseVoice && python3 webui.py --port=5306

以上。愿看到的小伙伴不迷路。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

1.2.1-2部分数据结构的说明02_链表

&#xff08;1&#xff09;链表数据结构&#xff1a; 概念&#xff1a; 将列表中相互连接的节点不连续的存储在内存中。与数据不同&#xff0c;我们无法再恒定时间内访问任何元组&#xff0c;如果遍历所有则花费时间与元素总数n成正比。插入和删除1个元素的时间复杂度都是O(n…

什么是.net framework,什么是.net core,什么是.net5~8,版本对应关系

我不知道有多少人和我一样&#xff0c;没学习过.netCore&#xff0c;想要学习&#xff0c;但是版本号太多就蒙了&#xff0c;不知道学什么了&#xff0c;这里解释下各个版本的关系 我们一般开始学习微软的时候&#xff0c;都是开始学习的.netframework&#xff0c;常用的就是4…

网站常用功能模块-鉴权

一&#xff1a;JWT是什么&#xff1f; 常用鉴权方式有很多种&#xff0c;今天主要介绍基于token的鉴权方式JWT&#xff08;Json JSON Web Token&#xff09;。因为这种方式实现起来方便快捷。整体实现逻辑如下 第一次登陆时&#xff0c;前端携带账号和密码请求登录接口。服务…

S32K144 UDSdoCAN 升级刷写实现笔记

文章目录 1. 摘要2. 开发环境搭建2.1 开发板2.2 IDE 安装2.3 更新扩展包2.4 烧录仿真测试2.4.1 新建工程2.4.2 导入已有工程2.4.3 编译工程2.4.4 硬件连接2.4.5 Debug2.4.6 添加 .c .h 文件2.5 串口配置2.5.1 时钟2.5.2 GPIO2.5.3 定时器2.5.4 uart 工程2.5.5 烧录验证3. 升级原…

《信息收集是这样吗?》

信息收集 前置&#xff1a;渗透思路&#xff1a; 1&#xff0c; 信息收集 2&#xff0c; 漏洞扫描 3&#xff0c; 漏洞挖掘 4&#xff0c; 开始攻击 5&#xff0c; 权限维持&#xff08;持久化&#xff09; 6&#xff0c; 权限提升 7&#xff0c; 免杀隐藏 8&#xff…

[深度学习] 大模型学习1-大语言模型基础知识

大语言模型&#xff08;Large Language Model&#xff0c;LLM&#xff09;是一类基于Transformer架构的深度学习模型&#xff0c;主要用于处理与自然语言相关的各种任务。简单来说&#xff0c;当用户输入文本时&#xff0c;模型会生成相应的回复或结果。它能够完成许多任务&…

用matlab调用realterm一次性发送16进制数

realterm采用PutString接口进行发送&#xff0c;需要注意的是发送的16进制数前面要加入0x标志。只有这样&#xff0c;realterm才能将输入的字符串识别为16进制数的形式。 另外,PutString函数支持两个参数输入&#xff0c;第一个参数为字符串&#xff0c;第二个参数为发送形式&…

【C++】B2099 矩阵交换行

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C 文章目录 &#x1f4af;前言&#x1f4af;题目描述题目描述输入格式输出格式输入输出样例输入 #1输出 #1 &#x1f4af;题目分析&#x1f4af;不同解法分析我的做法实现步骤&#xff1a;优点&#xff1a;不足&#…

HTML5实现好看的博客网站、通用大作业网页模板源码

HTML5实现好看的博客网站、通用大作业网页模板源码 前言一、设计来源1.1 主界面1.2 列表界面1.3 文章界面 二、效果和源码2.1 动态效果2.2 源代码 源码下载结束语 HTML5实现好看的博客网站、通用大作业网页模板源码&#xff0c;博客网站源码&#xff0c;HTML模板源码&#xff0…

动态规划六——两个数组的dp问题

目录 题目一——1143. 最长公共子序列 - 力扣&#xff08;LeetCode&#xff09; 题目二——1035. 不相交的线 - 力扣&#xff08;LeetCode&#xff09; 题目三——115. 不同的子序列 - 力扣&#xff08;LeetCode&#xff09; 题目四—— 44. 通配符匹配 - 力扣&#xff08;…

大模型与EDA工具

EDA工具&#xff0c;目标是硬件设计&#xff0c;而硬件设计&#xff0c;您也可以看成是一个编程过程。 大模型可以辅助软件编程&#xff0c;相信很多人都体验过了。但大都是针对高级语言的软件编程&#xff0c;比如&#xff1a;C&#xff0c;Java&#xff0c;Python&#xff0c…

单片机-串转并-74HC595芯片

1、74HC595芯片介绍 74HC595 是一个 8 位串行输入、并行输出的位移缓存器&#xff0c;其中并行输出为三态输出&#xff08;即高电平、低电平和高阻抗&#xff09;。 15 和 1 到 7 脚 QA--QH&#xff1a;并行数据输出 9 脚 QH 非&#xff1a;串行数据输出 10 脚 SCLK 非&#x…

融乐 1.1.6 | 拥有海量音乐资源的第三方音乐软件,支持无损音质下载

融乐Music是一款界面优美的第三方音乐软件&#xff0c;提供海量音乐资源。用户可以通过分类和搜索轻松找到想要的歌曲&#xff0c;并享受在线畅听和下载无损音质的功能。首页设有推荐歌单、精选和排行榜&#xff0c;帮助用户发现更多好音乐。此外&#xff0c;还支持设置歌词大小…

面试场景题系列:设计搜索自动补全系统

当我们在谷歌上搜索或者在亚马逊上购物时,只要在搜索框中打字,网页上就会展示一个或者更多的与搜索词匹配的结果。这个功能叫作自动补全(Autocomplete)、提前输入(Typeahead)、边输边搜(Search-as-you-type)或者增量搜索(Incremental Search)。图-1展示了一个谷歌搜索的示例,…

Leetcode打卡:设计一个ATM机器

执行结果&#xff1a;通过 题目 2241 设计一个ATM机器 一个 ATM 机器&#xff0c;存有 5 种面值的钞票&#xff1a;20 &#xff0c;50 &#xff0c;100 &#xff0c;200 和 500 美元。初始时&#xff0c;ATM 机是空的。用户可以用它存或者取任意数目的钱。 取款时&#xff0c…

【MySQL】九、表的内外连接

文章目录 前言Ⅰ. 内连接案例&#xff1a;显示SMITH的名字和部门名称 Ⅱ. 外连接1、左外连接案例&#xff1a;查询所有学生的成绩&#xff0c;如果这个学生没有成绩&#xff0c;也要将学生的个人信息显示出来 2、右外连接案例&#xff1a;对stu表和exam表联合查询&#xff0c;把…

在 IPhone 上检查 Safari 浏览历史记录的 5 种方法

与其他网络浏览器一样&#xff0c;Safari 会保留您的浏览历史记录&#xff0c;以便您可以输入之前访问过的网页。这是一个方便的功能。 但是如何在iPhone上查看已删除的浏览历史记录呢&#xff1f; 不用担心&#xff01;在本文中&#xff0c;我们将列出 5 个经过验证的选项&a…

使用Apache Mahout制作 推荐引擎

目录 创建工程 基本概念 关键概念 基于用户与基于项目的分析 计算相似度的方法 协同过滤 基于内容的过滤 混合方法 创建一个推荐引擎 图书评分数据集 加载数据 从文件加载数据 从数据库加载数据 内存数据库 协同过滤 基于用户的过滤 基于项目的过滤 添加自定…

SpringMVC(六)拦截器

目录 1.什么是拦截器 2.拦截器和过滤器有哪些区别 3.拦截器方法 4.单个拦截器的执行流程 5.使用拦截器实现用户登录权限验证&#xff08;实例&#xff09; 1.先在html目录下写一个login.html文件 2.在controller包下写一个LoginController文件 3.加拦截器 1.创建一个conf…

【FlutterDart】 拖动边界线改变列宽并且有边界高亮和鼠标效果(12 /100)

【Flutter&Dart】 拖动改变 widget 的窗口尺寸大小GestureDetector&#xff5e;简单实现&#xff08;10 /100&#xff09; 【Flutter&Dart】 拖动边界线改变列宽类似 vscode 那种拖动改变编辑框窗口大小&#xff08;11 /100&#xff09; 上效果 对比一下vscode的效果&…