ぱたへね

はてなダイアリーはrustの色分けができないのでこっちに来た

Learn or Die

PFNの西川さんと岡野原さんが書かれた本。ようやく時間取って読むことが出来ました。

www.amazon.co.jp

お二人の考え方も結構違う所があるので、どの章をどちらが書いているのかを確認しながら読んだ方が面白い。 本の内容は、今までの取り組みと今後の狙いを熱く語る内容で、2018年頃はこう思っていて、今はどうなんだろうと比べながら読むのがこの本の楽しみ方だと思う。

読んでいて面白かった所を紹介します。

GRAPEとMN-Core

最初から読んでいたら、いきなりGRAPEが出てきて驚きました。あ、MN-Coreの後ろにはGRAPEがあるんだと一気に興奮しました。GRAPEについては、スーパーコンピューターを20万円で創るに非常に詳しく開発時の思いが載っています。

www.amazon.co.jp

エンジニアなら誰でも自分の計算をする専用プロッセサーを自作したいと思うことがあると思います。専用プロセッサーは、専用OSだったり、専用コンパイラだったりしてもOKです。自分が使う道具を自分のためにチューニングしたい、そういう思いがMN-Coreに行ってるんだなと。

最近こういう気持ちを忘れているので、やっぱFPGAやりたいなと思いました。

クラウドとエッジと生物

クラウドとエッジの関係を生物のアーキテクチャに例えるのはすごく面白かったです。末端の神経はいろんな情報を持っているが、実際に脳に行く時には多くの情報が捨てられています。この本は情報を捨てることをサボると表現していて、「どうやって適当にサボるかをネットワーク全体で学習しても良いはずだ」と書いてあるのが面白い。

エッジ側の人間として極小のレイテンシと情報のフィルタリングだけに目が行きがちな所を、その役割分担も学習しても良いし動的に変わっても良いじゃんってのはなかなか思いつかないなと感じました。

まとめ

途中までは過去の経緯だったりAIについての期待だったりもやもやした感じでしたが、所々におおおっと思わせる記述があって楽しめました。起業までいかなくても、新規事業をしたい人や、社内で何か挑戦したいって人にも勇気づけられることが多くお勧めできます。

エラスティックリーダーシップ

エラスティックリーダーシップを今更ながら読みました。とても良かったので紹介します。

www.oreilly.co.jp

大きく前半、後半に分かれていて前半が本文、後半が業界の有名人のエッセイ集となっています。タイトルの通りチームリーダのポジション向けの本です。

本文

最初のリーダーシップとはなんぞやみたいな話の後に、チームの状態(サバイバルモード、学習モード、自己組織化モード)の説明があります。今までなんとなく分かっていたことが上手く説明されていました。

サバイバルモードは、炎上していたり納期が厳しかったりして学習する時間が無い状態。ここでは、肩書きを使って強権を発動してでもまず抜け出すことが大事。メンバーに学習する時間を作るようにすること。

学習モードはチームがゆとりを持ち、それを新しいスキルの集中的訓練に充てている時間。直接的な育成期間とも取れます。新しい事に挑戦しやすい環境を作り、学習の谷や失敗を受け入れてチーム全体として成長していく事。

自己組織化モードは、学習モードが上手くいて自立的に動ける状態。

自己組織化モードになったら、管理のレベルが一つ上がってくる。自己組織化モードになったチームには僕は何もしなくて良いので、実際はサバイバルモードと学習モードを繰り返す気がする。 そのモードであっても、気をつける言葉遣いやコミュニケーションについても具体的かつ、あまり押しつけがましくなく書いてあって、直ぐにでも導入できそうでした。

エッセイ

後半のエッセイについては、日本人のエッセイは心に来る物がありました。 過去、はてなダイアリーなどで目標としていた人達の話をもう一度聞けたようなそんなそんな感じをうけました。

ちょうど @yugui がこんなつぶやきをしていて、自分が10年前、20年前に目指していたエンジニアになれているのだろうかと考えてしましました。

頑張らねば。

はじめてでも安心!Unityの教科書

仕事でUnity絡みそうなので、Unityの本を何冊か買ってみて一番わかりやすそうな本を読んでみました。 プログラミング経験と簡単な座標系の知識があれば2日で掲載されているゲームは動かせるようになると思います。

www.sbcr.jp

ゲームで使うキャラクターの配置の仕方、C#での制御方法、Prefabの使い方、Physics等の機能を追加する方法、Assetの追加方法など分かりやすく書いてありました。 他の本に比べると、最初の画面の説明がミニマムでさっとゲームを作り始められるのが良かったです。サンプルゲームの作り方も、全くはしょらずに全部の手順が書いてありちょうど良いレベルでした。

