神野さんに言われました。

神野さんに言われました。

AIの勉強をしています @sesenosannko

音声分析アプリを作った

こんにちは。

先週の金曜日に音声分析アプリを作って、昨日今日でtkinterのアプリにしました。
そこまではよかったのですが、sptk等を使っていたことを完全に失念していたので、アプリ化するのが非常に面倒になったので諦めました。
今回で懲りたのと、神野さんが毎日のようにWEBアプリを勧めてくるので、次何かを作るときはWEBアプリで作ることになると思います。

作ったアプリはこんな感じです。
仕組みはお遊びなので非常に単純です。

動画の説明欄にある通りですが、僕の主観で6種類に分けたサンプル音声群に対してそれぞれ平均的な混合ガウス分布を学習して、録音した音声に対してそれぞれの分布との尤度を元にスコアをつけています。
平均の分布を用いることに関しては微妙な点ですが、一人ずつそれぞれの分布を学習して尤度を平均した結果と大きな差はなかった(と判断した)ので速度の観点から平均分布を用いることにしました。

ここまではそこまでは悪く無いのですが、良い録音環境で録音されたプロの声に対しては妥当と思える値を出すのに対して、違う録音環境の一般人の声に対しては桁が違うレベルで小さい値が出てしまいました。
録音環境の問題が大きいのか、声質の問題なのか、この結果も研究素材としては面白いんですが、三田祭が近くてそうも言っていられなかったので、0〜5点の間で良い感じの値になるように事後処理を加えています。

Tkinterで関数内でcanvasを変更するときの問題について

こんにちは。

Tkinterでボタンを押した時にcanvas等を変更したいときは、buttonのcommandに与える関数内で操作するのが定石だと思うのですが、アプリを作っている中で期待する挙動をしてくれないことがありました。
Tk自体やTkinterとTkの関係を全く知らないので、もしかしたら当たり前のことを言っているのかもしれないですが、

import time

def change(canvas):
    canvas.create_text(100, 100, text='スタート')
    
    time.sleep(5)
    
    canvas.delete('all')
    canvas.create_text(100, 100, text='ストップ')

このような関数に対して

button = tkinter.Button(root, text="5秒", command=lambda:change(canvas))
button.pack()

ありきたりなボタンを作ります。
期待する挙動は、ボタンを押したら「スタート」と表示され、5秒後に「ストップ」と表示されることですね。

しかし、実際には何も表示されないまま5秒が経過して「ストップ」と表示されます。
この問題についての情報は見つけられなかったのですが、どうやら関数が終了するまでcanvasは更新されないようです。

ここで、バインドを使用することにしました。
バインドはクリックや特定のキーの入力などに対してアクションを起こすことができる機能らしいです。
でクリックした時、でクリックをやめた時のアクションを指定することができます。
つまり、自然にボタンをクリックしてもらえれば、単純に2つの独立したアクションをほぼ同時に起こすことができます。

def before(canvas):
    canvas.create_text(100, 100, text='スタート')

def after(canvas):
    time.sleep(5)
    
    canvas.delete('all')
    canvas.create_text(100, 100, text='ストップ')

このように二つの関数を準備して、

button = Button(root, text="5秒")
button.bind('<Button-1>', lambda e:change(canvas))
button.bind('<ButtonRelease-1>', lambda e:after(canvas))
button.pack()

このように指定すれば、ボタンをクリックしたときに「スタート」と表示され、直ぐにボタンを離してくれれば5秒後に「ストップ」と表示されます。
bindでは指定した関数にevent objectが与えられ、クリックした位置などの情報を扱うことができますが、今回は必要無いのでlamba式に「e」として与えて、それ以降は使いません。

tkinter.PhotoImageとガベージコレクション

こんにちは。

PythonでTkを扱うためのライブラリであるTkinterでの画像表示で詰まったところがあったのでメモしておきます。
Tkinterも初めて使うので、いろいろと分からないことが多いです。

三田祭に向けて音声分析アプリ的なものを作っていたのですが、分析結果をmatplotlibで描写して画像で表示しようとしたところで失敗しました。
そもそもTinterのcanvasに直接プロットする方法もあるらしいのですが、サイトを参考にしたところ望んでいる機能と共存させるのが難しそうなので、画像を保存して表示するという原始的な方法を試していきます。
コードは激しく省略しています。

def show_img():
    result_img = tkinter.PhotoImage(file = 'result.gif')
    canvas.create_image(300, 300, image = result_img)

これを用いて、

button1 = tkinter.Button(root, text="録音開始",
                    command=analysis) # result.gifを作る
button1.pack(padx=5, pady=5) 

button2 = tkinter.Button(root, text="結果を見る", 
                     command=show_img) # 表示されない!!
button2.pack(padx=5, pady=5)

