pyreaperで音声データのピッチを掴むためのメモ書き(F0の抽出)

はじめに

最近、仕事で音声データを扱うことがあるのですが、アプローチの仕方を色々と調べています。

今のところ検討しているのが、

  • クラウドAPIなどによる文字起こしによるテキストアナリティクス
  • 音声の波形に関する分析
  • 音声のピッチに関する分析

の3つですが、1つ目と2つ目については比較的すぐにググってチャレンジできましたし、ビジネス上で役に立ちそうな発見もありました。

そこで今回は3つ目の「音声のピッチ」(音程)について扱おうと思います。

ピッチがわかると何が嬉しいかというと、顧客対応などの音声でピッチがどのようなものであれば顧客満足度が高いのかを分析できるようになり、担当者へのフィードバックに使える可能性があります。
今までなんとなく蓄積していた音声データが宝の山になるかどうか、それをジャッジするための一つの手段と考えることができます。

後輩からの聞き込み

大学院で動画の圧縮について研究していた元後輩社員くんがいたので、きっと知っているはずだろうと思い、その方からピッチに関する研究を進める上でのキーワードを教えてもらいました。
彼曰く、F1やF0というキーワードで探していけばピッチの抽出ができるそうなので、早速調べて実践できないかチャレンジします。

F0とF1

Wikipediaで調べて結果を以下に記します。

  • F0:基本周波数
    信号を正弦波の合成で表したときの最も低い周波数成分の周波数を基本周波数と呼ぶ。

  • F1:フォルマント周波数
    フォルマント:言葉を発している人の音声スペクトルを観察すると分かる、時間的に移動している複数のピークのこと。
    周波数の低い順に、第1フォルマント、第2フォルマントというように数字を当てて呼び、それぞれF1、F2とも表記する。
    観察の仕方としては、縦軸に周波数、横軸に時間を置くものとする。

ピッチはどうすれば求めることができるのか?

断創録さんのブログによると、ピッチとは声の高さのことで、基本周波数やF0とも呼ばれているそうです。
そのため、今回はF0を求めれば目的を果たすことができそうです。

今回扱うモジュール/今回のツール

今回は、ピッチ検出を行うためのツール、REAPERのPythonラッパーであるpyreaperを使います。

一発で入るはずです。

続いて、音声ファイルをWAVファイルに変換するためのツールとして、FFmpegをインストールします。
Macだと、

で一発で入るはずです。
使い方としては、

のようにターミナル上で使います。

データ

今回は、無料の音声素材でなにか無いかと探していたのですが、NHKの百人一首の読み上げデータにしました。
句に関してはこだわりはないので、適当に第5句にしています。

NHKの百人一首 第5句
奥山に紅葉踏み分け鳴く鹿の 声聞く時ぞ秋は悲しき/猿丸大夫

もう秋ですし、風情があって良いですね。

プログラム

実行プログラムはご丁寧にpyreaperのPyPIのページに良いものがありましたので、こちらをまるごと使います。

まず、百人一首の音声がm4a形式だったので、wav形式になるように、
先程インストールしたFFmpegを用いて、サンプルレート16000、チャネル数1のWAVファイルに変換します。

なお、電話などの話者が2名いるステレオのデータの場合、FFmpegを用いて左側成分、右側成分だけを抽出することができますので、分けて解析すると良いと思います。左右の分割に関してはFFmpegの参考文献で紹介されています。そうすれば、片方の話者の声だけを抽出することができますので、解析が捗ります。

実行結果

百人一首の音声の波形です。

ピッチマークです。ピッチマークとは、「単位波形を抽出する基準点」とされているとの説明があるのですが、あまり良くわかりません。無音のときに生成されていないので、ピッチ抽出の確信度という意味なんでしょうか。

F0です。音程とみなすことができるので、こちらを会話の分析の際に使ってみるのが良いのだと思います。

相関係数です。こちらもピッチ検出に使う指標のようです。

今後の使いみち

F0を集計してある水準のものが多い、時系列で見ると前半と後半でF0の水準が違っているというような情報と、その会話におけるラベル(会話の結果としての商談の成否)について分析することで、商談などがうまくいく際のヒントが得られるかもしれないですね。

