鈍足ランナーのIT日記

走るのが好きな5流のITエンジニアのブログ。

趣味の範囲は広いけど、どれも中途半端なクソブロガー楽しめるWebアプリを作ってあっと言わせたい。サーバーサイドPerl(Mojolicious)、クライアントサイドVue.js。Arduinoにも触手を伸ばす予定。

夏休みのギリギリですが自由研究終わりました!機械学習でアブラゼミとクマゼミの抜殻を見分けられるか?

自分に課したこの夏の自由研究。
機械学習でセミの抜け殻で、セミの種類を分類するを
なんとかやることができました。

今回用いたのはMxNetというライブラリのPerl版を使いました。

こちらがアブラゼミの抜け殻
f:id:kechiya:20170826141156p:plain
こちらがクマゼミの抜け殻
f:id:kechiya:20170826141140p:plain

どの方向で撮るのがいいのか、よくわからなかったのですが、横向きにして見ました。

ただし、アブラゼミとミンミンゼミの抜け殻は私の目には区別がつかなくて、
ミンミンゼミの抜け殻も混ざってしまっていると思います。

ソースはこちらです。
github.com

とりあえず、8割ラインの識別はクリアしました。
学習データ30枚、テストデータ15枚の貧弱な構成となっています。
内部ではグレースケールに変えて読み込んでいます。

協力者募集中

白い背景で128x128pixのjpg抜け殻の画像データをプルリクエストなどで
いただけると喜ぶかもしれません。
ツクツクボウシ、ヒグラシなど絶賛募集中です。
このモデルを発展させて、来年の小学生の自由研究に活用していただける方が出たら面白いかもかも?!

ミンミンゼミ、クマゼミ、アブラゼミの分類を機械学習させる

教師あり学習なのでセミの抜け殻に詳しくならないといけません。

blog.goo.ne.jp

触覚に毛が多く、触覚の2節より3節が長い→アブラゼミ
触覚に毛が少なく、触覚の2節と3節が同じ長さ→ミンミンゼミ
おへそがある→クマゼミ

PerlでMNISTを画像ファイルでやりたい

AI::MXNetを最近使って機械学習を勉強中。
0-9の手書き文字の認識するサンプルMNISTはサンプルコードもあるのですが
MNISTデータは28*28次元のバイナリデータでして、応用しようとしても
そのままだと使いづらい、画像データ(pngなど)でやりたいのです。

Githubを調べた結果MNISTのバイナリデータをpngに変換するツールがありました。
github.com

pngファイルになりますので。コントロールファイル形式(パス一覧のようなもの)のファイルをperlスクリプトで作りました。

use strict;
use warnings;

open my $train, ">./training.ctl";
open my $test, ">./testing.ctl";
my @png = glob "./*/*/*.png";
for my $png(@png){
  $png =~ /(training|testing)\/(\d)\/(\d+)\.png/;
  my $file;
  if ($1 eq "training" ){
      $file = $train;
  }
  else{
      $file = $test;
  }
  printf $file "%s\t%s\t./%s/%s/%s.png\n", $3 , $2, $1 , $2, $3;
}

close $train;
close $test;

コントロールファイルの内容はこんな感じです。

index    label    pngファイルのパス

コントロールファイルから今度はmxnetのファイル形式のrecord形式に変えてあげます
im2recというコマンドがmxnetには用意されています。color=0とする所が肝です
グレースケールのrecordファイルになります。

im2rec testing.crl ./ testing.rec encoding=.png color=0

詳細は、以下を参照してください。
github.com

テストが通らない!!

しかし、テストが通らない。仕方ない甘えではありますが、Issueを発行して
聞いてみようということで聞いてみました。

github.com

AI::MXNetモジュールの作者さんから回答があっという間にいただけました。
感謝の極みです。データをシャッフルしないとだめとか、色々と添削をいただきました。
これでテストが通りました!!!

やっと、次の段階に進むことができます。

AI::MXNetでイメージのロードに挑戦できた

 use AI::MXNet qw('mx');                                                     
 my $ite = mx->img->ImageIter(
   {path_root => "" , batch_size => 1, data_shape=> [3,224,224],label_width =    >1, path_imglist => "data/custom.lst"});
  for $data (@{$ite}){
    print $data->[0];
 }

Use of uninitialized value $fname in concatenation (.) or string 

