Mahoutにパッチを送ってみた

Preview:

DESCRIPTION

DSIRNLP勉強会 #2の資料です。

Citation preview

Mahout にパッチを送ってみた

@issay

自己紹介• 吉田一星(よしだ いっせい)• @issay• 某企業で検索や Hadoop に関する仕事をし

てます

今日は皆既月食• 11 年振りの好条件、次のチャンスは 2030

年 1 月 31 日らしい– 部分食始まり: 21 時 54 分– 皆既食始まり: 23 時 5 分– 皆既食最大 : 23 時 31 分– 皆既食終わり: 23 時 58 分

流れ• 実装寄りの勉強会ということなので・・・• Mahout がどのようにアルゴリズムを

MapReduce で実装しているかをひたすら解説

• 教師あり学習のみ• 送ったパッチについて紹介

機械学習の並列分散• 大規模データを扱うために機械学習の並

列分散は不可欠になりつつある• 機械学習を代表する学会、 NIPS には Big

Learning Workshop がある• 本も発売予定

Mahout とは?• Hadoop を使った機械学習ライブラリ• MapReduce での並列分散が主目的– すべての手法が MapReduce での分散に対応し

ているわけではない• コードの品質はバラツキがある• ドキュメントが未整備なものが多く、

コードを読みながら使うのが前提

実装している手法• リコメンデーション(協調フィルタリン

グ)– ユーザベース– アイテムベース– オンラインとオフラインの両方可能– 様々な類似度をサポートしている• Cosine, LLR, Tanimoto, Pearson…

実装している手法• クラスタリング– K-means / Fuzzy K-means– 階層クラスタリング– Canopy クラスタリング– EM アルゴリズム– Mean shift– ディリクレ過程– Latent Dirichlet Allocation– スペクトラルクラスタリング– LSH(Minhash)

実装している手法• 分類– Naïve Bayes / Complemetaly Naïve Bayes– ランダムフォレスト– 確率的勾配降下法 (SGD)• ロジスティック回帰• Passive Aggressive

– SGD は MapReduce での分散に対応していない• パッチを送ってみたよ

MapReduce

MapReduce の処理フロー

Map

Reduce

入力 出力

MapReduce

以上 Twitter 高負荷試験終了!はいはい、バルスバルスメガ!メガ!いやー、クジラさん見えためがぁぁぁぁぁぁぁぁ目がぁ目がーばるすぬるぽバルス!!バルス!ヴァルス!!!!!!!!!!!!!!!!!きたあああああああああああああああああバロスバルスバルス!!!!!!!!!!ふたりとも成長しすぎ30 秒前 バズー「僕の左手に手を乗せて」

例: Tweet の単語をカウントする

MapReduce: Map フェーズ

< バルス , 1>key value

以上 Twitter 高負荷試験終了!はいはい、バルスバルスメガ!メガ!いやー、クジラさん見えためがぁぁぁぁぁぁぁぁ目がぁ目がーばるすぬるぽバルス!!バルス!ヴァルス!!!!!!!!!!!!きたああああああああああああああバロスバルスバルス!!!!!!!!!!ふたりとも成長しすぎ30 秒前バズー「僕の左手に手を乗せて」

< バルス , 1>

< バルス , 1>

< ぬるぽ , 1>

< バルス , 1>

MapReduce: Shuffle フェーズ

< バルス , 1>

以上 Twitter 高負荷試験終了!はいはい、バルスバルスメガ!メガ!いやー、クジラさん見えためがぁぁぁぁぁぁぁぁ目がぁ目がーばるすぬるぽバルス!!バルス!ヴァルス!!!!!!!!!!!!きたああああああああああああああバロスバルスバルス!!!!!!!!!!ふたりとも成長しすぎ30 秒前バズー「僕の左手に手を乗せて」

< バルス , 1>

< バルス , 1>

< ぬるぽ , 1>

< バルス , 1>

< バルス , 1>

< バルス , 1>

< バルス , 1>

< バルス , 1>

Key 順にソート

MapReduce: Shuffle フェーズ

< バルス , [1,1,1,1,1,1,1,1,1,…]>

以上 Twitter 高負荷試験終了!はいはい、バルスバルスメガ!メガ!いやー、クジラさん見えためがぁぁぁぁぁぁぁぁ目がぁ目がーばるすぬるぽバルス!!バルス!ヴァルス!!!!!!!!!!!!きたああああああああああああああバロスバルスバルス!!!!!!!!!!ふたりとも成長しすぎ30 秒前バズー「僕の左手に手を乗せて」

< ぬるぽ , 1>

Key ごとにまとめる

MapReduce: Reduce フェーズ

