Open mzdk100 opened 2 months ago
把那个
from text import symbols
改成
from text.symbols2 import symbols
试试看?
现在这个脚本好像不是很好用,是否能实现CLI模式,因为这边有一些路径要手动写死到文件里面,不是很方便,现在测试好像也无法正常导出看到生成了onnx文件夹,但是里面是空的。
所以我无法找到我导出的onnx模型文件,没办法把这个路径替换成自己的onnx/koharu/koharu_vits.onnx
。
onnx_export.py 343 <module>
export(vits_path, gpt_path, exp_path)
onnx_export.py 303 export
a, b = gpt_sovits(ref_seq, text_seq, ref_bert, text_bert, ref_audio_sr, ssl_content, debug=debug)
module.py 1511 _wrapped_call_impl
return self._call_impl(*args, **kwargs)
module.py 1520 _call_impl
return forward_call(*args, **kwargs)
onnx_export.py 239 forward
sess = onnxruntime.InferenceSession("onnx/koharu/koharu_vits.onnx", providers=["CPU"])
onnxruntime_inference_collection.py 419 __init__
self._create_inference_session(providers, provider_options, disabled_optimizers)
onnxruntime_inference_collection.py 472 _create_inference_session
sess = C.InferenceSession(session_options, self._model_path, True, self._read_config_from_model)
onnxruntime.capi.onnxruntime_pybind11_state.NoSuchFile:
[ONNXRuntimeError] : 3 : NO_SUCHFILE : Load model from onnx/koharu/koharu_vits.onnx failed:Load model onnx/koharu/koharu
_vits.onnx failed. File doesn't exist
你是要导出到别的语言使用吗? 其实这个 onnx_export 也不完整,要运行还得导出很多其他的模型
没错,我准备导出onnx模型后,使用rust来推理。 之前我使用这个脚本导出过v1模型,但是好像bert的模型没有包含在内。
没错,我准备导出onnx模型后,使用rust来推理。 之前我使用这个脚本导出过v1模型,但是好像bert的模型没有包含在内。
我刚刚提的 https://github.com/RVC-Boss/GPT-SoVITS/pull/1640 我用 rust 试过了,可以run.
use std::collections::HashMap;
use tch::{IValue, Tensor};
use tokenizers::Tokenizer;
fn split_zh_ph(ph: &str) -> (&str, &str) {
if ph.starts_with("zh") || ph.starts_with("ch") || ph.starts_with("sh") {
ph.split_at(2)
} else {
ph.split_at(1)
}
}
fn phones(symbels: &HashMap<String, i64>, text: &str, device: tch::Device) -> (Tensor, Tensor) {
use pinyin::ToPinyin;
let mut word2ph = Vec::new();
let mut sequence = Vec::new();
for c in text.chars() {
if let Some(p) = c.to_pinyin() {
let (y, s) = split_zh_ph(p.with_tone_num_end());
sequence.push(symbels.get(y).map(|id| *id).unwrap_or(0));
sequence.push(symbels.get(s).map(|id| *id).unwrap_or(0));
word2ph.push(2);
} else {
let s = c.to_string();
sequence.push(symbels.get(&s).map(|id| *id).unwrap_or(0));
word2ph.push(1);
}
}
let word2ph = Tensor::from_slice(&word2ph);
let t = Tensor::from_slice(&sequence).to_device(device);
(t.unsqueeze(0), word2ph)
}
fn infer(
tokenizer: &Tokenizer,
symbels: &HashMap<String, i64>,
gpt_sovits: &tch::CModule,
ssl_content: &Tensor,
ref_audio_sr: &Tensor,
bert: &tch::CModule,
text: &str,
ref_seq: &Tensor,
ref_bert: &Tensor,
output: &str,
device: tch::Device,
) {
let (text_ids, text_mask, text_token_type_ids) = encode_text(text, &tokenizer, device);
let (text_seq, text_word2ph) = phones(&symbels, text, device);
let text_bert = bert
.forward_ts(&[text_ids, text_mask, text_token_type_ids, text_word2ph])
.unwrap();
println!("start gpt_sovits");
let audio = gpt_sovits
.forward_ts(&[
ssl_content,
ref_audio_sr,
ref_seq,
&text_seq,
ref_bert,
&text_bert,
])
.unwrap();
let audio_size = audio.size1().unwrap() as usize;
println!("audio size: {}", audio_size);
println!("start save audio");
let mut samples = vec![0f32; audio_size];
audio.f_copy_data(&mut samples, audio_size).unwrap();
println!("start write file");
let mut file_out = std::fs::File::create(output).unwrap();
let header = wav_io::new_header(32000, 16, false, true);
wav_io::write_to_file(&mut file_out, &header, &samples).unwrap();
}
fn main() {
let tokenizer =
Tokenizer::from_file("./pretrained_models/chinese-roberta-wwm-ext-large/tokenizer.json")
.unwrap();
let symbels = load_symbel();
let device = tch::Device::cuda_if_available();
println!("device: {:?}", device);
let ref_text = "声音,是有温度的.夜晚的声音,会发光~";
let (ref_text_ids, ref_text_mask, ref_text_token_type_ids) =
encode_text(ref_text, &tokenizer, device);
let (ref_seq, ref_text_word2ph) = phones(&symbels, ref_text, device);
let (ref_audio, sr) = load_ref_audio();
println!("ref_audio size: {:?}", ref_audio.size());
let ref_audio = IValue::Tensor(ref_audio.to_device(device));
let (bert, ssl, gpt_sovits) = check_vits_model(device);
let ref_audio_16k = ssl
.method_is(
"resample",
&[&ref_audio, &IValue::Int(sr as i64), &IValue::Int(16000)],
)
.unwrap();
let ref_audio_16k = match ref_audio_16k {
IValue::Tensor(ref_audio_16k) => ref_audio_16k,
_ => unreachable!(),
};
let ref_audio_sr = ssl
.method_is(
"resample",
&[&ref_audio, &IValue::Int(sr as i64), &IValue::Int(32000)],
)
.unwrap();
let ref_audio_sr = match ref_audio_sr {
IValue::Tensor(ref_audio_sr) => ref_audio_sr,
_ => unreachable!(),
};
let ssl_content = ssl.forward_ts(&[&ref_audio_16k]).unwrap();
println!("done ssl");
let ref_bert = bert
.forward_ts(&[
&ref_text_ids,
&ref_text_mask,
&ref_text_token_type_ids,
&ref_text_word2ph,
])
.unwrap();
println!("start infer");
let text = "我有一个奇怪的问题.你们谁知道什么是春晚?";
tch::no_grad(|| {
infer(
&tokenizer,
&symbels,
&gpt_sovits,
&ssl_content,
&ref_audio_sr,
&bert,
&text,
&ref_seq,
&ref_bert,
"output.wav",
device,
);
});
println!("start infer 2");
let text = "你们谁知道什么是春晚吗?第一年的春晚是什么时候?";
tch::no_grad(|| {
infer(
&tokenizer,
&symbels,
&gpt_sovits,
&ssl_content,
&ref_audio_sr,
&bert,
&text,
&ref_seq,
&ref_bert,
"output.wav",
device,
);
});
}
fn encode_text(text: &str, tokenizer: &Tokenizer, device: tch::Device) -> (Tensor, Tensor, Tensor) {
let encoding = tokenizer.encode(text, true).unwrap();
let ids = encoding
.get_ids()
.into_iter()
.map(|x| (*x) as i64)
.collect::<Vec<i64>>();
let text_ids = Tensor::from_slice(&ids);
let text_ids = text_ids.unsqueeze(0).to_device(device);
let mask = encoding
.get_attention_mask()
.into_iter()
.map(|x| (*x) as i64)
.collect::<Vec<i64>>();
let text_mask = Tensor::from_slice(&mask);
let text_mask = text_mask.unsqueeze(0).to_device(device);
let token_type_ids = encoding
.get_type_ids()
.into_iter()
.map(|x| (*x) as i64)
.collect::<Vec<i64>>();
let text_token_type_ids = Tensor::from_slice(&token_type_ids);
let text_token_type_ids = text_token_type_ids.unsqueeze(0).to_device(device);
(text_ids, text_mask, text_token_type_ids)
}
fn check_vits_model(device: tch::Device) -> (tch::CModule, tch::CModule, tch::CModule) {
let mut gpt_sovits = tch::CModule::load_on_device(
"/home/csh/ai/python/GPT-SoVITS/onnx/xw/gpt_sovits_model.pt",
device,
)
.unwrap();
gpt_sovits.set_eval();
println!("load gpt_sovits model success");
let mut bert =
tch::CModule::load_on_device("/home/csh/ai/python/GPT-SoVITS/onnx/bert_model.pt", device)
.unwrap();
bert.set_eval();
println!("load bert model success");
let mut ssl = tch::CModule::load_on_device(
"/home/csh/ai/python/GPT-SoVITS/onnx/xw/ssl_model.pt",
device,
)
.unwrap();
ssl.set_eval();
println!("load ssl model success");
(bert, ssl, gpt_sovits)
}
fn load_symbel() -> HashMap<String, i64> {
let f = std::fs::File::open("/home/csh/ai/python/GPT-SoVITS/onnx/symbols_v2.json").unwrap();
serde_json::from_reader(f).unwrap()
}
fn load_ref_audio() -> (Tensor, u32) {
let ref_path = "/home/csh/ai/python/GPT-SoVITS/chen1_ref.t.wav";
let file = std::fs::File::open(ref_path).unwrap();
let (head, samples) = wav_io::read_from_file(file).unwrap();
println!("head: {:?}", head);
let t = Tensor::from_slice(&samples);
(t.unsqueeze(0), head.sample_rate)
}
[package]
name = "gpt_sovits_rs"
version = "0.1.0"
edition = "2021"
[dependencies]
anyhow = "1.0.87"
# ort = "1.16.3"
tokenizers = { version = "0.20.0", features = ["http"] }
tch = { version = "0.17.0" }
pinyin = "0.10.0"
wav_io = "0.1.14"
serde_json = "1.0"
其实我是想使用onnx格式,然后使用ort库来加载,感觉性能更好,不知道您是否对比过tch和ort的性能表现,因为我还打算部署到移动设备。
为什么我编译会报错:
error: linking with `link.exe` failed: exit code: 1169
报错输出很长很长,但是大致的意思就是因为在链接过程中发现了重复定义的符号:
= note: "D:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\VC\\Tools\\MSVC\\14.41.34120\\bin\\HostX64\\x64\\link.exe" "/NOLOGO" "C:\\Users\\ADMINI~1\\AppData\\Local\\Temp\\rustc9Gy0BZ\\symbols.o" "G:\\workspace\\gpt_sovit\\target\\release\\deps\\gpt_sovits.gpt_sovits.51f8ba67aab9e335-cgu.00.rcgu.o" ...
= note: libtorch_sys-fa3fcb1194669bdb.rlib(19072f24a82f85ae-torch_api.o) : error LNK2038: 检测到“RuntimeLibrary”的不匹配项: 值“MD_DynamicRelease”不匹配值“MT_StaticRelease”(libesaxx_rs-3728ae13b4f0b997.rlib(2e40c9e35e9506f4-esaxx.o) 中)
libtorch_sys-fa3fcb1194669bdb.rlib(19072f24a82f85ae-dummy_cuda_dependency.o) : error LNK2038: 检测到“RuntimeLibrary”的不匹配项: 值“MD_DynamicRelease”不匹配值“MT_StaticRelease”(libesaxx_rs-3728ae13b4f0b997.rlib(2e40c9e35e9506f4-esaxx.o) 中)
libtorch_sys-fa3fcb1194669bdb.rlib(19072f24a82f85ae-torch_api_generated.o) : error LNK2038: 检测到“RuntimeLibrary”的不匹配项: 值“MD_DynamicRelease”不匹配值“MT_StaticRelease”(libesaxx_rs-3728ae13b4f0b997.rlib(2e40c9e35e9506f4-esaxx.o) 中)
msvcprt.lib(MSVCP140.dll) : error LNK2005: "public: struct _Cvtvec __cdecl std::_Locinfo::_Getcvt(void)const " (?_Getcvt@_Locinfo@std@@QEBA?AU_Cvtvec@@XZ) 已经在 libcpmt.lib(locale.obj) 中定义
msvcprt.lib(MSVCP140.dll) : error LNK2005: "public: unsigned short const * __cdecl std::_Locinfo::_W_Getdays(void)const " (?_W_Getdays@_Locinfo@std@@QEBAPEBGXZ) 已经在 libcpmt.lib(wlocale.obj) 中定义
msvcprt.lib(MSVCP140.dll) : error LNK2005: "public: unsigned short const * __cdecl std::_Locinfo::_W_Getmonths(void)const " (?_W_Getmonths@_Locinfo@std@@QEBAPEBGXZ) 已经在 libcpmt.lib(wlocale.obj) 中定义
msvcprt.lib(MSVCP140.dll) : error LNK2005: "protected: __cdecl std::basic_streambuf<char,struct std::char_traits<char> >::basic_streambuf<char,struct std::char_traits<char> >(void)" (??0?$basic_streambuf@DU?$char_traits@D@std@@@std@@IEAA@XZ) 已经在 libcpmt.lib(cout.obj) 中定义
...
msvcprt.lib(MSVCP140.dll) : error LNK2005: "public: __cdecl std::basic_ostream<char,struct std::char_traits<char> >::basic_ostream<char,struct std::char_traits<char> >(class std::basic_streambuf<char,struct std::char_traits<char> > *,bool)" (??0?$basic_ostream@DU?$char_traits@D@std@@@std@@QEAA@PEAV?$basic_streambuf@DU?$char_traits@D@std@@@1@_N@Z) 已经在 libcpmt.lib(cout.obj) 中定义
msvcprt.lib(MSVCP140.dll) : error LNK2005: "public: virtual __cdecl std::basic_ostream<char,struct std::char_traits<char> >::~basic_ostream<char,struct std::char_traits<char> >(void)" (??1?$basic_ostream@DU?$char_traits@D@std@@@std@@UEAA@XZ) 已经在 libcpmt.lib(cout.obj) 中定义
正在创建库 G:\workspace\gpt_sovit\target\release\deps\gpt_sovits.lib 和对象 G:\workspace\gpt_sovit\target\release\deps\gpt_sovits.exp
LINK : warning LNK4098: 默认库“LIBCMT”与其他库的使用冲突;请使用 /NODEFAULTLIB:library
G:\workspace\gpt_sovit\target\release\deps\gpt_sovits.exe : fatal error LNK1169: 找到一个或多个多重定义的符号
我尝试在tch和tokenizers的仓库查找问题,他们可以使用release模式构建,但我这边没有作用。
libcpmt.lib
lib冲突了,看起来像是 torch 静态编译,然后和 libcpmt.lib 冲突了。 我是在 wsl2 里面弄的。你这个我不太清楚。你翻翻源码让它动态链接吧。实在不行就 fork 下来
@L-jasmine 请问你的代码是不是不支持英文的?
@L-jasmine 请问你的代码是不是不支持英文的?
对 支持英文的我这两天就更新上去。然后我会publish一个独立的库。希望大家可以一起维护
@L-jasmine 请问你的代码是不是不支持英文的?
对 支持英文的我这两天就更新上去。然后我会publish一个独立的库。希望大家可以一起维护
导出的模型在gpu运行有问题 Expected all tensors to be on the same device, but found at least two devices, cuda:0 and cpu!\n
@L-jasmine 请问你的代码是不是不支持英文的?
对 支持英文的我这两天就更新上去。然后我会publish一个独立的库。希望大家可以一起维护
导出的模型在gpu运行有问题 Expected all tensors to be on the same device, but found at least two devices, cuda:0 and cpu!\n
https://github.com/L-jasmine/gpt_sovits_rs/blob/main/src/main.rs 试试这样
@L-jasmine 请问你的代码是不是不支持英文的?
对 支持英文的我这两天就更新上去。然后我会publish一个独立的库。希望大家可以一起维护
导出的模型在gpu运行有问题 Expected all tensors to be on the same device, but found at least two devices, cuda:0 and cpu!\n
https://github.com/L-jasmine/gpt_sovits_rs/blob/main/src/main.rs 试试这样
试过了,还是一样,报错是原因是因为导出TorchScripts脚本里有的Tensor没有转换成cuda布局,我对这个不是很熟悉,所以还没找到解决办法
@L-jasmine gpt_sovits_rs在windows上无法链接,我一直没能解决,能不能把tch改用ort实现呢,感觉tch有点复杂了。
@L-jasmine gpt_sovits_rs在windows上无法链接,我一直没能解决,能不能把tch改用ort实现呢,感觉tch有点复杂了。
windows上我是git clone了esaxx-rs和tokenizer库,然后在esaxx-rs里面的build.rs里static_crt(true)改成false。然后在tokenizer库和你rust项目引用你clone的esaxx-rs和tokenizer的地址就行了。
@L-jasmine export_torch_script.py里T2SModel里的forward在返回的时候是不是应该改成-idx:-1,把最后一个删掉。因为我推理的时候有时会报out of index,然后发现这里最后一个会是1024,导致embedding的时候越界。但我不知道怎么改最好,改成到-1至少没有报错。
@L-jasmine 请问你的代码是不是不支持英文的?
对 支持英文的我这两天就更新上去。然后我会publish一个独立的库。希望大家可以一起维护
导出的模型在gpu运行有问题 Expected all tensors to be on the same device, but found at least two devices, cuda:0 and cpu!\n
https://github.com/L-jasmine/gpt_sovits_rs/blob/main/src/main.rs 试试这样
试过了,还是一样,报错是原因是因为导出TorchScripts脚本里有的Tensor没有转换成cuda布局,我对这个不是很熟悉,所以还没找到解决办法
我自己电脑上是可以运行的。你在我那个repo里面提issue吧 我们到那边讨论
@L-jasmine export_torch_script.py里T2SModel里的forward在返回的时候是不是应该改成-idx:-1,把最后一个删掉。因为我推理的时候有时会报out of index,然后发现这里最后一个会是1024,导致embedding的时候越界。但我不知道怎么改最好,改成到-1至少没有报错。
y[0, -1] = 0 这样可以吗?我其实也不懂这些是啥东西,我只是抄别的部分的代码。我看 onnx_export.py 里面有这样一段
@L-jasmine export_torch_script.py里T2SModel里的forward在返回的时候是不是应该改成-idx:-1,把最后一个删掉。因为我推理的时候有时会报out of index,然后发现这里最后一个会是1024,导致embedding的时候越界。但我不知道怎么改最好,改成到-1至少没有报错。
y[0, -1] = 0 这样可以吗?我其实也不懂这些是啥东西,我只是抄别的部分的代码。我看 onnx_export.py 里面有这样一段
应该也可以吧,你之前没遇到过偶尔推理报错?
@L-jasmine export_torch_script.py里T2SModel里的forward在返回的时候是不是应该改成-idx:-1,把最后一个删掉。因为我推理的时候有时会报out of index,然后发现这里最后一个会是1024,导致embedding的时候越界。但我不知道怎么改最好,改成到-1至少没有报错。
y[0, -1] = 0 这样可以吗?我其实也不懂这些是啥东西,我只是抄别的部分的代码。我看 onnx_export.py 里面有这样一段
应该也可以吧,你之前没遇到过偶尔推理报错?
我推理没遇到过这个错,但是在torch 导出的时候有用随机输入去check,这个时候我见过out of index,我当时并不知道什么情况,我只是简单的把这个 check 关掉了。现在想来应该是这个问题导致的
@L-jasmine gpt_sovits_rs在windows上无法链接,我一直没能解决,能不能把tch改用ort实现呢,感觉tch有点复杂了。
ocr 我导出不了循环,我不知道是不是我姿势不对。在导出不了循环的情况下,它得在代码里面完成那个循环。运行起来又慢,导出的模型又大。所以我就改成了 tch。
我希望在代码里面来循环,这样可以流式推理呀,随时可以break。
@L-jasmine 能不能在gpt_sovits_rs里面写一个readme.md,后面我可能会来贡献
我希望在代码里面来循环,这样可以流式推理呀,随时可以break。
那你其实可以直接使用 onnx_export.py 就是原来就存在的那个 我用它+ocr 是跑通过的,但是我嫌慢 就用 tch 了
@L-jasmine export_torch_script.py里T2SModel里的forward在返回的时候是不是应该改成-idx:-1,把最后一个删掉。因为我推理的时候有时会报out of index,然后发现这里最后一个会是1024,导致embedding的时候越界。但我不知道怎么改最好,改成到-1至少没有报错。
y[0, -1] = 0 这样可以吗?我其实也不懂这些是啥东西,我只是抄别的部分的代码。我看 onnx_export.py 里面有这样一段
应该也可以吧,你之前没遇到过偶尔推理报错?
我推理没遇到过这个错,但是在torch 导出的时候有用随机输入去check,这个时候我见过out of index,我当时并不知道什么情况,我只是简单的把这个 check 关掉了。现在想来应该是这个问题导致的
嗯嗯 导出的时候也是有问题我才能debug的。另外我也遇到好像用导出的模型推理得到的效果没有用python推理的好, 不知道什么问题。然后torchscript这个怎么能优化性能呢,推理一次要好几秒。我还得用rust并行处理多个请求,就会更慢。
@L-jasmine export_torch_script.py里T2SModel里的forward在返回的时候是不是应该改成-idx:-1,把最后一个删掉。因为我推理的时候有时会报out of index,然后发现这里最后一个会是1024,导致embedding的时候越界。但我不知道怎么改最好,改成到-1至少没有报错。
y[0, -1] = 0 这样可以吗?我其实也不懂这些是啥东西,我只是抄别的部分的代码。我看 onnx_export.py 里面有这样一段
确实没报错了,今天上午我也遇到上面的错误了,加上就好了
速度还行,不知道怎么优化,感觉还可以优化
Any updates? Also, how to use the model in real-time / streaming?
使用onnx_export.py脚本无法导出v2模型:
输出: