にほんごのれんしゅう

日本語として伝えるための訓練を兼ねたテクログ

Deep Learningによる分布推定

Deep Learningによる分布推定

例えばこのような連続する事象の確率分布がある

横軸を時系列、縦軸を例えば企業の株価上がり下がり幅などとした場合、何か大局的なトレンドど業界のトレンドと国などのトレンドが入り混じり、単純な正規分布やベータ分布などを仮定できるものではなくなります。  

このとき、系列から学習して未来や未知の分布を直接求めることができ、かつ、異常値の検知などもしやすくすることなどを示したいと思います 

各系列で十分サンプリングでき、かつ、連続する事象の確率分布に対して予想したい場合  

例えば、この分布が日付のような連続なものとして扱われる場合、ある日のデータがサンプルできなかったり、まだサンプルが済んでない未来に対して予想しようとした場合、そういうことは可能なのでしょうか。  

ベイズでも可能ですが、せっかく十分にサンプリングできているので、ディープラーニングを用いて、KL距離、mean squre error距離などの距離関数で損失を決定して、分布を仮定せず、直接、確率分布を予想可能であることを示したいと思います  

上記の分布を生成する関数

正規分布2つから導かれる頻度を計算していって、最大となる点で割ることにより確率の密度を計算します

SIZEで定義される最大の値(時間)に対して、少しずつi(時間)をずらすことで、分布の中心点もまた変わっていくように、設計しました

import numpy as np

SIZE = 25000
for i in range(SIZE):
  sample1 = np.random.normal(loc=-2*np.sin(i/10), scale=1, size=10000)
  sample2 = np.random.normal(loc=5*np.cos(i/10), scale=2, size=30000)

微妙に距離がある2つの分布から構成されており、i(時系列)でlocのパラメータが変化し、支配的な正規分布と非支配的な分布が入りまじります  

時刻tから分布Dを予想するための距離関数

用いた損失関数は、Kullback-Leibler情報量 + 平均誤差の混合した損失関数です  

確率分布のような図が、問題なく各時間tにおいてDが定義できるので、何か特別な細工をせずとも、学習が可能です。

コードで表すとこんな感じです  

def custom_objective(y_true, y_pred):
  mse = K.mean(K.square(y_true-y_pred), axis=-1)
  y_true_clip = K.clip(y_true, K.epsilon(), 1)
  y_pred_clip = K.clip(y_pred, K.epsilon(), 1)
  kullback_leibler = K.sum(y_true_clip * K.log(y_true_clip / y_pred_clip), axis=-1)
  return mse + kullback_leibler / 1000.0

数式で表現すると以下のようになります

 

k:定数,0.001と今回は設定
これは、Image to Image[1]の論文と、この発表[2]に参考にしました(有効性の検証は別途必要でしょう)    

問題設定1. 欠けた部分から、もとの分布を予想する  

ある日のデータが何らの原因で欠けてしまった場合、周りの傾向を学習することで、欠けてしまったログから予想を試みます  

ところどころ、データが欠損しています。

これに対してDeepLearningのモデルで欠けた分布の予想をしていきましょう

このように周辺の値が非常に小さくなる分布となる非常に細かいところは欠けでしまいました(多分活性化関数の工夫の次第です)が、おおよそ再現できることがわかりました。  

ディープラーニングはサンプリング数が十分に多ければ、(正規分布、ベータ分布などの)分布を仮説せずとも、直接、求めることができることがわかりました。

操作方法

$ python3 distgen.py > dump.txt # 幾つかの分布からランダムに値をサンプリング
$ python3 make-dataset.py --invert # dump.txtを転地する
$ python3 make-dataset.py --np # numpyのアレイにする

$ python3 unlimited-dimention-spectre.py --train #学習
$ python3 unlimited-dimention-spectre.py --predict #抜けた穴の予想

問題設定2. 異常値検知を行う  

検定の話ですが、一般的に(95%などの)信頼区間に入るかどうかがよく使われる手法です。  

信頼区間確率密度関数が判明している必要がありますが、複雑な分布を本質的にもつようなものに当て推量で分布を仮定することが、事前に知識を外挿していることと等価であり、やらなくて済むケースが今回のケースです。  

この時、この分布が仮に確率分布と定義できるようなサンプリングをした場合、異常値の検出は、あるサンプルした点から95%の全体の面積を占める範囲外であるとき、と考えられれそうです。(これはディープラーニングの出力値が、離散値なので上から順に足し算、下から順に足し算でかんたんに求まります)

例えば、上記のような端っこの方に①のポイントにサンプルされたような場合、それが異常値かどうかは、②までの積分値(足し算)に、③の全体を割って、0.05以下になるとかと定義することが可能そうです  

(今回は十分に未来の確率密度までディープラーニングは学習できたので、一度作ったモデルでモデルの予想する分布から外れたところにあるものが、異常とみなせそうです)  

操作方法

$ python3 distgen.py > dump.txt # 幾つかの分布からランダムに値をサンプリング
$ python3 make-dataset.py --invert # dump.txtを転地する
$ python3 make-dataset.py --np # numpyのアレイにする

$ python3 unlimited-dimention-spectre.py --train #学習
$ python3 unlimited-dimention-spectre.py --future #未来の100系列を予想

少し細工した点

入力に対して、時系列のラベルは通常、一次元の数字なのですが、これを利用するとうまく収束しないです。(値が大きすぎるか小さすぎ、ネットワークが安定しない)

Dirty Hackっぽいですが、数字を2進数にしてN次元にします

ex)
5 -> [0, 0, 1, 0, 1]

このようにすると、今回のケースでは、うまく収束します  

コード

まとめ

  • 何か分布を仮定しない→知識の外挿なしなので、全く未知のこと、ドメイン知識がないことをやろうとするときなど便利です
  • その代わり完全な分布を各時系列などで構築している必要があり、これはどのようにデータを集めるかが鍵なきがします
  • データがそんなにないよ、ここまでパワフルな予想が必要がないよってときには、prophetがおすすめです

そもそも、DeepLearningは無限の重ね合わせによりガウス過程を構築していることと等価[3](これは感覚的に理解できます)ので、こういったタスクに実は向いているのではないでしょうか。テストデータからのハズレ具合による確信度の低さ(これはベイズの確信度の低さに該当するみたいです)みたいなのは今回利用していませんが、利用することはできそうです。つまり、もう一つのモデルの可能性として、ここまで大量の分布がサンプリングできないとき、testデータとの差を最小化するポイントを見つけることで、ガウス過程により導出したことと等価とみなせるモデルが構築可能でしょう。それでも、十分な期間とそれに該当するデータサンプル量が必要となりますが。  

参考文献

pytorch-pix2pix

pytorch-pix2pix

一年ほどまえ、pix2pix系のネットワークを編集して色々おもしろいことができると言うことを示しました。当時はブログ等に何かポストする際に再現可能なコードを添付することを諸事情により十分にできなかったのですが、pytorchに元論文の実装に近いImage to Imageが登場し、かなり強力で表現力の高いネットワークであったので、いくつか再現性とデータセットを再び添付して公開したいと思います  

  1. 白黒画像に色をつける
  2. 不完全な欠損した画像を復元する
  3. フォントのスタイル変換

Image-to-Imageのネットワークと論文とその実装系のForkのForkになります。

素晴らしい編集力と、コードの一般化を行った方々に感謝を申し上げます

A fork of PyTorch implementation of Image-to-Image Translation Using Conditional Adversarial Networks.

Based on pix2pix by Isola et al.

Update

Image to Imageの初版は2016年12月時点の論文ですが、2017年12月にもarXivにversion2が投稿されています。  

学習が安定しているかつ、複雑なネットワークにも対応していて、U-netと論文中では言われていますが、コード中ではResisual Blockなどと表現されており、入力情報を忘れないように細工をする仕組みが十分に入っていることがあるようです(経験的にこのネットワークはコンピュータリソースが十分にあれば巨大なネットワークでも学習できます)  

 

目的関数の設計については古典的な普通の表現を古典的な距離とGANでの距離のハイブリッドになっていて、古典距離はブラー(画像のボケ)を防ぐ効果が期待できます

 

GANの距離と

 

古典的な距離を

 

くっつけます

  

End2Endでラベルを用いるような学習をかなり色々試行錯誤しましたが、もう限界に達しているとも思い、これからは、学習自体に何らか意味あるような学習が優位になっていく用に思います。