サンプルに入っているイガグリ当てゲーム。

f:id:natsutan:20201201215410p:plain

山を作り、木を生やし、衝突のエフェクトなど、順番に作って行くのが楽しかったです。

Unityの文字が小さくて辛いときは、UI Scalingを変更しましょう。150%にするだけでもだいぶ楽になりました。

Unityが全くわからない状態から、なんとなく開発の雰囲気が分かり仕事もなんとかなりそうです。

TensorFlow User Group Meetup - ベイズ分科会

今年の頭からベイズを勉強していたので、興味満点で参加してきました。発表されるトピックも全て面白く、ベイズの可能性を感じる勉強会でした。

動画は公開されているので、見逃した人は今から見ましょう。

https://www.youtube.com/watch?v=7rBI11Rze2c

ハンズオン資料も公開されています。興味ある人は直ぐにでも動きを試せます。ありがとうございます。

ベイズ統計とPPLの基礎 須山 敦志さん

ベイズ推論による機械学習入門の筆者の方です。僕はPRML挫折してこの本で勉強しました。

www.amazon.co.jp

ベイズモデリングの基本的な考え方から実務での話など、導入の話としてとても面白かったです。聞きたかった質問にも丁寧に答えていただき勉強になりました。

気になる画像処理への応用については、こっちの本を見てくださいとのこと。

www.amazon.co.jp

読まなくては。

近年のPPLの動向 HELLO CYBERNETICSさん

実際にロボットの制御をされている人の発表でした。各PPLの紹介とともに、可視化ライブラリArvizの紹介がありました。ベイズの勉強をしていたとき、可視化が難しかったのでライブラリ使えるとうれしいです。どのPPL使っても可視化か部分が共通なら覚え直しも無くて良いなと思いました。

TF Probabilityは難易度高そう。情報があまりない頃のTensorflowを思い出しました。

TFPの基礎と応用 木田 悠歩さん

実際にTF Probabilityを使ったコードの説明がありました。やはりShapeが難しい。ちゃんと理解して、その気になれば手で数式終えるレベルでないとTF Probabilityは使うのが難しそうです。どんどんユーザーが増えて情報が増えていくと楽になると思います。

TFPの基礎と応用 森賀 新さん

TV番組IPPONを題材にベイズを使って推論する過程が見れました。個人のポテンシャルと問題の相性といった仮定を数式に落としていくのが良かったです。仮定を置いて数式に反映させる流れが、教科書では良く分からなかったのでとても勉強になりました。また、ベイズが主観的では無いかという問が発生する理由も分かりました。

深層生成モデルと世界モデル,深層生成モデルライブラリPixyzについて 鈴木 雅大さん(東京大学 松尾研究室)

世界モデルの話は初めて聞いたので夢中で聞いてしまいました。Deep Learningだと画像生成はVAEよりはGANの方が派手な成果があるのですが、VAEの応用の話がいっぱいあって良かったです。もっと詳しく聞きたい発表でした。どこで現実の世界とゲームの世界が融合するのか、時間の問題の気がします。

時系列データと確率的プログラミング 柏野 雄太さん(バクフー株式会社)

座談会で脳の話をされたインパクトが強く、やりたいことをするにも健康が大事だと思いました。

カルマンフィルターはさらっと勉強したけども分からなかったところが少し分かりました。 この講義の27番目が良いとのこと。時間があれば挑戦したい。

www.youtube.com

最後に

TFUGとしては初めてのベイズ分科会でした。

勉強に関しては基本はPRMLっぽい雰囲気ですが、独学は厳しいし、もっとわかりやすい本がでてくると期待しています。Deep Learningも最初はさっぱりだったのが、とりあえず動くMNISTや絶対に動く学習済みモデルなどが公開されて、ハードルが下がった気がします。ベイズもそういう情報が増えるとうれしいですね。

発表全てが面白く勉強になりました。次回もぜひ開催して欲しいです。企画をされた佐藤さん、発表者の皆さんありがとうございました。

F#でEM法

入門機械学習による異常検知のEM法(期待値最大化、expectation–maximization algorithm)をF#で書いてみました。

www.amazon.co.jp

出てくる数式とキーワードはこんな感じで、詳細は本を買って読んでみてください。

データ

教科書と同じ平均3.0、標準偏差0.5のデータに対して、平均0.0、標準偏差3.0のノイズが乗っているデータを分離します。

