数字人解决方案——NeRF实现实时对话数字人环境配置与源码

news2024/11/14 17:32:42

前言 

1.这是一个能实时对话的虚拟数字人demo,使用的是NeRF(Neural Radiance Fields)训练方式可以看看我前面的博客。

2.文本转语音是用了VITS语音合成,项目git:https://github.com/jaywalnut310/vits .

3.语言模型是用了新开源的ChatGLM2-6B,当前的项目暂时没有加上这个接口。GitHub - THUDM/ChatGLM2-6B: ChatGLM2-6B: An Open Bilingual Chat LLM | 开源双语对话语言模型 )

4.声音克隆用的是PaddleSpeech,这个语音克隆训练起来很快,使用的数据集也相对少一些,当前的项目暂时没有加上语音克隆。

GitHub - PaddlePaddle/PaddleSpeech: Easy-to-use Speech Toolkit including Self-Supervised Learning model, SOTA/Streaming ASR with punctuation, Streaming TTS with text frontend, Speaker Verification System, End-to-End Speech Translation and Keyword Spotting. Won NAACL2022 Best Demo Award.Easy-to-use Speech Toolkit including Self-Supervised Learning model, SOTA/Streaming ASR with punctuation, Streaming TTS with text frontend, Speaker Verification System, End-to-End Speech Translation and Keyword Spotting. Won NAACL2022 Best Demo Award. - GitHub - PaddlePaddle/PaddleSpeech: Easy-to-use Speech Toolkit including Self-Supervised Learning model, SOTA/Streaming ASR with punctuation, Streaming TTS with text frontend, Speaker Verification System, End-to-End Speech Translation and Keyword Spotting. Won NAACL2022 Best Demo Award.https://github.com/PaddlePaddle/PaddleSpeech

5.当现实现的效果:

实时对话数字人

语音合成

1.VITS(Variational Inference with adversarial learning for end-to-end Text-to-Speech)是一种结合变分推理(variational inference)、标准化流(normalizing flows)和对抗训练的高表现力语音合成模型。VITS通过隐变量而非频谱串联起来语音合成中的声学模型和声码器,在隐变量上进行随机建模并利用随机时长预测器,提高了合成语音的多样性,输入同样的文本,能够合成不同声调和韵律的语音。

2.声学模型是声音合成系统的重要组成部分:

 它使用预先训练好的语音编码器 (vocoder声码器) 将文本转化为语音。

3.VITS 的工作流程如下:

  • 将文本输入 VITS 系统,系统会将文本转化为发音规则。
  • 将发音规则输入预先训练好的语音编码器 (vocoder),vocoder 会根据发音规则生成语音信号的特征表示。
  • 将语音信号的特征表示输入预先训练好的语音合成模型,语音合成模型会根据特征表示生成合成语音。
  • VITS 的优点是生成的语音质量较高,能够生成流畅的语音。但是,VITS 的缺点是需要大量的训练语料来训练 vocoder 和语音合成模型,同时需要较复杂的训练流程。

4.把项目git下来后,我们试试用VITS做个语音合成,这里使用gradio来辅助创建个demo。

import os
from datetime import datetime
current_path = os.path.dirname(os.path.abspath(__file__))
os.environ["PATH"] = os.path.join(current_path, "ffmpeg/bin/") + ";" + os.environ["PATH"]
import torch
import commons
import utils
import re
from models import SynthesizerTrn
from text import text_to_sequence_with_hps as text_to_sequence
from scipy.io.wavfile import write
from pydub import AudioSegment
import gradio as gr

dir = "data/video/results/"

device = torch.device("cpu")  # cpu  mps
hps = utils.get_hparams_from_file("{}/configs/finetune_speaker.json".format(current_path))
hps.data.text_cleaners[0] = 'my_infer_ce_cleaners'
hps.data.n_speakers = 2
symbols = hps.symbols
net_g = SynthesizerTrn(
    len(symbols),
    hps.data.filter_length // 2 + 1,
    hps.train.segment_size // hps.data.hop_length,
    n_speakers=hps.data.n_speakers,
    **hps.model).to(device)