requirements

  • Python3 with numpy
  • cuda
  • pytorch
  • torchvision

Getting Started

git clone

$ git clone https://github.com/GINK03/pytorch-pix2pix
$ cd pix2pix-pytorch

train dataset

$ python3 train.py --dataset facades --nEpochs 100 --cuda

train dataset

$ python3 test.py --dataset facades --model checkpoint/facades/netG_model_epoch_200.pth --cuda

Examples

白黒写真に色を付ける

夏+花のデータセットを用いて、学習します Download

$ wget https://www.dropbox.com/s/yhstjhqmsy1cneb/grayscale.zip
$ mv grayscale.zip dataset
$ cd dataset 
$ unzip grayscale.zip

train dataset

$ python3 train.py --dataset grayscale --nEpochs 100 --cuda

predict dataset

$ python3 test.py --dataset grayscale --model checkpoint/grayscale/netG_model_epoch_100.pth --cuda

example output

ノイズや欠落情報を復元する

"自然"のデータセットに対して、ノイズを乗せて復元を試みます   Download

$ wget https://www.dropbox.com/s/1yvr560s24sliay/random_drop.zip
$ mv random_drop.zip dataset
$ cd dataset 
$ unzip random_drop.zip

train dataset

$ python3 train.py --dataset random_drop --nEpochs 50 --cuda

predict dataset

$ python3 test.py --dataset random_drop --model checkpoint/random_drop/netG_model_epoch_50.pth --cuda

example output

フォントのスタイルの変換を行う

人間が習字で書いたデータセットに対して、Takao Fontと対応させて、新規フォントを作るという発想です

Download

$ wget https://www.dropbox.com/s/owee6hxopnr4dpo/font.zip
$ mv font.zip dataset
$ cd dataset 
$ unzip font.zip

train dataset

$ python3 train.py --dataset font --nEpochs 150 --cuda

predict dataset

$ python3 test.py --dataset font --model checkpoint/font/netG_model_epoch_150.pth --cuda

example output

コード

ご自由にご利用ください

参考

RNNで関数近似

RNNで関数近似

DeepLearningの一種であるRNNで、任意の関数を学習させて、十分にある関数の挙動が観測できたとき、未知の任意の点で予想できることを示したいと思います。

始める前に諸々調査したこと

ディープラーニングで任意の連続する関数を再現可能です。

しかし、ディープラーニングは無限やかなり大きな値を扱うことは難しく、適切にフィットしない問題があります。無限大に発散しない(発散してもいいけど、目的とする値をなにか閉域に限定して変換する操作を行う)必要があります

もっと有機的で人間的な特徴を学習と予想を行う問題として、sketch-rnnというrnnで最初の一部だけを描き、学習した内容で残りを予想するという問題設定もあって面白くユニークです

図1. 関数近似もスケッチの特徴を学び学習するのも一緒な気がします

耳だけ描くと、残りの部分が自動的に機械学習の予想結果により描かれます

様々な関数をDeepLearingのRNNで近似する

RNNはn-1からn-mまでの情報を特徴量にnの系列でのデータを予想することができます。
この時、連続であることが望ましく、無限小、無限大を取らないような、一定の再帰性があると収束しやすいです。(発散する関数は予想が大きくなるに近づくにつれ、難しくなります)

 

図2. アステロイド(うまくいく)

 

図3. 二次関数(うまくいかない)

数式で表現する

ディープラーニングのRNNのEncoder-Decoderの一つの機能の粒度を関数として表現すると、このように表現することができると思います。

ディープラーニングで適切なF1, F2, F3を決定することで、次の系列のX,Yが予想可能になります

ネットワークで表現する

ディープラーニングのネットワークではこのように表せるように思います

図4. 作成したネットワーク(RNNのAutoEncoderモデルを参考に作成)

このネットワークは特に媒介変数がないと表現できないようなネットワークについて高い力を発揮しそうだと考えました。

実験

サイクロイド

サイクロイドはこのような図形になます

 

媒介変数をもちいた表現はこのようになります

 

学習

$ python3 20-train-cicloid.py --train

評価

trainで使用しなかったデータを使用して予想

$ python3 20-train-cicloid.py --predict

 

図6. 予想したサイクロイド

ステロイド

ステロイドはこのように表現され、一定の大きさよりは大きくなりません

 