canvas = tkinter.Canvas(root, width=600, height=600)    
canvas.place(x=200, y=150)

直感的にはこれで動くと思ったのですが、「結果を見る」ボタンを押しても何も起こりません。


[Tkinter-discuss] refreshing images

いろいろと調べた結果、このサイトによると新しいPhotoImageオブジェクトをレファレンスに登録しないと処理が終了した扱いとなり直ぐにガベージコレクションによって消去されることが原因であると分かりました。
僕はメモリ関係の知識が全く無いので、正直細かいことはよく分からないのですが、このようにPhotoImageオブジェクトをグローバル変数として登録することで避けられることが分かりました。
この辺りも勉強しないといけないですね。

def show_img():
    global result_img
    result_img = tkinter.PhotoImage(file = 'result.gif')
    canvas.create_image(300, 300, image = result_img)

brewを使わずにmp3環境とともにsoxをMacにインストールする

Anacondaとの衝突によりbrewを入れていないので、soxのインストールに手こずりました。
今はAnacondaは使っていないので機会があればbrewは導入するべきですね。
でもよくわからなくなっていた理由は単純にosx用にビルドされたファイルの使い方がよくわからなかっただけです。
初心者はまずインストールができない。

何も考えずに最初からtarの方を使えばよかったんです。
このサイトに従えば僕でもできたのでどうぞ。

http://ggkarman.de/tech/building-sox-with-mp3-support-on-osx/

フレームごとのGMM-based mappingによる声質変換

こんにちは。
個人的にはなかなか良い結果を得られたので書いておきます。

https://www.cs.cmu.edu/~pmuthuku/mlsp_page/lectures/Toda_VC.pdf

例によってこの論文なんですが、とりあえず2章の従来の方法というやつを試してみます。
この手法はフレームごとに完全に独立して変換を行う方法で、動的特徴量も系列内変動も何も考えていません。
ただ、どれくらい行けるのかというのを試してみました。

ライブラリを駆使、というか全て投げてとりあえず実装するということに全力を入れました。
そして、とりあえず実装に命をかけた結果、お手本のようなスパゲッティコードができたので、もう少し綺麗にする元気があったら上げるかもしれません・・・

かなりこのサイト様を参考にしたので、これを読んでください。

aidiary.hatenablog.com

音声関連はSPTK、GMMの学習はsklearn、あとはfastdtwとかいう神ライブラリとかを使っています。
こうやってみてみると自分では何もしてない。悲しい。

音声データはここのデータを使わせていただきました。
8. 発話のプロフェッショナルによるATR 25文の読み上げ の8モーラ/秒の女性1人目を男性に変換しています。
こういう研究室は本当にありがたいですね。

http://www.it.ice.uec.ac.jp/SRV-DB/

今回はGMMの構成ガウス分布は32個でやりました。
戸田さん論文によれば、25文程度の場合は32個らしいです。
あとのパラメータとかは色々ネットで調べたり、上のサイトのものを丸パクリしたりです。

さて、本題です。
変換元の声はこれ



そして変換先はこれです。



これはデータセットの1個目の文章です。一応学習からは除いています。
そして、変換した結果がこれです。
正直、これでも結構感動しました。
明らかに男性の声質に変わっているのがわかると思います。
ただ、少し声が高く、違和感がありますね。
ここでは基本周波数を変更せずに変換したメルケプストラムを合成しているので、声の高さが女性のままになっているんですね。



意外なことに基本周波数の変換に関する文献が適当に探しただけでは見当たらなかったのですが(2017/04/04追記:log F0などの平均と分散を合わせるのが通例のようです)グラフを書いたらかなり綺麗に線形になっていました。
ちなみに、どちらかに0を含むデータは取り除いてあります。
DTWをしていますが、結構ずれるので、片方が0で、もう一方が数百とかいうデータがそれなりの数あります。
これがかなり学習を邪魔するので、事前に取り除くことにしました。


f:id:sesenosannko:20161002220225p:plain


ということで、ここで学習した線形変換を掛けた結果がこれです。



かなりノイズがありますが、明らかに男性の声になっているのがわかると思います。
単純に線形変換しただけだからか、よりノイズが増えてしまった気がします。

ノイズには幾つかの原因があります。
1つ目は、MLSAフィルタによるものですね。
このモデルを用いた手法では、このノイズは少なくとも掛かります。
今回は慣れてるのでSPTKを使ったんですが、World等に比べると質が低いと言われています。
あと、ピッチを適当に線形変換したせいで起こるノイズはこれに関係するものですね。
2つ目は、完全にフレームごとに変換を行っているためですね。
むしろフレームごとに変換して、よく音声の体を保っていられるなと感心するレベルです。
これに関してはもちろん戸田さんの論文に書いてある通りですね。

