RvcPyInfer 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- RvcPyInfer/InferProviders.py +108 -0
- RvcPyInfer/InferTask.py +210 -0
- RvcPyInfer/RvcContext.py +125 -0
- RvcPyInfer/__init__.py +42 -0
- RvcPyInfer/__main__.py +4 -0
- RvcPyInfer/_version.py +1 -0
- RvcPyInfer/audio/audio_utils.py +346 -0
- RvcPyInfer/cli.py +112 -0
- RvcPyInfer/error/InferEnvError.py +2 -0
- RvcPyInfer/error/NotSupportedAlgorithmError.py +2 -0
- RvcPyInfer/f0_utils.py +125 -0
- RvcPyInfer/index/RvcFeatIndex.py +19 -0
- RvcPyInfer/infer_env.py +28 -0
- RvcPyInfer/onnx/ContentVec.py +38 -0
- RvcPyInfer/onnx/ModelSimplePool.py +26 -0
- RvcPyInfer/onnx/RvcGen.py +51 -0
- RvcPyInfer/onnx/export/Exporter.py +130 -0
- RvcPyInfer/onnx/export/cli.py +104 -0
- RvcPyInfer/onnx/export/direct_read_sr.py +109 -0
- RvcPyInfer/onnx/model_loader.py +41 -0
- RvcPyInfer/ov/OVCoreSingleton.py +3 -0
- RvcPyInfer/path_utils.py +10 -0
- RvcPyInfer/resource/template/export_onnx.py +249 -0
- RvcPyInfer/type_alist.py +13 -0
- RvcPyInfer/warn/InferEnvWarn.py +5 -0
- RvcPyInfer/warn/InferModelWarn.py +5 -0
- RvcPyInfer/warn/InferWarn.py +2 -0
- rvcpyinfer-0.1.0.dist-info/METADATA +158 -0
- rvcpyinfer-0.1.0.dist-info/RECORD +31 -0
- rvcpyinfer-0.1.0.dist-info/WHEEL +4 -0
- rvcpyinfer-0.1.0.dist-info/entry_points.txt +3 -0
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
# ----------------------------------------------------------------
|
|
2
|
+
# 这只是一个用于自动生成导出脚本的模板而已,它不是正常代码!
|
|
3
|
+
# ----------------------------------------------------------------
|
|
4
|
+
|
|
5
|
+
# -- Template --
|
|
6
|
+
ModelPath = None
|
|
7
|
+
ExportedPath = None
|
|
8
|
+
ParsePrefix = None
|
|
9
|
+
Root = None
|
|
10
|
+
|
|
11
|
+
ModelPath = '/./..{code.InsertionPoint.0}.././'
|
|
12
|
+
ExportedPath = '/./..{code.InsertionPoint.1}.././'
|
|
13
|
+
ParsePrefix = '/./..{code.InsertionPoint.2}.././'
|
|
14
|
+
Root = '/./..{code.InsertionPoint.3}.././'
|
|
15
|
+
|
|
16
|
+
assert ModelPath is not None, "ModelPath 不能为 None"
|
|
17
|
+
assert ExportedPath is not None, "ExportedPath 不能为 None"
|
|
18
|
+
assert ParsePrefix is not None, "ParsePrefix 不能为 None"
|
|
19
|
+
|
|
20
|
+
# 以上是需要动态生成的
|
|
21
|
+
device = "cpu" # 一般 cpu 就可以
|
|
22
|
+
|
|
23
|
+
import sys
|
|
24
|
+
if Root is not None:
|
|
25
|
+
sys.path.insert(0, Root)
|
|
26
|
+
|
|
27
|
+
def set_hook() -> None:
|
|
28
|
+
import infer.lib.infer_pack.attentions as attentions # pyright: ignore[reportMissingImports]
|
|
29
|
+
|
|
30
|
+
def attention_fix(
|
|
31
|
+
self,
|
|
32
|
+
query: attentions.torch.Tensor,
|
|
33
|
+
key: attentions.torch.Tensor,
|
|
34
|
+
value: attentions.torch.Tensor,
|
|
35
|
+
mask: attentions.Optional[attentions.torch.Tensor] = None,
|
|
36
|
+
):
|
|
37
|
+
# reshape [b, d, t] -> [b, n_h, t, d_k]
|
|
38
|
+
b, d, t_s = key.size()
|
|
39
|
+
t_t = query.size(2)
|
|
40
|
+
query = query.view(b, self.n_heads, self.k_channels, t_t).transpose(2, 3)
|
|
41
|
+
key = key.view(b, self.n_heads, self.k_channels, t_s).transpose(2, 3)
|
|
42
|
+
value = value.view(b, self.n_heads, self.k_channels, t_s).transpose(2, 3)
|
|
43
|
+
|
|
44
|
+
scores = attentions.torch.matmul(query / attentions.math.sqrt(self.k_channels), key.transpose(-2, -1))
|
|
45
|
+
if self.window_size is not None:
|
|
46
|
+
# source: assert (
|
|
47
|
+
# source: t_s == t_t
|
|
48
|
+
# source: ), "Relative attention is only available for self-attention."
|
|
49
|
+
if not attentions.torch.jit.is_tracing(): # 大概率是没有问题的,大不了咱直接抛维度错误
|
|
50
|
+
attentions.torch._assert(
|
|
51
|
+
t_s == t_t,
|
|
52
|
+
"Relative attention is only available for self-attention."
|
|
53
|
+
)
|
|
54
|
+
key_relative_embeddings = self._get_relative_embeddings(self.emb_rel_k, t_s)
|
|
55
|
+
rel_logits = self._matmul_with_relative_keys(
|
|
56
|
+
query / attentions.math.sqrt(self.k_channels), key_relative_embeddings
|
|
57
|
+
)
|
|
58
|
+
scores_local = self._relative_position_to_absolute_position(rel_logits)
|
|
59
|
+
scores = scores + scores_local
|
|
60
|
+
if self.proximal_bias:
|
|
61
|
+
# source: assert t_s == t_t, "Proximal bias is only available for self-attention."
|
|
62
|
+
if not attentions.torch.jit.is_tracing():
|
|
63
|
+
attentions.torch._assert(
|
|
64
|
+
t_s == t_t,
|
|
65
|
+
"Proximal bias is only available for self-attention."
|
|
66
|
+
)
|
|
67
|
+
scores = scores + self._attention_bias_proximal(t_s).to(
|
|
68
|
+
device=scores.device, dtype=scores.dtype
|
|
69
|
+
)
|
|
70
|
+
if mask is not None:
|
|
71
|
+
scores = scores.masked_fill(mask == 0, -1e4)
|
|
72
|
+
if self.block_length is not None:
|
|
73
|
+
# source: assert (
|
|
74
|
+
# source: t_s == t_t
|
|
75
|
+
# source: ), "Local attention is only available for self-attention."
|
|
76
|
+
if not attentions.torch.jit.is_tracing():
|
|
77
|
+
attentions.torch._assert(
|
|
78
|
+
t_s == t_t,
|
|
79
|
+
"Local attention is only available for self-attention."
|
|
80
|
+
)
|
|
81
|
+
block_mask = (
|
|
82
|
+
attentions.torch.ones_like(scores)
|
|
83
|
+
.triu(-self.block_length)
|
|
84
|
+
.tril(self.block_length)
|
|
85
|
+
)
|
|
86
|
+
scores = scores.masked_fill(block_mask == 0, -1e4)
|
|
87
|
+
p_attn = attentions.F.softmax(scores, dim=-1) # [b, n_h, t_t, t_s]
|
|
88
|
+
p_attn = self.drop(p_attn)
|
|
89
|
+
output = attentions.torch.matmul(p_attn, value)
|
|
90
|
+
if self.window_size is not None:
|
|
91
|
+
relative_weights = self._absolute_position_to_relative_position(p_attn)
|
|
92
|
+
value_relative_embeddings = self._get_relative_embeddings(
|
|
93
|
+
self.emb_rel_v, t_s
|
|
94
|
+
)
|
|
95
|
+
output = output + self._matmul_with_relative_values(
|
|
96
|
+
relative_weights, value_relative_embeddings
|
|
97
|
+
)
|
|
98
|
+
output = (
|
|
99
|
+
output.transpose(2, 3).contiguous().view(b, d, t_t)
|
|
100
|
+
) # [b, n_h, t_t, d_k] -> [b, d, t_t]
|
|
101
|
+
return output, p_attn
|
|
102
|
+
attentions.MultiHeadAttention.attention = attention_fix
|
|
103
|
+
|
|
104
|
+
def _get_relative_embeddings_fix(self, relative_embeddings, length: int):
|
|
105
|
+
max_relative_position = 2 * self.window_size + 1 # 不知道有什么用,反正不敢删
|
|
106
|
+
# Pad first before slice to avoid using cond ops.
|
|
107
|
+
pad_length: int = attentions.torch.clamp(length - (self.window_size + 1), min=0)
|
|
108
|
+
slice_start_position = attentions.torch.clamp((self.window_size + 1) - length, min=0)
|
|
109
|
+
slice_end_position = slice_start_position + 2 * length - 1
|
|
110
|
+
# source: if pad_length > 0:
|
|
111
|
+
if True: # pad 0 那不就是没有 pad嘛,搞个分支干什么,我还得改
|
|
112
|
+
padded_relative_embeddings = attentions.F.pad(
|
|
113
|
+
relative_embeddings,
|
|
114
|
+
# commons.convert_pad_shape([[0, 0], [pad_length, pad_length], [0, 0]]),
|
|
115
|
+
[0, 0, pad_length, pad_length, 0, 0],
|
|
116
|
+
)
|
|
117
|
+
else:
|
|
118
|
+
padded_relative_embeddings = relative_embeddings
|
|
119
|
+
used_relative_embeddings = padded_relative_embeddings[
|
|
120
|
+
:, slice_start_position:slice_end_position
|
|
121
|
+
]
|
|
122
|
+
return used_relative_embeddings
|
|
123
|
+
attentions.MultiHeadAttention._get_relative_embeddings = _get_relative_embeddings_fix
|
|
124
|
+
|
|
125
|
+
def _relative_position_to_absolute_position_fix(self, x):
|
|
126
|
+
"""
|
|
127
|
+
x: [b, h, l, 2*l-1]
|
|
128
|
+
ret: [b, h, l, l]
|
|
129
|
+
"""
|
|
130
|
+
batch, heads, length, _ = x.size()
|
|
131
|
+
# Concat columns of pad to shift from relative to absolute indexing.
|
|
132
|
+
x = attentions.F.pad(
|
|
133
|
+
x,
|
|
134
|
+
# commons.convert_pad_shape([[0, 0], [0, 0], [0, 0], [0, 1]])
|
|
135
|
+
[0, 1, 0, 0, 0, 0, 0, 0],
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
# Concat extra elements so to add up to shape (len+1, 2*len-1).
|
|
139
|
+
x_flat = x.view([batch, heads, length * 2 * length])
|
|
140
|
+
x_flat = attentions.F.pad(
|
|
141
|
+
x_flat,
|
|
142
|
+
# commons.convert_pad_shape([[0, 0], [0, 0], [0, int(length) - 1]])
|
|
143
|
+
# source: [0, int(length) - 1, 0, 0, 0, 0],
|
|
144
|
+
[0, length - 1, 0, 0, 0, 0],
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
# Reshape and slice out the padded elements.
|
|
148
|
+
x_final = x_flat.view([batch, heads, length + 1, 2 * length - 1])[
|
|
149
|
+
:, :, :length, length - 1 :
|
|
150
|
+
]
|
|
151
|
+
return x_final
|
|
152
|
+
attentions.MultiHeadAttention._relative_position_to_absolute_position = _relative_position_to_absolute_position_fix
|
|
153
|
+
|
|
154
|
+
def _absolute_position_to_relative_position_fix(self, x):
|
|
155
|
+
"""
|
|
156
|
+
x: [b, h, l, l]
|
|
157
|
+
ret: [b, h, l, 2*l-1]
|
|
158
|
+
"""
|
|
159
|
+
batch, heads, length, _ = x.size()
|
|
160
|
+
# padd along column
|
|
161
|
+
x = attentions.F.pad(
|
|
162
|
+
x,
|
|
163
|
+
# commons.convert_pad_shape([[0, 0], [0, 0], [0, 0], [0, int(length) - 1]])
|
|
164
|
+
# source: [0, int(length) - 1, 0, 0, 0, 0, 0, 0],
|
|
165
|
+
[0, length - 1, 0, 0, 0, 0, 0, 0],
|
|
166
|
+
)
|
|
167
|
+
# source: x_flat = x.view([batch, heads, int(length**2) + int(length * (length - 1))])
|
|
168
|
+
x_flat = x.view([batch, heads, length**2 + length * (length - 1)])
|
|
169
|
+
# add 0's in the beginning that will skew the elements after reshape
|
|
170
|
+
x_flat = attentions.F.pad(
|
|
171
|
+
x_flat,
|
|
172
|
+
# commons.convert_pad_shape([[0, 0], [0, 0], [int(length), 0]])
|
|
173
|
+
[length, 0, 0, 0, 0, 0],
|
|
174
|
+
)
|
|
175
|
+
x_final = x_flat.view([batch, heads, length, 2 * length])[:, :, :, 1:]
|
|
176
|
+
return x_final
|
|
177
|
+
|
|
178
|
+
attentions.MultiHeadAttention._absolute_position_to_relative_position = _absolute_position_to_relative_position_fix
|
|
179
|
+
|
|
180
|
+
def main():
|
|
181
|
+
import torch # pyright: ignore[reportMissingImports]
|
|
182
|
+
|
|
183
|
+
cpt = torch.load(ModelPath, map_location="cpu")
|
|
184
|
+
cpt["config"][-3] = cpt["weight"]["emb_g.weight"].shape[0]
|
|
185
|
+
print(f'{ParsePrefix}/./..{{"sr":{cpt["config"][-1]}}}.././')
|
|
186
|
+
version = cpt["version"]
|
|
187
|
+
hidden_channels = 256 if version == "v1" else 768
|
|
188
|
+
|
|
189
|
+
test_phone = torch.rand(1, 200, hidden_channels) # hidden unit
|
|
190
|
+
test_phone_lengths = torch.tensor([200]).long() # hidden unit 长度(貌似没啥用)
|
|
191
|
+
test_pitch = torch.randint(size=(1, 200), low=5, high=255) # 基频(单位赫兹)
|
|
192
|
+
test_pitchf = torch.rand(1, 200) # nsf基频
|
|
193
|
+
test_ds = torch.LongTensor([0]) # 说话人ID
|
|
194
|
+
test_rnd = torch.rand(1, 192, 200) # 噪声(加入随机因子)
|
|
195
|
+
|
|
196
|
+
set_hook() # 强制误差调整大法!强制替换不支持追踪的实现
|
|
197
|
+
|
|
198
|
+
from infer.lib.infer_pack.models_onnx import SynthesizerTrnMsNSFsidM # pyright: ignore[reportMissingImports]
|
|
199
|
+
|
|
200
|
+
net_g = SynthesizerTrnMsNSFsidM(
|
|
201
|
+
*cpt["config"], version=version, is_half=False
|
|
202
|
+
) # fp32导出(C++要支持fp16必须手动将内存重新排列所以暂时不用fp16)
|
|
203
|
+
net_g.load_state_dict(cpt["weight"], strict=False)
|
|
204
|
+
input_names = ["phone", "phone_lengths", "pitch", "pitchf", "ds", "rnd"]
|
|
205
|
+
output_names = [
|
|
206
|
+
"audio",
|
|
207
|
+
]
|
|
208
|
+
# net_g.construct_spkmixmap(n_speaker) 多角色混合轨道导出
|
|
209
|
+
|
|
210
|
+
try:
|
|
211
|
+
torch.onnx.export(
|
|
212
|
+
net_g,
|
|
213
|
+
(
|
|
214
|
+
test_phone.to(device),
|
|
215
|
+
test_phone_lengths.to(device),
|
|
216
|
+
test_pitch.to(device),
|
|
217
|
+
test_pitchf.to(device),
|
|
218
|
+
test_ds.to(device),
|
|
219
|
+
test_rnd.to(device),
|
|
220
|
+
),
|
|
221
|
+
ExportedPath,
|
|
222
|
+
dynamic_axes={ # 记得批处理维度!
|
|
223
|
+
"phone": {0: "batch_size", 1: "frame_sequence"},
|
|
224
|
+
"pitch": {0: "batch_size", 1: "frame_sequence"},
|
|
225
|
+
"pitchf": {0: "batch_size", 1: "frame_sequence"},
|
|
226
|
+
"rnd": {0: "batch_size", 2: "frame_sequence"},
|
|
227
|
+
"audio": {0: "batch_size", 2: "sampling_sequence"}
|
|
228
|
+
},
|
|
229
|
+
do_constant_folding=False,
|
|
230
|
+
opset_version=16, # 其实我觉得可以更高
|
|
231
|
+
verbose=False,
|
|
232
|
+
input_names=input_names,
|
|
233
|
+
output_names=output_names,
|
|
234
|
+
)
|
|
235
|
+
except Exception as e:
|
|
236
|
+
old_line = "\n"
|
|
237
|
+
new_line = "\\n" # python 的奇妙切词
|
|
238
|
+
old_str = "\""
|
|
239
|
+
new_str = "\\\""
|
|
240
|
+
print(f'{ParsePrefix}/./..{{"status":"fail","msg":"{str(e).replace(old_line, new_line).replace(old_str, new_str)}"}}.././')
|
|
241
|
+
import traceback
|
|
242
|
+
traceback.print_exc()
|
|
243
|
+
sys.exit(1)
|
|
244
|
+
|
|
245
|
+
print(f'{ParsePrefix}/./..{{"status":"success"}}.././')
|
|
246
|
+
sys.exit(0)
|
|
247
|
+
|
|
248
|
+
if __name__ == "__main__":
|
|
249
|
+
main()
|
RvcPyInfer/type_alist.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from typing import BinaryIO, Literal
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
from numpy.typing import NDArray
|
|
6
|
+
|
|
7
|
+
type PathLike = str | Path
|
|
8
|
+
type FileLike = PathLike | BinaryIO
|
|
9
|
+
type Audio = tuple[NDArray[np.float32], int]
|
|
10
|
+
type AudioLike = FileLike | Audio
|
|
11
|
+
|
|
12
|
+
F0ExtractAlgorithmList = ["dio", "harvest"]
|
|
13
|
+
type F0ExtractAlgorithm = Literal["dio", "harvest"]
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: RvcPyInfer
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Rvc 的 ONNX 模型导出格式推理实现
|
|
5
|
+
Project-URL: Homepage, https://github.com/TwoCreepers/RvcPyInfer
|
|
6
|
+
Project-URL: Repository, https://github.com/TwoCreepers/RvcPyInfer
|
|
7
|
+
Author: 观赏鱼
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
Requires-Python: >=3.13
|
|
10
|
+
Requires-Dist: numpy>=2.3
|
|
11
|
+
Requires-Dist: pyworld>=0.3.5
|
|
12
|
+
Requires-Dist: samplerate>=0.2.4
|
|
13
|
+
Requires-Dist: soundfile>=0.14.0
|
|
14
|
+
Provides-Extra: cpu
|
|
15
|
+
Requires-Dist: onnxruntime>=1.27.0; extra == 'cpu'
|
|
16
|
+
Provides-Extra: cuda
|
|
17
|
+
Requires-Dist: onnxruntime-gpu>=1.27.0; extra == 'cuda'
|
|
18
|
+
Provides-Extra: dev
|
|
19
|
+
Requires-Dist: pyright>=1.1.411; extra == 'dev'
|
|
20
|
+
Requires-Dist: ruff>=0.15.21; extra == 'dev'
|
|
21
|
+
Provides-Extra: dml
|
|
22
|
+
Requires-Dist: onnxruntime-directml>=1.24.4; extra == 'dml'
|
|
23
|
+
Provides-Extra: index
|
|
24
|
+
Requires-Dist: faiss-cpu>=1.14.3; extra == 'index'
|
|
25
|
+
Provides-Extra: openvino
|
|
26
|
+
Requires-Dist: openvino>=2026.2.1; extra == 'openvino'
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
|
|
29
|
+
# [RvcPyInfer](https://github.com/TwoCreepers/RvcPyInfer)
|
|
30
|
+
|
|
31
|
+
[](https://mit-license.org/)
|
|
32
|
+
[](https://www.python.org/downloads/)
|
|
33
|
+

|
|
34
|
+
|
|
35
|
+
[RVC](https://github.com/RVC-Project/Retrieval-based-Voice-Conversion-WebUI) 的 ONNX 模型导出格式推理实现。
|
|
36
|
+
|
|
37
|
+
- 支持原 RVC 项目的 ONNX 模型推理。
|
|
38
|
+
- 跨平台支持多种推理引擎(CPU, CUDA, DirectML, OpenVINO)。
|
|
39
|
+
- 提供 Windows 下一键导出 ONNX 模型的 CLI 工具。
|
|
40
|
+
- 兼容原项目的 `.index` 特征索引文件。
|
|
41
|
+
|
|
42
|
+
## Python 版本需求
|
|
43
|
+
本项目要求 Python 版本 `>= 3.13`。由于项目代码中使用了 `Python 3.12+` 引入的 `TypeParam` 等现代语法特性,因此无法向下兼容更低版本的 Python。
|
|
44
|
+
~~并且推理真的很难测试欸。~~
|
|
45
|
+
|
|
46
|
+
## 安装
|
|
47
|
+
本库尚未上传至 [PyPI](https://pypi.org) ,我们还在筹备这方面的工作。
|
|
48
|
+
你可以直接 clone 该仓库然后使用如下命令构建 `.whl` 文件。
|
|
49
|
+
```shell
|
|
50
|
+
# 克隆该仓库
|
|
51
|
+
git clone https://github.com/TwoCreepers/RvcPyInfer.git
|
|
52
|
+
# 进入该仓库目录
|
|
53
|
+
cd RvcPyInfer
|
|
54
|
+
# 使用 uv 构建
|
|
55
|
+
uv build
|
|
56
|
+
# 安装生成的 wheel 包 (以实际文件名为准)
|
|
57
|
+
pip install ./dist/rvcpyinfer-0.1.0-py3-none-any.whl
|
|
58
|
+
```
|
|
59
|
+
不出意外的话,现在你需要的轮子文件应该出现在 `dist/` 下面了。
|
|
60
|
+
这里出现的 [`uv`](https://github.com/astral-sh/uv) 是一个使用 `Rust` 编写的 `Python` 项目管理工具。
|
|
61
|
+
它可以为你剩下非常多在依赖管理方面的麻烦,就比如上面的 `uv build` 它会自动为你生成虚拟环境并安装好依赖。
|
|
62
|
+
当然了, [`uv`](https://github.com/astral-sh/uv) 不是必须的,我们使用 [`hatchling`](https://pypi.org/project/hatchling) 作为构建后端,你可以自己研究一下如何构建。
|
|
63
|
+
|
|
64
|
+
或者你也可以直接把当前项目作为库安装,例如:
|
|
65
|
+
```shell
|
|
66
|
+
# 假设你已经在仓库目录里了
|
|
67
|
+
pip install .
|
|
68
|
+
# 如果需要安装 CPU 引擎和特征索引支持的话是
|
|
69
|
+
pip install ".[cpu,index]"
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
## 关于特征模型
|
|
74
|
+
你可以在[这里](https://huggingface.co/NaruseMioShirakana/MoeSS-SUBModel/tree/main)找到 `MoeSS` 使用的 `onnx` 特征模型。它们是通用的。
|
|
75
|
+
**通常情况下最常见的 `v2` 版本的生成器模型使用的是 `vec-768-layer-12.onnx`**
|
|
76
|
+
|
|
77
|
+
## 关于推理引擎
|
|
78
|
+
你可能已经看到了那个未安装任何推理引擎的警告或者错误。
|
|
79
|
+
请在安装命令后面添加 `[xxx]` 来安装可选依赖。
|
|
80
|
+
例如:
|
|
81
|
+
```shell
|
|
82
|
+
# 假设你已经在 dist/ 目录下构建好了 whl 文件
|
|
83
|
+
pip install "./dist/rvcpyinfer-0.1.0-py3-none-any[cpu]"
|
|
84
|
+
```
|
|
85
|
+
目前我们支持以下推理引擎:
|
|
86
|
+
|
|
87
|
+
- `onnxruntime`
|
|
88
|
+
- `[cpu]`:ONNX Runtime (CPU),通用
|
|
89
|
+
- `[cuda]`:ONNX Runtime (CUDA),Nvidia GPU 加速
|
|
90
|
+
- `[dml]`:ONNX Runtime (DML),Windows DirectML 加速
|
|
91
|
+
- `openvino`
|
|
92
|
+
- `[openvino]`:OpenVINO,Intel 硬件加速
|
|
93
|
+
|
|
94
|
+
请注意 `onnxruntime` 的三个可选依赖是互斥的,你只能选择其中的一个。
|
|
95
|
+
关于 `openvino` 的 `IR` 格式,本库会转换 `IR` 格式并存档在 `.onnx` 同目录下的同名文件中,以便在下一次加载时加速,该行为目前无法被禁用。
|
|
96
|
+
|
|
97
|
+
## 关于特征索引
|
|
98
|
+
原项目的 `.index` 文件可直接使用,无需转换。
|
|
99
|
+
但你需要使用 `[index]` 来安装我们需要用于读取特征索引的依赖—— `faiss`。
|
|
100
|
+
|
|
101
|
+
## 快速使用
|
|
102
|
+
一个简单的示例:
|
|
103
|
+
```python
|
|
104
|
+
import RvcPyInfer
|
|
105
|
+
|
|
106
|
+
context = RvcPyInfer.RvcContext() # 创建一个上下文
|
|
107
|
+
|
|
108
|
+
task = context.build_task(
|
|
109
|
+
"./你的特征模型.onnx",
|
|
110
|
+
"./你的 Rvc 生成器模型.onnx",
|
|
111
|
+
48000, # 你的 Rvc 生成器模型的生成采样率
|
|
112
|
+
"./你要推理的源文件.wav", # 可以填多个源文件
|
|
113
|
+
# 后续可选参数需显式写明名称,例如:
|
|
114
|
+
sid=1, # 说话者 id,一般情况下就是 0
|
|
115
|
+
seed=4321 # 噪声种子,默认 1234
|
|
116
|
+
)
|
|
117
|
+
task.run_and_save(
|
|
118
|
+
"./你要保存的结果.wav" # 请注意,它不会自动创建目录
|
|
119
|
+
)
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## CLI
|
|
123
|
+
我们已经预制了一些 `CLI` 在库中了,并随库一并打包。
|
|
124
|
+
以下是库内置的命令:
|
|
125
|
+
- `rvc-infer`:用以快速推理模型而无需编写代码
|
|
126
|
+
- `rvc-model`:与原项目模型相关的命令
|
|
127
|
+
|
|
128
|
+
### rvc-infer
|
|
129
|
+
最简格式: `rvc-infer --vec-model <你的特征模型路径> --gen-model <你的生成器模型路径> --gen-model-sr <你的生成器模型的输出采样率> -i <输入音频文件路径> -o <输出音频文件路径>`
|
|
130
|
+
**Tips:可出现多个 -i 和 -o,只要它们的数量一致,多个 -i 和 -o 按出现顺序一一对应。**
|
|
131
|
+
|
|
132
|
+
### rvc-model
|
|
133
|
+
该命令用于查看原项目的 `.pth` 模型的生成采样率,以及在 `Windows` 上快速导出 onnx 模型。
|
|
134
|
+
|
|
135
|
+
#### rvc-model show-sr
|
|
136
|
+
格式: `rvc-model show-sr -m <你的pth模型路径>`
|
|
137
|
+
|
|
138
|
+
#### rvc-model export
|
|
139
|
+
**⚠️注意:你必须安装源项目的整合包或至少有一个能运行源项目的环境以便 `PyTorch` 导出 `.onnx` 模型。**
|
|
140
|
+
它并不依赖项目内置的 `tools/export_onnx.py` 我们有自己的方法。
|
|
141
|
+
~~事实上原项目的 export_onnx.py 甚至没有做 v2 版本的支持~~
|
|
142
|
+
格式: `rvc-model export -m <你的pth模型路径> -t <你希望输出到哪> -r <rvc 原项目的根路径> --runtime <可选的导出用的 python 解释器路径,默认使用 rvc 原项目整合包自带的解释器>`
|
|
143
|
+
|
|
144
|
+
## 未来的计划
|
|
145
|
+
- [ ] Github Action 可重现性构建流水线
|
|
146
|
+
- [ ] 发布至 PyPI
|
|
147
|
+
|
|
148
|
+
## 许可证
|
|
149
|
+
在文件头部或文件所在目录未有额外说明的情况下,本项目代码部分使用 [`MIT`](https://mit-license.org/) 许可证授权与你,非代码部分使用 `CC BY 4.0` 授权与你。
|
|
150
|
+
|
|
151
|
+
## 🎉鸣谢
|
|
152
|
+
|
|
153
|
+
- [原项目组的所有成员](https://github.com/RVC-Project)
|
|
154
|
+
没有TA们的付出就没有 RVC 模型,该项目也不会出现
|
|
155
|
+
- [提前打好特征模型 ONNX 的 MoeSS](https://github.com/Miuzarte/MoeSS)
|
|
156
|
+
省去了诸多导出特征模型的麻烦
|
|
157
|
+
- [帮了作者很多的 GLM AI](https://chatglm.cn)
|
|
158
|
+
省去了很多查资料和写 CLI 的时间
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
RvcPyInfer/InferProviders.py,sha256=8Jn3Xi90wjrLU83egM7C24PCUFajWm75CI-pMXrFzJ4,4378
|
|
2
|
+
RvcPyInfer/InferTask.py,sha256=7UyUzDID-yvZO_2m65gB7KnshKmHVutpFjle7catB0c,8004
|
|
3
|
+
RvcPyInfer/RvcContext.py,sha256=v1Y9RxFj_L9iYc6FUvkxohov2qGQRxSFB-Y3FBcHvjA,4494
|
|
4
|
+
RvcPyInfer/__init__.py,sha256=rHx3jplir7VUN_dLb8ynuUXTo7h_c-5BnZLW8iKl58w,1424
|
|
5
|
+
RvcPyInfer/__main__.py,sha256=SXbzIbZgMuLH5wS9awdNRWoZLXoEu5WvWJ953gGTRIs,80
|
|
6
|
+
RvcPyInfer/_version.py,sha256=Pru0BlFBASFCFo7McHdohtKkUtgMPDwbGfyUZlE2_Vw,21
|
|
7
|
+
RvcPyInfer/cli.py,sha256=WsdGmsZqnYabLOhayq56-lZW2u7FkV7JLpzT2xlPDeg,5053
|
|
8
|
+
RvcPyInfer/f0_utils.py,sha256=WoGjxNDqmJdD5_p25_aqEJA0MrhyRQtHgyrEE2E13F8,4418
|
|
9
|
+
RvcPyInfer/infer_env.py,sha256=8bS1bkzLIqw6aKubGbfOiQXp6aIdVH4cHxP-pakZZd0,691
|
|
10
|
+
RvcPyInfer/path_utils.py,sha256=W2VP1xe3Cev5eDeBb_GNkn9o-ObcQ1LD89HFY1-4090,180
|
|
11
|
+
RvcPyInfer/type_alist.py,sha256=WuSioYk5b5LhqcusGPzY0oZJOA-k1S1d_x0hb54ZV2E,354
|
|
12
|
+
RvcPyInfer/audio/audio_utils.py,sha256=xw-sDPA6z-IBpfL6Od0-M8eHVCNSfljuZE8zm6GgJtY,11629
|
|
13
|
+
RvcPyInfer/error/InferEnvError.py,sha256=oBWiXBQBTbWlsxYKRtcKMnFK_c1yITqtT-pXeEDU4po,40
|
|
14
|
+
RvcPyInfer/error/NotSupportedAlgorithmError.py,sha256=_daqjLlyN-vXgcogrwi1RCNzv17YzWSMH6--TOdhAQM,53
|
|
15
|
+
RvcPyInfer/index/RvcFeatIndex.py,sha256=b4XOblLwf3y72RQjqYnL16kw5Xp4PySyTp631wZKooM,836
|
|
16
|
+
RvcPyInfer/onnx/ContentVec.py,sha256=phpD0tZa4EobEa7xXkm4035VsXuVZ5I9nvxaKx4-eGc,1581
|
|
17
|
+
RvcPyInfer/onnx/ModelSimplePool.py,sha256=w9A3SU9H8tkBxlGV5qkHCirSEYpQpddhId3nAt6YwVI,824
|
|
18
|
+
RvcPyInfer/onnx/RvcGen.py,sha256=EApnlYIXRNwk6jPa5ERnbyjlzIuwmyBm98hkZxoPRTU,2330
|
|
19
|
+
RvcPyInfer/onnx/model_loader.py,sha256=0daGfPzWWZ4RzOF55zvGNa1wnOfwW_-XNf50NhRF88s,2156
|
|
20
|
+
RvcPyInfer/onnx/export/Exporter.py,sha256=pVTa9H1NhIkPMjpvMFNqJYWQFAsutdmgC8Z9QOkiJrc,5138
|
|
21
|
+
RvcPyInfer/onnx/export/cli.py,sha256=cdP1MG9Pp3nkRpnQQNS1gOVi_Jk7bs894C82PKooliA,3640
|
|
22
|
+
RvcPyInfer/onnx/export/direct_read_sr.py,sha256=rQPdaXjK0PTqjGeqLRwmegSg2ETXgEwjMcfBNPa4NDQ,3775
|
|
23
|
+
RvcPyInfer/ov/OVCoreSingleton.py,sha256=JpYEZ0lo3vqlbhIVsvd32oufcbQ5rw7ErHZDljUnyJM,80
|
|
24
|
+
RvcPyInfer/resource/template/export_onnx.py,sha256=GEDb2qoD5a8XEKzWB5ZCJdQYV6fdxrR2gUjw1J9aLR0,10817
|
|
25
|
+
RvcPyInfer/warn/InferEnvWarn.py,sha256=H3ibEJULsZi_qhXOHNLDwZ62Cb9Dkp2MRNmVer4jeSA,74
|
|
26
|
+
RvcPyInfer/warn/InferModelWarn.py,sha256=xdiOonWO1DA0gsxC1j4kEIK9RMb14ea5un_lqhGgqEA,76
|
|
27
|
+
RvcPyInfer/warn/InferWarn.py,sha256=I4lXXhtlowlkxESwX823fbALCRu7UUy9Cge4NJij5tg,34
|
|
28
|
+
rvcpyinfer-0.1.0.dist-info/METADATA,sha256=frDwFbzgS8iULMJbQt6wstCxmQ-OT0RKfLKKbX230tE,7143
|
|
29
|
+
rvcpyinfer-0.1.0.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
|
|
30
|
+
rvcpyinfer-0.1.0.dist-info/entry_points.txt,sha256=dfU76sq76486FT-4NFaMhwL-j8fyoApLcLMExRRmqc4,105
|
|
31
|
+
rvcpyinfer-0.1.0.dist-info/RECORD,,
|