HuBERTを初心者に使ってもらう

## はじめに


### この記事の目的

- HuBERTの概要を知る  
- HuBERTを使えるようになる 

HuBERTを使ってみたい機械学習初心者が目標を達成できるように最小限の知識を解説します。  
今回は日本語のデータで事前学習されている[rinna様のモデル](https://rinna.co.jp/news/2023/04/20230428.html)の使い方を解説します。  
HuBERTの元の論文は[こちら](https://arxiv.org/pdf/2106.07447)


### 対象読者  
- 機械学習実装の流れは知ってる
- なにか１つのモデルを勉強したことがある  
- HuBERTを使ってみたい


## ０．HuBERTに向けた前提知識  


### 埋め込みとは  
機械学習において埋め込みとはベクトル表現を表します。  
現実世界の特徴を捉えた埋め込みを作成することで分類などを行えるようになります。  
ここでは、**入力データの特徴を捉えた100次元以上のでっかいベクトル**と思ってください。

[AWS様の具体的な説明](https://aws.amazon.com/jp/what-is/embeddings-in-machine-learning/)  
[IBM様の詳しい説明](https://www.ibm.com/jp-ja/topics/embedding)  


### 自己教師あり学習  
HuBERTは自己教師あり学習という手法が使われます。  
自己教師あり学習はラベルが不要で多くのデータを簡単に学習させることができます。  
自己教師あり学習の手法は様々ですが、今回は**学習に使ったデータの特徴を勝手に学習してくれる便利なもの**と思ってください。

詳しく知りたい方は[HubERTの元の論文](https://arxiv.org/pdf/2106.07447)が分かりやすいです。  


## １．HuBERTの特徴

HuBERTは、音声データから埋め込みを出力するモデルです。  
音声データは扱う上で３つの問題があります。  

**➀ 各入力発話に複数の音声単位がある**  
**➁ 事前トレーニング段階では入力音声単位の語彙集がない**  
**➂ 音声単位の長さは可変で、明示的なセグメンテーションがない**
  
少し難しいですが、音声データは扱うのが大変でHuBERTがうまくこの問題を解決しています。


### HuBERTの仕組み  
まずは[公式ドキュメント](https://huggingface.co/docs/transformers/model_doc/hubert)からモデルの入力と出力を見てみます。  

| 項目 | 説明 |
| --- | --- |
| **入力** | Float values of input raw speech waveform. |
| **入力の形** | `(batch_size, sequence_length)` |
| **出力** | Sequence of hidden-states at the output of the last layer of the model.|
| **出力の形** | `(batch_size, sequence_length, hidden_size)` |

入力は音声の波をテンソルに変換したもので、出力は最後の隠れ層の状態を表します。  

つまり音声を入力すると、音声をユニットに分け、各ユニットの埋め込みを出力してくれるようです。  

イメージ図を作りました。  
![スクリーンショット 2024-06-11 153432.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3808337/f771da26-42f4-e365-8ea4-5fa61c1d5f91.png)



### どんな時にHuBERTを使うか  

HuBERTから得られる埋め込みを利用することで、さまざまなタスクに取り組むことができます。

- **音声認識**：音声からテキストへの変換
- **音声分類**：感情認識、話者認識、音響イベント認識など
- **音声合成**：テキストから音声への変換


## ２． HuBERTの実装

HuBERTを使って音声データを処理し、埋め込みを取得してみようと思います。  
埋め込みの応用やファインチューニングについては機会があれば別の記事で解説していきたいと思います。

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

まず、必要なライブラリをインストールします。以下のコマンドを実行してください：

```python
!pip install torchaudio transformers
```

### HuBERTの実装

HuBERTを使って音声データを処理し、埋め込みを取得してみます。  
Google Colabで実行してみてください。

```python
import torch
import torchaudio
import librosa
import soundfile as sf
from transformers import AutoFeatureExtractor, AutoModel
    
# wavファイルの読み込み（wav形式の音声データを読み混みます。
raw_speech, sr = sf.read("/content/drive/MyDrive/audio.wav") # パスを変更
    
# サンプリングレートの変換
if sr != 16000:
    raw_speech_16kHz = librosa.resample(raw_speech, orig_sr=sr, target_sr=16000)
else:
    raw_speech_16kHz = raw_speech

# モデルと特徴量抽出器の準備
model_name = "rinna/japanese-hubert-base"
feature_extractor = AutoFeatureExtractor.from_pretrained(model_name)
model = AutoModel.from_pretrained(model_name)
model.eval()

# 特徴量の抽出（モデルと形式を合わせるために転置してます）
inputs = feature_extractor(raw_speech_16kHz, sampling_rate=16000, return_tensors="pt")
inputs['input_values'] = inputs['input_values'].transpose(0, 1)

# 入力データの形状を確認
print(f"入力のテンソルの形式: {inputs['input_values'].shape}")

outputs = model(**inputs)
    
# 埋め込み表現の取得
embeddings = outputs.last_hidden_state
print(f"出力の形式(batch_size, sequence_length, hidden_size): {embeddings.size()}")
```
出力の例  
**入力のテンソルの形式: torch.Size([1, 308700])**
**出力の形式(batch_size, sequence_length, hidden_size): torch.Size([1, 964, 768])**

このコードを実行することで、`rinna/japanese-hubert-base` モデルを使用して音声データから埋め込みを取得することができます。

## まとめ

HuBERTを使用することで音声データを効果的に処理し、高性能なモデルを簡単に構築することができます。ぜひ、HuBERTを使ってみてください！  
紹介してない内容もたくさんあるのでもっと詳しく知りたい方は論文や他の記事を読んでみてください！  

# Reference
[1] Wei-Ning Hsu, Benjamin Bolte, Yao-Hung Hubert Tsai, Kushal Lakhotia, Ruslan Salakhutdinov, Abdelrahman Mohamed, "HuBERT: Self-Supervised Speech Representation Learning by Masked Prediction of Hidden Units", 2021.  
[2] https://rinna.co.jp/news/2023/04/20230428.html
[3] https://aws.amazon.com/jp/what-is/embeddings-in-machine-learning/
[4] https://www.ibm.com/jp-ja/topics/embedding
[5] https://huggingface.co/docs/transformers/model_doc/hubert