多分それ以外にも色々あるでしょう。
文章が25文程度の場合はGMMの構成要素は32個がベストらしいですが、当然文章とGMMの自由度を大きくすれば精度は上がるでしょう。

とりあえず、これをベースラインとして頑張りたいと思います。

VC Based on MLE of Spectral Parameter Trajectoryを読む②

続きです。
今回は3章の提案手法のところを読みました。
論文のメインですね。
それ以降は手法の評価なので、重要だとは思いますがとりあえず今の所はここまでにしておきます。
いろいろな手法を読みたいので。


sesenosannko.hatenablog.com

Outline


Abstract
1. Introduction
2. Conventional GMM-Based Mapping ⇦前回はここまでです
3. Proposed Spectral Conversion ⇦今回はここまでです
4. Experimental Evaluations ⇦ここからは面倒なので保留です
5. Conclusions

3. Proposed Spectral Conversion


提案手法では、
 x = [x_1^T, x_2^T, \cdots, x_t^T, \cdots , x_T^T]^T
 y = [y_1^T, y_2^T, \cdots, y_t^T, \cdots , y_T^T]^T
と置いて
 \hat{y} = f(x)
のようにしてマッピング関数を適用します。

提案手法は以下の2点に重点が置かれています。
1. フレーム間の特徴量の相互関係
2. 系列内変動を考慮した変換

A. Conversion considering dynamic features


提案手法では以下のように静的特徴量と動的特徴量を並べた2D次元の特徴量ベクトルを用います。

 X_t = [x_t^T, \Delta x_t^T]^T
 Y_t = [y_t^T, \Delta y_t^T]^T

また、以下のようにX、Yを定義します。

 X = [X_1^T, X_2^T, \cdot, X_t^T, \cdots , X_T^T]^T
 Y = [Y_1^T, Y2^T, \cdots, Y_t^T, \cdots , Y_T^T]^T

ここで Z_t = [X_t^T, Y_t^T]^Tと置いて、従来の手法と同様の訓練手法を適用する。


1) Likelihood function


(19)のように条件付き確率をGMMでモデリングして尤度関数を定める。


2) MLE of parameter trajectory


変換後の特徴量ベクトルは以下のように最尤推定で求められる(24)。

 \hat{y}  = argmax P \left(Y|X, \Lambda^{(Z)} \right)

また、Y(静的特徴量と動的特徴量)とy(静的特徴量)の関係は線形変換で求められる。
 \Delta y_t = -0.5 \times y_{t-1} + 0.5 \times y_{t+1}となっている(fig. 4)。

(24)式を解く方法として、この論文では2つの手法を紹介している。
また詳しく読む時がくると思うので飛ばします。

B. Conversion considering GV


統計的モデルにおいて系列内変動は目標と大きく異なる結果をもたらす場合がある。
本章では、最適化問題において直接考慮することによって精度の向上をもたらす手法を示す。


1) Globali variance


ターゲットの系列内変動は下式(47)のように表されます。

 v(y) = [v(1), v(2), \cdots, v(d), \cdots, v(D)]^T

それぞれのv(d)は各次元の特徴量の時間軸における分散を表しています。
原文式(45)〜(47)を見ると良くわかります。
この論文では系列内変動は1発言ごとに計算されています。

系列内変動の減少はGMMを構成するそれぞれのガウス分布が、異なる文脈を含む音声から学習されることによって発生すると考えられています。
(つまり、汎化したモデルを学習したことによって細かい変動が殺され、過度に滑らかな音声が作られやすいということでしょう。)


2) Likelihood function


元の尤度関数(19)に単一ガウス分布 P\left) v(y)|\Lambda ^{(v)}\right) = N\left(v(y);\mu ^{(v)}, \Sigma ^{(vv)} \right)を掛け合わせたもの(48)を新たな尤度関数として用います。
 \Sigma ^{(v)}は元の尤度関数のパラメータである \Sigma ^{(Z)}とは独立して学習されます。
新しい尤度関数において、従来の尤度関数と加えた部分の重みは、従来の尤度関数の部分を定数 \omega乗することで制御されます。


3) MLE of parameter trajectory


アルゴリズムの説明なので省略します。


4) Effectiveness


系列内変動を考慮した手法を用いた結果、特定の次元やフレームでは改善が見られましたが、変化が見られない部分もあります。

GMMの構成ガウス分布数を増やすことも過度な平滑化の緩和につながりますが、この手法では過学習が起こりやすくなります。
系列内変動を考慮する提案手法の利点はパラメータ数の増加が小さいことです。




今回はここで終わり。

とりあえず近いうちに、いろいろな手法の論文を読みたいところです。
戸田さんのページにいろいろなpptがありました。
様々な手法が概観できそうなので、明日にでもさらっと見ます。

