高火力 DOK × OpenVoice ハンズオン

# はじめに

---

## OpenVoiceとは？

[OpenVoice](https://github.com/myshell-ai/OpenVoice/)は、ボイスクローンができるAIモデルです。OpenVoiceは、以下の特徴を持っています。


1. 正確なトーンカラーのクローニング  
2. 柔軟なボイススタイルコントロール  
3. ゼロショット学習  

---

## OpenVoice V2

OpenVoice V2は、2024年4月にリリースされました。V1と比べて、以下の特徴があります。

1. より良いオーディオ品質
2. ネイティブの多言語サポート

---

V2では、以下の言語がサポートされています。

- 英語
- 日本語
- フランス語
- スペイン語
- 中国語
- 韓国語

---

## 複数のイントネーション

英語はイントネーション別として、イギリス・アメリカ・インド・オーストラリアの4つのアクセントがサポートされています。

---

# まずは試してみる

---

## 高火力 DOKにログインする

[さくらのクラウド](https://cloud.sakura.ad.jp/)にログインしてください

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/2a6f68ee-639a-472b-b285-5f1d252b2115.png)


---

## ログインする

ユーザーコード・会員ID・パスワードは指定したものを使ってください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/ffb50626-8709-42e6-979f-0f1f76ef9f84.png)

---

## 高火力 DOKを選択する

デザインがレスポンシブなので、<font color="red">高火力 DOKのアイコンが下にある</font>かも

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/3557e3f9-8aab-41e4-baab-049d7e9e9aab.png)

---

## タスクを選ぶ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/65b9b208-5bdc-444a-ade8-22dcca2bafa2.png)

---

## タスクの新規作成を選ぶ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/19cf9826-8f96-4dc3-8c57-f58fae81d528.png)

---

## 以下の通りに入力

環境変数は `+ 追加` ボタンを押して追加してください。

- イメージ  
dok-handson.sakuracr.jp/openvoice
- 環境変数
    - TEXT
    Hello, everyone. We're holding the DOK hands-on, today.
    - LANG  
    EN

---

入力イメージ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/ac43c7e1-6e5c-49a8-83cb-86b754cf85a4.png)


---

入力が終わったら、 `作成` ボタンを押してください

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/74313c10-8107-42c8-b340-55d16a3fc1f5.png)

---

確認ダイアログが出るので、　`作成` ボタンを押してください

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/bae8e636-6aec-496c-be2c-5bcb5b7366bb.png)


---

実行中の画面です。 `状態` のところの文字で状況が判断できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/311138ae-ca9f-47f5-8a4b-a4f5bdd17fa0.png)

---

## DOKのタスクで行っていること

1. Dockerイメージの取得
1. コンテナの実行
1. コンテナの破棄

---

## メモ

- Dockerイメージの取得には、それなりに時間がかかります（10GB超えもざらなので…）
- コンテナ実行時にモデルを取得するものが多く、そこも時間がかかります
- HTTP URIは、タスク実行中にアクセスできるHTTPサーバーです  
スクリプト側でリクエストを受け取って処理できます

---

## 実行完了後

実行完了すると、 `アーティファクト` の項目に `ダウンロード` が表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/e548a6a7-63e2-4693-93c8-a3844e1fb373.png)

---

## 音声の確認

ダウンロードしたtar.gzファイルを解凍すると、MP3ファイルが確認できます。再生して、 `Hello, everyone. We're holding the DOK hands-on, today.` を話しているのを確認してください。

英語の場合、各イントネーションでのMP3ファイルが作成されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/8210e210-c898-4243-ad1c-1ea9c90b842f.png)

## リファレンス音声を作る

自分の声をクローンする場合には、まずリファレンス（参考）になる音声データが必要です。

スマートフォンのボイスレコーダーで録音したり、[Online Voice Recorder \- マイクからの音声録音](https://online-voice-recorder.com/ja/)が利用できます。

---

### 音声を録音する

ある程度長い方が良いので、[青空文庫のアクセスランキング](https://www.aozora.gr.jp/access_ranking/2009_01_txt.html)から気に入った作品を読んでみてください（3〜4分程度）。

例： [グリム兄弟　Bruder Grimm 楠山正雄訳 赤ずきんちゃん ROTKAPPCHEN](https://www.aozora.gr.jp/cards/001091/files/42311_15546.html)

---

### 音声ファイルをアップロードする

音声ファイルを、HTTPアクセスできる場所に保存します

以下は、さくらのクラウドのオブジェクトストレージを利用する例ですが、ご自身で別なクラウドストレージを使ってもらっても大丈夫です

---

### オブジェクトストレージを選択する

さくらのクラウドのホームに戻ります

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/dfa6e2ab-15ac-4aad-9fd7-c10506236821.png)

---

### オブジェクトストレージを選択

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/052c32eb-b167-4698-9509-3d927cbd6d54.png)

---

### サイトを選択

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/4f659502-9230-45ff-9150-978a293d48a4.png)

---

### バケットを選択

さらに `バケットの追加` ボタンを押してください

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/403cda92-cb9f-4e2a-8031-14240a0cb4e7.png)

---

### バケットの追加

分かりやすいものを設定してください

![FireShot Capture 541 - オブジェクトストレージ - secure.sakura.ad.jp.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/24cbf179-bff1-44a6-97f9-8628b2116f1a.jpeg)


---

### アップロード

作成したバケットを選んで、 `アップロード` ボタンを押します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/3e0070a1-e4d8-45c3-bc9c-3ee8e17a4752.png)

---

### アップロードする

`public-read` を付けておいてください

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/a7d6bc4b-a66c-4f9d-87ed-5f513299c704.png)

---

アップロードしたら、以下のURLでMP3ファイルにアクセスできるか確認してください。このURLをDOKの環境変数 `REFERENCE` として指定します。

```
https://s3.isk01.sakurastorage.jp/(バケット名)/(ファイル名).mp3
```

---

## タスクのコピー

先ほど実行完了したタスクを開きます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/64d53215-3635-4e19-85bb-2e4f88754a29.png)

---

### コピーする

`コピーして新規作成` を押します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/7ccbae7d-091b-4bb4-a3f5-b54913699907.png)

---

### リファレンスを追加する

環境変数に `REFERENCE` を追加して、先ほどアップロードしたMP3ファイルのURLを設定してください

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/72ec02c0-336a-4241-9869-9f75809b22a0.png)

---

### タスクを再実行する

タスクを再度実行して、自分の声のクローニングが成功しているか確認してください

---

# 一旦終了

ハンズオンの内容は以上になります。DOKの面白さとして「タスクをたくさん作成できる」点があります。ぜひタスクをコピーして、さまざまな条件で実行してください。

---

# ここからの流れ

ここからはDockerイメージの作成を行います。作成には1時間以上かかると思われますので、ハンズオン実施中には終わらないはずです。

---

# Dockerイメージの作り方

ここからはテクニカルな内容になります

---

## 必要なもの

- ターミナル

---

## オプショナル

- Docker

---

- 手元にDocker環境がある方は、ローカルでも構築可能です
- Docker環境がない場合は、さくらのクラウドを利用できます

---

## さくらのクラウドでサーバを立てる

さくらのクラウドのホームに戻り、 `さくらのクラウド（IaaS）` を選択します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/c9c556f6-7d17-4585-8eac-c5fe16c716cf.png)

---

## 追加ボタンを押す

`サーバ` の `追加` ボタンを押します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/c72d9011-3eb7-491a-ab9b-a093f29e9e5d.png)

---

## 情報を入力する

サーバのスペックを以下のように設定してください

- 仮想コア  
4
- メモリ  
4GB
- 新規ディスクを作成
- アーカイブ  
Ubuntu Server 24.04.1 LTS 64bit
- ディスクサイズ  
100GB
- インターネットに接続
- 管理者のパスワード  
十分分かりづらいもの
- ホスト名  
分かりやすいもの（dokなど）
- 公開鍵  
必要であれば
- サーバーの名前  
分かりやすいもの（dokなど）


---

## サーバを追加

`作成` ボタンを押します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/f7be13e9-ae6b-4447-8653-739dc8702c73.png)

---

## 確認する

確認ダイアログが出るので、 `作成` ボタンを押してください

![スクリーンショット 2025-02-19 12.17.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/33d1672a-413e-4d4c-abd6-62ce2bfc8871.png)

---

## サーバを確認

少し待つと、サーバが立ち上がります

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/e922309c-07c1-47a1-9488-10f64f1b6394.png)

---

## サーバに接続する

サーバへは ssh で接続してください。ユーザー名は `ubuntu` です。

---

## サーバ内での作業

ここからはサーバ内（またはローカル）での作業になります

---

### Dockerのインストール

Dockerをインストールします

```
$ sudo apt-get update -y
$ curl -fsSL https://get.docker.com -o get-docker.sh
$ sudo sh ./get-docker.sh
```

---

## Dockerを試す

今のコマンドが通れば、Dockerはインストールされています

```
$ sudo docker run hello-world

Hello from Docker!
  :
For more examples and ideas, visit:
 https://docs.docker.com/get-started/
```

---

## ベースになるリポジトリ

