2.NLP

TTS

1.介绍

TTS(Text-to-Speech,文本转语音)是一项将文字信息转换为可听的自然语音的技术。

开源的TTS项目有:

  1. TTS-Pytorch。https://github.com/jaywalnut310/vits
  2. IndexTTS2。https://github.com/index-tts/index-tts.git
  3. voicebox。https://github.com/jamiepine/voicebox
    • 完全免费开源,无需API Key,不限使用次数,数据本地存储不外流。
    • 内置7种TTS引擎,支持23国语言。
    • 播客、视频配音、智能体开发直接拉满效率。
    • 特点:任意声音克隆、全局实时语音输入、AI Agent专属配音。

基于大模型的TTS.

模型 开发团队 主要特点 核心优势 主要适用场景
CosyVoice 3 阿里通义实验室 - 中文CER低至0.71%网页
- 3秒零样本语音克隆网页
- 150ms流式首包延迟网页
- 支持18种方言与精细情感控制网页
- 端到端LLM架构
综合性能最强的"六边形战士",在合成质量、克隆速度、延迟和可控性上全面领先。 语音助手/对话机器人、虚拟主播/AI配音(需结合GPT-SoVITS进行深度定制)网页
GPT-SoVITS v2 社区驱动 - 中文CER约1.2%网页
- 1分钟少样本语音克隆网页
- 不支持流式输出网页
- 支持粤语方言网页
"克隆之王",在声音克隆的效果和定制化上尤为突出,且拥有完善的训练工具链。 游戏NPC配音、需要批量生产或深度定制声音的场景网页
ChatTTS 2noise团队 - 中文CER约1.5%网页
- 不支持语音克隆网页
- 不支持流式输出网页
- 支持笑声、停顿等副语言行为控制网页
"对话之王",在纯对话场景下的停顿、换气等细节最为自然,对话感强。 纯文本对话TTS、追求自然对话韵律的场景网页
Fish Speech 1.5 Fish Audio - 中文CER约1.4%网页
- 支持语音克隆网页
- 支持流式输出网页
- 情感控制能力基础网页
"省资源之王",对GPU显存等计算资源的需求最低,适合在低配置设备上运行。 低配机器运行TTS、对资源消耗敏感的场景网页

适用场景

  1. 语音助手/对话机器人:首选 CosyVoice 3,因其流式延迟低且支持情感控制。
  2. 虚拟主播/AI配音:建议组合使用 CosyVoice 3(快速克隆)和 GPT-SoVITS(深度定制)。
  3. 游戏NPC配音:推荐 GPT-SoVITS v2,因其训练工具链完善,适合批量生产。
  4. 纯文本对话TTS:推荐 ChatTTS,因其在对话自然度上表现佳。
  5. 低配置机器:推荐 Fish Speech 1.5。

2.Genius-Society/hoyoTTS

原神崩铁角色语音 BertVITS2 模型 V1 版是一款专为游戏《原神》、《崩坏:星穹铁道》角色语音而设计的人工智能语音合成模型。 该模型基于先进的深度学习技术,结合了 BERT 的语言理解能力和 VITS 的语音合成技术,实现了高度自然、流畅的语音输出。 它能够根据文本输入,生成与崩铁角色声音特征相匹配的语音,提供沉浸式的游戏体验。 V1 版在语音的自然度、情感表达以及语音合成的准确性方面进行了优化,使得角色语音更加贴近原角色的声音特点,为玩家带来更加真实和愉悦的听觉享受。

2.1. 设备支持矩阵

设备 支持方式 改动量 建议
CPU PyTorch CPU 0 当前默认,稳定
NVIDIA GPU CUDA 版 PyTorch 很小 最推荐先试
Apple GPU MPS 很小 部分算子可能回退
Windows 任意 GPU DirectML 小 兼容性一般
Intel NPU OpenVINO(ONNX → IR → NPU) 大 需要改造推理代码,适合 PoC
华为昇腾 NPU torch_npu + CANN 中 仅 Linux/昇腾,不适用于 Intel NPU
AMD Ryzen AI NPU 专用工具链 很大 不建议作为第一步

注意:torch_npu 是华为昇腾的,不是 Intel NPU。Intel NPU 不能 .to('npu')。

2.2. 环境与模型准备