参考情報

IPythonデータサイエンスクックブック ―対話型コンピューティングと可視化のためのレシピ集
音声生成の基礎と音声学
Is there a way to convert audio files in Mac OS X or the command line without using iTunes?
やる夫で学ぶディジタル信号処理 東北大学 大学院情報科学研究科 鏡 慎吾
[vDSP][信号処理]オーディオ・音声分析への道7 FFT 自己相関関数 ピッチ検出
REAPER: Robust Epoch And Pitch EstimatoR
FFmpeg wiki:AudioChannelManipulation
基本周波数抽出器 REAPERによる抽出実験
SPTKの使い方 (3) ピッチ抽出

rstanarmパッケージを使って簡単にベイズモデリングを実行する

はじめに

今回は、rstanarmというパッケージを用いて赤ワインデータを色々といじってみようと思います。
マーケティングの意思決定のための分析などでベイズ統計を使う場面が多々あるのですが、似たような属性のデータがあるのであれば、
一つ一つstanコードを書くのではなく、Rの関数でサクッと実行して試行錯誤していくという形に持っていけたらいいなぁと感じていました。
本気を出すところではstanを、ルーティンワーク的なタスクではrstanarmをみたいな形で使い分けれると良いのではないでしょうか。

rstanarmとは

バックエンドの計算をStanに実行させて、統計モデルの推定を行うためのパッケージ。R上でlm関数のように簡単にベイズ推定を行うことができる。対象ユーザーはベイズ推定に慣れ親しんでいない頻度主義系のソフトウェアユーザー。
詳しくはこちら

インストールする

まずはrstanarmのインストールするのですが、コケまくりました。そのため、バージョンを下げてみることにします。

ここに過去のバージョンがありますが、2.17.4だと動かなかったものの、2.17.3なら動きました。

rstanarmのサンプルを回してみる

今回は、以下の文献を参考にして、大人のIrisとも言える、ワインデータを扱い、質の高いワインかどうかを決める要素を探ります。
How to Use the rstanarm Package | Jonah Gabry and Ben Goodrich

こちらの文献には、ベイズ分析の4つのステップとして以下があげられています。

  • 1.同時分布の特定(同時分布は事前分布と条件付きの尤度をかけ合わせたもの。)
  • 2.MCMCで事後分布を描く
  • 3.モデルがフィットしているか評価する
  • 4.事後予測分布を描き、結果に影響を与える予測項を確認する。

これらのステップをできるだけ素早くできると良いですね。

まずはデータを読み込んで、スケーリングしておきます。(可視化結果は前回と同じなので、載せません。)
加えて、6点以上の評価であれば1を取る二項変数を作成しておきます。

 

GLMでロジスティックモデルを推定し、rstanarmで推定した結果と比較します。rstanarmでは傾きや切片の事前分布にスチューデントのt分布を、尤度にロジスティック分布を設定しています。

ほとんど係数の大きさが同じであることが確認できます。

ベイズ推定の良いところは事後分布から関心のある係数に関しての取りうる値などをシミュレーションできるところですが、
posterior_interval関数で簡単に計算することができます。

肝心のMCMCの収束診断ですが、shinystanを使います。

やや余談ですが、他のデータセットでshinystanを用いた際に、予測結果にNAsが含まれている場合に、
shinystanが起動しないという問題があり、以下のようなエラー文が吐かれます。

調べたところ、こちらのgithubにあるように、

のように引数でppd=FALSEのように設定することで、立ち上げることができました。

3つの基準をクリアしているため、収束しています。

係数の分布についても可視化します。

rstanarmの良い点の一つとして、モデルのアップデートが容易に行える点があげられると思いますが、実際、以下のように先程のモデルに変数を追加して推定することができます。
今回は、alcoholを二乗したものを新しい変数として加えます。

次に、looパッケージを用いて、更新したモデルと元のモデルの性能の比較を行います。
looパッケージは統計モデルの予測精度の指標として扱われる、WAIC(Widely Applicable Information Criterion)を計算するためのパッケージで、WICは事後分布から得られる対数尤度の平均や分散からなる値として表されます。looはleave-one-out cross-validationのleave-one-outの頭文字。

