2017年6月28日水曜日

強化学習してみた。

昨日書いた、便利なtiny-dnnとstbライブラリ。さらにstbの動画版の簡単に動画ファイルを出力できるjo_mpeg。
これらのライブラリと強化学習と組み合わせれば、CaffeとかKerasとかを使わないでDQN(深層Qネットワーク)とかできんでない?

と思ったのですが、おじさん仕事が忙しくて、実装や学習させる根性がないので、今日はまずC++で普通の強化学習をやるところまで。

強化学習ってなんなのかというと、ここに理論とソースコードが書いてあります。
http://kivantium.hateblo.jp/entry/2015/09/29/181954

すごいねー。おじさんが大学生だった時代はこんな便利なWebページなかったのね。
深くない普通の強化学習はとってもわかりやすいですね。
おじさんのような浅い知識でも大丈夫。

いつものようにここのソースをそのままとってきて、ちょっと改良。
stbで途中経過と結果の画像を作ります。

おじさん意地でもC++でやるんです。
なんか同じ結果になったぞ。




これに深層学習とかDNNとかを組み合わせるとDQNになるらしい。
ほんとかよ。
ということで、次はC++でtiny-DQNとかやりたいんだけどなー。
そんなに暇ないしなー。誰かライブラリ作ってくれないかなぁ。



-----------------------------
#include <iostream>
#include <cmath>
#include <algorithm>
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"

using namespace std;

double V[101]; // 状態価値関数
double pi[101];   // 方策
int ct = 1;

void write_graph(const char* name,int n,double* d)
{
int x, y,my;
unsigned char img[100 * 100*4];
char fn[256];
sprintf(fn, "%s%d.png",name, n);
memset(img, 255, sizeof(img));

for (x = 0; x < 100; x++){
my = d[x]*100;
if (my > 100)my = 100;
for (y = 0; y < my; y++){
img[(100 - 1 - y) * 100 * 4 + x * 4] = 0;
img[(100 - 1 - y) * 100 * 4 + x * 4+1] = 0;
img[(100 - 1 - y) * 100 * 4 + x * 4+2] = 255;
img[(100 - 1 - y) * 100 * 4 + x * 4+3] = 255;
}
}
stbi_write_png(fn, 100, 100, 4, img, 4 * 100);
}


int main(void){
const double p = 0.4; //表が出る確率

// 状態価値関数の初期化
for (int s = 0; s<100; ++s) V[s] = 0;
V[100] = 1.0;

const double theta = 1e-5; // ループ終了のしきい値
double delta = 1.0; // 最大変更量

// 状態価値関数の更新
while (delta >= theta){
delta = 0.0;
for (int s = 1; s<100; ++s){
double V_old = V[s];
double cand = 0.0;
// 可能な掛け金ごとに勝率を調べる
for (int bet = 1; bet <= min(s, 100 - s); ++bet){
double tmp = p*V[s + bet] + (1.0 - p)*V[s - bet];
cand = max(tmp, cand);
}
V[s] = cand;
delta = max(delta, abs(V_old - V[s])); // 変更量のチェック
}
//状態価値関数の表示
//for (int i = 0; i<101; i++){
// cout << V[i] << ", ";
//}
//cout << endl << endl;
write_graph("v",ct,V);
ct++;
}

// 最適方策の更新
double threshold = 1e-5;
for (int s = 1; s<100; ++s){
double cand = 0;
double tmp;
for (int bet = 1; bet <= min(s, 100 - s); ++bet){
tmp = p*V[s + bet] + (1 - p)*V[s - bet];
if (tmp > cand + threshold){
cand = tmp;
//pi[s] = bet
pi[s] = (double)bet / 100;
}
}
}
// 最適方策の表示
//for (int i = 1; i<100; i++){
// cout << pi[i] << ", ";
//}
//cout << endl << endl;
write_graph("s",0,pi);
}


2017年6月27日火曜日

C++ヘッダーだけで動くライブラリstbってなに?

前回tiny-dnnのライブラリはヘッダーだけで他のライブラリはインストールしないで動くと書きました。今回はその原理というか中身についてちょろっとみてみたので、説明しようと思います。

まず画像の読み書きから。

tiny-dnnのなかでも使われているのですが、世の中にはすごい人がいまして、C++のヘッダーだけで動くいろんなフォーマットの画像を読み込める画像ライブラリstbがあります。

https://github.com/nothings/stb


これを使えば簡単にC++言語で画像の読み書きができます。
すーげーなー。
ちょー簡単に画像ファイルの読み書きとリサイズ、さらにいろんな変換ができます。
あの重いOpenCV使わないでいいんです。