f:id:natsutan:20200810221106p:plain

アルゴリズム

山iへの帰属度 q_i^{(n)} を求める

q_i^{(n)} = \frac {\pi_i N (x^{(n)}) | u_i ,  \sigma ^2 ) } { \sum_{ l = 1 } ^ K  \pi_l N(x^{(n)} | u_l , \sigma_l ^2) }

 q_i^{(n)} を基に3つの値を更新する

\mu_i = \frac { \sum_ { n = 1 } ^ N  q_i ^ { ( n ) } x^{ ( n ) } }{  \sum _ { n' = 1 } ^ N q_i ^ {(n)} }

 \sigma ^ 2 = \frac { \sum _ {n=1} ^ N q _ i ^ {(n)}(x ^ {(n)}-{\mu}_i ^ 2)}{\sum _ {n'=1} ^ N q_i ^ {(n')}}

 \hat { \pi } _ i = \frac 1 N \sum _ {n=1} ^ N q _ i ^ {(n)}

この計算を10回回して計算します。

教科書と大体同じ結果になりました。これくらいならF#使いやすいです。

以下ソース。

// Learn more about F# at https://fsharp.org
// See the 'F# Tutorial' project for more help.
open MathNet.Numerics.Distributions
open FSharp.Charting

type GaussDistri = { mu :float ; sigma :float}
let randgen = System.Random()
let output_path = @"C:\home\myproj\study_ml\abnormaly_detection\fsharp\abnormal_data\output\"


let sampleData(gd0:GaussDistri, gd1:GaussDistri, pi:float):float = 
    
    if randgen.NextDouble() < pi then
        Normal(mean=gd0.mu, stddev= gd0.sigma).Sample()
    else
        Normal(mean=gd1.mu, stddev= gd1.sigma).Sample()


let generateData = 
    let N = 1000
    let pi0 = 0.6
    let gd0:GaussDistri = {mu = 3.0; sigma =  0.5}
    let gd1:GaussDistri = {mu = 0.0; sigma =  3.0}

    [| for _ in 1 .. N -> sampleData(gd0, gd1, pi0) |]


let plotData (data:double[]) = 
    let n = Seq.length data

    let chart =  Chart.Point [for i in 0 .. n - 1 -> (i + 1,  data.[i]) ]
    let output_file = output_path + @"em.png" 

    Chart.Save output_file chart
    printf "%s\n"  output_file
    None

let calcMu(x:double[], q:double[], pi:double[]):float =
    let numerator = Array.map2 (fun x y -> x * y) x q |> Array.sum
    let denominator = Array.sum q

    numerator / denominator

let calcSigma(x:double[], q:double[], mu:float, pi:float) :float = 
    let x_minus_mu = Array.map (fun x -> (x - mu)**2.0 ) x
    let numerator = Array.map2 (fun x y -> x * y) q x_minus_mu|> Array.sum
    
    let denominator = Array.sum q

    sqrt (numerator / denominator)


let em (data:double[]) = 
    //初期値
    let mutable pi0 = 0.5
    let mutable pi1 = 0.5
    let mutable mu0 = 5.0
    let mutable mu1 = -5.0
    let mutable sigma0 = 1.0
    let mutable sigma1 = 5.0

    let mutable qn0 = 0.0
    let mutable qn1 = 0.0

    for _ in 0 ..10 do
        let piN0 = Array.map (fun x -> pi0 * Normal.PDF(mu0, sigma0, x)) data
        let piN1 = Array.map (fun x -> pi1 * Normal.PDF(mu1, sigma1, x)) data
        let qn0 = Array.map2 (fun p0 p1 -> p0 / (p0 + p1)) piN0 piN1
        let qn1 = Array.map2 (fun p0 p1 -> p1 / (p0 + p1)) piN0 piN1
        pi0 <- Array.average qn0
        pi1 <- Array.average qn1
        mu0 <- calcMu(data, qn0, piN0)
        mu1 <- calcMu(data, qn1, piN1)
        sigma0 <- calcSigma(data, qn0, mu0, pi0)
        sigma1 <- calcSigma(data, qn1, mu1, pi1)

    let gd0:GaussDistri = {mu = mu0; sigma =  sigma0}
    let gd1:GaussDistri = {mu = mu1; sigma =  sigma1}

    gd0, gd1, (pi0, pi1)
    

[<EntryPoint>]
let main argv =
    let data = generateData
    plotData data |> ignore
    let gd0, gd1, pis = em data

    printf "gd0 %A\n" gd0
    printf "gd1 %A\n" gd1
    printf "%A\n" pis


    0 // return an integer exit code

F#で多変量正規分布に基づく異常検知

natsutan.hatenablog.com

の続き。入門機械学習による異常検知の多変量正規分布に基づく異常検知をF#で書いてみました。

入門 機械学習による異常検知―Rによる実践ガイド | 剛, 井手 |本 | 通販 | Amazon

出てくる数式とキーワードはこんな感じで、詳細は本を買って読んでみてください。

平均値

 \hat{{\bf { \mu }}} = \frac 1 N \sum_{n=1}^N {\bf { x }}^{(n)}

共分散行列

 \Sigma = \hat{\Sigma} =  \frac 1 N \sum_{n=1}^N ({\bf { x }}^{(n)} - {\bf {\mu}})   ({\bf { x }}^{(n)} -\hat{\bf { \mu }}) ^T

異常度の定義、マハラノビス距離

 a({\bf { x }}') = ({\bf { x }}' -  \hat { \mu } ) ^ T \hat { \Sigma } ^ {-1}({\bf { x }} ' - \hat{{\bf { \mu }}})

実行結果

教科書と同じ結果になりました。

f:id:natsutan:20200809164626p:plain

F#実装

MathNet周りでちょっと詰まったところを整理しました。

List、配列からMatrix型を作る

一度array2Dを作って、Matrix.Build.DenseOfArrayを呼び出せばOK。list0とlist1に同じ数のデータが入っているとして、このように書けばMatrixが作れます。

let arr = array2D [ list0; list1 ]
let data = Matrix.Build.DenseOfArray  arr

Matrix型からRowやColumnを取り出す。

Column(i), Row(i)を使う。2次元のMatrix xから0番目のコラムと1番目のコラムを取り出すにはこのようにします。

let c0 = x.Column(0)
let c1 = x.Column(1)

Matrixの平均値を求める。

MathNet.Numerics.Statistics.meanを使う。体重の値がはいったMatrixから平均値を求めるにはこうします。

let weight_mean = Statistics.Mean weights

RowやColumnでイテレートする

2次元MatrixからRow方向にデータを取り出して処理するには、EnumerateRowsを使います。

for row_data in  x.EnumerateRows() do
  ...

分からないこと

2次元配列のRow方向に一定の値を引く方法が良く分からないです。 数式だと x - \mu のように、体重や身長からそれぞれの平均値を引く操作です。

Pythonだと何も考えずにできます。

>>> import numpy as np
>>> a = np.array([[1,2,3], [4,5,6]])
>>> b = [[1],[2]]
>>> a - b
array([[0, 1, 2],
       [2, 3, 4]])
>>>                                    

row方向にmapができれば良さそうだが、結局やり方分からず。

F#ソース

以下ソースです。

open FSharp.Data
open FSharp.Charting
open MathNet.Numerics.LinearAlgebra
open MathNet.Numerics.Statistics
open MathNet.Numerics.Distributions

let csv_path = @"C:\home\myproj\study_ml\abnormaly_detection\data\car2.csv"
let output_path = @"C:\home\myproj\study_ml\abnormaly_detection\fsharp\Hotelling\output\"
type CarDB = CsvProvider<"C:/home/myproj/study_ml/abnormaly_detection/data/car2.csv">

let plotAbnormality (xs :List<float>, th:float)  = 
    let mutable chart_list = []
    let n = Seq.length xs

    let chart1 =  Chart.Point [for i in 0 .. n - 1 -> (i + 1,  xs.[i]) ]
    let output_file = output_path + @"abnomality.png" 

    let chart2 = Chart.Line [ for x in 0.0 .. 200.0 -> (x, th) ]

    let chart_comb = Chart.Combine [chart1; chart2]

    Chart.Save output_file chart_comb
    
    printf "%s\n"  output_file
    None

let getData = 
    let car = CarDB.Load(csv_path)
        
    let weight = [ for row in car.Rows -> (float row.Weight)]
    let height = [ for row in car.Rows -> (float row.Height)]
    //weight, height
    let n = List.length weight

    //let data = DenseMatrix.init 2 n (fun i j -> if i == 0 then weight.Item j else height.Item j)
    let arr = array2D [ weight; height ]
    let data = Matrix.Build.DenseOfArray  arr

    data.Transpose()

let calcMahalanobis(x:Vector<float>, mu_hat:Vector<float>, sig_hat_inv:Matrix<float>) =
    let x_minus_mu_hat = x - mu_hat
    let a = x_minus_mu_hat * sig_hat_inv * x_minus_mu_hat

    a

let calcAbnormality (x:Matrix<float>) =
    let n = float x.RowCount
    let weights = x.Column(0)
    let heights = x.Column(1)

    // \hat μ
    let weight_mean = Statistics.Mean weights
    let height_mean = Statistics.Mean heights
    let mu_arr = [|weight_mean; height_mean|]
    let mu_hat = Vector.Build.DenseOfArray mu_arr

    // \hat Σ
    let sig_arr = array2D [ weights - weight_mean; heights - height_mean ]
    let x_minus_mu = Matrix.Build.DenseOfArray  sig_arr
    let sig_hat = (x_minus_mu * x_minus_mu.Transpose()) / n
    let sig_hat_inv = sig_hat.Inverse()

    // 異常度の計算
    let mutable abnormality = []
    for d in  x.EnumerateRows() do
        let a = calcMahalanobis(d, mu_hat, sig_hat_inv)
        abnormality <- a :: abnormality

    List.rev abnormality


[<EntryPoint>]
let main argv =    
    let data = hdtwo.getData
    let abnormality = hdtwo.calcAbnormality data
    
    let threshhold = ChiSquared.InvCDF(1.0, 0.99)
    hdtwo.plotAbnormality (abnormality, threshhold) |> ignore

    0 // return an integer exit code

F#でホデリングT^2法

入門機械学習による異常検知の最初の例題をF#で書いてみました。

www.amazon.co.jp

内容は入力されたデータの分布推定を行い、異常度の計算を行います。詳細は本を買ってください。

異常度の式 a(x') = ( \frac {x' - \hat \mu }{ \hat \sigma} ) ^ 2 を使ってデータから異常検知を行います。

F#での実行結果。Rと同じ結果になりました。

f:id:natsutan:20200807122957p:plain
異常検知

詰まりそうな所は2箇所です。

Rのライブラリをcsv化

Rを立ち上げて、write.csv()を使えばOK

> library(car)
> data(Davis)
> write.csv(Davis, "C:/home/tmp/car.csv")

カイの二乗分布の計算

次にRのqchisqに相当する関数をどうやって用意するかですが、MathnetのChiSquaredを使いました。

numerics.mathdotnet.com

qchisqに相当する関数はInvCDFなので引数に注意して呼び出せばOKです。

ソースコード

ソースはこんな感じで。

// Learn more about F# at https://fsharp.org
// See the 'F# Tutorial' project for more help.
open FSharp.Data
open FSharp.Charting
open MathNet.Numerics.Distributions

let csv_path = @"C:\home\myproj\study_ml\abnormaly_detection\data\car.csv"
let output_path = @"C:\home\myproj\study_ml\abnormaly_detection\fsharp\Hotelling\output\"
type CarDB = CsvProvider<"C:/home/myproj/study_ml/abnormaly_detection/data/car.csv">

let getWeights = 
    let car = CarDB.Load(csv_path)
    
    [ for row in car.Rows -> (float row.Weight)]
    
let plotWeights (xs :List<float>)  = 
    let n = Seq.length xs
    let chart =  Chart.Point [for i in 0 .. n - 1 -> (i + 1,  xs.[i]) ]
    let output_file = output_path + @"weights.png" 
    Chart.Save output_file chart
    
    printf "%s\n"  output_file
    None

let statWeight (xs:List<float>) =
    let mu = List.average xs
    let sigma2 = List.map (fun x -> (x - mu) ** 2.0) xs  |> List.average

    (mu, sigma2)

let calcAbnormality (xs:List<float>) =
    let mu, sigma2 = statWeight xs
    List.map (fun x -> (x - mu) ** 2.0 / sigma2) xs
   
let plotAbnormality (xs :List<float>, th:float)  = 
    let mutable chart_list = []
    let n = Seq.length xs

    let chart1 =  Chart.Point [for i in 0 .. n - 1 -> (i + 1,  xs.[i]) ]
    let output_file = output_path + @"abnomality.png" 

    let chart2 = Chart.Line [ for x in 0.0 .. 200.0 -> (x, th) ]

    let chart_comb = Chart.Combine [chart1; chart2]

    Chart.Save output_file chart_comb
    
    printf "%s\n"  output_file
    None


[<EntryPoint>]
let main argv =
    let weights = getWeights
    plotWeights weights |> ignore

    let abnormality = calcAbnormality weights
    let threshhold =  ChiSquared.InvCDF(1.0, 0.99)
    printfn "閾値 = %A" threshhold

    plotAbnormality (abnormality, threshhold) |> ignore


    0 // return an integer exit code