さっそく入れようと思ったところ、

というエラーが出ました。
こちらでも議論されていましたが、

でバージョンを2.0.0から1.1.0に落としたら動きました。

ここで、事後分布が特定のサンプルデータに対して敏感であるかどうかをlooパッケージを用いて可視化します。

縦軸のshape parameter kは推定の信頼性の指標とされ、大きければ大きいほど信頼できないと見なし、横軸は今回推定したワインデータのデータの番号で、左が元のモデル、右が変数を追加したモデルのものです。
どうやらどちらも0.4未満のkに収まっているようです。参考情報の事例では0.5を超えていましたが、moderate outliersと説明されていたので、今回の推定は問題ないと思われます。

続いてモデルの比較を行います。

elpd_diffに関しては右のモデルの精度が高ければ正の値を、低ければ負の値を取るようになっています。標準誤差も返されます。
どうやら変数を追加したモデルの方が、ちょっとだけ良さそうです。

続いて、事後予測分布から、どの変数がどのように予測に影響を与えるのかを確かめます。
比較のためにデータを2つほど作成し、両者において一つだけ変数が違うという状況下での、予測される確率の比較を行います。

他の要素をある一定水準で保った際に、alcoholだけ1度下げることで、平均3%ほど高い評価が得られる確率が高まるという考察となります。

以上で、rstanarmの一連の使い方となるのですが、
一部の関数においては、階層ベイズモデルも行えるので、試してみようと思います。

ただ、階層ベイズにするにも、赤ワインのデータしかないので、グループ変数をどうにか作らないといけません。
あまりやりたくはありませんが、データがないので、説明変数を元にk-means(K=3)によるクラスタリングを行い、それをグループ変数とします。

stan_glmer関数を使えば、以下のような簡単な記述で定数項や係数がグループごとに異なるパラメータの分布に従うとする階層ベイズモデルを推定できます。

今回は、切片だけがグループごとに異なるモデル、傾きだけがグループごとに異なるモデル、切片も傾きも異なるモデルを作成します。

先程紹介した、looパッケージを使って、ベースとなるモデルとの比較を行います。

うーん、残念ながらどのモデルもベースモデルよりも圧倒的に強いものは無さそうです。

感想

まだまだrstanarmの関数やら機能やら定義を全て把握しきれていないですが、そこらへんがクリアーになれば、これまでのstanでの推定業務において生産性が高まる可能性を感じました。
簡単な階層ベイズモデルくらいなら、非常に直感的に書ける点や、変数の追加によるモデルのアップデートが容易な点などはポイント高いなぁと思います。
とはいえ、実務としてマニュアルでstanコードを作成していくのは必須なので、このパッケージを使うことによって、stanコードの改善に時間をより一層割けるようになるなら、それが一番だと思いました。
あと、「ベイズ初めてです!」という新入りの方とかには慣れ親しんでもらうには良さそうですね。lm関数レベルで実行できてしまうので。
今回、mc-stan.orgの配下にあるページなどを漁る過程で、ベイズ推定結果の可視化などで知らないことにも色々と出会えたので、今後も読み進めていきます。

追記

2018-09-10: Stanを使って変数選択したいにprojpredというパッケージが紹介されており、これを使えば、情報量基準に従った変数選択を簡単に行えるそうです。こうなると、「ベイズ推定に慣れ親しんでいない頻度主義系のソフトウェアユーザー」に限らず多くの人が幸せになれるパッケージなのかもしれませんね。

参考情報

Using the loo package (version >= 2.0.0)
Leave-one-outクロスバリデーションの2つのデメリット、からの解決方法
stan_glmer | Bayesian Generalized Linear Models With Group-Specific Terms Via Stan
WAICを計算してみる
Package ‘bayesm’
Hierarchical Partial Pooling for Repeated Binary Trials
Leave-one-out cross-validation for non-factorizable models
priors | Prior Distributions And Options
StanとRでベイズ統計モデリング (Wonderful R)