エラーを吐いて読むことができない。
これはバグなのかpath_rootを渡したいのだけど、渡せないのはなぜだろう。。。

github.com

バグだったようで、作者の方から迅速な返事もあり。解決しました。サンプルソースまで添削していただけました。
どんどん、アウトプットしていきましょう。
jpgなどの画像データをパスリスト作っておくとndarrayへ格納できるようになります。
data_shapeと画像のサイズを揃えて置かないと叱られますので注意です。

  1  use AI::MXNet qw('mx');                                                    
  2  use Data::Dumper;
  3  my $ite = mx->img()->ImageIter(
  4  {  batch_size => 1, data_shape=> [3,183,275],label_width =>1, path_imglist     => "custom.lst", path_root => '.' });
  5  for $data (@{$ite}){
  6    print Dumper($data);
  7    print $data->data->[0]->aspdl;
  8    print $data->label->[0]->aspdl;
  9  }

MacでAI::MXNetを動かして見た

公式ドキュメントを見ながらやってみる
http://mxnet.io/get_started/osx_setup.html#build-the-shared-library
Perlが公式ドキュメントにありテンションが上がる。

exampleを実行してみる

cd ~/mxnet/perl-package/AI-MXNet/examples/
perl mnist.pl 

動いたようだ!

折角だシンボルAPIを試してみよう

use AI::MXNet qw('mx');
$aaa = mx->symbol->Variable("aaa");
$bbb = mx->symbol->Variable("bbb");
$c = $aaa + $bbb;
$nd1 = mx->nd->array([1,2]);
$nd2 = mx->nd->array([3,4]);
$executor = $c->bind(ctx => mx->Context('cpu'), args=> [$nd1, $nd2]);
$result = $executor->forward();
print $result->[0]->aspdl();
[4,6]

SYNOPSISの方のMINISTを動かしてみる

dataフォルダに以下の4ファイルを格納しておく
t10k-images.idx3-ubyte
t10k-labels.idx1-ubyte
train-images.idx3-ubyte
train-labels.idx1-ubyte

あとはsynopsisのファイルをtest.plとして格納して実行するだけで動きました。
wgetほにゃららとでていて、ネットからダウンロードしようとしているのかな??

$ perl test.pl 
1..1
Can't exec "wget": No such file or directory at /Users/dokechin/perl5/lib/perl5/AI/MXNet/TestUtils.pm line 85.
unzip:  cannot find or open mnist.zip, mnist.zip.zip or mnist.zip.ZIP.
[20:50:08] src/io/iter_mnist.cc:94: MNISTIter: load 60000 images, shuffle=1, shape=(100,1,28,28)
[20:50:09] src/io/iter_mnist.cc:94: MNISTIter: load 10000 images, shuffle=1, shape=(100,1,28,28)
Epoch[0] Train-accuracy=0.657233
Epoch[0] Time cost=9.599
Epoch[0] Validation-accuracy=0.944500
ok 1

SYNOPSYSのモデルを簡略化してみたけど

accuracyは変わらない。むしろ良くなっている?

### model
  my $data = mx->symbol->Variable('data');
### 畳み込み
  my $conv1= mx->symbol->Convolution(data => $data, name => 'conv1', num_filter => 32, kernel => [3,3], stride => [2,2]);
### バッチ正規化
  my $bn1  = mx->symbol->BatchNorm(data => $conv1, name => "bn1");
### 活性化関数
  my $act1 = mx->symbol->Activation(data => $bn1, name => 'relu1', act_type => "relu");
  my $mp1  = mx->symbol->Pooling(data => $act1, name => 'mp1', kernel => [2,2], stride =>[2,2], pool_type=>'max');
   
  my $fl   = mx->symbol->Flatten(data => $mp1, name=>"flatten");
  my $fc1  = mx->symbol->FullyConnected(data => $fl,  name=>"fc1", num_hidden=>30);
  my $act3 = mx->symbol->Activation(data => $fc1, name=>'relu3', act_type=>"relu");
  my $fc2  = mx->symbol->FullyConnected(data => $act3, name=>'fc2', num_hidden=>10);
  my $softmax = mx->symbol->SoftmaxOutput(data => $fc2, name => 'softmax');

吉祥寺pm #11に参加しました

感想を雑につらつらと。

19:30〜19:40(10分) オープニングトーク(magnolia)

回を重ねるごとに大盛況。そろそろ3周年なんですね。やっぱ
雰囲気が良いので、また行きたくなるんですよね。