図7. アステロイド

媒介変数をもちいた表現はこのようになります

 

学習

$ python3 20-train-asteroid.py --train

評価

trainで使用しなかったデータを使用して予想します

$ python3 20-train-asteroid.py --predict

 

図8. 予想したアステロイド(たまにyが0にドロップする)

対数らせん

対数らせんはこのように表現されます。無限に大きくなるので、媒介変数thetaを一定の大きさでストップします

 

図9. 対数らせん

媒介変数を用いた表現はこのようになります

 

対数らせんの図

図10. 予想すした対数らせん(微妙に歪んでいる)

コード説明

Githubからどなたでも確認することができます
10-prepare.py
上記の例で示した図を描くような数字の系列のデータセットを出力します
以下のファイルが生成されます

サイクロイド.pkl
アステロイド.pkl
カージオイド.pkl
対数らせん.pkl
リサージュ.pkl
インボリュート.pkl

20-train-asteroid.py
ステロイドを学習&予想します
20-train-kardio.py
カージオイドを学習&予想します
20-train-cicloid.py
サークロイドを学習&予想します
20-train-spiral.py
対数らせんを学習&予想します

まとめ

  • いろいろな媒介変数でないと表現が難しい関数をy = f(x)でない、系列予想の問題設定とすることで簡単に予想することができそうだとわかりました
  • とにかく時系列でもなんでも連続した数字として表現できるのであれば、(モデルが十分に大きければ)予想が可能そうです
  • 仮定や解析プロセスを挟まずに学習&予想することができるので、楽です

参考文献

Microsoft Bingのランキングエンジンをxgboostでシミュレート

Microsoft Bingのランキングエンジンをシミュレートし、ランキングを学習します

目的

inspector(検査官、監査人、検閲官、視学、警視正、警部補)

ランキングアルゴリズムは日々進化しています。Googleサーチエンジン200以上の特徴量を用いたり色々しています。

これらはGoogleでないと手に入らない特徴量も多数存在しており、容易に、ユーザが最適化できるものではなかったりします

わかりやすいものでは、ドメイン以内にコンテンツが十分に存在し、それがある程度参照されるものであれば、以前あったようにWelqさんのようにコンテンツの内容の是非によらず、ランクアップしてしまうような問題もございました。

意図しない作用をもたらすから、狙ってはいけないなどということはなく、SEOはビジネスにおいて極めて重要な課題です。  

SEOでどの要素(サイト規模?テキスト数?キーワードの作り?コンテンツの内容?)などどれにどの程度注力すればいいのか判明したら大変なビジネスインパクトがあります。

ここでは、クリエイティブのキーワード(title, meta, body)で何がどの程度重要か、BingさんやGoogleさんなどを教師データとしたときに、機械学習アルゴリズムでサイトを、どの程度有益なのか定量化してみようと思います。  

お題

Rankingエンジンのランクの傾向を、検索クエリ結果から、ランキンされたサイトの自然言語的特徴から、獲得しようという意図です。

これを行うにあたって1つの制約があります。

1. ランキングエンジンのリバースエンジニアリングのような行為は認められるのか

  1. に関して述べると、この行為は、例えばGoogleやBingなどのサーチエンジンの競合を作るという意図がない、広域に解釈すれば、ビジネスでなければよいと言えそうである。例えば今回は、自己研究に基づくので問題がない。  

Microsft Bingのランキングエンジンのクエリ(neologdに内在している辞書を利用)することによって、膨大なダイバシティの検索結果が得られます。
検索結果のランキングを見ることにより、同等のランキングエンジンが作成可能であると期待できます

ランキングアルゴリズム一覧

読むべき論文

よく見る評価指標

目的関数

ranksvmフォーマット

資料が全くなく、調査して理解するまで結構かかりました。
ranksvmフォーマットはgroup fileというのが別途必要になっている

bingのデータクローン

  • neologdで一般単語をとりだす
  • bingでクエリを作成して、ひたすら大量に集める
  • 1位=4, 2位=3, 3位=2, 4位=1で、単一ページでないドメイントップのサイトをランキングする  
  • 言語処理的にtitle, meta, bodyの自然言語でランキングしてみる

(本当はこれ+DeepLearningでやってもいい)

オペレーション

