本記事は機械学習の徹底解説シリーズに含まれます。
初学者の分かりやすさを優先するため,多少正確でない表現が混在することがあります。もし致命的な間違いがあればご指摘いただけると助かります。
はじめに
非負値行列因子分解(NMF:Nonnegative matrix factorization)は,非負値のデータを要素にもつ行列を,頻出パターン行列とその係数行列に分解する多変量解析の手法です [1]。Leeらによって効率的な更新アルゴリズム [2] が発見されて以来,文書データ [3] や音源分離 [4] など様々な分野で応用されています。NMFの利点は,以下の三点に集約されます。
- 非負制約による解釈容易性
- 乖離度の選択自由性
- 教師なし学習モデルとしての理論的な裏付け
NMFは行列が非負値であるという制限から数値計算で減算されることがないため,正負の値をとり得る行列を扱う主成分分析や特異値分解とは異なる解析結果が得られます。実際,Leeらによって導かれた反復的な更新式は,乗算近似であるため各要素の非負値性を保持するアルゴリズムとなっています。このような性質のことをスパース性,または低ランク性とよびます。また,NMFの更新式では乖離度とよばれる様々な近似の指標を用います。乖離度には任意の関数を設定することが可能ですが,特定の関数を設定することにより,確率的生成モデルによる理論的な裏付けが可能になります。
問題設定
NMFの目的は,ある非負値行列を二つの非負値行列の積で近似することです。
ただし,
これらのベクトルを用いると,行列積の定義より式(
繰り返しますが,我々の目的は観測行列
- ユークリッド距離
-
ダイバージェンス-
- 板倉斎藤擬距離
-
いずれの乖離度も,
音源分離では,板倉斎藤擬距離基準のNMFはスペクトルピークの一致度を重要視することや,音響信号の低域と高域を同等の重要度で扱うことを可能にし,
乖離度の選択には,背後に仮定された生成モデルについても考慮する必要があります。ユークリッド二乗距離,
以上をまとめます。乖離度を
ただし,subject toは「〇〇という制約の下で」を意味し,
補足
上で紹介した三つの乖離度に加え,理論的な議論を行うため以下の二つの乖離度が用いられることもあります。
ダイバージェンス-
- Bregmanダイバージェンス
-
更新式の導出
我々の目的は,
補助関数である目的関数の上限を探すために,以下のイェンセン(Jensen)の不等式と接線の不等式がよく用いられます。
ただし,等号成立条件は
ただし,等号成立条件は
以下では,これらの不等式と補助関数法を用いて,乖離度にユークリッド距離,
ユークリッド距離
最初に結論を述べます。
に非負の初期値を与える- 以下の更新式を収束するまで繰り返す
早速更新式の導出を始めます。簡単のため,行列表記でなく要素を書き下す形で計算します。
この式を最小にする
補助関数法を用いるために,
を満たす補助変数
ただし,二階微分が正であるならば狭義凸であること,すなわち
のとき成り立ちます。式(
これを
すなわち,以下が得られます。
ここで,表記を簡潔にするために
式(
が成り立ちます。あとは補助関数法に従い,
狭義凸関数は,極小値が存在するならば最小値だけであるという性質をもちます。したがって,狭義凸関数
しかし,
まずは,
これを整理すると,以下が得られます。
次に,
これを整理すると,以下が得られます。
さて,式(
Iダイバージェンス
最初に結論を述べます。
に非負の初期値を与える- 以下の更新式を収束するまで繰り返す
更新式の導出方法は,ユークリッド距離の場合と同様です。
この式を最小にする
補助関数法を用いるために,
ただし,二階微分が正であるならば狭義凸であること,すなわち
のとき成り立ちます。これは,ユークリッド距離の等号成立条件(
式(
が成り立ちます。あとは補助関数法に従い,
上で説明した通り,狭義凸関数には極小値が存在するならば最小値だけであるという性質があります。したがって,狭義凸関数
まずは,
これを整理すると,以下が得られます。
次に,
これを整理すると,以下が得られます。
板倉斎藤擬距離
最初に結論を述べます。
に非負の初期値を与える- 以下の更新式を収束するまで繰り返す
更新式の導出方法は,ユークリッド距離・
実はFevotteらよりも早く、亀岡らによりNMFとは別文脈で補助関数法を用いた板倉斎藤擬距離に基づく最適化手法が提案されています。
とはいえ,更新式の導出方法の大枠はユークリッド距離の場合と同様です。
この式を最小にする
補助関数法を用いるために,
ただし,二階微分が正であるならば狭義凸であること,すなわち
のとき成り立ちます。これは,ユークリッド距離の等号成立条件(
続いて,式(
ただし,
のとき成り立ちます。ここで,表記を簡潔にするために
式(
が成り立ちます。あとは補助関数法に従い,
まずは,
これを整理すると,以下が得られます。
ただし,
これを整理すると,以下が得られます。
ただし,
生成モデルによる解釈
ユークリッド二乗距離,
を満たす
以下では,各種乖離度に基づくNMFはある確率分布に対する最尤推定問題と等価になることを示します。
ユークリッド二乗距離基準
観測行列の要素
を仮定します。このとき,対数尤度を
と表されます。
Iダイバージェンス基準
観測行列の要素
を仮定します。ただし,ポアソン分布の実現値は整数値であることから,
と表されます。
板倉斎藤擬距離基準
観測行列の要素
を仮定します。ただし,
と表されます。
上述の通り,
実装
本章では,ユークリッド二乗距離基準・
なお,Githubで公開している実装では,dockerを用いてNMFが実行できる環境を用意しています。上記パラメータを含め,さまざまなパラメータをdocker-compose.yml
で管理しています。
ソースコードのコメントは英語で書いています。これはGithubで公開する際に,外国の方々にも参考にしていただきたいからです。また,コメント規則であるdocstringはGoogleスタイルを利用しています。
ここからは,以下の形式でメソッド単位で解説を行っていきます。
[メソッド名・その他タイトルなど]
# ソースコード
[ソースコードの解説]
データの準備
以下では,NMFを適用するデータを生成していきます。
import numpy as np
import matplotlib.pyplot as plt
import sys
標準的なライブラリをインポートします。
Y = np.random.randint(1, 10, (10, 10)) # [1,10]の値を取る(10,10)サイズの行列を分解する
適当な近似行列を定義します。ただし,GitHubで公開している実装では,docker-compose.yml
によって,与えたパラメータにしたがって観測行列Y
を自動生成する仕組みになっています。
NMFクラスの定義
class NMF():
ここからは,NMFクラスを定義していきます。
コンストラクタ
def __init__(self, Y, M):
"""コンストラクタ
Args:
Y (numpy ndarray): (N, L)サイズの観測行列
M (int): 基底の数
Returns:
None.
Note:
eps (float): オーバーフローとアンダーフローを防ぐための微小量
"""
self.eps = np.spacing(1)
self.Y = Y
self.M = M
コンストラクタでは,観測行列Y
と基底数M
を初期化します。また,ゼロ除算やゼロの対数によるオーバーフローとアンダーフローを防ぐための微小量eps
も定義します。
パラメータ初期化メソッド
def init_params(self):
"""パラメータ初期化メソッド
Args:
None.
Returns:
None.
"""
self.cost_tmp = 10**6 # 適当に大きな数
self.cost = np.array([self.cost_tmp]) # 乖離度を記録するための配列
self.cnt_iteration = 1 # イテレーション回数を記憶しておく変数
コンストラクタとは別に,パラメータ初期化メソッドを定義します。これは,一つのクラスで複数の乖離度に基づく更新を行うためです。
行列初期化メソッド
def init_matrix(self):
"""行列初期化メソッド
Args:
None.
Returns:
None.
"""
self.H = np.random.uniform(low=1, high=10, size=(self.Y.shape[0], self.M)) # (L, M)
self.U = np.random.uniform(low=1, high=10, size=(self.M, self.Y.shape[1])) # (M, N)
self.X = self.H @ self.U
パラメータ初期化メソッドと同様に,パラメータ初期化メソッドを定義します。
乖離度計算メソッド
def EU_divergence(self):
"""ユークリッド二乗距離計算メソッド
Args:
None.
Returns:
None.
"""
self.cost_tmp = ((self.X-self.Y)**2).mean()
def I_divergence(self):
"""Iダイバージェンス計算メソッド
Args:
None.
Returns:
None.
"""
self.cost_tmp = (self.Y*np.log(self.Y/(self.X+self.eps)+self.eps)-self.Y+self.X).mean()
def IS_divergence(self):
"""板倉斎藤擬距離計算メソッド
Args:
None.
Returns:
None.
"""
self.cost_tmp = (self.Y/(self.X+self.eps)-np.log(self.Y/(self.X+self.eps)+self.eps)-1).mean()
各種乖離度を計算するメソッドを定義します。ここに他の乖離度を定義することも可能です。
更新メソッド
def EU_update(self):
"""ユークリッド二乗距離基準のNMF更新式計算メソッド
Args:
None.
Returns:
None.
"""
self.H *= (self.Y @ self.U.T) / ((self.H @ self.U) @ self.U.T + self.eps)
self.U *= (self.Y.T @ self.H).T / ((self.H @ self.U).T @ self.H + self.eps).T
def I_update(self):
"""Iダイバージェンス基準のNMF更新式計算メソッド
Args:
None.
Returns:
None.
"""
self.H *= ((self.Y / ((self.H @ self.U) + self.eps)) @ self.U.T) / (self.U.sum(axis=1, keepdims=True).T + self.eps)
self.U *= ((self.Y / ((self.H @ self.U) + self.eps)).T @ self.H).T / (self.H.sum(axis=0, keepdims=True).T + self.eps)
def IS_update(self):
"""板倉斎藤擬距離基準のNMF更新式計算メソッド
Args:
None.
Returns:
None.
"""
self.H *= np.sqrt(((self.Y / ((self.H @ self.U)**2 + self.eps)) @ self.U.T) / (self.U @ (1/((self.H @ self.U) + self.eps)).T + self.eps).T)
self.U *= np.sqrt(((self.Y / ((self.H @ self.U)**2 + self.eps)).T @ self.H).T / (self.H.T @ (1/((self.H @ self.U) + self.eps)) + self.eps))
各種乖離度に対する解析的な更新式を定義します。特に,ゼロ除算やゼロの対数によるオーバーフローとアンダーフローを防ぐためにコンストラクタで定義した微小量を利用する点に注意してください。
学習メソッド
def execute(self, n_iteration, divergence):
"""学習メソッド
Args:
n_iteration (int): 学習回数の上限
divergence (String): "EU", "I", "IS"のうちいずれかの乖離度
Returns:
None.
"""
while True:
if (divergence=="EU"):
self.EU_update()
self.EU_divergence()
elif (divergence=="I"):
self.I_update()
self.I_divergence()
elif (divergence=="IS"):
self.IS_update()
self.IS_divergence()
else:
print("Please select from EU, I, IS for the divergence.")
sys.exit(1)
if (self.cnt_iteration >= n_iteration or self.cost_tmp > self.cost[-1]):
print(f"====={self.cnt_iteration}回目でcostが悪化したため終了=====")
break
else:
self.X = self.H @ self.U
self.cost = np.append(self.cost, self.cost_tmp)
self.cnt_iteration += 1
上で定義した各種メソッドを利用して,学習を行うメソッドを定義します。DNNの確率的勾配降下法とは異なり,NMFでは解析的な解に基づく更新式を繰り返し適用していきますので,本来であれば学習回数のみを指定してあげればよいのです。しかし,今回は「更新回数の上限に到達した」または「コストである乖離度が悪化した」場合に学習を停止させるようにしています。後者を入れているのは,微小量とはいえゼロ除算やゼロの対数に近い演算を行うことによる情報の欠落や,初期値のランダム性による局所解への収束が考えられるためです。
乖離度の減少過程描画メソッド
def visualize_cost(self):
"""乖離度減少過程可視化メソッド
Args:
None.
Returns:
None.
"""
index = np.arange(self.cost.size-2)
plt.figure(figsize=(16,9))
plt.rcParams["font.size"] = 18
plt.plot(index, self.cost[2:], color=(0.93,0.27,0.17))
乖離度の減少過程をグラフ化するメソッドを定義します。ここではplotしていますが,GitHubで公開している実装ではコンテナとvolumeマウントを行い,画像を保存しています。
観測行列と近似行列の描画メソッド
def visualize_heatmap(self):
"""観測行列と近似行列の描画メソッド
Args:
None.
Returns:
None.
"""
fig, axes = plt.subplots(1, 2, figsize=(16,9))
fig.subplots_adjust(wspace=0.1, hspace=0.1)
axes[0].imshow(self.Y, cmap="inferno")
axes[0].axis("off")
axes[1].imshow(self.X, cmap="inferno")
axes[1].axis("off")
plt.show()
観測行列と近似行列をヒートマップで可視化するメソッドを定義します。このメソッドを通して,NMFがどれだけ精度良く加速行列を近似できたかを定性的に観察することができます。
パラメータの設定
M = 5 # 基底の数は5
n_iteration = 100 # 更新回数は100
各種パラメータを設定します。
NMFクラスのインスタンス化
model = NMF(Y, M)
上で定義したNMFクラスをインスタンス化しましょう。
NMFの実行
上でも言及した通り,NMFでは適切でない初期値を与えると局所解に収束してしまう可能性があります。そこで,今回は「パラメータで設定した更新回数の上限に初めて達した場合」の結果を抽出することにします。
ユークリッド二乗距離基準
while True:
model.init_matrix()
model.init_params()
model.execute(n_iteration, "EU")
if model.cnt_iteration == n_iteration:
break
model.visualize_cost()
model.visualize_heatmap()
ユークリッド二乗距離基準の乖離度減少過程は以下のようになりました。
ユークリッド二乗距離基準の観測行列と近似行列の可視化は以下のようになりました。
Iダイバージェンス基準
while True:
model.init_matrix()
model.init_values()
model.execute(n_iteration, "I")
if model.cnt_iteration == n_iteration:
break
model.visualize_cost()
model.visualize_heatmap()
板倉斎藤擬距離基準
while True:
model.init_matrix()
model.init_values()
model.execute(n_iteration, "IS")
if model.cnt_iteration == n_iteration:
break
model.visualize_cost()
model.visualize_heatmap()
板倉斎藤擬距離基準の乖離度減少過程は以下のようになりました。
板倉斎藤擬距離基準の観測行列と近似行列の可視化は以下のようになりました。
おわりに
深層学習(DNN:deep neural networks)の発展が凄まじい昨今においても,NMFにはDNNを用いた手法と匹敵するポテンシャルがあります。数学的な妥当性の担保が難しいDNNベースの手法とは対照的に,確率的生成モデルによる裏付けが可能なNMFを用いた研究には,地に足つけた取り組みが多い印象があります。特に音源分離の分野では,いまだにNMFに基づく手法の性能が高いことが知られています。
しかしながら,NMFには残された課題も数多く存在します。まず,モデルの緻密さを表す基底数が自明でないため,状況によって設定する必要があります [8]。さらに,自明なパラメータが多数存在することからNMFの最適化問題はNP困難であることが知られています [9]。実際,NMFの分解には一意性がなく [10],初期値に依存して意図しない解に収束することが多いです。これらの課題を克服し,DNNベースの手法を理論・性能の両側面から凌駕するような研究が今後積極的になされることを期待しています。
NMFを音響信号の観測スペクトログラムに適用する場合には,スペクトルは加法的であるという仮定と周波数成分比が時不変でゲインのみが時間変化するという仮定をおいています。これらの仮定は実際には成り立たないため,NMFを複素領域に拡張してモデルとしての妥当性を担保する複素NMF [11] が提案されています。
参考文献
[1] Lee+. Learning the Parts of Objects by Non-negative Matrix Factorization. Nature, 1999.
[2] Lee+. Algorithms for Non-negative Matrix Factorization. NeurIPS, 2001.
[3] Xu+. Document Clustering Based on Non-negative Matrix Factorization. ACM, 2003.
[4] Smaragdis+. Supervised and Semi-supervised Separation of Sounds from Single-channel Nixtures. ICA, 2007.
[5] King+. Optimal Cost Function and Magnitude Power for NMF-based Speech Separation and Music Interpolation. MLSP, 2012.
[6] Fitzgerald+. On the Use of the Beta Divergence for Musical Source Separation. In IET, 2009.
[7] Nakano+. Convergence-guaranteed Multiplicative Algorithms for Nonnegative Matrix Factorization with β-divergence. MLSP, 2010.
[8] Tan+. Automatic Relevance Determination in Nonnegative Matrix Factorization with the/spl beta/-divergence. TPAMI, 2012.
[9] Vavasis. On the Complexity of Nonnegative Matrix Factorization. SIAM, 2010.
[10] Huang+. Non-negative Matrix Factorization Revisited: Uniqueness and Algorithm for Symmetric Decomposition. TSP, 2013.
[11] Kameoka+. Complex NMF: A New Sparse Representation for Acoustic Signals. ICASSP, 2009.
コメント