_ = net_g.eval()
#    G_latest  G_trilingual  G_930000  G_953000 G_984000 G_990000 G_1004000 G_1021000
# _ = utils.load_checkpoint("C:/code/vrh/models/G_1/G_1.pth", net_g, None)
_ = utils.load_checkpoint("C:/code/vrh/models/G_1/G_1.pth", net_g, None)


def add_laug_tag(text):
    '''
    添加语言标签
    '''
    pattern = r'([\u4e00-\u9fa5,。!?;:、——……()]+|[a-zA-Z,.:()]+|\d+)'
    segments = re.findall(pattern, text)
    for i in range(len(segments)):
        segment = segments[i]
        if re.match(r'^[\u4e00-\u9fa5,。!?;:、——……()]+$', segment):
            segments[i] = "[ZH]{}[ZH]".format(segment)
        elif re.match(r'^[a-zA-Z,.:()]+$', segment):
            segments[i] = "[EN]{}[EN]".format(segment)
        elif re.match(r'^\d+$', segment):
            segments[i] = "[ZH]{}[ZH]".format(segment)  # 数字视为中文
        else:
            segments[i] = "[JA]{}[JA]".format(segment)  # 日文

    return ''.join(segments)


def get_text(text, hps):
    text_cleaners = ['my_infer_ce_cleaners']
    text_norm = text_to_sequence(text, hps.symbols, text_cleaners)
    if hps.data.add_blank:
        text_norm = commons.intersperse(text_norm, 0)
    text_norm = torch.LongTensor(text_norm)
    return text_norm


def infer_one_audio(text, speaker_id=94, length_scale=1):
    '''
        input_type: 1输入自带语言标签  2中文  3中英混合
        length_scale: 语速,越小语速越快
    '''
    with torch.no_grad():
        stn_tst = get_text(text, hps)
        x_tst = stn_tst.to(device).unsqueeze(0)
        x_tst_lengths = torch.LongTensor([stn_tst.size(0)]).to(device)
        sid = torch.LongTensor([speaker_id]).to(device)  # speaker id
        audio = \
            net_g.infer(x_tst, x_tst_lengths, sid=sid, noise_scale=.667, noise_scale_w=0.8, length_scale=length_scale)[
                0][0, 0].data.cpu().float().numpy()
        return audio
    return None


def infer_one_wav(text, speaker_id, length_scale, wav_name):
    '''
        input_type: 1输入自带语言标签  2中文  3中英混合
        length_scale: 语速,越小语速越快
    '''
    audio = infer_one_audio(text, speaker_id, length_scale)
    write(wav_name, hps.data.sampling_rate, audio)
    print('task done!')

def add_slience(wav_path, slience_len=100):
    silence = AudioSegment.silent(duration=slience_len)
    wav_audio = AudioSegment.from_wav(wav_path)
    wav_audio = wav_audio + silence
    wav_audio.export(wav_path, format="wav")
    pass


# if __name__ == '__main__':
#     infer_one_wav(
#         '觉得本教程对你有帮助的话,记得一键三连哦!',
#         speaker_id=0,
#         length_scale=1.2)

def vits(text):
    now = datetime.now()
    timestamp = datetime.timestamp(now)
    file_name = str(timestamp%20).split('.')[0]
    audio_path = dir + file_name + ".wav"
    infer_one_wav(text,0,1.2,audio_path) #语音合成
    return audio_path
    
inputs = gr.Text()
outputs = gr.Audio(label="Output")

demo = gr.Interface(fn=vits, inputs=inputs, outputs=outputs)

demo.launch()

 合成视频

1.RAD-NeRF是可以对视频中所出现的说话者进行实时的人像合成。它是一种基于神经网络从一组二维图像重建三维体景。

RAD-NERF网络概述 

RAD-NeRF使用一个网络来预测正在可视化的相机视点的所有像素颜色和密度,当镜头围绕主题旋转时,想要显示的所有视点都是这样做的,这是非常需要计算力的,因为在每次学习预测图像中每个坐标的多个参数。此外,在这种情况下,这不仅仅是一个NeRF产生一个3D场景。还必须匹配音频输入,使嘴唇、嘴巴、眼睛和动作与人说的话相匹配。

