考え中

営業なのに営業力が皆無のためゲーム作って癒やされたい。

MacのLocal環境でTerminal作業するときに,東アジア文字幅問題の沼から抜け出す

Mac(Mavericks)を使い始めました.WindowsLinux出身者なので,慣れません.
それでも,Macで快適にTerminalで作業したいと思って,iTermとか入れて,Localでの作業環境を整えようとしました.
すると,UTF-8の東アジア文字幅でambiguous widthなものの表示がズレておかしくなるので,それを修正する話です.

修正すると言っても,場当たり的な修正です.
ロケールのファイルも上書きしてしまうので,アプリとかとの連携が取れない場合もあるかもしれません.
自己責任でお願いします.


Macを使ってターミナルで作業していると ambiguous width の文字がたまにあって表示がおかしくなります.
ambiguous width の問題についてググっても,「iTermでオプション有効にしたら解決した」って記事ばかり出て来て,「そんな馬鹿な」「このMacは本物のMacか?」という状態になってました.
結局,研究室の先輩に助けてもらいました.

まず問題について,sshでつないだ先(ロケールいじってambiguous widthは2で統一してある環境)だと表示ズレが起きないのに,Localで作業すると,表示ズレが起きました.
これはiTermでのオプションのambiguous widthを2で扱うっていうオプションをオンにしても改善されませんでした.
そのため,Macで文字幅を指定してしていそうなファイルをいじることにしましたが,一体どれが該当ファイルなのか分かりませんでした.
研究室の先輩によると,MacBSD系らしいので,Linuxの構成はあまり参考にならない模様.結果的に,FreeBSDでの文字幅の問題について調べてもらい,解決案を頂きました(本当にありがとうございます).

### FreeBSD用で,ambiguous widthを2に変更したロケールのソースファイルを落とす
$ wget http://sourceforge.jp/projects/mutt-j/scm/svn/blobs/146/mutt-ja-doc/trunk/samples/UTF-9.src?export=raw -O UTF-9.src
#### localeのバイナリのファイルを作成
$ mklocale -o ~/LC_CTYPE UTF-9.src
$ cd /usr/share/locale/
$ su
### UTF-8のlocaleファイルに上書き
# cp /usr/share/locale/UTF-8/LC_CTYPE /usr/share/locale/UTF-8/LC_TYPE.bak
# cp ~{LC_CTYPEを置いたUser}/LC_CTYPE /usr/share/locale/UTF-8/


短いですが,これで完了です.
iTermとかも再起動すれば,多分反映される気がします.

最初は,UTF-9(コンパイルし直したLC_CTYPEを置く)やja_JP.UTF-9(LC_CTYPE以外はja_JP.UTF-8の構成をコピー)というディレクトリを作って,LANGやLC_ALLをja_JP.UTF-9に変更して,使おうとしましたが,他のアプリとの連携がとれないらしいので,結局UTF-8に上書き安定になりました.自分は忘れましたが,戻せるようにバックアップは取って置いた方がいいです^^;
(ちなみに,ja_JP.UTF-9にja_JP.UTF-8と同じ構成にしないと,LANGとLC_ALLの変更は出来ませんでした.)

あとは,私事ですが,screenをGitから落として,コンパイルしたのを使ってます.
その場合,UTF-8-MAC問題に出くわします.
この問題に対処した先駆者がいたので,URLを張って置きます.
https://sites.google.com/site/togino77/home/screen-410

なんというか,上の作業は意味ない感じになった気がします^^;
結構この記事もリファレンスされているっぽくて,有名な問題だったみたいですね….

自分が修正したときは,こんな感じになりました(ansi.cの箇所が1行ズレただけでした).

 --- ansi.c
 +++ ansi.c
@@ -726,6 +726,10 @@
                      LPutChar(&curr->w_layer, &omc, ox, oy);
                      LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
                    }
 +               if( curr->w_mbcs)
 +                         {
 +                                       curr->w_rend.mbcs = curr->_mbcs = 0;
 +                         }
                  break;
                }
              font = curr->w_rend.font;
 --- display.c
 +++ display.c