これ大学の実験とかにもつかえるじゃん。

PNGとかzlib使っているはずなのでzlibとかもどうしているのかと調べるとさらにびっくり。

世の中にはもっとすごい集団というのがありまして、C++のヘッダーだけで動くライブラリをたくさん作っている方々もいます。

https://github.com/nothings/single_file_libs

このグループの哲学がすばらしいですね。


一つ、ライブラリはCまたはC++で動かないといけない
一つ、ライブラリはデスクトップやモバイルなどの複数のあらゆるプラットフォームで動かないといけない
一つ、ライブラリは32ビット環境でもでも64ビット環境でも動かないといけない
一つ、ライブラリは最大で二つのファイルでないといけない。

きちんとした理由があるのならば例外も許す。


C++のヘッダーだけで動くmpegエンコーダーとかC++のヘッダーだけで動くオーディオミキサーとかもうなんでもあるのですね。


これらを使うと、簡単にC++で音声や画像を読み込んで結果を動画で出力できます。
機械学習の結果やテストの結果など数値の羅列になりがちなプログラムを簡単にビジュアル化。
ラズパイのような非力な組み込みの環境でも簡単に音声や画像の処理ができてすごいことができてしまいます。

というわけで、C++でライブラリを作るときはヘッダーだけで動くように作るといろんな人が使ってくれるらしいです。



tiny-dnnでディープラーニングしてみた。

おじさんWindowsとC++言語大好きなのですが、なかなかWindowsのC++言語で動くディープラーニングのライブラリってないんですよね。

ディープラーニングは無理かなと思っていたのですが、C++で簡単に使えるtiny-dnnという深層ニューラルネットワークのライブラリがあることがわかったので、遊んでみました。

最近のC++のライブラリの流れとして、ヘッダーファイルだけ取ってくればインストールなしで使えるものが多いですね。
Pythonと競争しているのか、Pythonを使う上でめんどくさいライブラリーをインストールする作業をしないで使えるというのはよいですね。ライブラリをインストールすると起きるバージョン問題とか起きないし。


ということでtiny-dnnをGitHubから取ってきます。
https://github.com/tiny-dnn/tiny-dnn

このライブラリの作者は日本人のようで、日本人でこんなの作れるなんてすごいですね。最初tiny-dnnのマスターの最新を取ってきたのですが、これだと、なぜかMacやVisualStudio2013でビルドできません。

しょーがねーなー。
というとこでv1.0.0.a3のタグのものを取ってきます。


なにかデモでも動かしてみようと。
tiny-dnnのソースを展開するとexamplesディレクトリにおなじみの文字認識mnist
があるので、それを動かしてみます。

ministディレクトリにTest.cppがあるのでg++やVisualStudioで

g++ -I../.. Test.cpp

のように簡単にコンパイルして実行できます。
とっても簡単。

  nn << convolutional_layer(32, 32, 5, 1, 6,   // C1, 1@32x32-in, 6@28x28-out
                            padding::valid, true, 1, 1, backend_type)
     << tanh_layer()
     << average_pooling_layer(28, 28, 6, 2)    // S2, 6@28x28-in, 6@14x14-out
     << tanh_layer()
     << convolutional_layer(14, 14, 5, 6, 16,  // C3, 6@14x14-in, 16@10x10-out
                            connection_table(tbl, 6, 16),
                            padding::valid, true, 1, 1, backend_type)
     << tanh_layer()
     << average_pooling_layer(10, 10, 16, 2)   // S4, 16@10x10-in, 16@5x5-out
     << tanh_layer()
     << convolutional_layer(5, 5, 5, 16, 120,  // C5, 16@5x5-in, 120@1x1-out
                            padding::valid, true, 1, 1, backend_type)
     << tanh_layer()
     << fully_connected_layer(120, 10, true,   // F6, 120-in, 10-out
                              backend_type)
     << tanh_layer();


こんな風に「<<」演算子で連結すると深層ニューラルネットワークが組めるのも面白いですね。

Test.cppをコンパイルして実行してみてわかったのですが、学習したデータがないよ。
作者のホームページ上で公開している学習済みデータは違うものだし。


しょーがーねーなー。
ということでTrain.cppを同じようにコンパイルして学習プログラム動かします。

Train.exe ../../data

これで学習するようです。
とりあえず学習開始。
最適化をしないで普通にコンパイルをかけて実行したら、1エポック実行するのに2時間くらいかかるようです。
冗談じゃない。明日までかかるじゃないか。

なのでコンパイル時の最適化をマックスにしてもう一度再コンパイルして実行。
一回実行するのに2分くらいになりました。

