変わりモノがいい!

変わりモノには価値がある・・・ハズ?

憧れだった文字認識にチャレンジしました。

時代の流れを感じます。

僕が社会に出たのは1981年、当時はPCも珍しく、マイコンもあまり復旧していない状況でした。 例えば、モトローラの究極の8ビットMPUである6809をつかっている某社のPCの上で6809のアセンブラを走らせようにもアセンブラが存在しませんでした。 色々探して雑誌に載っていたアセンブラを使って開発中の製品のプログラムを作りました。 当時は大変でした。 雑誌にのっていたアセンブラを使ってアセンブル言語を機械語に変換し、変換結果をデータ分として出力しました。 そのデータ分をBASICのプログラムの中で読み込み、それをメモリに書き込みます。 そして実行開始の指示をかけます。 PCに載せたBASIC言語でマンマシンI/Fの部分を作り、高速処理の部分をアセンブラで作って機器の制御をやりました。 懐かしいです。 このやり方で最初に作ったのが、製鋼所の圧延コイルの画像認識です。 トレーラーの上に載っている圧延コイル(重さ20トンとか40トンで直径1メートル以上)の中心座標や直径、幅を測定するものです。 こういうアプリの開発を経験し、当時は難関の文字認識にチャレンジしました。 技術力がある工場では専用のチップを開発したりしていましたが、弱小チームであった僕のチームは全てソフトウエアで対応しました。 結構難しかったですね。 それが今や、やろうと思えば小学生だって文字認識ができます。 技術革新の力強さというか人間の知力、長い長い努力の積み上げの日々に耐える忍耐力には脱帽です。

f:id:ken2017:20200323093742j:plain

sklearnのdatasetsにある文字データを見てみました。

先の記事で書いたアヤメの分類で使ったsklearnには文字に関するデータも入っています。 0から9までの手書き文字です。 それがコレ。

f:id:ken2017:20200323101455p:plain

サンプル数は、1797と膨大な数です。 一つ一つの文字は8X8のマスに書かれています。 これが教師データになります。 いつも思うのですが、こういう共通のデータベースを使って技術の改善を行っていくことが重要ですね。 僕が若いころはそういうものがなく、作ったアルゴリズムが良いのか悪いのか、改善したものが改善されたのか改悪されたのかの判断が非常に難しかった記憶があります。

教師データの姿を把握しよう。

さて教師データとして使う文字データが手に入ったところで、まずは、これらのデータがどういう姿をしているものかを理解しておきましょう。 データの表示方法には色々あると思いますが、今回は、0から9の各文字に対して各3枚のデータを選んで教師データを表示します。 表示の仕方は、簡単に言えば重ね合わせです。 ランダムに選んだ3枚の画像を重ねる(ORですね)ことで作ります。 その結果がコチラ。

f:id:ken2017:20200323105021j:plain
思ったより奇麗ではないですね。 これを教師データにして大丈夫?と思ってしまいますね。
このためのコードは、
ライブラリの取り込み:3行(gatasets、 numpy、 matplotlib)
手書き文字データの入力:1行
手書き文字データの特徴量のセット:2行(Xとy)
手書き文字の画像を変数に格納:1行
0から9までの文字ごとに3枚づつ手書き画像の重ね合わせ:7行
画面に表示:2行
簡単ですよね、本当にPythonはプログラムを書くというより所定のフォーマットにデータをセットする、ことが主な作業になります。 これはこれで良いと思いますが、プログラマーが本質的なところを理解しにくくなっているなと感じます。 余談ではありますが、そのためにデータサイエンティストというような話も出てきますね。 でも、世の中で言っているデータサイエンティストというのは現場で求められている人種とはちょっと違うかな、という感じがしています。 統計学に詳しい人間も必要ですが、現場では、解決したいお題を前提としてデータの解釈ができる人間を必要としているわけで、統計学以前にお題に関する知識や経験が必要で、その人間が機械学習における、Pythonにおける各種ライブラリや関数に関する深い知識が必要で、そういう意味でのデータサイエンティストになる人間が求められているように思います。 言うは易しですが、これは本当に難しいと思います。
僕がアメリカでPythonを勉強するときに使ったのは、アマゾンで買って日本からアメリカに送った沢山の書籍と下の2つのサイト。 この2つには本当にお世話になりました。

qiita.com

scikit-learn.org
教師データの良さ加減を主成分分析を使って確認してみましょう。

教師データを重ね合わせた画像で教師データの姿を見ることができましたが、画像だけでは良さ加減が判らない、という人も出てくると思います。 その意見に僕も賛成です。 これで本当に大丈夫?という感じはします。 ということで、もう少し判りやすい結果が手に入る手法を適用してみましょう。 それが主成分分析という手法です。 主成分分析とは、統計学上のデータ解析手法のひとつで、たくさんの量的な説明変数を、より少ない指標や合成変数(複数の変数が合体したもの)に要約する、すなわち、次元を要約する手法です。 要約した合成変数のことを「主成分」と呼びます。
わかりやすく言えば、たくさんの次元(指標)のデータから、全体をわかりやすく見通しの良い1~3程度の次元に要約していくことになります。

f:id:ken2017:20200323131305j:plain
上のグラフがその結果です。 手書き文字データは、8X8のマスによるデータで表されているので64次元のデータになります。 それを主成分分析によって次元を減らして3次元にしたものが上のグラフです。 グラフの色は0から9の数字のデータを示しており、このグラフを見る限りそれぞれの色は比較的良く判れているので、この64次元の教師データは結構使えるデータだということが判ります。 データの質を目に見える形で評価できる今の時代は本当に良い時代です。
ちなみに、上の結果を得るためのコードは、
ライブラリの入力:4行
手書き文字のデータ入力:1行
手書き文字データの特徴量のセット:2行(Xとy)
主成分分析:2行
結果の描画:29行(0から9の文字データに色を付けるので行数が沢山になった)