@@ -603,7 +603,7 @@
            D_x += D_AM ? 1 : -1;
          D_mbcs = 0;
        }
 -      else if (utf8_isdouble(c))
 +      else if (utf8_isdouble(c) || (0xdf00 <= c && c < 0xe000))
        {
          D_mbcs = c;
          D_x++;


ansi.c とdisplay.c を修正しないとダメっぽいです.
変更箇所の位置はそんなに変わってませんでしたが,git から clone してきた段階で自分でソースを見て,判断するしかない気がします.
上記のサイトにならって,patch を書こうかとも思いましたが,すぐに意味なくなるかもしれないので,やめました.

デタッチしたときの utmp のエラーを出さないようにすることも出来るようで,下の diff みたいに,acconfig.h を修正する必要があるみたいです.
https://gist.githubusercontent.com/yujinakayama/4608863/raw/75669072f227b82777df25f99ffd9657bd113847/gistfile1.diff


とりあえず,これで文字幅の深い沼から少し抜け出した気がします.

[References]
http://www.csie.ntu.edu.tw/~r92030/project/big5width/
https://github.com/jj1bdx/mutt-ja-freebsd-private-port/blob/master/mutt/mutt-1.5.21-ja.1/UTF-8.txt
http://en.sourceforge.jp/projects/mutt-j/wiki/FreeBSD%E3%81%AEwcwidth
https://sites.google.com/site/togino77/home/screen-410
https://gist.githubusercontent.com/yujinakayama/4608863/raw/75669072f227b82777df25f99ffd9657bd113847/gistfile1.diff

Front-End Factor Analysis for Speaker Verificationを読んだメモ

IEEEのAudio, Speech and Languageから2011年5月発表の論文について読んだメモ.
(Author: Najim Dehak, 他)

メモどころか下手くそな訳みたいになってしまったので,今後はもっと簡潔にメモを取りたい(ついでに途中で大変になってきたので,省略が多い).
メモ中に(#...)と書いているのは,自分の解釈です.間違っている可能性高いです.
Baum-Welch statisticsというのが出てきたが,とりあえずBaum-Welchの統計量?とした.
レイリー係数もなんのことか分からない.


[用語]
WCCN: Within-Class Covariance Normalization
LDA: Linear Discriminate Analysis
NAP: Nuisance Attribute Projection
EER: Equal Error Rate
MinDCF: minimum Detection Cost Function
JFA: Joint Factor Analysis
UBM: Universal Background Model

[ざっくりとした概要]
話者照合に使う特徴ベクトル(i-vector)についての論文.
GMMスーパベクトルからi-vectorを取り出すよう因子分析する.
i-vectorだと低次元の話者とチャネル依存の特徴ベクトルとして扱えて,チャネル依存の因子の影響を抑えるために,後でチャネル補正の手法(WCCN,LDA,NAP)を適用するらしい.
コサインカーネルを使ったSVMでの識別と,i-vectorのcos類似度をとって閾値で照合を決定する方法を比較したら,後者の方が精度良いし高速という結果.
最も精度が良かったのは,NIST2008評価セットの男性英語話者に対して,i-vectorにWCCNを適用後,LDAを適用してcos類似度を計算した場合で,EERが1.12%で,MinDCFが0.0094になった.ちなみに,JFAよりもi-vectorでcos類似度計算して比較した結果の方がEERが4ポイント男女ともに改善したとのこと.

[モデルについて]
[既存手法(JFA)]
JFAだと1つの発話のGMMスーパベクトルが次のようにモデル化されると仮定している.
 M = m + Vy + Ux + Dz
 m : UBMからの一般的なスーパベクトル
 V, D : 話者部分空間( V : 固有声行列(発話ごとに変化しない要因), D : 残差行列(対角行列))
 U : セッション空間(固有チャネル行列(発話(セッション)ごとに変化してしまう要因)

このモデルの中で, y z は話者依存の因子で, x はセッション依存の因子と見なせ,それぞれの部分空間で N(0, 1) 正規分布するランダムな値.
このJFAを話者認識に適用するには,まず開発コーパス(学習データ)から V, D, U の部分空間を推定して,それから話者とセッション因子の x, y, z を評価したいターゲットの話者に対して推定するっぽい.

話者依存のスーパベクトルは,(セッション空間のものを除いて)
s = m + Vy + Dz
(セッション補正は  (M - Ux) ということ)

ただし,このJFAだとチャネル因子にも話者情報が含まれていることが実験的に分かっているらしい(N. Dehak, "Discriminative and generative approches for long- and short-term speaker characteristics modeling: Application to speaker verification").

この話者依存スーパベクトルに対して、(学習で得た発話のスーパベクトルと)テスト発話の類似度を計算して,スコアリングして照合を決定するらしい.
スコアリング手法もいくつか種類がある模様.


[提案手法(i-vector)]
JFAだと固有声行列Vと固有チャネル行列Uの2つの空間で定義していたのを,i-vectorだと1つの空間で再定義するらしい.
その1つの空間というのが,総変動空間であって,話者変動もチャネル変動も同時に含んだ空間になって,総変動行列で最大の固有値を持つ固有ベクトルを含むように定義されるらしい.
(#総変動行列の,最大の固有値固有ベクトルで空間を定義する?)

このモデルだと,GMMスーパベクトルに対して話者もチャネルも分離されないので,ある1つの発話に対してのモデルとしては以下の式のようになる.

 M = m + Tw

M: GMMスーパベクトル
m: 話者とチャネルに独立なスーパベクトル
T: 低ランクの矩形行列
w: N(0, 1)の正規分布をするランダムベクトル

 wの要素は総変動因子(the total factor)?で,これらのベクトルを"i-vector"(個人を特定するベクトル)と呼ぶ.

このモデルの特徴は、 Mを平均ベクトル mと共分散行列 TT^t正規分布すると仮定していることで,総変動行列 T の学習過程は固有声行列 V の学習とほぼ全く同じで,唯一違うのは,固有声学習で,所与の話者の全ての録音音声が同一の人のものだという過程をしているのに対し,総変動行列の学習には,ある所与の話者の発話セットの全体が異なる話者によって生成された(所与の話者からの全ての発話が異なる話者によって生成された)と見なしていることである.

つまり,この提案手法のモデルでは,発話を低次元の総変動空間に写像するシンプルな因子分析のように見なせる

ただ,総変動因子の wは,所与の発話に対しBaum-Welchの統計量?(#Baum-Welchアルゴリズムのこと?)での条件付き事後分布で定義されうる隠れ変数で,その事後分布は正規分布であり,平均はi-vectorと一致する.

Baum-Welchの統計量?はUBMを使って抽出される(UBMからBaum-Welchアルゴリズムで事後分布を導出する?).

例えば,Lフレーム {y_1, y_2, ..., y_L} と特徴空間の次元数 F で混合数 C のUBM  Ω とすると,Baum-Welchの統計量では,所与の発話 u に対してi-vectorを推定するのに, N_c F_c を得る.

 N_c = \sum^L_{t=1} { P ( c | y_t, \Omega)  }
 F_c = \sum^L_{t=1} { P ( c | y_t, \Omega) y_t }

ただし, c = \{ 1, ..., C \} 正規分布の添字(index)で, P( c | x_t, \Omega) はベクトル y_t を生成する混合要素 c の事後確率に一致する.

つまり,i-vectorを推定するには,UBMの混合要素の平均(UBMの混合平均?)に基づいて集約化した1次のBaum-Welchの統計量を計算する必要があって以下の式のように計算される?.

 \tilde{F}_c = \sum^L_{t=1} { P( c | y_t, \Omega ) ( y_t - m_c ) }

この m_cは混合要素 c に対するUBMの平均であり,所与の発話に対するi-vectorは,以下の公式から得られる.

 w = ( I + T^T \sigma^{-1} N(u) T )^{-1} \cdot  T^t \sigma^{-1} \tilde{F} (u)

N(u)は CF \times CF 次元の対角行列として定義してあり,対角成分はN_c I (c = 1, ..., C).
 \tilde{F}(u)  CF \times 1 次元のスーパベクトルで,所与の発話uに対してBaum-Welch統計量 \tilde{F}_c(u) の第1次元を全て連結したもの.
 \Sigma は因子分析の学習中に推定される CF \times CF 次元の対角共分散行列であり,総変動行列Tでは捉えられないようなものの残差分散をモデル化している.

[SVMを使って識別する場合]
cosカーネルを使ったSVMで識別する場合について述べているところ.
どうやらcos類似度使って閾値用意して、決定した方が精度も処理も高速らしいので,飛ばす.

[cos類似度スコアリング]
cosカーネルの値を直接使ってスコアリングしよう,という話.
target話者のi-vector  w_{target} とtestのi-vector  w_{test} とのcosカーネルの値を決定値 \theta と比較することで,照合するか否かを決定する.

 score( w_{target}, w{test} ) = \frac{ \< w_{target}, w_{test} \> } { \|\| w_{target} \|\| \|\| w_{test} \|\| } \lessgtr \theta

注目すべきは,targetとtestのi-vectorの両方が,全く同じように推定されるため,i-vectorは話者認識の新しい特徴と見なせるということ
enrollmentステップは要らない.(#話者のラベル付けが要らないってこと?)

この提案手法なら因子分析をしているが,話者とチェネルの影響をモデル化しているというよりも,特徴抽出器のような役割を果たして,cosカーネルの値を決定値と比較するだけだからJFAと比べて複雑じゃなく,凄い速いらしい.

[セッション間補正]
チャネル補正をGMMスーパベクトル空間ではなく,低次元の総変動因子空間で行うことで計算が少なくなるらしい.
邪魔な影響(nuisance effect)の補正手法は,大体3つあるらしく,WCCN,LDA,NAPを試して実験.

i) WCCN
話者因子空間に対して適用.クラス内共分散の逆行列を使って,cosカーネルを正規化する手法.
Hatchにより導入された手法.
1対他クラス分類を使って,対象話者と詐称者の間に線形分離するSVMで使用された.
WCCNの基本的な考えは,SVMの学習段階での誤受理率と誤棄却率を最小化することである.
そのエラー率を最小化するために,クラス分類のエラー尺度の上界を定義している.
最適解は,これらの上界を最小化するのと同様にクラス分類エラーを最小化するものを見つけることで,
結果的に得られる解は,線形カーネルの式で与えられる.

 k(w_1, w_2) = w^t_1 R w_2

R: 半正定値の対称行列

最適に正規化されたカーネル行列は、 R = W^{-1} で与えられ,W は学習時にバックグラウンドで,全ての詐称者に対して計算されるクラス内共分散行列である.
これは,1クラスに属する1人の所与の話者から全ての発話がなされたと仮定しているため,そのクラス内共分散行列は,以下のように計算される.

 W = \frac{1}{S} \sum^S_{s=1} { \frac{1}{n_s} } \sum^{n_s}_{i=1} { (w^s_i - \bar{w_s} ) ( w^s_i - \bar{w_s} )^t ) \hspace{10mm} \cdots (13)

ただし,  \bar{w_s} = ( 1 / n_s ) \Sigma^{n_s}_{i=1} {w^s_i} は各話者のi-vectorの平均であり,
 S は話者数, n_s は話者  s の発話数である.(発話ごとにi-vectorが存在する.)

cosカーネルでの内積を保存するために,特徴写像関数  \phi は以下のように定義される.

 \phi (w) = B^t w

ただし,B は [ tex:W^{-1} = B B^t ] のようにコレスキー分解によって得られる.
この論文では,WCCNアルゴリズムはcosカーネルに適用したらしく,その新しく得られたカーネルの式は以下のようになる.

 k(w_1, w_2) = \frac{ ( B^t w_1 )^t ( B^t w_2 ) } { \sqrt{ ( B^t w_1 )^t ( B^t w_1 ) } \sqrt{ ( B^t w_2 )^t ( B^t w_2 ) } }

WCCNアルゴリズムは,セッション間の分散を補正するために,クラス内共分散行列を使って,cosカーネル関数を正規化しているが,
NAPやLDAといった手法と違い,(#元の?)空間での(#データの分布の?ベクトルの向きの?)方向性の保存を保証している.


ii) LDA
1人の所与の話者から全ての発話が1つのクラスの表現をしていると仮定する場合,LDAはチャネルの影響によるクラス内分散を最小にするように、新しい空間軸を定義することに当たる.LDAの手法は,いらないものを除くように識別基準を元にして,話者間の分散に関するものを最小化するために行う.

パターン認識の分野で広く使われている,次元削減の手法.
この手法にある考えは,異なるクラス間をより識別しやすくなるように新しく直交軸を見つけることである.
その軸はクラス間分散を最大化して,クラス内分散を最小化するように求める.
この論文のモデルでは,各クラスは1人の話者からの全ての発話によって構成されるものとし,LDAの最適問題は,以下の比率に沿って定義される.

 J(v) = \frac{ v^t S_b v } { v^t S_w v }

この比率は,レイリー(#減衰?)係数と言われたりする.
これは,所与の空間方向 vでの,クラス間分散 S_b とクラス内分散 S_w (式(13)と同じ) の情報率の量を表しており,以下のように計算される.

 S_b = \sum^S_{s=1} { ( w_s - \bar{w} ) ( w_s - \bar{w} )^t
 S_w = \sum^S_{s=1} \frac{1}{n_s} \sum^{n_s}_{i=1} { (w^s_  - \bar{w_s} ) (w^s_i - \bar{w_s} )^t }

ただし, \bar{w_s} = (1 / n_s) \Sigma^{n_s}_{i=1} w^s_i は各話者のi-vectorの平均で, S は話者数, n_s は話者 s の発話数.

i-vectorの場合,話者の母平均ベクトル \bar{w} はnullベクトルと同じで,理由は因子分析において,
これらのi-vector w \sim N(0, I) の標準正規分布(0の平均ベクトル)を持つためである.

つまるところLDAの目的は,レイリー係数を最大化することであり,
この最大化は,一般的な固有値公式から得られる,最大の固有値を持つ固有ベクトルによって構成される写像行列 A を定義するのに使われ,

 S_b v = \lambda S_w v

 \lambda固有値の対角行列.
LDAによって得られた写像行列 A をi-vectorは通るため,2つのi-vector  w_1 w_2 間のcosカーネル式は以下のように書き換えられる.

 k(w_1, w_2) = \frac{ ( A^t w_1 )^t ( A^t w_2 ) } { \sqrt{ ( A^t w_1 )^t ( A^t w_1 ) } \sqrt{ ( A^t w_2 )^t ( A^t w_2 ) } }


iii) NAP
i-vectorのバックグラウンド?で計算されたクラス内共分散の最大の固有値をもつ固有ベクトルに基づくチャネル空間を定義する[5].その後,直交的に補正されたチャネル空間(話者空間)に,新しくi-vector写像する手法.

邪魔な方向性(#影響)を除くように適切な写像行列を見つける手法.
その写像行列は,特定の話者にのみ依存するような,チャネルの補空間で直行に写像してくれるもので,以下のように定式化される.

 P = I - R R^t

Rは式(13)でのクラス内共分散(もしくはチャネル共分散)の最大の固有値を持つ k 個の固有ベクトル(kベスト固有ベクトル)を列に持つ,
低次元の矩形行列である.

これらの固有ベクトルはチャネル空間を定義し,NAP行列でのcosカーネルは以下のように定式化される.

 k(w_1, w_2) = \frac{ (P w_1)^t (P w_2) } { \sqrt{ (P w_1)^t (P w_1) } \sqrt{ (P w_2)^t (P w_2) } }

ここでの w_1 w_2 は2つの全てのi-vectorである.


[実験]
[結果]

データセット 手法 EER(English) DCF(English) EER(All) DCF(All)
NIST2006 SRE JFA( s = m + Vy) 1.74 % 0.012 3.84 % 0.022
NIST2006 SRE SVM-FA(WCCN) 1.87 % 0.011 2.76 % 0.017
NIST2006 SRE SVM-FA(WCCN + LDA(200) ) 2.05 % 0.010 2.72 % 0.016
NIST2006 SRE SVM-FA(WCCN + NAP(150) ) 1.83 % 0.010 2.66 % 0.015
NIST2008 SRE JFA( s = m + Vy) 3.68 % 0.015 6.3 % 0.032
NIST2008 SRE SVM-FA(WCCN) 4.73 % 0.018 7.32 % 0.035
NIST2008 SRE SVM-FA(WCCN + LDA(200) ) 3.95 % 0.014 6.09 % 0.032
NIST2008 SRE SVM-FA(WCCN + NAP(150) ) 4.73 % 0.015 6.7 % 0.030

全部女性話者での結果.理由はどこかに書いたかもしれないけど,既存研究で女性話者の結果が悪くなりやすいので,その改善を今回図るため.
結果を見ると,「あれ?JFAの方が良いんじゃ?」ってなる.
しかし注目すべきはNIST2008SREで,SVM-FA(WCCN + LDA(200) )が最小のDCFをEnglishで出していて,ALLでもEERが最小である点とのこと.
Englishは,English trialsでAllはAll trialsのこと(英語データセットとすべての言語のデータセット).

[データベース]
だいたいのことは,飛ばす.
NIST2006(SRE)を開発データセットにして,NIST2008(SRE)をテストデータにして実験.
学習データもテストデータも電話回線のものを使っていて,各話者には5分間の電話回線での会話の録音があって,大体2分間くらいはある1人の話者の分らしい.
最初の条件として,1つの電話回線での会話を使って,targetモデルを登録(1140人の女性話者,648人の男性話者,21907個のテスト音声ファイル)して,それから10秒間の電話音声から話者を特定する.
次に,10秒の電話音声セグメントでtarget話者を登録して,また10秒の電話音声セグメントでテストする.
(# 結局,10秒の電話音声でtarget話者を登録して,また10秒の電話音声でテスト.この10秒の音声が同じか別かの言及はなし.(両方共,a 10-s speech segment))

NISTのevaluationプロトコルだと,他のevaluationデータセットとかも使っていいらしく,パラメータを求めるのにいろいろ使った模様(省略).

[実験環境]
[特徴量]
25msのHamming窓(フレームシフト10ms),19次元のMFCCCsと対数パワー(計20次元).
この20次元の特徴ベクトルは,3-s sliding windowを使って,feature warping してあるらしい.
5フレームの幅をとって,デルタとデルタデルタ係数も計算して,最終的には60次元の特徴ベクトルとしている.

2048個の正規分布を持つ性別ごとのUBM(#60次元の混合数2048のGMM?)と,2つの性別ごとのJFA用の設定を使用.
1つ目のJFAは300の話者因子と100のチャネル因子だけで構成されており,2つ目は全部で構成されている(対角行列 D を話者と共通因子を持たせるために加えている).
この対角行列 D が推定されると,固有声行列 V と対角行列 D の分解された推定値を使う.
つまり,総変動行列 Tによって定義された400もの総因子を使う.

JFA scoringで得られる決定値は,zt-normで正規化される.
女性話者に対しては,300t-norm(テスト正規化)モデルを使い,約1000z-norm(ゼロ正規化)の発話を使用した.

この論文のSVMのモデルでは,307の女性話者モデルと,SVMのバックグランドでの1292もの女性の詐称者モデルにt-正規化.
男性話者に対しては,1007の詐称者をSVMの学習で用いている(この詐称者はNIST2005(SRE)のデータセットを除いたもので学習したUBMと同じデータセットから得ている).
LDAとWCCNの行列を推定するのに,別のデータセットを使っている(LDA: switchboard + NIST2004 + NIST2005, WCCN: NIST2004 + NIST2005)のは,LDAが話者間分散をモデル化するのに対し,WCCNはチャネルをモデル化するため,異なるチャネル(固定電話回線,携帯電話回線)での録音があるNIST-SREで揃えた方がいいということ.


[SVM-FA]
(i)WCCN (ii)LDA (iii) NAP と組み合わせてやった結果について書いてある.
しかし,後の章でcos類似度を比較したほうが早くて精度もいいらしいので,実験条件だけ書いて飛ばす.

(i) WCCN
総因子空間のチャネル分散に対して補正する.
データセットによって,JFAの方がEERやminDCFが低かったりする.
理由は,NIST2004とNIST2005で推定されたWCCNがテストのNIST2008のチャネル補正には適切でなかったと考えているらしい.

(ii) LDA
チャネル補正をするために,i-vectorにLDAを適用.
次元削減をせずに(dim=400),話者内分散を最小化するように空間を回転させたら,cosカーネルのパフォーマンスが上がる.
次に,色々と次元削減の削減数を試した結果,次元数を250まで削減したらminDCFが低くなり(0.011),LDAした後にWCCNを適用すると,minDCFが次元数200の時に低くなった(0.010).
ただこれも,データセットによってはJFAの方がEERが低かったりするらしいが,minDCFが最も低いのはLDA+WCCNなので有効という主張.

他にも実験していて,LDAの2次元写像行列を使ってi-vectorの散布図を見てみたり,LDA+WCCNでその後,(# ベクトルの?)長さの正規化をして比較した.
その結果,WCCNは話者間分散を最小化することで,チャネルの影響を削減している.
ついでに,LDAとWCCNも適用されていない元の空間からの各話者のi-vectorの膨張が生じる(# 無駄にでかくなる?)が,cosカーネルを通してその膨張は除去される(長さが正規化される).
これはi-vector空間や話者因子空間でのcosカーネルで得られる結果らしい.

(iii) NAP
他のチャネル補正と比べて,そこまで結果は良くない模様.
NAPだけなら,corankが200のときにminDCFが低い結果(0.011).
これもLDAのときのように,WCCNと組み合わせて使用した結果,corankが150のときにminDCFが0.010と低くなった.
WCCNと組み合わせる上で,学習は,

NAP行列を総変動行列の学習で使った全部のデータで学習 -> 新しく写像された空間でWCCN行列を計算

という形でやる.

iv) 結果の性別での違いについて
実験に当たって,UBMと因子分析の条件は同じ(400総因子)だが,データセットを増やしている.結構増やしている.
その理由は,より幅広い変動を捉えるため.
ただ,総変動行列の学習に増やしたデータセットは使うが,JFAのパラメータ学習には使わない.
それは,JFAの学習には最低限5つの録音がある話者だけを使うが,増やしたデータセット中には5つ以上の録音があるような話者がほとんどいないためらしい.
増やしたデータセットは,1人の話者につき多くても3つの録音がほとんど.
一方,総変動行列の学習では,最低限でも2つの録音がある話者を使うので,増やしたデータセットでも大体のものが使える.
評価データセットは,NIST2008SREのcore conditionの電話回線のもの.
結果は,以下に記載.最良だった結果のみ(女性はEnglishとAllで最良が違うため2項目).

性別 手法 EER(English) DCF(English) EER(All) DCF(All)
女性 JFA( s = m + Vy + Dz) 3.17 % 0.015 6.15 % 0.032
女性 SVM-FA(WCCN + LDA(200) ) 3.68 % 0.015 6.02 % 0.031
男性 SVM-FA(WCCN + LDA(200) ) 1.28 % 0.009 4.57 % 0.024

結果的に,SVM-FAが全部の因子を使ったJFAよりも結果が良くなったことが注目点(特に男性).
これら4つの点からも,新しく定義した総変動空間でなら,話者間において線型分離がしやすいと言っている.


[cos類似度計算]
学習条件などは,前節までのSVM-FAの条件と一緒のまま,cos類似度を計算して閾値と比較する.
SVM-FAで詐称者モデルをt-normしたように,このモデルではzt-normでスコアを正規化する.
ただし,このシステムではSVMの学習で使われた詐称者はz-normされた発話として使われ,LDAとWCCNもSVM-FAと同じ行列が使われる.

実験では,"(話者登録に使うデータの録音時間)-(テストに使うデータの録音時間)"で,
short2-short3,short2-10sec,10sec-10sec
の3つの組み合わせで行う(secじゃない方はminite).
結果は以下.JFASVM-FAでの値は上記にある.

short2-short3の結果

性別 手法 EER(English) DCF(English) EER(All) DCF(All)
女性 cosine 2.90 % 0.012 5.76 % 0.032
男性 cosine 1.12 % 0.009 4.48 % 0.024

short2-10secの結果

性別 手法 EER(English) DCF(English) EER(All) DCF(All)
女性 cosine 5.91 % 0.034 9.59 % 0.050
男性 cosine 5.18 % 0.026 7.38 % 0.036

10sec-10secの結果

性別 手法 EER(English) DCF(English) EER(All) DCF(All)
女性 cosine 12.19 % 0.057 16.59 % 0.072
男性 cosine 11.09 % 0.047 14.44 % 0.063

short2-10secと10sec-10secの結果には,他手法との比較するための値があるが省略.
short2-10secでは女性は他手法と比べ2ポイントくらい改善したが,男性では大きな改善がなかった.
10sec-10secでは,他手法と比べ,男女共に4ポイントくらい改善.
流石に,話者登録に使う時間が短いと精度が下がるが,cos類似度での方がどの組み合わせでも最良の結果だった.

このような結果となった理由として,SVMの学習でのbackground話者が適切でなかったかもしれないという考察している.
また10sec-10secで凄い良い結果になったのは,提案手法だとパラメータ数が総因子400とJFAと比べ,少ないためじゃないかと考察している.

[結論]
既存手法と提案手法の違いは,高次元なGMM平均スーパベクトル空間じゃなくて,低次元なi-vector空間でチャネルの影響を処理している点.
最も良かったチャネル補正は,WCCN+LDAで,LDAで邪魔な情報を除去して話者間分散を最大化している点が話者照合においてデカい.


[Z-normとT-normについての補足]
Vijendra Raj Apsingekar, Phillip L. De Leon, "Speaker verification score normalization using speaker model clusters"(http://www.ece.nmsu.edu/~pdeleon/Research/Publications/SPECOM_2011.pdf)からT-normとZ-normについての話を見つけてきた.
どうやら,話者照合でよく使われる正規化手法らしい.(最初Triangular Norm(三角ノルム)とかだと思っていた.)
[Z-norm]
Z-normでは学習時に,詐称者の発話セットがtarget話者モデルに対してスコア付けされ,その結果得られる詐称者のスコア分布で
 \Lambda(X) = \log p(X \| \lambda_c) - \log p(X \| \lambda_{UBM})
 \Lambda(X) \geq \theta
 \tilde{\Lambda}(X) = \frac{\Lambda(X) - \alpha_c} {\beta_c} \hspace{10mm} \cdots (3)
 X: テスト音声からの特徴ベクトル系列
 \Lambda(X): targetモデル \lambda_c とUBMモデル \lambda_{UBM} に対してテスト音声の特徴ベクトルをスコア付けして計算された対数尤度
の式(3)での正規化パラメータ \alpha_c \beta_c を推定するらしい.
この推定は学習段階で行われ,テスト段階では特に追加的な計算はない(そこがZ-normの方が"マシ"なように見える原因らしい).
基本的に,利用できる詐称者の発話は全て使って正規化パラメータを推定する手法.

[T-norm]
T-normでは,テスト段階で,テスト発話がコーホートモデルの事前選択されたものに対してスコア付けされる(事前選択はターゲットモデルに基づいて行われる.)
結果として得られるスコアの分布は,式(3)の正規化パラメータの推定に用いられる.Z-normにさらにT-normを重ねてするところの良いところは,テストの音声間にどんな音響やセッションのミスマッチがあっても,詐称者の発話が削減されるところにある.しかしながら,T-normの悪いところは,コーホートモデルのスコア付けをするため,テスト段階で追加的な計算が必要になることである.

canvas上で2点間の直線を傾きを計算して回転させるメモ

タイトルが既に訳分からないですね.
今回もjavascriptを適当に書いた初心者メモです.

あるプログラムを書いていて,canvas上の2点間を傾きを計算して,直線化したくなったので,その方法を考えました.
まだ変なこと言ってそうな気がするので,下で図を使ってやろうとしていることを書きます.

今からやろうとしていることは,ある直線的なオブジェクトがあったとして,それを2点間においての直線のように配置したいときに便利な気がします.
正確には,x軸に平行に描画される,ある直線的なオブジェクトを特定の座標に平行移動させて,別の座標に向けて(長さを調整して)回転させたいときの,その回転角度の計算をします.

例えば

こんな感じで,直線的なオブジェクトを平行移動(translate)させて,そこから回転(rotate)させて,2点あるうち,もう一方の点に傾きを合わせたい場合です.(すでに一方の点にはtranslateさせた時点で接してます)

2点間に合わせるとこんな感じになります.

これを座標から回転させる角度を計算します.
今更ですが,今回の記事は canvasだと普通の xy軸に対して,y軸が反転していることと,直線的なオブジェクトが何もしないと,x軸に平行なため,傾きの計算が面倒なので,そんな変な場合の傾きの計算方法をメモしておくために書きました.

多分,こんな計算今後しないと思いますが,一応メモ.

2点間の始点を(startx, starty),終点を(endy, endx)と座標表記します.

 len = Math.sqrt(Math.pow(startx - endx, 2) + Math.pow(starty - endy, 2));
 w = (endy - starty) / (endx - startx);
 w = Math.atan(w);
 if(startx > endx) {
     w += Math.PI;
 }
 var canvas = document.getElementById('hoge');
 if ( ! canvas || ! canvas.getContext ) return false;
 var ctx = canvas.getContext('2d');
 ctx.save();
 ctx.translate(startx, starty);
 ctx.rotate(w);
 ctx.translate(0, -3*sx/5); // ここはいらない
 /*
     直線的なオブジェクトの描写
 */
 ctx.closePath();
 ctx.restore();

こんな感じで上図のように出来ました.
tan を計算して,それの atan を取って,始点の x座標が終点の x座標より大きい場合は,π を足すだけです.はい.
len は直線的オブジェクトの長さの値を入れてます.

今回は,直線的なオブジェクトの真ん中に始点と終点が来てほしかったので,ctx.translate(0, -3*sx/5); ってしてます.
-3*sx/5 だけ y座標をズラしてます.

終わりです.

javascriptでcanvas上に画像を描画するときの初心者メモ

最近ふと思い立ってjavascriptを特に勉強せず,適当に書いています.
そのうち,ちゃんとした入門書を読もうと考えています.

今のところcanvasで図形描くことしかやってません.
ブラウザは普段ChromeFirefoxを使っているのですが,画像をcanvas上に描画するところで,ちょっと動作が違った(というより書き方が悪かった)ので,後で自分が勉強し直すとき用のメモを残します.

onload = function() {
    draw();
};
function draw() {
    var canvas = document.getElementById('hoge');
    if( !canvas || !canvas.getContext ) return false;
    var ctx = canvas.getContext('2d');
    var img = new Image();
    img.src = "img.png";
    ctx.drawImage(img, 0, 0);
}

最初Firefoxで動作を確認しながら見ていたので,これでも画像がcanvas上に描画されてました.
ところが,Chromeだと何も表示されず,ただ真っ白(画像が表示されない状態)になってました.

調べたら,drawImage()する際に,画像がloadし終わる前だとダメみたいです.
次のように書くと,loadが終わったらdrawImage()するように出来るらしいです.

onload = function() {
    draw();
};
function draw() {
    var canvas = document.getElementById('hoge');
    if( !canvas || !canvas.getContext ) return false;
    var ctx = canvas.getContext('2d');
    var img = new Image();
    img.src = "img.png";
    img.onload = function() {
        ctx.drawImage(img, 0, 0);
    }
}

IEだとこれでもダメっぽくて,他にもいろいろ足すようです.(http://www.html5.jp/canvas/how6.html)
下のような感じになるみたいですが,Chromeとかだとうまく動作しなかったので,また暇な時に調べ直したい.

onload = function() {
    draw();
};
function draw() {
    var canvas = document.getElementById('hoge');
    if( !canvas || !canvas.getContext ) return false;
    var ctx = canvas.getContext('2d');
    var img = new Image();
    img.src = "img.png?" + new Date().getTime();
    img.onload = function() {
        ctx.drawImage(img, 0, 0);
    }
}

weechatとtiarra,bitlbeeを使って,IRCとtwitterをまとめたい

普段,weechatでIRCを見てます.
twitterも公式で見てたりするのですが,weechat内で見れると聞き,ターミナル内で見てたらtwitter見てるとバレにくいし,なんとなくcool感出る気がしたので,導入しようとしたメモです.
今回は,twitterのタイムラインをざっくり見るだけで,ログを取ったり,発言するところまではいきません.(後で加筆・修正するかも)

とりあえず,tiarraとbitlbeeを用意.(ircクライアントもないなら用意)

tiarrahttp://www.clovery.jp/tiarra/#downloadから落とします.

$ pacman -S bitlbee
$ wget http://www.clovery.jp/tiarra/archive/2010/02/tiarra-20100212.tar.gz
$ tar xvf tiarra-20100212.tar.gz

まずは,bitlbeeの設定ファイルをいじります.

$ su
# vi /etc/bitlbee/bitlbee.conf

とりあえず,localhostでデーモンとして起動するようにします.

RunMode = Daemon
DaemonInterface = 127.0.0.1
DaemonPort = xxxx(空いている適当なポート番号)

次に,tiarraの設定です.
解凍したディレクトリへ飛びます.INSTALLの手順通りに進めます.

$ cd tiarra-20100212
$ cp sample.conf tiarra.conf
$ vi tiarra.conf

設定ファイルはとりあえず,generalブロック,networkブロックをいじります.
*-encoding: utf8
のようなところは,環境に合わせて書きます.所々出てくるので,全部修正します.
ここではutf8としました.
[]書きにしているところは,各自由来の設定です.

general {
  nick: [nick_name]
  user: [user_name]
  name: Tiarra the "Aeon"(多分適当でいい気がする)
}
network {
  # 適当につけます
  name: irc
  name: bitlbee
  #separatorはデフォルトで#ですが,なんとなく&に変えました
  channel-network-separator: &
}
irc {
  server [serverIP] [port]
}
bitlbee {
  # host: localhostでもよいのかも
  host: 127.0.0.1
  port: xxxx(bitlbeeに当てたポート番号)
  # 実はここらへんのnick, user, passwordの設定が反映されませんでした.
  # bitlbeeでAuthModeとAuthPasswordをしないよう設定したせいなのか不明
  nick: [twitter_nickname]
  user: [twitter_ID]
  password: ***(AuthModeとか設定してないから多分意味ない)
}
$ bitlbee
$ ./tiarra --config=tiarra.conf --quiet

tiarraの設定で結構手間取って,最初は--quietオプション付けずに動作確認しながらやりました.
あとは,weechatを起動して,つなぎます.

$ weechat-curses

weechatでのコマンドを打ちます.

[@user] /connect irc
[@user] /join channel
[@user] /connect bitlbee

IRCはおそらく開けると思います.
bitlbeeも新バッファが開かれるので,そこへ移ります.

bitlbeeのバッファ画面だと,サーバ名がbitlbee,チャネル名が&bitlbeeになってます.(&なのは適当に自分で設定しました)
チャネルには,@rootと,自分だけがいると思います.(見た目は,普通のIRCと同じです)

とりあえず,bitlbeeで扱うtwitterのアカウントを追加します.
普通にIRCで発言する感じで,bitlbeeのコマンドを打つと,@rootさんが返事を返してくれます.
([twitter_ID]の[]は,勿論実際には付けません.)

[@user] account add twitter [twitter_ID]

アカウントを追加し,成功したら@rootが返事してきます.

@root | Account successfully added with tag twitter
@root | No need to enter a password for this account since it's using OAuth
[@user] account on

アカウントをonすると,@rootさんが何か言って,新バッファが開かれます.

@root | Trying to get all accounts connected...
@root | twitter - Logging in: Connecting 


新バッファに移ると,twitter_twitterIDさんがbitlbeeをtwitterの連携アプリとして登録するために,URIが提示してくるので,コピペしてブラウザで開いて,認証します.
既にtwitterにログインしているブラウザで開くと,連携アプリの「許可する」,「拒否する」の画面にすぐ行けます.
「許可する」と7桁のPINコードが出るので,それをtwitter_twitterIDさんに返事すると,新バッファが開かれてtwitterのログが見れるようになります.


[@user] 0000000 # これは適当です


[2014/06/26追記]
bitlbeeでのtwitterの基本的使い方


# tweet
[@user] hoge
# reply
[@user] reply [screenname] hoge
# retweet
[@user] rt [screenname]


others_twitter_id | [screenname] ほげほげ
となっているので,その16進数の番号がscreenname.

参考: http://wiki.bitlbee.org/HowtoTwitter


最後に,参考にしたWebページのURIを載せて終わります.
http://runeleaf.wordpress.com/2009/04/16/irc-irssi%E3%81%A8tiarra%E3%81%A8tigrb%E3%81%A8bitlbee%E3%81%A7%E3%82%82%E3%81%86%E3%81%84%E3%81%84%E3%82%88%E3%81%AD%EF%BC%9F/
http://d.hatena.ne.jp/tksthdnr/20090314/1237051567
http://wiki.bitlbee.org/HowtoTwitter
http://cynical-penguin-cafe.com/?p=795
http://karia.hatenablog.jp/entry/20071010/1192018415
http://yoosee.net/d/archives/2007/05/13/002.html
http://tatsu.jottit.com/tiarra%E3%81%A8bitlbee%E3%81%AE%E3%81%BE%E3%81%A8%E3%82%81

Arch Linux で cpanminus を使おうとしたときのメモ

少し前に,冬コミで『雅なPerl入門 第2版』を買いました.
読み進めていく内に,オブジェクト指向プログラミングのところでCPANのMinillaを使うと便利いうことでした.
この本だと,Macでcpanminusを使っていたので,Arch Linux でcpanminusを使おうとしたら,少し躓いたので,メモです.
ちなみにMinillaを入れて,minilを使うまでの話です.


とりあえず,cpanminusをpacmanで入れます.

$ pacman -S cpanminus

ここで,pacmanで入れたのに,$PATHの中にないようです.

$ which cpanm
which: no cpanm in ( ... )

探したら,/usr/bin/vendor_perl/にありました.
パスを追加します.

$ export PATH=$PATH:/usr/bin/vendor_perl

ようやくcpanmが使えるようになり,Minillaを入れようとします.

$ su
# cpanm Minilla

無事入ったので,適当にモジュールのテンプレを作ります.

$ minil new Foo::Bar --username=hoge
The "git" executable has not been found.

gitがいると怒られたので,gitも落とします.

$ pacman -S git
$ minil new Foo::Bar --username=hoge

gitでuser.nameを設定するか,--usernameオプションを使わないとダメだと怒られるので,今回は練習でminil使うだけなので,--usernameオプションを付けました.


これでカレントディレクトリ下に Foo-Bar/ のディレクトリが作成されて,minil を使えました.

こんなことでメモ書くのも何なのですが,初心者なのでしょうがないということで….