Solution humaine numérique - NeRF réalise la configuration et le code source de l'environnement humain numérique de dialogue en temps réel

avant-propos 

1. Il s'agit d'une démo humaine numérique virtuelle qui peut parler en temps réel. Elle utilise NeRF (Neural Radiance Fields) . Pour la méthode de formation, veuillez vous référer à mon blog précédent.

2. La synthèse vocale utilise la synthèse vocale VITS, projet git : https://github.com/jaywalnut310/vits  .

3. Le modèle de langage utilise la nouvelle source open source ChatGLM2-6B, et le projet actuel n'ajoute pas cette interface pour le moment. GitHub - THUDM/ChatGLM2-6B : ChatGLM2-6B : un LLM de chat bilingue ouvert | Modèle de langage de dialogue bilingue Open Source )

4. PaddleSpeech est utilisé pour le clonage de voix. Ce clonage de voix est formé très rapidement et l'ensemble de données utilisé est relativement petit. Le projet actuel n'ajoute pas de clonage de voix pour le moment.

GitHub - PaddlePaddle/PaddleSpeech : boîte à outils vocale facile à utiliser comprenant un modèle d'apprentissage auto-supervisé, SOTA/Streaming ASR avec ponctuation, Streaming TTS avec interface texte, système de vérification du locuteur, traduction vocale de bout en bout et détection de mots clés. A remporté le prix de la meilleure démo NAACL2022. Boîte à outils vocale facile à utiliser comprenant un modèle d'apprentissage auto-supervisé, SOTA/Streaming ASR avec ponctuation, Streaming TTS avec interface texte, système de vérification du locuteur, traduction vocale de bout en bout et détection de mots clés. A remporté le prix de la meilleure démo NAACL2022. - GitHub - PaddlePaddle/PaddleSpeech : boîte à outils vocale facile à utiliser comprenant un modèle d'apprentissage auto-supervisé, SOTA/Streaming ASR avec ponctuation, Streaming TTS avec interface texte, système de vérification du locuteur, traduction vocale de bout en bout et détection de mots clés. A remporté le prix de la meilleure démo NAACL2022.https://github.com/PaddlePaddle/PaddleSpeech

5. L'effet actuel :

Dialogue numérique humain en temps réel

synthèse de discours

1. VITS (Variational Inference with adversarial learning for end-to-end Text-to-Speech) est un modèle de synthèse vocale hautement expressif qui combine l'inférence variationnelle, la normalisation des flux et l'entraînement à la confrontation. VITS relie le modèle acoustique et le vocodeur dans la synthèse vocale via des variables cachées au lieu du spectre. Une modélisation aléatoire est effectuée sur des variables cachées et des prédicteurs de durée aléatoires sont utilisés pour améliorer la diversité de la parole synthétisée. Le même texte d'entrée peut être synthétisé Discours avec différentes tonalités et rythmes.

2. Le modèle acoustique est une partie importante du système de synthèse sonore :

 Il utilise un codeur vocal pré-formé (vocodeur) pour convertir le texte en parole.

3. Le flux de travail de VITS est le suivant :

  • Entrez du texte dans le système VITS, qui convertit le texte en règles de prononciation.
  • Entrez les règles de prononciation dans l'encodeur vocal pré-formé (vocodeur), et le vocodeur générera une représentation caractéristique du signal vocal selon les règles de prononciation.
  • Entrez la représentation caractéristique du signal vocal dans le modèle de synthèse vocale pré-formé, et le modèle de synthèse vocale générera une parole synthétique en fonction de la représentation caractéristique.
  • L'avantage de VITS est que la parole générée est de haute qualité et peut générer une parole fluide. Cependant, l'inconvénient de VITS est qu'il nécessite une grande quantité de corpus de formation pour former le modèle de vocodeur et de synthèse vocale, et nécessite un processus de formation plus compliqué.

4. Une fois le projet terminé, essayons d'utiliser VITS pour faire de la synthèse vocale. Ici, nous utilisons gradio pour aider à créer une démo.

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()

 vidéo composite

1. RAD-NeRF peut effectuer une synthèse de portrait en temps réel sur les haut-parleurs apparaissant dans la vidéo. Il s'agit d'une reconstruction basée sur un réseau de neurones d'une scène de volume 3D à partir d'un ensemble d'images 2D.

Présentation du réseau RAD-NERF 

RAD-NeRF utilise un réseau pour prédire toutes les couleurs et densités de pixels des points de vue de la caméra visualisés. Lorsque la caméra tourne autour du sujet, tous les points de vue que vous souhaitez afficher le font. Plusieurs paramètres sont appris pour prédire chaque coordonnée de l'image à un temps. De plus, dans ce cas, ce n'est pas seulement un NeRF générant une scène 3D. L'entrée audio doit également être adaptée afin que les lèvres, la bouche, les yeux et les mouvements correspondent à ce que la personne dit.