网络不再预测所有像素的密度和颜色与特定帧的音频相匹配,而是使用两个独立的新压缩空间,称为网格空间,或基于网格的NeRF。再将坐标转换成较小的3D网格空间,将音频转换成较小的2D网格空间,然后将其发送到渲染头部。这意味着网络永远不会将音频数据与空间数据合并在一起,这将以指数方式增加大小,为每个坐标添加二维输入。因此,减少音频特征的大小,同时保持音频和空间特征的分离,将使这种方法更加有效。

但是,如果使用包含较少信息的压缩空间,结果如何会才能更好呢?在NeRF中添加一些可控制的特征,如眨眼控制,与以前的方法相比,模型将学习更真实的眼睛行为。这对能还原更加真实的人尤其重要。

 RAD-NeRF所做的第二个改进(模型概述中的绿色矩形)是使用相同的方法用另一个 NERF 建模躯干,而不是试图用用于头部的相同 NERF 建模躯干,这将需要更少的参数和不同的需求,因为这里的目标是动画移动的头部而不是整个身体。由于躯干在这些情况下是相当静态的,他们使用一个更简单和更有效的基于 NERF 的模块,只在2D 中工作,直接在图像空间中工作,而不是像平时通常使用 NERF 那样使用摄像机光线来产生许多不同的角度,这对躯干来说是不需要的。然后,重新组合头部与躯干,以产生最后的视频。

头像调整演示操作

2.当模型训练完之后,只需要data目录下的transforms_train.json文件和微调身体的后的模型文件就可以开始写推理代码了。步骤如下:

  • 输入语音或文字(这里为了方便演示,只写了文字输入的接口)
  • 获取输入的信息,调LLM(大型语文模型)来回答 (该项目当前还没有引入LLM,只写了几句固定的回答,之后有时间会把LLM与本地知识库加上)。
  • 对获取的回答进行语音合成,并生成用于驱动视频的.npy文件。
  • 使用.npy与transforms_train.json里面的数据合成视频,输出。
import gradio as gr
import base64
import time
import json
import gevent
from gevent import pywsgi
from geventwebsocket.handler import WebSocketHandler
from tools import audio_pre_process, video_pre_process, generate_video, audio_process
import os
import re
import numpy as np
import threading
import websocket
from pydub import AudioSegment
from moviepy.editor import VideoFileClip, AudioFileClip, concatenate_videoclips
import cv2
import pygame
from datetime import datetime

import os

dir = "data/video/results/"


audio_pre_process()
video_pre_process()
current_path = os.path.dirname(os.path.abspath(__file__))
os.environ["PATH"] = os.path.join(current_path, "ffmpeg/bin/") + ";" + os.environ["PATH"]
import torch
import commons
import utils
import re
from models import SynthesizerTrn
from text import text_to_sequence_with_hps as text_to_sequence
from scipy.io.wavfile import write

device = torch.device("cpu")  # cpu  mps
hps = utils.get_hparams_from_file("{}/configs/finetune_speaker.json".format(current_path))
hps.data.text_cleaners[0] = 'my_infer_ce_cleaners'
hps.data.n_speakers = 2
symbols = hps.symbols
net_g = SynthesizerTrn(
    len(symbols),
    hps.data.filter_length // 2 + 1,
    hps.train.segment_size // hps.data.hop_length,
    n_speakers=hps.data.n_speakers,
    **hps.model).to(device)
_ = net_g.eval()
#    G_latest  G_trilingual  G_930000  G_953000 G_984000 G_990000 G_1004000 G_1021000
_ = utils.load_checkpoint("C:/code/vrh/models/G_1/G_1.pth", net_g, None)


def add_laug_tag(text):
    '''
    添加语言标签
    '''
    pattern = r'([\u4e00-\u9fa5,。!?;:、——……()]+|[a-zA-Z,.:()]+|\d+)'
    segments = re.findall(pattern, text)
    for i in range(len(segments)):
        segment = segments[i]
        if re.match(r'^[\u4e00-\u9fa5,。!?;:、——……()]+$', segment):
            segments[i] = "[ZH]{}[ZH]".format(segment)
        elif re.match(r'^[a-zA-Z,.:()]+$', segment):
            segments[i] = "[EN]{}[EN]".format(segment)
        elif re.match(r'^\d+$', segment):
            segments[i] = "[ZH]{}[ZH]".format(segment)  # 数字视为中文
        else:
            segments[i] = "[JA]{}[JA]".format(segment)  # 日文

    return ''.join(segments)