これならエポック値30で1時間。
とりあえずしばらく放置します。
ファンがマックスで回りますが一時間くらいするとLeNet-modelというファイルができます。
おじさんせっかちなんだよね。なんで機械学習ってそんなに時間かかるんだ。
でもこれで、文字認識をすることができる。

Test.exe hati.png

と指定して「8」の文字を認識させてみました。


3,41.5217
8,40.3152
2,23.789


なんと、「3」という結果に。
おじさん字を書くの汚いし、確かに「3」と「8」にてるからなぁ。
やっぱ、一時間くらいの学習では文字は認識できないらしいです。


2017年3月21日火曜日

プログラムの勉強

2020年度から小学校でもプログラムを教えるようになるそうです。
いったいどんなプログラム言語で勉強するんでしょうね。

個人的にはPythonとかBasicよりはJavaScriptのほうがいいと思っています。
その方がきれいにキャラクターがアニメーションしたり、学習意欲がわきそうに思うんですよね。
僕が小学生のときは算数の計算がめんどくさくて電卓で計算していたのすが、いまやブラウザに計算式をいれると計算してくれる時代。
小学生もおうちのスマホでプログラムとかもできるといいですよね。

キャラクターは動きませんがとりあえず小学生でもスマホやPCでJavaScriptのプログラムを作って遊べるサイトを作ってみました。

http://2nd.agolamusic.com/trial/jslearning/jslearning.html

でもこれスマホだとセミコロンとか入力しづらい・・・。
よく考えたら、varとかセミコロンとかなくても文法上大丈夫だね。
やっぱりスマホだけで計算できるじゃん。

とりあえずJavaScriptを実行するサイトは簡単に作れるのですが、世の中にはJavaScriptで書かれたPythonとかBasicもあるので、これらのライブラリを使えば、Pythonプログラムページとかも作れる?

おじさんのような悪い大人になると、このサイトにお花とかワニとか電車の絵をつけると高く売れそうな気がしてしまいます。
誰かこのサイト買ってくれないかなあ。



まあ、いろいろ利権がありますが、JavaScriptのほうがこういうサイトもすぐ作れるし、教材楽に作れそうな気がします。



2017年2月22日水曜日

転職電車

どうも僕の毎日利用している山手線には転職したいと思っている人が多いらしく、かならず扉のところにはいつも転職サービスへの広告があります。
仕事に疲れて電車を降りるときふと見上げると転職サービスの広告が・・・・。


そんなに転職ビジネスって儲かるんだと思っていたら、転職電車が登場していました。




電車の扉はビズリーチ、中刷りもビズリーチ、車内の動画広告もビズリーチ、電車の先頭から最後までもう全部ビズリーチ。


しかも毎日たくさん走っている。
明電舎、テイジン、楽天、ソニー、募集はいわゆつIT系のソフトウェアエンジニア系の会社ばかり。
あらー、日本という国はこんなに理系のエンジニア不足してるんだね。
そりゃー、給料が安い旧態依然の自動車メーカーや電気メーカーから人いなくなるわ。

会社にいくときもビズリーリ。
外に打ち合わせにいくときもビズリーチ。
会社にもどるときもビズリーチ。
家に帰る時もビズリーチ。
のんびり家族で出かけるときもビズリーチ。

こんな電車に毎日乗るとほんとうに転職したくなっちゃうじゃないか。
あらー、うちの会社のおっさんが真剣に見てるよ。
おい君、いったいどうしたんだ?


Android用のPythonをビルドしてみた

忙しくてブログが更新できていなかったのですが、大作を作ったので今日は更新。


Android端末で動くPythonがない。

ラズパイ版のPythonもあるのになんでAndroid版だけないんだ。
ということで、PythonのAndroid版をビルドしてみました。

まず、SL4A (Scripting Layer for Android)というGoogleの方が移植したAndroid用のPythonのソースをgithubからとってきます。
https://github.com/damonkohler/sl4a

--------------------
SL4A (Scripting Layer for Android) とは、 Android 上で、スクリプト言語によるコーディングや、スクリプトおよび対話式インタプリタの実行を可能とするソフトウェアです。 サポートされているスクリプト言語は Python、Perl、PHP、JRuby、Lua、JavaScript 等で、今後さらに追加される予定です。 また、これらのスクリプト言語から Android の API を呼び出すための仕組みが用意されているため、 HTML で UI を記述し、JavaScript で Android API を呼び出すといった使い方も可能です。
--------------------