ベースは[myshell\-ai/OpenVoice](https://github.com/myshell-ai/OpenVoice)を利用し、この中に必要なファイルを作成していきます。

```bash
git clone https://github.com/myshell-ai/OpenVoice.git
cd OpenVoice
```

---

## checkpoint のダウンロードと解凍

[checkpoint](https://myshell-public-repo-host.s3.amazonaws.com/openvoice/checkpoints_v2_0417.zip)をダウンロードし、 `checkpoints_v2` ディレクトリに解凍します。

```bash
$ wget https://myshell-public-repo-host.s3.amazonaws.com/openvoice/checkpoints_v2_0417.zip -O checkpoints_v2.zip
$ unzip checkpoints_v2.zip
$ rm checkpoints_v2.zip
```

---

## Dockerfile の作成

ここからはDockerfileの中で行っていきます。リポジトリの中に Dockerfile を作成して、編集してください

---

### ベースイメージ

ベースは `FROM continuumio/miniconda3` です

```Dockerfile
FROM continuumio/miniconda3
```

---

### conda の設定

condaの設定を行います

```Dockerfile
RUN conda create -n openvoice python==3.9
SHELL ["conda", "run", "-n", "openvoice", "/bin/bash", "-c"]
```

---

### 必要なライブラリのインストール

OpenVoiceはffmpegを使っているので、それをインストールします。 `/opt/artifact` はDOKのアウトプット先のディレクトリです

```Dockerfile
RUN apt-get update && \
    apt-get install -y ffmpeg && \
    mkdir /app /opt/artifact
```

---

### 必要なPythonライブラリのインストール

OpenVoiceのリポジトリのファイルをすべてコピーします。そして、OpenVoice用に[MeloTTS](https://github.com/myshell-ai/MeloTTS)をインストールします。argparseやboto3はCLI実行用です。

```Dockerfile
WORKDIR /app
COPY . .
RUN pip install -e . && \
  pip install argparse && \
  pip install boto3 && \
  pip install git+https://github.com/myshell-ai/MeloTTS.git && \
  python -m unidic download
```

---

#### docker-entrypoint.sh の準備

Docker実行の際に呼び出す `docker-entrypoint.sh` （内容は後述）を準備します

```Dockerfile
RUN chmod +x /app/docker-entrypoint.sh

# Dockerコンテナー起動時に実行するスクリプトを指定して実行
CMD ["/bin/bash", "/app/docker-entrypoint.sh"]
```

---

### Dockerfile全体

Dockerfileの全体は[GitHubリポジトリ](https://github.com/goofmint/Dok-OpenVoice-Handson/blob/main/Dockerfile)で確認してください

---

## docker-entrypoint.sh の作成

`docker-entrypoint.sh` はDockerコンテナー起動時に実行するスクリプトです。ここでは環境変数をチェックして、 `runner.py` を呼び出します。

```bash
$ wget https://raw.githubusercontent.com/goofmint/Dok-OpenVoice-Handson/refs/heads/main/docker-entrypoint.sh
```

---

#### docker-entrypoint.shの内容

行っている処理はシンプルなので、内容は[GitHubリポジトリ](https://github.com/goofmint/Dok-OpenVoice-Handson/blob/main/docker-entrypoint.sh)で確認してください

---

## runner.py の作成

runner.py は実際に処理を行うスクリプトです。まず必要なライブラリをインポートします。

```python
import os
import torch
from openvoice import se_extractor
from openvoice.api import ToneColorConverter
from melo.api import TTS
import argparse
import nltk
import boto3

nltk.download('averaged_perceptron_tagger_eng')
```

---

### パラメータの取得

`docker-entrypoint.sh` から渡されたパラメータを取得します。

```python
arg_parser = argparse.ArgumentParser()

arg_parser.add_argument(
    '--output',
    default='/opt/artifact',
    help='出力先ディレクトリを指定します。',
)
arg_parser.add_argument(
    '--text',
    default='',
    help='読み上げる文章',
)
arg_parser.add_argument(
    '--id',
    default='',
    help='タスクIDを指定します。',
)
arg_parser.add_argument(
    '--lang',
    default='JP',
    help='読み上げる言語を指定',
)
arg_parser.add_argument(
    '--reference',
    default='resources/example_reference.mp3',
    help='リファレンスの音声',
)

arg_parser.add_argument('--s3-bucket', help='S3のバケットを指定します。')
arg_parser.add_argument('--s3-endpoint', help='S3互換エンドポイントのURLを指定します。')
arg_parser.add_argument('--s3-secret', help='S3のシークレットアクセスキーを指定します。')
arg_parser.add_argument('--s3-token', help='S3のアクセスキーIDを指定します。')

args = arg_parser.parse_args()
```

---

### オブジェクトストレージ用のオブジェクトを準備

S3_ではじまる環境変数があれば、それを使ってS3オブジェクトを作成します。

```python
s3 = None
if args.s3_token and args.s3_secret and args.s3_bucket:
    # S3クライアントの作成
    s3 = boto3.client(
        's3',
        endpoint_url=args.s3_endpoint if args.s3_endpoint else None,
        aws_access_key_id=args.s3_token,
        aws_secret_access_key=args.s3_secret)
```

---

### OpenVoiceの設定

[OpenVoice/demo\_part3\.ipynb at main · myshell\-ai/OpenVoice](https://github.com/myshell-ai/OpenVoice/blob/main/demo_part3.ipynb)の内容に沿って、OpenVoiceを準備します。

```python
ckpt_converter = 'checkpoints_v2/converter'
device = "cuda:0" if torch.cuda.is_available() else "cpu"
output_dir = args.output

tone_color_converter = ToneColorConverter(f'{ckpt_converter}/config.json', device=device)
tone_color_converter.load_ckpt(f'{ckpt_converter}/checkpoint.pth')

os.makedirs(output_dir, exist_ok=True)

reference_speaker = args.reference
target_se, audio_name = se_extractor.get_se(reference_speaker, tone_color_converter, vad=True)

from melo.api import TTS

src_path = f'{output_dir}/tmp.wav'

speed = 1.0

model = TTS(language=args.lang, device=device)
speaker_ids = model.hps.data.spk2id
```

---

### 音声の生成とアップロード

音声を生成し、アップロードします。たとえば `EN` を指定した場合、インド風英語やオーストラリア風英語など複数のキーが `speaker_ids` に入ってきます。

```python
for speaker_key in speaker_ids.keys():
    speaker_id = speaker_ids[speaker_key]
    speaker_key = speaker_key.lower().replace('_', '-')
    source_se = torch.load(f'checkpoints_v2/base_speakers/ses/{speaker_key}.pth', map_location=device)
    model.tts_to_file(args.text, speaker_id, src_path, speed=speed)
    save_path = f'{args.output}/{args.id}_{speaker_key}.wav'
    # Run the tone color converter
    encode_message = "@MyShell"
    tone_color_converter.convert(
        audio_src_path=src_path, 
        src_se=source_se, 
        tgt_se=target_se, 
        output_path=save_path,
        message=encode_message)
    # オブジェクトストレージにアップロード
    if s3 is not None:
        s3.upload_file(
            Filename=save_path,
            Bucket=args.s3_bucket,
            Key=os.path.basename(save_path))
```

---

### 全体の処理

`runner.py` の全体の内容は [GitHubリポジトリ](https://github.com/goofmint/Dok-OpenVoice-Handson/blob/main/runner.py)で確認してください

---

## Dockerイメージのビルド

ここまでの内容で、Dockerイメージをビルドします

---

### コンテナレジストリの用意

Dockerイメージを登録するコンテナレジストリを作成します。さくらのクラウドのホームで、`さくらのクラウド` を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/e247a30c-bbc7-fb7e-136d-71ee2a795533.png)

---

左側のメニューの `グローバル` の中にある `コンテナレジストリ` を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/58707eb1-b602-437e-bfcc-2edcfa15c3e5.png)


---

`追加` を押して、コンテナレジストリを作成します。最低限、以下の入力が必要です。

| 項目                 | 設定                                                                      |
| -------------------- | ------------------------------------------------------------------------- |
| 名前                 | 分かりやすい、任意の名前を入力してください                                |
| コンテナレジストリ名 | ドメイン名に使われます。以下では、 `EXAMPLE.sakuracr.jp` として説明します |
| 公開設定             | Pullのみとします                                                          |

---

### ユーザーの作成

コンテナレジストリを作成したら、作成したコンテナレジストリを一覧でダブルクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/6425f493-0ce1-db62-f322-64a51867ce58.png)

---

詳細表示にて、ユーザータブをクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/79bdc51c-ea66-8d8f-c801-8f54346cf960.png)

---

`追加` ボタンを押し、ユーザーを作成します。 `YOUR_USER_NAME` と `PASSWORD` は任意のものを指定してください。

| 項目           | 設定           |
| -------------- | -------------- |
| ユーザー名     | YOUR_USER_NAME |
| パスワード     | YOUR_PASSWORD  |
| ユーザ権限設定 | All            |

---

### Dockerイメージのビルド

`EXAMPLE.sakuracr.jp` の部分は、作成したコンテナレジストリのドメイン名に置き換えてください。また、 `openvoice` は任意の名前で大丈夫です（以下はその名称で読み替えてください）。

```bash
sudo docker build \
-t EXAMPLE.sakuracr.jp/openvoice:latest .
```

---

### コンテナレジストリへのログイン

作成したコンテナレジストリにログインします。ログインIDとパスワードが求められるので、作成したものを入力してください。

```bash
sudo docker login EXAMPLE.sakuracr.jp
```

---

### イメージのプッシュ

作成したイメージをコンテナレジストリにプッシュします。イメージサイズが大きいので、数十分かかります。

```bash
sudo docker push EXAMPLE.sakuracr.jp/openvoice:latest
```

---

##  DOKで実行する

リポジトリがプッシュできたら、一番最初に行ったようにDOKでタスクを実行します。

- イメージ  
EXAMPLE.sakuracr.jp/openvoice
- 環境変数
    - TEXT
    お疲れ様でした！
    - LANG  
    JP

---

# お片付け

忘れずに停止・削除をお願いします

- さくらのクラウドのサーバ
- オブジェクトストレージ

DOKについては、特に作業はありません