1. 基础依赖。`ffmpeg` 必须在 PATH。
pip install modelscope numpy scipy soundfile
pip install pypinyin jieba
pip install funasr edge-tts          # 质量闸门/兜底,可选但建议


2. 模型
python -c "from modelscope import snapshot_download; \
snapshot_download('Genius-Society/hoyoTTS', local_dir='models/hoyoTTS')"

python -c "from modelscope import snapshot_download; \
snapshot_download('dienstag/chinese-roberta-wwm-ext-large', \
local_dir='models/chinese-roberta-wwm-ext-large')"


推理代码(创空间仓库)用 Git clone 到 `models/hoyoTTS-code`。

关键文件:

models/hoyoTTS/config.json
models/hoyoTTS/G_78000.pth
models/hoyoTTS/D_78000.pth
models/hoyoTTS/DUR_78000.pth
models/chinese-roberta-wwm-ext-large/
models/hoyoTTS-code/models.py
models/hoyoTTS-code/utils.py
models/hoyoTTS-code/text/

2.3. 设备检测

import torch, importlib.util

print("torch:", torch.__version__)
print("cuda:", torch.cuda.is_available(), torch.version.cuda)
print("mps:", getattr(getattr(torch.backends, "mps", None), "is_available", lambda: False)())
print("torch_npu:", bool(importlib.util.find_spec("torch_npu")))
print("directml:", bool(importlib.util.find_spec("torch_directml")))

try:
    import openvino as ov
    print("openvino devices:", ov.Core().available_devices)
except Exception as e:
    print("openvino:", e)

本机输出会是:

torch: 2.14.1+cpu
cuda: False None
mps: False
torch_npu: False
directml: False
openvino devices: ['CPU', 'GPU', 'NPU']

2.4. 统一推理封装(CPU / CUDA / MPS)

先把模型改成设备无关,后面加 GPU/NPU 都方便。

import os, sys, json, torch, numpy as np
from scipy.io import wavfile

HOYO_MODEL = r"D:/workspace/longevity-world-text/tmp/models/hoyoTTS"
HOYO_CODE  = r"D:/workspace/longevity-world-text/tmp/models/hoyoTTS-code"
BERT       = r"D:/workspace/longevity-world-text/tmp/models/chinese-roberta-wwm-ext-large"

# 本地化 snapshot_download
import modelscope
_orig = modelscope.snapshot_download
def _local(mid, *a, k):
    mid = str(mid)
    if "hoyoTTS" in mid:
        return HOYO_MODEL
    if "chinese-roberta" in mid:
        return BERT
    return _orig(mid, *a, k)
modelscope.snapshot_download = _local

sys.path.insert(0, HOYO_CODE)
from text.symbols import symbols
from text.cleaner import clean_text
from text import cleaned_text_to_sequence, get_bert
from models import SynthesizerTrn
import commons, utils

def pick_device():
    if torch.cuda.is_available():
        return torch.device("cuda")
    if getattr(getattr(torch.backends, "mps", None), "is_available", lambda: False)():
        return torch.device("mps")
    return torch.device("cpu")

DEVICE = pick_device()
print("TTS device:", DEVICE)

hps = utils.get_hparams_from_dir(HOYO_MODEL)
net = 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)
utils.load_checkpoint(f"{HOYO_MODEL}/G_78000.pth", net, None, skip_optimizer=True)
net.eval()
sr = hps.data.sampling_rate

def synth(text, sid, out_wav="out.wav",
          sdp_ratio=0.2, noise_scale=0.667, noise_scale_w=0.8,
          length_scale=1.0, seed=42):
    torch.manual_seed(seed)
    if DEVICE.type == "cuda":
        torch.cuda.manual_seed_all(seed)

    norm_text, phone, tone, word2ph = clean_text(text, "ZH")
    phone, tone, lang = cleaned_text_to_sequence(phone, tone, "ZH")

    if hps.data.add_blank:
        phone = commons.intersperse(phone, 0)
        tone = commons.intersperse(tone, 0)
        lang = commons.intersperse(lang, 0)
        for i in range(len(word2ph)):
            word2ph[i] = word2ph[i] * 2
        word2ph[0] += 1

    bert = get_bert(norm_text, word2ph, "ZH").to(DEVICE)
    assert bert.shape[-1] == len(phone)

    with torch.no_grad():
        audio = net.infer(
            phone.unsqueeze(0).to(DEVICE),
            torch.LongTensor([phone.size(0)]).to(DEVICE),
            torch.LongTensor([sid]).to(DEVICE),
            tone.unsqueeze(0).to(DEVICE),
            lang.unsqueeze(0).to(DEVICE),
            bert.unsqueeze(0),
            sdp_ratio=sdp_ratio,
            noise_scale=noise_scale,
            noise_scale_w=noise_scale_w,
            length_scale=length_scale,
        )[0][0, 0].data.cpu().float().numpy()

    wavfile.write(out_wav, sr, (np.clip(audio, -1, 1) * 32767).astype(np.int16))
    return out_wav