このレポジトリにビルドしたPythonインタープリタのバイナリーも含まれているのですが、出力されたコードがPIEではないため比較的新しいAndroidではこのバイナリーが実行できないのです。
仕方がないので自分でビルドします。

が、やはりGoogleにはWindowsはないようで僕のAndroid-NDKがはいっているWindowsマシンではデフォルトのビルドが通らない・・・・・・。


ということで、いくつか修正してビルドします。


1. ソースのコピー
sl4a-master/python/srcをsl4a-master/python-build/python-srcにコピーします。


2.  NDK_MODULE_PATHを設定します

cd sl4a-master/python-build
export NDK_MODULE_PATH=$(pwd)


3. makefileにPIEオプションの追加

sl4a-master/python-build/jniにある、modules.mkとpython.mkに次の二行を追加

LOCAL_CFLAGS += -pie -fPIE
LOCAL_LDFLAGS += -pie -fPIE


4. ビルド

cd sl4a-master/python-build/python
ndk-build

途中の3つくらいのファイルでビルドエラーが出ますが、まぁその部分たいしたことないのでコメントアウトすればビルド完了

sl4a-master/python-build/python/libs/armeabi
このフォルダにpythonの実行形式のバイナリーとsoファイルが出来上がります。


5. LD_LIBRARY_PATHの設定

上でできたバイナリーをAndroid端末にもっていって、環境変数LD_LIBRARY_PATHをsoのあるフォルダに設定してあげればpythonを実行することができます。
だけどこれでは

import os

などのimport文が通りません。
なので、Pythonのライブラリを持ってきます。


6. PYTHONPATHの設定

sl4a-master/python/src/Libにあるファイル一式をAndroid端末にもってきて、そのパスを環境変数PYTHONPATHに設定します。


これでAndroid端末用のPythonが出来上がります。
コンソールのままAndroid端末の開発ように使うもよし、apkにいれてアプリとして使うもよし。

今回、SL4Aに含まれているPytyhon2.6をビルドしましたが、Android用のパッチを当てなくてもなんとなくビルドは通るんですね。ということはPython2.7もビルドできるかも。

Android用のPythonのバイナリーだけほしい方はこちら:
https://drive.google.com/file/d/0B5M9qMMg3tfQbkNTaUdkUnBHV1k/view?usp=sharing

Android用のPythonのソース一式がほしい方はこちら:
https://drive.google.com/file/d/0B5M9qMMg3tfQeTZ5LXRRcG5INDg/view?usp=sharing

Pythonって結構簡単にしかも高速にビルドできるのね。
Pythonの動作原理を勉強するのにもちょうどいいですね。
ということで今日はAndroid版のPythonのビルド方法の解説でした。

2017年1月11日水曜日

地図を表示してみた

最近、スマホアプリで近くのお店を探すアプリが増えてきました。
自分のいる場所とかで違うアイテムがもらえるゲームの位置ゲーとかもあるし。
技術的にどうやってんだろうと思って調べてみました。

どうやら、最近はブラウザでGPSの位置情報が取得できて、その位置情報をもとにJavaScriptでいろいろ処理したり、地図とかを表示しているようです。

ということで位置情報の取得はAPIを呼びだけなので、地図を表示するWebサイトのHTMLをつくってみました。

10分くらいごにょごにょJavaScriptを書けば位置情報とか地図ってすぐできんじゃん。

<html>

<head>
<style type="text/css">
#map-canvas {
width: 800px ;
height: 600px ;
}
</style>
</head>

<body>
<h1>Google Map Test</h1>



<!-- 地図が描画されるキャンパス -->
<div id="map-canvas">ここに地図が表示されます</div>


<!-- GoogleMap API JavaScript -->
<script src="https://maps.googleapis.com/maps/api/js?key=ここにAPIキーを入れる&v=3.24"></script>


<script language="JavaScript">

// 地図表示
var canvas = document.getElementById( 'map-canvas' ) ;
var latlng = new google.maps.LatLng( 35.792621, 139.806513 );
var mapOptions = {
zoom: 15 , // ズーム値
center: latlng , // 中心座標 [latlng]
};
var map = new google.maps.Map( canvas, mapOptions ) ;

// マーカーのインスタンスを作成する
var marker = new google.maps.Marker( {
map: map ,
position: new google.maps.LatLng( 35.792621, 139.806513 ) ,
} ) ;

//イベント
map.addListener('click', function(e) {

 alert("kita!");
 var lat=e.latLng.lat();
 var lng=e.latLng.lng();
 alert(""+lat);
 alert(""+lng);

});


</script>

<!-- User JavaScript -->
<script src="googlemap_test.js" language="JavaScript"></script>

</body>
</html>