https://sites.google.com/site/tomokitoda/


あと、そもそもの音声信号処理の本を先輩からお勧めして頂いたので、これを最優先で読みたいと思います。

音声信号処理―音声の性質と聴覚の特性を考慮した信号処理

音声信号処理―音声の性質と聴覚の特性を考慮した信号処理

VC Based on MLE of Spectral Parameter Trajectoryを読む①

ブログを見返すたびに集中して一つの分野をやれって言いたくなりますが、今回は統計的声質変換の論文を読みます

近年の統計的声質変換から見ると単純な手法だと思いますが、戸田智基教授の有名(たぶん)な「Voice Conversion Based on Maximum Likelihood Estimation of Spectral Parameter Trajectory」という論文です。

https://pdfs.semanticscholar.org/d419/ceb2753232373fd4ab9534b371e017cd9dc1.pdf

Outline


Abstract
1. Introduction
2. Conventional GMM-Based Mapping ⇦今回はここまでです
3. Proposed Spectral Conversion
4. Experimental Evaluations
5. Conclusions

Abstract


提案手法はGMMでソースとターゲットの特徴量の同時分布を表すことで声質変換を行うものです。

以前の手法ではフレームごとに最小二乗法でパラメータを求めています。
この手法によって音質が低下する要因は以下の二つ。
1つ目は、フレームごとの変換では不適切な動特性がもたらされること。
2つ目は、変換後のスペクトルが過度に滑らかになること。

提案手法ではスペクトルパラメータトラジェクトリの最尤推定により動的な特徴変化も音声変換に用いられています。
過度な平滑化に関しては、系列内変動*1を考慮することによって改善が見られています。

1. Introduction


声質変換には統計的な特徴量マッピングがしばしば用いられます。
このような手法は非言語的特徴量による変換が行われます。

声質変換への統計的なアプローチは1980年代後半から行われています。
以来、ハードクラスタ、ソフトクラスタを用いたマッピングによる手法が提案されてきました。
そして、コードブック、線形回帰、補間法、ニューラルネットワーク、GMMなどを用いた手法があります。

マッピングを用いた手法は効果的ではありますが精度は不十分です。
前述のように、フレームごとの変換によって不適切な動特性がもたらされる、変換後のスペクトルが過度に平滑化されるなどの要因によって精度が下がってしいます。


提案手法ではスペクトルパラメータトラジェクトリの最尤推定に基づいた声質変換を行っています。
適切なスペクトルの運動をもたらすために、HMMを用いた音声合成で用いられる特徴量のフレームごとの相互関係を動的特徴量を用いたパラメータ生成アルゴリズムを、GMMに基づいたマッピングに適用することを考えます。

この手法により動特徴においても適切な値となるスペクトル配列を推定することができます。
さらに、系列内変動を特徴量をつかむ特性であると考えることで、過度な平滑化についての解決を試みています。
このアイデアは統計的変換によって失われる情報を効果的にモデリングしています。

2. Conventional GMM-Based Mapping


以降、式を書くのは面倒なので括弧で式を示します。原文を参照してください。

A. Probability density function


tフレーム目のD次元のソースとターゲットのベクトルを x_t^T,  y_t^Tとして、結合ベクトル [ x_t^T, y_t^T ]を z_t^Tと置いて、 z_t^Tを確率変数とするGMMを考えます(6)。

提案手法ではGMMを構成するそれぞれのガウス分布の共分散行列について、xx、xy、yx、yyの4つに分割した行列はそれぞれ対角行列としている。

GMMはEMアルゴリズムを用いて学習されます。
また、結合ベクトルは動的時間伸縮法(Dynamic Time Warping, DTW)を用いて生成されます。
この手法は最小二乗法を用いた手法に比べて頑健性が高く、特に訓練データが小さい場合にはその差が顕著になります。

B. Mapping function


同時確率がGMMならば条件付き確率もGMMで与えられます。
PRMLの2.3章の話と同じことでしょう。

ターゲットとなる特徴ベクトルは y_t x_tに関する条件付き期待値で与えられます(13)。
この手法はVQに比べて高い精度であることが示されています。

C. Problems


GMMに基づくマッピング関数を用いた手法は様々な問題を含みます。
この論文では2つの主要な問題に焦点をおきます。

1点目は時間に対して独立したマッピングであることです。
フレーム間の相互関係が無視されるため、狭い範囲でのスペクトルの時間変化に差が出ることがあります。

2点目は過度な平滑化が起こることです。
統計的なモデリングでは、しばしばスペクトルの詳細な構造が失われます。
この変化によって品質の低下が起こります。



今回はここまでです。
後半も早いうちに読みたい。

*1:一発話単位など,パラメータ時系列全体 における静的特徴量の分散のことである。 ci.nii.ac.jp