以上 Twitter 高負荷試験終了!はいはい、バルスバルスメガ!メガ!いやー、クジラさん見えためがぁぁぁぁぁぁぁぁ目がぁ目がーばるすぬるぽバルス!!バルス!ヴァルス!!!!!!!!!!!!きたああああああああああああああバロスバルスバルス!!!!!!!!!!ふたりとも成長しすぎ30 秒前バズー「僕の左手に手を乗せて」

バルス 14594ぬるぽ 1

単語のカウントを足しあわせて

結果を出力

Shuffle って何?• Shuffle で行われること– ソートする– 同じキーをまとめる

• Shuffle は抽象的概念?• Map タスクと、 Reduce タスクで分散ソー

トを行なっているだけ

分散ソート

Map

Reduce

入力 出力

それぞれキーをソートし Reduce

タスクに転送

Reduce タスクでは複数のソート済みファイルの

マージを行う

キーのハッシュ値(デ

フォルト)で各 Reduce タスクごとに分割

Map タスク内のソート• バッファサイズを超えたら、バッファに

たまったデータのキーをソートしてファイルに書きだす

• 最後に書きだしたファイルをマージして、Reduce タスクに転送する

というわけで本題

ナイーブベイズ

ナイーブベイズとは?• 単語 w のカテゴリ c における確率

• 文書 d のカテゴリ c における確率– 文書 d に出てくる単語 w の確率の積と定義

• 確率が最も高いカテゴリに分類すればよい• 単語の相関関係や語順は考慮していない

カテゴリ c の単語 w の頻度の合計

カテゴリ c のすべての単語の頻度の合計

0.07 × 0.1 × 0.01… = 0.000025

ナイーブベイズとは?• 文書 d のカテゴリ c における確率は P(d|c)– カテゴリ c が与えられた上での文書 d の確率

• ほんとは P(c|d) を求めたい– 文書 d が与えられた上でそれがカテゴリ c で

ある確率• そこでベイズの定理

P(c|d) =P(d|c) P(c)

P(d) 文書 d を分類するときには考慮しな

くていい

カテゴリ c の文書数

すべての文書数

アンダーフロー対策• 確率を掛け合わせるとすぐにアンダーフ

ローになってしまう0.07 × 0.1 × 0.01…

• Log をとって足し合わせれば OKLog(0.07) + Log(0.1) + Log(0.01)

ゼロ頻度問題• 単語の確率が一つでもゼロになると文書全体の確率もゼロになってしまう0.07 × 0.1 × 0.01 × 0 … = 0

• 単語 w がクラス c に出現しないからといって確率がゼロなわけではない

• スムージングを行うカテゴリ c の単語 w の頻度の合計 + 1

カテゴリ c のすべての単語の頻度の合計 + すべての単語の種類数

さらなる実装の工夫• Mahout では、以下の論文に書かれている

実装の工夫を行っているTackling the Poor Assumptions of Naive Bayes Text

Classifiers (2003)

• 単語頻度 (TF) の変換• 文書頻度の逆数 (IDF) を掛ける• 文書長正規化• Competent Naïve Bayes• カテゴリ正規化

単語頻度 (TF) の変換• 頻出語の影響を減らすため以下の正規化

を行うlog( 文書 d の単語 w の頻度 + 1)

文書頻度の逆数 (IDF) を掛ける• 単語のレア度を考慮するため、文書頻度

の逆数 (IDF) を掛ける– ある文書にだけ多くその単語が出現するなら、

スコアを上げる

すべての文書数

単語 w を含む文書数log ( 文書 d の単語 w の頻度 + 1) × log

文書長正規化• 文書の長さによってばらつきが出ないよう

に正規化を行う

文書 d における単語 w の重み

文書 d における単語の重み全ての二乗の合計

Complement Naïve Bayes

• カテゴリごとの文書数にばらつきがあると精度が出ない

• カテゴリ c に含まれない文書で学習すればよい– カテゴリ c以外の文書ならば、数のばらつきが少ない

• カテゴリ c以外の全てのカテゴリでの単語 w の確率

• 確率が最も低いカテゴリに分類すればいい– カテゴリ c以外での確率が最も低い=カテゴリ c での確率が

最も高い

全体での単語 w の重み合計 - カテゴリ c の単語 w の重み合計

全体での全ての単語の重みの合計 - カテゴリ c の単語全ての重みの合計

カテゴリ正規化• 最後にカテゴリごとにばらつきが出ない

ように、カテゴリごとに単語の確率の合計で正規化する

• 学習ではなく分類の時に正規化する

カテゴリ c の単語 w の確率

カテゴリ c の全ての単語の確率の合計

カテゴリ c以外のすべてのカテゴリ

の確率

Mahout での実装• 基本的にはカウント問題– Mapper

• 何かの Key と、それに対する数値を Value で出力– Reducer