Githubで公開しています(問題等があればtwitterにておしらせくださいませ)

Operation 1. ランククエリ生成

neologdなどからnoun(名詞)を取り出して、それを検索クエリ群にする

import glob
import pickle
import json 
nouns = []
for name in glob.glob('mecab-ipadic-neologd/build/*/*.csv'):
   f = open(name)
   for line in f:
     ents = line.strip().split(',')
     if '名詞' not in ents:
       continue
     term = ents[0]
     nouns.append(term)
open('nouns.json', 'w').write( json.dumps(nouns, indent=2, ensure_ascii=False) )

Operation 2. bingをスクレイピング

$ python3 scrape.py

Operation 3. フルドメインが入っているリンクをパース

$ python3 scan_pair.py

Operation 4. bingの結果からフルドメインスクレイピング

$ python3 pair_scrape.py

Operation 5. フルドメインのHTMLをパース

$ python3 10-parse-htmls.py

Operation 6. 分かち書きして特徴量化

$ python3 20-make-vector.py

Operation 7. 疎行列で表現してranksvm形式のファイルを出力

$ python3 30-index.py

学習

OP7を実行すると学習可能なファイル群が出力されます
(xgboostのバイナリがlibcなどの互換がなくて実行できない場合は、xgboostを再コンパイルしてください)

$ cd rank
$ ./xgb mq_train.conf 

map(mean average precision)の略で、平均精度です。pairwiseで評価すると、mapでの評価になります。他の関数のndcgなどはうまく動作しません。なぜ?

1000roundでの精度はこの程度です

[20:36:05] src/tree/updater_prune.cc:74: tree pruning end, 1 roots, 936 extra nodes, 1252 pruned nodes, max_depth=36                                                                                 
[20:36:05] [999]        test-map:0.721291        

学習が完了すると、rank.modelというファイルが出力されます

予想

rank.modelをもちいて未知のクエリに対してランキングすることができます

$ ./xgb mq_predict.conf 
[20:51:20] 144775x162216 matrix with 3899318 entries loaded from test.data
[20:51:20] start prediction...
[20:51:49] writing prediction to pred.txt

pred.txtの中にランキングされたファイルが記されています。

ランクの値と、実際のランクはこのように表現され、やはり相関など何も考えなくても単純にランキングが上になりがちな構成という物がありそうです
(予想ランク@左、実測ランク@右)

1.05754 4
-0.578957 2
0.386893 0
0.511651 4
0.683687 2
-0.800342 0
0.642033 4
0.35129 2
0.74472 0
1.39248 4
0.454038 2
0.221512 0
...

単純なSVMなどを利用すると、簡単に配信システムで計算できますが、勾配ブーストのようなランキングはどうなんですかね。決定木なのでC++のファイルなどに変換させるのが良いと思います

xgboost, lightgbmランキング意外と便利

ランキング学習はレコメンドエンジンとも深く結びついた技術でマネタイズのコアをなしうる重要なテクノロジーです

AIで自動判別でなんかすごいのを作る前の前哨戦で、レコメンドはぜひとも検討に値するテクノロジーです  

おまけ

勾配ブーストによる特徴量選択の結果を見ることができます

強力に非線形化されているので、これ単独で見ることにあんまり意味はないのですが、どんな特徴量が選ばれやすいのかは視覚的に確認できます

例えばランキングに影響する単語群はtitleとkeywordの重要度が高いのはなるほどという感じなのですが、車なども強いことがわかります

title:インポートファッションアイテム 1989114     
title:Sledge 680939                              
title:バンキング 465049                          
title:西善 314689                                
title:メイプルストーリー 188914                  
keyword: ベローズ の 専門 メーカー  180548       
title:ラセン 153568                              
title:DV 86233                                   
keyword:建築 資材  68659                         
title:あぜ 68124                                 
body:none 60321                                  
keyword: クロス ロード  51767                    
title:Shade 46926                                
title:食通 44635                                 
body:, 43729                                     
keyword:競艇  38174                              
keyword: 常滑  32940                             
title:多摩丘陵 29434                             
title:cherry 25848                               
body:MAZDA 25152                                 
title:の 23459                                   
title:エビス 23234                               
title:本田技研工業 23085                         
body:Jewelry 22530                               
title:・ 21902     
...