php-ml で手書き数字認識
TRANSCRIPT
自己紹介内山雄司 (@y__uti)
◦ http://y-uti.hatenablog.jp/ (phpusers-ja)
仕事◦ 受託開発の会社 (株式会社ピコラボ) でプログラマをしています
興味◦ プログラミング言語処理系
◦ 機械学習
2017-11-29 第120回 PHP勉強会 2
やったことPHP-ML に実装されている「ロジスティック回帰」という手法で
手書き数字認識を試してみました
簡単なデモを用意したので以下の URL で試せます
http://150.95.149.208/digit/
フロントエンドできないおじさんなのでタッチデバイスには対応していません
2017-11-29 第120回 PHP勉強会 4
手書き数字認識画像を受け取って 0 ~ 9 の数字のいずれかを返す
2017-11-29 第120回 PHP勉強会 5
function recognizeDigit($image) : int{
$digit = "0 ~ 9 の中で $image に一番近い数字"
return $digit;}
手書き数字認識画像をピクセル値の配列と考えれば、単なる数値計算の問題
2017-11-29 第120回 PHP勉強会 6
function recognizeDigit(array $data) : int{
$digit = "0 ~ 9 の中で $data に一番近い数字"
return $digit;}
◦ $data の "0 っぽさ" ~ "9 っぽさ" をそれぞれ計算して
◦ 一番それっぽい数字を返す
"1" っぽさの計算各座標に得点を配分して合計する◦ 真ん中あたりはピクセルが "ON" になっていたら加点する
◦ 左右の端の方でピクセルが "ON" になっていたら減点する
2017-11-29 第120回 PHP勉強会 8
加点されまくり = 1 っぽい!
"1" っぽさの計算各座標に得点を配分して合計する◦ 真ん中あたりはピクセルが "ON" になっていたら加点する
◦ 左右の端の方でピクセルが "ON" になっていたら減点する
2017-11-29 第120回 PHP勉強会 9
このあたりは加点されるが
このあたりは減点される
減点要素が多い = 1 っぽくない
手書き数字認識「どのように得点を配分するか」が性能の良し悪しを決める
良い得点配分を (大量の) データから計算で求めるのが機械学習◦ 具体的な計算方法は色々ある
◦ 得点の付け方自体も「座標ごとの合計」より複雑な手法が色々ある
2017-11-29 第120回 PHP勉強会 10
デモの説明The MNIST database of handwritten digits
◦ http://yann.lecun.com/exdb/mnist/
◦ 全部で 70,000 文字の手書き数字画像が含まれるデータセット
学習方法◦ 今回は 10,000 文字を利用 (全部使うにはメモリが足りなかった)
◦ PHP-ML の LogisticRegressionという手法で学習
◦ 学習された「得点」を使ってデータを判別
機械学習の特徴 (例外もあります)
◦ 学習には時間がかかる ⇒オフラインのバッチでゴリゴリやる
◦ 判別は一瞬 ⇒サービスとして提供する
2017-11-29 第120回 PHP勉強会 11
大まかな実装 (学習)デモサイトの実際の実装とは異なります
2017-11-29 第120回 PHP勉強会 12
$dataset = new CsvDataset($trainfile, 784, false);
$classifier = new LogisticRegression($maxiter,false,LogisticRegression::BATCH_TRAINING,'log','L2');
$classifier->train($dataset->getSamples(), $dataset->getTargets());
$modelManager = new ModelManager();$modelManager->saveToFile($classifier, $modelfile);
大まかな実装 (判別)デモサイトの実際の実装とは異なります
2017-11-29 第120回 PHP勉強会 13
$dataset = new CsvDataset($testfile, 784, false);
$modelManager = new ModelManager();$classifier = $modelManager->restoreFromFile($modelfile);
$predicted = $classifier->predict($dataset->getSamples());
$actual = $dataset->getTargets();$accuracy = Accuracy::score($actual, $predicted);