• Value をすべて足し合わせて出力• カウントしなければならないものが多いので

MapReduce を 4 回行っている• Mapper で複数の種類の Key を出力し、 Reducer で

は種類ごとに出力先を変えている• 単語の分割はスペース区切りでしか対応していない

ナイーブベイズの学習• BayesFeatureDriver• BayesTfIdfDriver• BayesWeightSummerDriver• CBayesThetaNomalizerDriver(BayesThetaNom

alizerDriver)

BayesFeatureDriver

• 文書と正解カテゴリを入力とする• Mapper

– 単語 w の重みを計算する( TF正規化 + 文書長正規化)<Key: カテゴリ c+ 単語 w> <Value: 単語 w の重みの合計 ><Key: カテゴリ c+ 単語 w> <Value: 1><Key: 単語 w> <Value: 1><Key: カテゴリ c> <Value: 1>

• Reducer– カテゴリ c での単語 w の重みの合計– カテゴリ c で単語 w を含む文書数– 単語 w を含むすべての文書数– カテゴリ c に属する文書数

BayesTfIdfDriver

• Mapper– IDF を計算する<Key: カテゴリ c+ 単語 w> <Value: 単語 w のカテゴ

リ c の重みの合計 ><Key: カテゴリ c+ 単語 w> <Value: IDF><Key: 固定キー > <Value: 1>

• Reducer– TF と IDF を掛け合わせるカテゴリ c での単語 w の重みの合計すべての単語の種類数

単語の種類数を計算しようとしてい

BayesWeightSummerDriver

• Mapper<Key: 単語 w> <Value: 単語 w のカテゴリ c の重みの合計 ><Key: カテゴリ c> <Value: 単語 w のカテゴリ c の重みの合

計 ><Key: 固定キー > <Value: 単語 w のカテゴリ c の重みの合計

>

• Reducer– すべての文書の単語 w の重み合計– カテゴリ c におけるすべての単語の重み合計– すべての文書のすべての単語の重み合計

BayesThetaNomalizerDriver

• Competent Naïve Bayes の場合は、 CBayesThetaNomalizerDriver を起動

• 最後のカテゴリ正規化のために使う• Mapper– 単語 w のカテゴリ c の最終的な確率を計算<Key: カテゴリ c> <Value: 単語 w のカテゴリ c の確率

>

• Reducer– カテゴリ c におけるすべての単語の確率の合計

ランダムフォレスト

決定木とは?

身長 > 170cm

髪の毛の数 < 8 万 偏差値 > 40

年収 > 800 万

女 男

男 女 男

ランダムフォレストとは?• 複数の決定木を用いる• 分類の場合、それぞれの木の出力するカ

テゴリの多数決で最終的な出力を決定• とてもシンプルながら、学習・テストが高速かつ精度がいい。素性が多い場合にも有利

決定木の構築• 学習データをブートストラップサンプリング

し、 B組のデータセットを作成する– 重複を許したサンプリング

• それぞれのデータセットごとに B組の決定木を構築する– M個の素性を選択する– M個の素性のうち、最も学習データをよく分類

する素性と閾値を用いて、枝を分岐– 分岐した先の学習データがすべて同じカテゴリに属していれば終了

枝の分岐• 正解カテゴリのエントロピーを計算する–びっくり度の期待値、乱雑さを測る指標

カテゴリ c に属するデータ数すべてのデータ数

P(Y=y) = カテゴリが c である確率 =

H(Y) = -Σ P(Y=y) log P(Y=y)y 2

枝の分岐• 枝を分岐後のエントロピーを計算する

ある素性が x であるデータ数すべてのデータ数

H(Y|X) = H(Y|X>=t)P(X>=t) + H(Y|X<t)P(X<t)

P(X=x) = ある素性が x である確率 =

相互情報量• 枝を分岐前と分岐後のエントロピーの差が、どれ

だけ良く学習データを分類しているかの指標になるI(X,Y) = H(Y) – H(Y|X)

• 相互情報量とも呼ばれ、どれだけ2つの確率分布が独立に近いかを表す独立なとき I(X,Y)=0

• 相互情報量が大きい=2つの確率分布に関係がある– カテゴリが c である確率と、素性が x以上である確率に

より関係があるような素性と x で分類

枝の分岐• すべての素性について、どこで分割するかをすべて

の場合について相互情報量を計算

• 最も相互情報量の高い素性と、その分割値で分割

身長 年収 偏差値 髪の毛の数155 300万 30 8万156 900万 70 11万158 220万 56 12万

左に分岐

右に分岐

身長 > 156身長をソート

Mahout での実装• 決定木の数だけ処理を分散できる• Mapper だけで Reducer は使っていない• ブートストラップサンプリングと、単純に

データを分割する2通りが実装されている