19:40〜19:55(15分) Talk1: Using Scala.js with the JavaScript ecosystem(しんぺい a.k.a. 猫型蓄音機)

レイヤを綺麗に書いて、依存関係をいい感じにするというお話でした。
適材適所に使い分けるというのはためになりました。

19:55〜20:10(15分) Talk2: MySQLステータスモニタリング 〜それ、Perlで(も)できるよ〜(yoku0825)

SQLでモニタリングすることができるというお話でした。新しい方と古い方で
方式が違うなど、とても丁寧に解説されておりました。

20:10〜20:25(15分) Talk3: yoku0825とsoudai1025のキャッキャウフフです(soudai1025)

MySQL,Postgres。適材適所。レプリケーションが弱いとか。ためになります。
トーク面白いですなぁ。とにかく、中国地方のDB勉強会がすごいんですね。

20:25〜20:40(15分) Talk4: タイトル未定(Songmu)

1つにまとめることでバイナリのサイズが小さくなるというお話。なるほどしならなったです。
Perlも出てきました!

20:45〜20:50(5分) LT1: 検索について(sakura)

広告を排除したらどんな世界になるのか見てみたいです。
それにしても、検索サイトを1から作ってすごいですね。
続けて入ればいいことがあるという言葉が突き刺さりました。私も頑張ろう。

20:50〜20:55(5分) LT2: タイトル未定(ytnobody)

運用関連は専門に任せてというところ。私もアプリ大好き人間なので
開発していたいです。これからも開発に注力していこうという気になってきました。
あれもこれもやるには人生短すぎる。

20:55〜21:00(5分) LT3: タイトル未定(otukutun)

UI周りのライブラリはカスタマイズが効かなくて大変というお話でした。
私は、Androidでアルバムサイトを作ろうとしてほったらかしにしております。
全部自分で実装してしまうなんて、すごいなぁ。

21:00〜21:05(5分) LT4: タイトル未定(mackee_w)

三島PM#1が出てきて、嬉しかったです。自分の作ったツールがギークたちの手でさらに
洗練かして、社内でも使われてきているというお話でした。さすがです。

21:05〜21:10(5分) LT5: fields は CLI ツールに使っても ええんやで(hkoba)

fieldsは使ったことないけれど、頭の片隅に入れておこう。
綴りミスを防ぐことができるみたいです。

21:10〜21:15(5分) LT6: タイトル未定(toku_bass)

マイクロサービスについて、アプリからアプリを呼ばなくして
サービスAPIとして叩くというお話でした。なるほど。

お土産付きでした。

マカレルノベルティ。とマカマカさんノベルティをもらえました。嬉しいです。

懇親会は遠方でさすがに参加できないので、名残おしいです。
今日は終電1本前に乗れました!

Arduinoで音源方向に振り向く雲台を作れないか?

2chマイクにこだわって、いろいろと試しているのですが、
ネタをばらすと音源方向に振り向く雲台を作れないかと試行錯誤しているからです。

高速なサンプリングレートで扱うには、それなりのCPUパワーが必要という点で
Arduinoでは少し厳しいですが。Genuino101等の高速処理に向いたものならば
なんとかこなせそうな気がします。1アナログリードに27マイクロsec程度の
性能が出ます。

マイクとマイクの距離は近すぎると、到達時間の差があまり出ないので
10cmは欲しいところ。

マイクはこちらから購入。200円程度です。Rail to Railのオペアンプと言うらしいです。
VCCで与えた電圧の半分を中央に波形を出してくれると言う単純明快扱いやすいです。

rover.ebay.com

左右2つのコンデンサマイクで取得した信号をオペアンプで増幅して
アナログ入力。1000個、値を拾って。
左右の波形の位相差を計算して距離に換算します。
計算方法は単純で左右の値を掛け合わせて和を求めて。最大になるところが
位相が一致したところとしています。

アルゴリズムはこちらを参照しました。
http://www.ieice-hbkb.org/files/02/02gun_06hen_03.pdf

できたのは、こんな感じのプログラムです。
github.com

Genuino101が壊れた!

Uno R3という互換ボードを購入してアナログリードの性能を調べたら
116マイクロsecもかかってしまった。これは実用に耐えられなさそうだ。
でも、大丈夫以下の記事を発見。これをしたら、なんと20マイクロ秒まで速度アップしました。
ameblo.jp