def get_text(text, hps):
    text_cleaners = ['my_infer_ce_cleaners']
    text_norm = text_to_sequence(text, hps.symbols, text_cleaners)
    if hps.data.add_blank:
        text_norm = commons.intersperse(text_norm, 0)
    text_norm = torch.LongTensor(text_norm)
    return text_norm


def infer_one_audio(text, speaker_id=94, length_scale=1):
    '''
        input_type: 1输入自带语言标签  2中文  3中英混合
        length_scale: 语速,越小语速越快
    '''
    with torch.no_grad():
        stn_tst = get_text(text, hps)
        x_tst = stn_tst.to(device).unsqueeze(0)
        x_tst_lengths = torch.LongTensor([stn_tst.size(0)]).to(device)
        sid = torch.LongTensor([speaker_id]).to(device)  # speaker id
        audio = \
            net_g.infer(x_tst, x_tst_lengths, sid=sid, noise_scale=.667, noise_scale_w=0.8, length_scale=length_scale)[
                0][0, 0].data.cpu().float().numpy()
        return audio
    return None


def infer_one_wav(text, speaker_id, length_scale, wav_name):
    '''
        input_type: 1输入自带语言标签  2中文  3中英混合
        length_scale: 语速,越小语速越快
    '''
    audio = infer_one_audio(text, speaker_id, length_scale)
    write(wav_name, hps.data.sampling_rate, audio)
    print('task done!')


def add_slience(wav_path, slience_len=100):
    silence = AudioSegment.silent(duration=slience_len)
    wav_audio = AudioSegment.from_wav(wav_path)
    wav_audio = wav_audio + silence
    wav_audio.export(wav_path, format="wav")
    pass

def play_audio(audio_file):
    pygame.mixer.init()
    pygame.mixer.music.load(audio_file)
    pygame.mixer.music.play()
    while pygame.mixer.music.get_busy():
        pygame.time.Clock().tick(10)
    pygame.mixer.music.stop()

def answer(message, history):
    global dir
    history = history or []
    message = message.lower()
    if message=="你好":
        response = "你好,有什么可以帮到你吗?"

    elif message=="你是谁":
        response = "我是虚拟数字人幻静,你可以叫我小静或者静静。"

    elif message=="你能做什么":
        response = "我可以陪你聊天,回答你的问题,我还可以做很多很多事情!"

    else:
        response = "你的这个问题超出了我的理解范围,等我学习后再来回答你。"

    history.append((message, response))

    save_path = text2video(response,dir)
    
    return history,history,save_path

def text2video(text,dir):
    now = datetime.now()
    timestamp = datetime.timestamp(now)
    file_name = str(timestamp%20).split('.')[0]
    audio_path = dir + file_name + ".wav"
    infer_one_wav(text,0,1.1,audio_path) #语音合成 

    audio_process(audio_path)
    audio_path_eo = dir+file_name+"_eo.npy"

    save_path = generate_video(audio_path_eo, dir, file_name,audio_path)

    return save_path


with gr.Blocks(css="#chatbot{height:300px} .overflow-y-auto{height:500px}") as rxbot: 
    with gr.Row():
        video = gr.Video(label = "数字人",autoplay = True)
        with gr.Column():
            state = gr.State([])
            chatbot = gr.Chatbot(label = "消息记录").style(color_map=("green", "pink"))
            txt = gr.Textbox(show_label=False, placeholder="请输入你的问题").style(container=False)
    txt.submit(fn = answer, inputs = [txt, state], outputs = [chatbot, state,video])
    
rxbot.launch()

运行代码,然后打开http://127.0.0.1:7860/ ,然后输入文字就可得到回答合成的视频。

源码

1.当前的源码包含了语音合成与视频合成两个模型,环境依赖最难装的部分应该是pytorch3d,这个可以参考我之前的博客:

数字人解决方案——基于真人视频的三维重建数字人源码与训练方法_知来者逆的博客-CSDN博客

2.源码在win10,cuda 11.7,cudnn 8.5,python3.10,conda环境下测试运行成功。源码下载地址:

https://download.csdn.net/download/matt45m/88078575

下载源码后,创建conda环境:

cd vrh
#创建虚拟环境
conda create --name vrh python=3.10
activate vrh
#pytorch 要单独对应cuda进行安装,要不然训练时使用不了GPU
conda install pytorch==2.0.0 torchvision==0.15.0 torchaudio==2.0.0 pytorch-cuda=11.7 -c pytorch -c nvidia
conda install -c fvcore -c iopath -c conda-forge fvcore iopath
#安装所需要的依赖
pip install -r requirements.txt

windows下安装pytorch3d,这个依赖还是要在刚刚创建的conda环境里面进行安装。

git clone https://github.com/facebookresearch/pytorch3d.git
cd pytorch3d
python setup.py install

如果下载pytorch3d很慢,可以使用这个百度网盘下载:链接:https://pan.baidu.com/s/1z29IgyviQe2KQa6DilnRSA  提取码:dm4q 

如果安装中间报错退出,这里建议安装vs 生成工具。Microsoft C++ 生成工具 - Visual Studio​编辑https://visualstudio.microsoft.com/zh-hans/visual-cpp-build-tools/https://visualstudio.microsoft.com/zh-hans/visual-cpp-build-tools/3.如果对该项目感兴趣或者在安装的过程中遇到什么错误的的可以加我的企鹅群:487350510,大家一起探讨。

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

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

相关文章

Oracle 最高安全架构

​在当今世界中,数据库是存储敏感信息的宝贵资料库,攻击者总是在寻找目标。这导致网络安全威胁的增加,因此有必要采取适当的保护措施。Oracle Maximum Security Architecture(MSA)就是一种提供数据库端到端安全的解决方…

YOLOv6 论文学习

1. 解决了什么问题? 吸收了学术圈和工业界最新的目标检测方法,包括网络结构、训练策略、测试技巧、量化和优化方法。 作者有如下几点发现: 目前还没有人深入研究 RepVGG 重参数化对检测任务的影响。直接缩放 RepVGG 模块的效果并不好&…

苹果电脑系统优化工具:Ventura Cache Cleaner for mac

Ventura Cache Cleaner for Mac是一款专门为苹果电脑开发的系统优化工具,旨在帮助用户清理和优化Mac电脑,提高系统性能和速度。该软件由美国公司Northern Softworks开发,已经推出了多个版本,适用于不同版本的Mac操作系统。 Ventu…

pdf文件太大了不能上传怎么办?这几招值得学

PDF文件是一种常见的文档格式,但有时会遇到文件太大无法上传的问题,这时候简单的做法就是直接压缩文件的大小,但很多朋友还不知道怎么操作,下面就给大家介绍几个简单好用的,一起来看看吧。 工具一、嗨格式压缩大师 这…

二十七、响应式布局练习- 美图导航栏1

目录: 准备工作界面结构开发样式设计 - style.less 一、准备工作 开发响应式设计的网页需要注意以下几点: 1.移动端优先 - 先写完移动端的界面,再写网页。 因为现在都是手机用的比较多; 2.渐进增强 - 当移动端写完后,…

【Spring Cloud Gateway 新一代网关】—— 每天一点小知识