• 数値の大小で枝を分割するのと、すべての数値ごとに枝を分割する2通りが実装されている

Mahout での実装• ImMemInputFormat– Mapper の数 / 決定木の数 だけ各 Mapper に処理を割り当てる

– 学習データを各 Mapper の入力にするのではない

• InMemMapper–決定木の数だけ map 関数が呼ばれる• それぞれの繰り返しで、ブートストラップサンプ

リングを行って、決定木の構築を行う

ロジスティック回帰

ロジスティック回帰とは?• ある重みベクトル w からあるクラス c に属する確率を予測したい– x がサンプル

2 クラスの場合

ロジスティック回帰とは?• 多クラスの場合

すべてのカテゴリの合計

カテゴリ k に属する確率

尤度関数• 正解のカテゴリに属する確率

• 正解のカテゴリに属する確率を掛け合わせたのが尤度関数

• この尤度関数ができるだけ大きくするような重み wを推測すればよい– 正解カテゴリに属する確率が大きければ、正解カテゴリに

分類される

損失関数• 尤度関数は大きければ大きいほどよかったが、小さくなればなるほどよい損失関数を考える

• 掛け算は扱いにくいので対数をとる

• 以下の更新式を繰り返し適用していけば、損失関数が最小値に近づく–この更新を確率的勾配降下法 (SGD) という

確率的勾配降下法 (SGD)

• 最終的に以下の式を更新すればよい

学習データの正解ラベル

最小値にだんだん近づく

学習レート

Mahout の実装• 今まで解説したのはオンラインでの学習

の手法– データを一つづつ見ていってその都度重みを更新

– データをすべてをいっぺんにみて更新するバッチ学習もある

• Mahout に実装されているのもオンラインで、 MapReduce での分散には対応していない

Mahout の実装• L1/L2正則化に対応している

– 過学習を防ぐために損失関数にペナルティ項を設ける

• FOBOS でペナルティ項も含めてオンラインで更新– 重みがゼロになりやすいように工夫

• Lazy Update で高速化– 0 の素性は更新しない– 素性が 0 ではないデータが来た場合、今までゼロだった分を一気に更新する– スパースなベクトル(ほとどんどゼロなベクトル)の場合有効

• 学習レート– 素性ごとと、全体の2種類の学習レートがある– それぞれ、更新されるごとに減少させている

L1正則化重みが大きな値を取り過ぎ

るとペナルティ

Adaptive Logistic Regression

• ハイパーパラメータ(学習レートなど)が違う学習器を n個用意

• データ数件を、それぞれの学習器で学習– スレッドで並列に学習させている

• 学習結果がよい学習器(尤度の合計がよいもの)上位m 件を選択

• 上位m 件の学習器と、上位の学習器のパラメータを少しランダムに変化させた n-m個の学習器で再度学習を行う

送ったパッチの概要• オンライン学習を MapReduce で行う–近年オンライン学習を並列分散する手法が多

く提案されている– 最も良い結果が出ている Iterative Parameter

Mixing という手法を実装• 以下のアルゴリズムに対応– Logistic Regression– Adaptive Logistic Regression– Passive Aggressive

Iterative Parameter Mixing

Mapper Mapper Mapper

Reducer

重みベクトルを更新

重みベクトルを更新

重みベクトルを更新

重みベクトルを平均

[Mann et al. 09][Mcdonald et al. 10]

MapReduce

• Mapper– 正解データを入力– 前回の繰り返しの重みを Map の初期化処理で読み込んで

おく– オンライン学習で、重みを更新

• Reducer– Reducer は一つだけ立ち上げる– 重みをスコアで重み付き平均して出力する

• この MapReduce を繰り返す

Key スコア(尤度の合計など)Value 重み

送ろうパッチ• Mahout はパッチを送ってみるにはいいの

かも– Mahout は Hadoop 本体などと比べて、それほ

ど完成されておらず、改善の余地も多い–全体のコード量も Hadoop 本体と比べて少な

い– Hadoop / MapReduce 使わなくても Java で書きさえすればいいらしい

Mahout の問題点• 日本語のテキストを扱いたい• MapReduce を繰り返すようなアルゴリズ

ムでは、 MapReduce を立ち上げるコストがかかるので非効率– クラスタリング– グラフ– Iterative Parameter Mixing…

Iteration効率化• たくさんのフレームワークが存在する– HaLoop– MapReduce Online– iMapReduce– Spark– Twister– Hadoop ML…

Hadoop 0.23

• MapReduce以外のフレームワークをサポート– MPI– Spark– Graph– Hama

• 今後は MapReduce以外や、 MapReduce と他のフレームワークの組み合わせが増えるかもしれない– MPI と MapReduce をうまく組み合わせた All

Reduce

以上!

Recommended