CPU / CUDA / MPS 都靠 pick_device() 自动选。

2.5. GPU 使用

第一:NVIDIA CUDA

当前 PyTorch 是 +cpu,不能直接用 CUDA,必须重装 CUDA 版:

# 以 CUDA 12.x 为例,具体版本看你的驱动
pip uninstall -y torch
pip install torch --index-url https://download.pytorch.org/whl/cu121

确认:

import torch
print(torch.__version__, torch.cuda.is_available(), torch.cuda.get_device_name(0))

然后上面的 pick_device() 会自动返回 cuda,其余代码不用改。

可选优化:

# 固定 shape 时开 cudnn benchmark;文本长度变化大时未必有益
torch.backends.cudnn.benchmark = True

# 混合精度(先测音质,Bert-VITS2 对精度敏感)
with torch.autocast("cuda", dtype=torch.float16):
    ...

显存:模型约 600MB+,batch 1 通常 2–4GB 显存够用。

第二: Apple Silicon MPS

DEVICE = torch.device("mps")

某些算子 MPS 不支持时会报错,可以设:

export PYTORCH_ENABLE_MPS_FALLBACK=1

速度不一定比 CPU 快,先 benchmark。

第三:Windows DirectML(任意显卡)

pip install torch-directml
import torch_directml
DEVICE = torch_directml.device()
net.to(DEVICE)

DirectML 算子覆盖不如 CUDA,遇到不支持会报错或回退;不建议作为首选。

2.6.参数与音色(简要)

PARAM_GRID = [
    dict(sdp=0.0, noise=0.667, noise_w=0.8),
    dict(sdp=0.2, noise=0.3,   noise_w=0.3),
    dict(sdp=0.4, noise=0.667, noise_w=0.8),
    dict(sdp=0.0, noise=0.3,   noise_w=0.3),
    dict(sdp=0.1, noise=0.5,   noise_w=0.5),
]
  • sdp_ratio:韵律变化,0–0.4
  • noise_scale:音色随机性,默认 0.667
  • noise_scale_w:时长/节奏随机性,默认 0.8
  • length_scale:语速
  • seed:固定种子 + 固定参数 = 相同音频
  • 重跑改 --seed-offset 换采样

音色选择:

  • 一角色一音色,重要角色不共用
  • 旁白单独一个 sid(本项目旁白 111)
  • 动作/第三人称叙述走 sidAction
  • 非人声走兽音/中性音
  • 用基频校验:男声通常 <155Hz,女声 >175Hz

2.7.性能与选型建议

方案 预期 备注
CPU 单条 2–5 秒;1261 条约 78–90 分钟(含闸门) 当前实际
CUDA GPU 单条可能 0.5–2 秒 最推荐先试
Apple MPS 视算子支持 先 benchmark
DirectML 兼容性一般 不优先
OpenVINO GPU 通常比 NPU 容易 先试这个
OpenVINO NPU 不确定,可能不如 CPU 适合低功耗,不适合盲目追速度
昇腾 NPU 取决于 CANN/算子 仅昇腾机器

建议顺序:CPU → CUDA GPU → OpenVINO GPU → OpenVINO NPU。

NLP

NLP(Natural Language Processing) 让计算机理解和生成人类语言

核心流程:文本 → 向量 → 模型 → 任务

三大核心知识

  1. 文本处理:也就是分词、清洗。常见库:spaCy
  2. 向量表示(重点) 现在基本直接用 BERT(上下文语义) 模型(核心) :👉 Transformer

项目流程(5步)

  1. 数据清洗
  2. 向量化(BERT)
  3. 模型微调
  4. 评估
  5. 部署

文章信息

张雪随笔
master
Homepage
Issues
Download

This Software is under the terms of The Unlicense.