Au lieu de prédire la densité et la couleur de tous les pixels pour correspondre à une image audio particulière, le réseau utilise deux nouveaux espaces de compression distincts appelés espaces de grille ou NeRF basés sur une grille. Les coordonnées sont ensuite converties en un espace de grille 3D plus petit, et l'audio est converti en un espace de grille 2D plus petit, qui est ensuite envoyé à la tête de rendu. Cela signifie que le réseau ne fusionne jamais les données audio avec les données spatiales, ce qui augmenterait de façon exponentielle en taille, ajoutant des entrées bidimensionnelles pour chaque coordonnée. Par conséquent, réduire la taille des caractéristiques audio tout en maintenant la séparation des caractéristiques audio et spatiales rendra cette méthode plus efficace.

Mais comment le résultat peut-il être meilleur en utilisant un espace compressé qui contient moins d'informations ? En ajoutant des fonctionnalités contrôlables dans NeRF, telles que le contrôle des clignements, le modèle apprendra un comportement oculaire plus réaliste par rapport aux méthodes précédentes. Ceci est particulièrement important pour les personnes qui peuvent restaurer plus d'authenticité.

 La deuxième amélioration apportée par RAD-NeRF (le rectangle vert dans la vue d'ensemble du modèle) est d'utiliser la même méthode pour modéliser le torse avec un autre NERF au lieu d'essayer de modéliser le torse avec le même NERF utilisé pour la tête, ce qui nécessiterait plus Moins de paramètres et des besoins différents, puisque le but ici est d'animer une tête en mouvement plutôt qu'un corps entier. Étant donné que le torse est assez statique dans ces cas, ils utilisent un module basé sur NERF plus simple et plus efficace qui ne fonctionne qu'en 2D, travaillant directement dans l'espace image au lieu d'utiliser des rayons de caméra comme d'habitude avec NERF Crée de nombreux angles différents, ce qui n'est pas nécessaire pour le torse. Ensuite, recombinez la tête et le torse pour produire la vidéo finale.

Opération de démonstration d'ajustement d'avatar

2. Une fois le modèle formé, vous n'avez besoin que du fichier transforms_train.json dans le répertoire de données et du fichier de modèle après avoir affiné le corps pour commencer à écrire le code de raisonnement. Procédez comme suit:

  • Saisir de la voix ou du texte (ici, pour la commodité de la démonstration, seule l'interface de saisie de texte est écrite)
  • Obtenez les informations d'entrée et appelez LLM (Large Language Model) pour répondre (le projet n'a pas encore introduit LLM, n'a écrit que quelques réponses fixes, et ajoutera LLM et la base de connaissances locale plus tard quand il sera temps).
  • Une synthèse vocale est effectuée sur les réponses obtenues et un fichier .npy est généré pour piloter la vidéo.
  • Utilisez les données dans .npy et transforms_train.json pour synthétiser la vidéo et la sortie.
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()

Exécutez le code, puis ouvrez http://127.0.0.1:7860/  , puis saisissez le texte pour obtenir la vidéo synthétisée de la réponse.

code source

1. Le code source actuel comprend deux modèles de synthèse vocale et de synthèse vidéo. La partie la plus difficile de la dépendance à l'environnement devrait être pytorch3d. Pour cela, veuillez vous référer à mon blog précédent :

Digital Human Solution - Code source humain numérique de reconstruction 3D et méthode de formation basée sur la vidéo en direct

2. Le code source a été testé avec succès dans les environnements win10, cuda 11.7, cudnn 8.5, python3.10 et conda. Adresse de téléchargement du code source :

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

Après avoir téléchargé le code source, créez un environnement 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

Pour installer pytorch3d sous windows, cette dépendance doit encore être installée dans l'environnement conda qui vient d'être créé.

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

Si le téléchargement de pytorch3d est très lent, vous pouvez utiliser ce disque réseau Baidu pour télécharger : Lien : https://pan.baidu.com/s/1z29IgyviQe2KQa6DilnRSA Code d'extraction : dm4q 

Si une erreur est signalée et quittée lors de l'installation, il est recommandé d'installer l'outil de génération vs ici. Outils de construction Microsoft C++ - Modification de Visual Studio https://visualstudio.microsoft.com/zh-hans/visual-cpp-build-tools/ https://visualstudio.microsoft.com/zh-hans/visual-cpp-build -tools/ 3. Si vous êtes intéressé par ce projet ou rencontrez des erreurs lors du processus d'installation, vous pouvez ajouter mon groupe de pingouins : 487350510, et nous en discuterons ensemble.

Je suppose que tu aimes

Origine blog.csdn.net/matt45m/article/details/131866012
conseillé
Classement