初めに
LinearVC は、線形回帰のみで音声変換(Voice Conversion)を行う手法です。
Interspeech 2025 に採択された論文の実装になります。
github.com
arxiv.org
処理パイプラインは以下の3ステップで構成されています。
- WavLM Large(レイヤー6)で自己教師あり特徴量を抽出
- ソース話者とターゲット話者の特徴量から線形回帰で射影行列を学習
- 特徴量を変換し HiFiGAN で波形を生成
開発環境
環境構築
fork したリポジトリを clone します。
github.com
git clone https://github.com/ayutaz/linearvc.git
cd linearvc
pyproject.toml は以下の内容です。
PyTorch を CUDA 12.6 対応版でインストールするため、explicit = true で専用のインデックスを指定しています。
[project]
name = "linearvc"
version = "0.1.0"
description = "Add your description here"
requires-python = ">=3.13"
dependencies = [
"celer>=0.7.4",
"ipython>=9.10.0",
"jupyter>=1.1.1",
"numpy>=2.4.2",
"torch>=2.10.0",
"torchaudio>=2.10.0",
"tqdm>=4.67.3",
]
[[tool.uv.index]]
name = "pytorch-cu126"
url = "https://download.pytorch.org/whl/cu126"
explicit = true
[tool.uv.sources]
torch = [{ index = "pytorch-cu126" }]
torchaudio = [{ index = "pytorch-cu126" }]
依存パッケージをインストールします。
uv sync
データの準備
音声変換には、ソース話者(変換元)とターゲット話者(変換先)の音声データが必要です。
今回はソース話者に LibriSpeech dev-clean の話者 1272(英語男性)、ターゲット話者につくよみちゃんコーパス Vol.1(日本語女性)を使用します。
LibriSpeech dev-clean のダウンロード
mkdir -p data
cd data
wget https://www.openslr.org/resources/12/dev-clean.tar.gz
tar xzf dev-clean.tar.gz
cd ..
展開すると以下のようなディレクトリ構成になります。
data/LibriSpeech/dev-clean/
├── 1272/ # 話者ID
│ ├── 128104/ # チャプターID
│ │ ├── 1272-128104-0000.flac
│ │ ├── 1272-128104-0001.flac
│ │ └── ...
│ └── 135031/
│ └── ...
└── ...
サブセットの作成
linearvc.py の --extension オプションはソースとターゲット両方に適用されるため、拡張子を .wav に統一します。
LibriSpeech の .flac を .wav に変換し、それぞれ数ファイルずつのサブセットを作成します。
import torchaudio
from pathlib import Path
src_dir = Path("data/LibriSpeech/dev-clean/1272")
wav_dir = Path("data/subset_libri1272")
wav_dir.mkdir(exist_ok=True)
for flac_file in sorted(src_dir.rglob("*.flac"))[:3]:
wav, sr = torchaudio.load(flac_file)
out_path = wav_dir / flac_file.name.replace(".flac", ".wav")
torchaudio.save(str(out_path), wav, sr)
つくよみちゃんコーパスも同様に数ファイルコピーします。
mkdir -p data/subset_tsukuyomi
cp path/to/つくよみちゃんコーパス/02\ WAV(+12dB増幅)/VOICEACTRESS100_00{1,2,3}.wav data/subset_tsukuyomi/
実行
linearvc.py を実行して音声変換を行います。
ソース話者のディレクトリ、ターゲット話者のディレクトリ、変換したい入力音声ファイル、出力ファイル名を指定します。
文では非並列モードで話者あたり約3分以上のデータを推奨しています。そのため3-5分程度を最低限指定するようにしてください
パターン1: LibriSpeech 1272 → つくよみちゃん(英語男性 → 日本語女性)
uv run python linearvc.py \
data/subset_libri1272 \
data/subset_tsukuyomi \
data/subset_libri1272/1272-128104-0000.wav \
output.wav
実行すると以下のようなログが出力されます。
Reading from: data\subset_libri1272
Reading from: data\subset_tsukuyomi
Reading: data\subset_libri1272\1272-128104-0000.wav
Source features:
100%|██████████| 3/3 [00:00<00:00, 14.13it/s]
Target features:
100%|██████████| 3/3 [00:00<00:00, 21.18it/s]
Writing: output.wav
パターン2: つくよみちゃん → LibriSpeech 1272(日本語女性 → 英語男性)
uv run python linearvc.py \
data/subset_tsukuyomi \
data/subset_libri1272 \
data/subset_tsukuyomi/VOICEACTRESS100_001.wav \
output_tsukuyomi2libri.wav
Reading from: data\subset_tsukuyomi
Reading from: data\subset_libri1272
Reading: data\subset_tsukuyomi\VOICEACTRESS100_001.wav
Source features:
100%|██████████| 3/3 [00:00<00:00, 20.83it/s]
Target features:
100%|██████████| 3/3 [00:00<00:00, 36.68it/s]
Writing: output_tsukuyomi2libri.wav
パターン3: LibriSpeech 1272 → LibriSpeech 1462(英語男性 → 英語女性)
uv run python linearvc.py \
data/subset_libri1272 \
data/subset_libri1462 \
data/subset_libri1272/1272-128104-0000.wav \
output_libri2libri.wav
Reading from: data\subset_libri1272
Reading from: data\subset_libri1462
Reading: data\subset_libri1272\1272-128104-0000.wav
Source features:
100%|██████████| 3/3 [00:00<00:00, 20.81it/s]
Target features:
100%|██████████| 3/3 [00:00<00:00, 20.43it/s]
Writing: output_libri2libri.wav
各パターンとも output.wav が生成されていれば成功です。
精度はそれなりのものができてそうでした
参考