💧 S p r i n g C l o u d G a t e w a y 新一代网关 \color{#FF1493}{Spring Cloud Gateway 新一代网关} SpringCloudGateway新一代网关💧 🌷 仰望天空,妳我亦是行人.✨ 🦄 个人主页——微风撞见云的博客&a…

js学习 记录(二)

js学习 记录(二) 匿名函数 函数表达式

节省近2400亿,中国芯片拿下7纳米工艺,外媒:挡不住中国芯了

从去年至今中国进口的芯片减少了1400亿颗,芯片进口金额减少了300多亿美元(约合近2400亿元人民币),尤为让人高兴的是近期频频传出中国或已搞定接近7纳米的N1工艺,并将为一家中国芯片企业生产芯片。 一、中国芯片夯实成熟…

InnoDB 的隔离级别是如何实现的

点击上方↑“追梦 Java”关注,一起追梦! MySQL 数据库 InnoDB 存储引擎的隔离级别是通过锁和 MVCC 的机制实现的。 1 了解 MySQL 中锁的机制 锁是用于避免不同事务对共享资源的并发访问的产生读一致性的问题的机制。 1、表锁和行锁 InnoDB 存储引擎支持行…

如何与 Zappos 建立 EDI 连接?

Zappos 是一家享誉全球的知名在线鞋类和服饰零售商,经营范围涵盖各类时尚品牌的鞋类、服饰及配饰等,使命是为广大消费者提供方便、愉悦、优质的购物体验,让每一位顾客都能找到心仪的产品。多年来,Zappos 卖场凭借卓越的服务与产品…

通用VS垂直,讯飞星火与网易子曰不同的“大模型解法”

配图来自Canva可画 随着大模型商业化应用的提速,全世界各国都开始孵化和孕育各自的行业大模型。在此背景下,国内各个细分行业的垂直大模型,日益受到产业界的关注和重视。 相比通用大模型,垂直大模型具有门槛较低、数据质量较好且…

安装虚拟机

分区 根分区5个G 同理 交换分区 最后一个分区,默认所有

串口环形缓冲区

文章目录 一、串口环形缓冲区概念二、STC12例程(1)环形串口缓冲区结构体(2)串口环形缓冲区存和取数据(3)完整工程demo 一、串口环形缓冲区概念 串口环形缓冲区应用于嵌入式、物联网开发中处理接收串口数据…

windows C++多线程同步<3>-互斥量

windows C多线程同步<3>-互斥量 概念,如下图: 另外就是互斥对象谁拥有,谁释放 那么一个线程允许多次获取互斥对象吗? 答案是允许,但是申请多次就要释放多次,否则其他线程获取不到互…

在线进销存-亿发移动进销存管理系统,助力批发零售企业线上线下同步经营

随着移动互联网的蓬勃发展,商品进销存管理日益变得复杂而关键,数字化转型已经成为批发零售企业增强竞争力的有效工具。移动进销存管理系统为批发零售企业提供一体化 解决方案,实现线上线下同步经营,帮助企业实现对商品的有效管理&…

TDengine Cloud 加入 AWS 合作伙伴网络,助力出海企业数字化转型

近日,全托管的时序数据云平台 TDengine Cloud 正式入驻 AWS Marketplace(海外区),用户可通过 AWS Marketplace 轻松实现 TDengine Cloud 的订阅与部署,以最低的成本搭建最高效的数据处理架构。此外,早在 20…

python新手如何系统学习,走过这4个阶段成为高手

目录 python初级阶段学习 python中级阶段学习 python高级阶段学习 python进阶阶段学习 Python是一种简洁而强大的编程语言,广泛应用于软件开发、数据科学、人工智能等领域。很多新手如何系统学习python,今天我们从4个阶段来学习,就能成为高…

SpringBoot实现的旅游酒店管理系统源码附带视频运行教程

基于SpringBootMybatissThymeleaf框架系统主要有以下功能:分为前后台 前台用来展示数据,预定酒店、预定旅游、预定车票、购买保险等 后台:旅游路线管理、景点管理、酒店管理、车票管理、保险管理、攻略管理、留言管理、订单管理等后台管理员 …

关注这些问题,助你找到理想工作

导语:在寻找理想工作的过程中,有一些关键问题需要我们特别关注。了解并回答这些问题将有助于我们更好地定位自己,并找到符合自身需求和目标的职位。本文将介绍一些在找工作时需要关注的重要问题。 个人定位:首先,我们…

失去SSL证书,会对网站安全造成什么影响?

作为网络世界中的“身份证”,SSL证书可以在网络世界中证明你是一个真实可信的企业或个人网站,而不是一个钓鱼网站。且在网站的服务器上部署SSL证书后,可以使网站与访问者之间通过SSL协议建立安全的加密连接,确保在Web服务器和浏览…