サポートベクトルマシンによる文字データの

評価をやってみた。

アヤメの分類で使った線形サポートベクトルマシンに今回の0から9までの1797個の文字データを適用してみた。 その結果は、当然といえば当然だが正解率100%となった。 1797個のデータを誤りなく分類できたということ。 その結果を示したのが下の画像。

f:id:ken2017:20200323140524j:plain

学習用データとテスト用データに分けての文字データの評価をしてみた。

次のステップは、教科書での定番である1797個の文字データを学習用データとテストデータに分けて評価を行うということをやってみます。 1797個のデータをランダムに並べ替え、先頭の1697個のデータを学習用データとして使い、残りの100個のデータをテスト用のデータとして使います。 学習用データとテスト用データを決めた後に、まずは学習フェーズに入ります。 学習フェーズでは、学習用データと学習用ターゲットが一致するように分類器の学習を行います。 要は、学習用データにおける0は0として、1は1として9は9として認識できるように学習を行うということです。 学習が終わったらテスト用データとテスト用ターゲットを用いて分類器の評価を行います。

f:id:ken2017:20200323144738j:plain
   Raspberry Piではじめる機械学習から引用
その評価を行った結果がコチラ。

f:id:ken2017:20200323144941j:plain
テスト用データでの正解率が99.0%となりました。 同じデータの集合体から選んだテスト用データということもありますが、結構いい結果かなと思います。 ちなみに、これ用のコードは、
ライブラリの入力:2行
手書き文字データの入力:1行
手書き文字データの特徴量のセット:2行(Xとy)
手書き文字データの順番の並べ替え:1行
学習用データの設定:2行
テスト用データの設定:2行
サポートベクトルマシンの準備:1行
学習用データを用いて最適化:1行
テスト用データを用いた分類器の評価:1行
テスト結果の評価:2行
テスト結果の印字:2行

さて、作った分類器の出来栄えはどんなものかを確かめましょう。

sklearnに入っていたデータセットを使った評価では正解率が99.0%でしたが、実際の手書き文字をキチンと認識できるでしょうか。 ということで、その評価をやりました。 その結果、残念ながら誤認識もでる、という結果でした。 その結果を画面に出したものを添付します。 これはマウスを使って文字を書き、それを認識するというものです。

f:id:ken2017:20200324090401j:plain f:id:ken2017:20200324090428j:plain
  1の誤認識:1を3と認識       1の正常認識

f:id:ken2017:20200324090511j:plain f:id:ken2017:20200324090537j:plain
  3の誤認識:3を7と認識       3の正常認識
f:id:ken2017:20200324090632j:plain f:id:ken2017:20200324090710j:plain
   4の正常認識            6の正常認識

f:id:ken2017:20200324090737j:plain
   9の正常認識
sklearnに入ってる手書き文字データは調べたところ43名のデータのようで、もっと正解率を上げるには幅広くデータを集める必要があるかなとも思いしたが、どうもそれだけではないようで、別の原因もあるように思いました。 ひょっとして8X8のデータの大きさと位置補正をしていないことが影響しているのかな、ということでコードの改善に取り組みました。 8X8のマスの中での大きさと位置補正は当たり前のことなので手を抜いてはいけないということですね。
ちなみに、上の結果を得た時のコードは、
ライブラリの入力:7行
手書き文字データの入力:1行
手書き文字データの特徴量のセット:2行(Xとy)
分類用のサポートベクトルマシンの準備:1行
データの最適化:1行
マウスを使っての文字入力:28行
入力した文字の認識:22行

データの補正を行うと正解率は高くなるね。 でも・・・

ということで改善版のコードでの結果がこれら。

f:id:ken2017:20200324100715j:plain f:id:ken2017:20200324100737j:plain f:id:ken2017:20200324100818j:plain
  1の位置を色々と変えた結果、全て正解

f:id:ken2017:20200324101048j:plain f:id:ken2017:20200324101113j:plain f:id:ken2017:20200324101156j:plain
  3の位置を色々と変えた結果、全て正解

f:id:ken2017:20200324101354j:plain あれれ、誤認識した、3を9と認識した。

f:id:ken2017:20200324101451j:plain f:id:ken2017:20200324101520j:plain
  5の位置を変えて認識したが、両方とも正解だった。

f:id:ken2017:20200324101628j:plain f:id:ken2017:20200324101651j:plain
  7の正常認識         7を3と誤認識
だいぶ良くなったが、まだ誤認識があります。 データを8X8と粗いマスで入力していることや文字の傾き補正をしていないことなどが影響している可能性もあります。 これをアルゴリズムで改善しようとすると、いよいよディープラーニングのお出まし、ということになります。 ディープラーニングを用いた手書き文字認識は別途やってみたいと思います。 
そうは言っても昔に比べたら遥かに良い結果です。 若いころにこういうものを作りたかったですね。 僕が作った文字認識ソフトも学習機能を使っていました。 学習機能と言っても原始的なものでしたが。 懐かしさと技術の進化を感じます。 ちなみに僕が作った文字認識の適用先は、自動車のエンジンブロック(鋳物)に浮き出ている文字の読み取りでした。 ラインに投入はされましたが、結果的には適用されなかったと思います。 苦い思い出の一つです。 さて、気分を新たにして次のお題に取り組みましょう。

(参考図書)

 

 

プライバシーポリシー お問い合わせ