強化学習 FROZEN_LAKE 8x8

PythonでなくC++最短経路を探すプログラムを書いてみました。

 

ソースはこちら https://github.com/sugarontop/etc/tree/master/Qlearning2

 

★最短経路を検索
S: スタート
G: ゴール
H: 穴(hole)
o: フリー

// 地図
block BlockMap1[] = {
 S, o, H, o, H, o, o, o,
 o, o, H, o, H, o, H, o,
 H, o, o, o, H, o, H, o,
 o, o, H, o, H, o, H, o,
 o, H, o, o, o, o, H, o,
 o, H, o, H, o, o, H, o,
 o, o, o, H, o, H, o, o,
 o, o, o, H, o, H, o, G
};

//以下 結果の例
...
cnt=22 状態価値の変化5.6345e-07
cnt=22 状態価値の変化5.02914e-07
cnt=22 状態価値の変化4.49363e-07
cnt=22 状態価値の変化4.02797e-07
cnt=22 状態価値の変化3.60422e-07
cnt=22 状態価値の変化3.21772e-07
cnt=22 状態価値の変化2.8545e-07
action:右 s_position:0->s_next_position:1 cnt=1
action:下 s_position:1->s_next_position:9 cnt=2
action:下 s_position:9->s_next_position:17 cnt=3
action:右 s_position:17->s_next_position:18 cnt=4
action:右 s_position:18->s_next_position:19 cnt=5
action:下 s_position:19->s_next_position:27 cnt=6
action:下 s_position:27->s_next_position:35 cnt=7
action:右 s_position:35->s_next_position:36 cnt=8
action:右 s_position:36->s_next_position:37 cnt=9
action:上 s_position:37->s_next_position:29 cnt=10
action:上 s_position:29->s_next_position:21 cnt=11
action:上 s_position:21->s_next_position:13 cnt=12
action:上 s_position:13->s_next_position:5 cnt=13
action:右 s_position:5->s_next_position:6 cnt=14
action:右 s_position:6->s_next_position:7 cnt=15
action:下 s_position:7->s_next_position:15 cnt=16
action:下 s_position:15->s_next_position:23 cnt=17
action:下 s_position:23->s_next_position:31 cnt=18
action:下 s_position:31->s_next_position:39 cnt=19
action:下 s_position:39->s_next_position:47 cnt=20
action:下 s_position:47->s_next_position:55 cnt=21
action:下 s_position:55->s_next_position:63 cnt=22
 
強化学習については以下を参照
「つくりながら学ぶ! 深層強化学習 ~PyTorchによる実践プログラミング」

UWP Framework Direct2D TypeScript


TypeScriptでこんなコードを書いて、Chakra.dllに読み込ませるとButtonクラスはIDispatch*に
なりC++の世界でそれを操作できます。(IDispatchが何物なのかは、ググって下さい。)


declare function CreateWindow(me:any, ty:string,title:string, x:number,y:number,cx:number,cy:number ):void;
declare function SetWindowText( me:any, text:string ): void;
declare function GetWindowText( me:any ): string;

type click_delegate = (me: any) => void;

export module U {
export class Button {

Click : click_delegate;

constructor(title: string,x: number,y:number, cx:number) {
CreateWindow( this, 'button',title,x,y,cx,26);
}

OnClick():void{
if ( this.Click )
this.Click(this);
}

SetText( s: string ): void {
SetWindowText(this, s);
}

GetText(): string {
return GetWindowText(this);
}
}
...

var obj = new U.Button("Create Textbox",100, 500, 300 );
obj.Click = test_function;

new U.ButtonによってCreateWindowが呼ばれます。
thisがIDispatchです。CreateWindowは自前作成でWin32ではありません。
以下はC++のコードです。


D2DButton* btn = new D2DButton();
btn->Create( gparent, gf1, rc, VISIBLE, text.c_str(), L"noname" );
gWindowMap[disp.p] = btn;
btn->SetTarget( disp.p );

btn->OnClick_ = [](D2DButton* b)
{
variant v;
InvokeMethod0(b->GetTarget(), L"OnClick", v); // test_functionが呼ばれる
};

ボタンをクリックするとJavaScrit側のtest_functionが呼ばれます。

以上、JavaScript->C++の関数のcallとC++->JavaScriptのcallです。


Direct2DのWindowシステムを作ってみました。リンク
UWPはHWNDが消えたため、裏の仕組みを想像しながらDirect2Dで実装しました。

Windowシステムの肝はキャプチャーの仕組みです。
キャプチャーとはWindowsメッセージを一時的にあるオブジェクトに集中させる事を意味します。

UWPではWM_PAINTなどのWindowsメッセージが消えてなくなっていますが、不便なので仮想でApp.cpp内で再作成してすべてのコントロール類にSendすることで、昔(WIN32)と同じ仕組みになっています。

Textboxのチカチカが表示されている間は、キーやマウスのメッセージはTextboxに集中させなければなりません。
同じくComboboxで候補が表示されている時、MessageBoxも同じでメッセージはそのコントロールに集中させなければなりません。

メッセージの扱いはコントロールのクラス内では収まらないため、その上位のクラスで管理します。

テストしてませんが、ARMでも動作するはずです。
VSのTemplateに付いていたSampleVertexShader.hlslなどは使用していません。不要です。

Sybilという名前は、いつもですが命名に悩むのでたまたまかかっていた曲(Sybil - When I'm Good And Ready)をつけました。


1、WindowsPython インストール

Python 3.5.2 [Windows x86-64 executable installer] をインストール
Visual Studio 2015 の Visual C++ 再頒布可能パッケージ vc_redist.x64.exe をインストール
○ C:\Users\[your name]\AppData\Local\Programs\Python\Python35 へパスを通す

2、機械学習用のPythonライブラリをインストール

>python -m pip install --upgrade pip
>python -m pip install wheel

http://www.lfd.uci.edu/~gohlke/pythonlibs/ から numpyとscipyのwhlをダウンロード

>python -m pip install C:\Users\[your name]\Downloads\numpy-1.11.1+mkl-cp35-cp35m-win_amd64.whl
>python -m pip install C:\Users\[your name]\Downloads\scipy-0.17.1-cp35-cp35m-win_amd64.whl

>python -m pip install pandas
>python -m pip install matplotlib
>python -m pip install scikit-learn

3、試しに以下のプログラムを実行


#グレースケールの8x8(セル64個のそれぞれの色の濃さ)の不明瞭な数字画像を読むプログラム
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn import svm

#用意されている不明瞭画像とその答えがペアになったサンプルデータをダウンロード
digits = datasets.load_digits()

print(u'サンプルデータ数:', len(digits.data))

#アルゴリズム指定
clf = svm.SVC(gamma=0.001,C=100)

#学習数 1700個
learning_cnt = 1700
question,ans = digits.data[:learning_cnt], digits.target[:learning_cnt]

#機械学習?する
clf.fit(question,ans)

#例えば、学習していない1750番目の画像データから数字を予想
index = 1750
predicted_ans = clf.predict(digits.data[index])
print(u'予想値:', predicted_ans)

#答えを見る。1750番目の画像表示
plt.imshow(digits.images[index], cmap=plt.cm.gray_r, interpolation="nearest")
plt.show()

#予想値と一致!

参考:Windows環境にPython 3.5.1+numpy+scipy+αをインストール

Scikit Learn Machine Learning SVM Tutorial with Python p. 2 - Example

4、便利なのでさらに追加
>python -m pip install sympy

 HDCとID2D1RenderTargetとの大きな違い


従来のHDCとID2D1RenderTargetとの大きな違いは、
HDCというデバイスコンテキストはWM_PAINT段階で作成->廃棄されるのに対して、
ID2D1RenderTargetはアプリ起動時にコンテキストが作成され、終了時までそれを使用し続けることにある。
しかし、あるタイミングでコンテキストが廃棄される場合があり、アプリ側でこれに対処しなければならない。
HDCでは絶えず廃棄されているので、これは大きな違いである。

UWP場合、DX::DeviceResources::HandleDeviceLost()を呼び出すとID2D1RenderTargetを廃棄->作成してくれるらしい。


// すべてのデバイス リソースを再作成し、現在の状態に再設定します。
// void DX::DeviceResources::HandleDeviceLost()
// std::shared_ptr m_deviceResources;

m_deviceResources->HandleDeviceLost();

開発途中で時々、確認しなければならないのはこのHandleDeviceLost()を呼び出し、きれいに元の画面に戻るかどうかである。



どこかわからない場所で多分話題のUWP(UniversalWindowsPlatform)というWindows10以降の開発環境が用意されているので、せっかくだからこれのTextboxを作ってみた。
VisualSudio2015にあるC++ユニバーサルWindowsのテンプレート(DirectX11アプリ)をもとに3DをDirect2Dにかえて、日本語変換のIMEを搭載。
TSFという長年仕様が中々固まらなかったらしいIME APIは、Windows::UI::Text::Core内で抑え込まれていて割と簡易に実装できた。C++/CXを使用。
ソースコードここにあります。

Y = WX+B の式の意味は次のところ(51/187)で。
この式を高速で計算するC++AMPでの行列演算をつくってみた。(CUDAがこの分野での業界標準で、C++AMPの今後はどうよという気もするけど。)


#include "stdafx.h"
#include
#include

using namespace concurrency;

class Vector
{
friend class Matrix;
public :
Vector():cnt_(0){};
Vector( float* v, int cnt ){ set(v,cnt);}


void set( float* v, int cnt )
{
cnt_ = cnt;
val_ = std::shared_ptr( new float[cnt], std::default_delete() );

if ( v == nullptr )
{
for (int i = 0; i < cnt; i++)
val_.get()[i] = 0;
}
else
{
for( int i = 0; i < cnt; i++ )
val_.get()[i] = v[i];
}

}
Vector& operator+=( const Vector& v )
{
_ASSERT( cnt_ == v.cnt_ );
_ASSERT( this != &v );

for (int i = 0; i < cnt_; i++)
val_.get()[i] += v.val_.get()[i];

return *this;
}

float* get(){ return val_.get(); }
int count() const{ return cnt_; }

float& operator[](int idx )
{
return get()[idx];
}

private :
std::shared_ptr val_;
int cnt_;
};
class Matrix
{
friend class Vector;
public :
Matrix():col_ (0),row_(0){}
Matrix(int row, int col){ init(row,col); }

void init( int row, int col )
{
col_ = col;
row_ = row;
int cnt = col*row;
w_ = std::shared_ptr(new float[cnt], std::default_delete());

Zero();
}
void Zero()
{
memset( w_.get(), 0, sizeof(float)*row_*col_ );
}

Vector Multi( Vector& x)
{
_ASSERT(row_ > 0 && col_ > 0);
_ASSERT(row_ == x.count());

Vector r(nullptr, x.count());

array_view ww( row_, col_, w_.get());
array_view xx( x.count(), 1, x.get());
array_view rr( r.count(), 1, r.get());

int cnt = col_;

parallel_for_each(
ww.extent,
[=](index<2> idx) restrict(amp)
{
int row = idx[0];
int col = idx[1];
for (int i = 0; i < cnt; i++)
{
rr[idx] += ww(row, i) * xx(i, col);
}
}
);

ww.synchronize();

return r;
}
Vector WXplusB(Vector& x, Vector& b)
{
_ASSERT(row_ > 0 && col_ > 0);
_ASSERT(row_ == x.count());

Vector r(nullptr, x.count());

array_view ww(row_, col_, w_.get());
array_view xx(x.count(), 1, x.get());
array_view rr(r.count(), 1, r.get());
array_view bb(r.count(), 1, b.get());

int cnt = col_;

parallel_for_each(
ww.extent,
[=](index<2> idx) restrict(amp)
{
int row = idx[0];
int col = idx[1];
for (int i = 0; i < cnt; i++)
{
rr[idx] += ww(row, i) * xx(i, col);
}

rr[idx] += bb[idx];
}
);

ww.synchronize();

return r;
}

float* get() { return w_.get(); }
float& w( int row, int col ){ return w_.get()[row*col_ + col]; }
private :
std::shared_ptr w_;
int col_,row_;


};

int main()
{
// 3行3列 重み行列
Matrix m(3,3);

m.w(0, 0) = 2;
m.w(0, 1) = -3;
m.w(0, 2) = 4;

m.w(1, 0) = -4;
m.w(1, 1) = 1;
m.w(1, 2) = -5;

m.w(2, 0) = -4;
m.w(2, 1) = -2;
m.w(2, 2) = 5;

// input
float v1[] = {1,0,1};
Vector in( v1, _countof(v1) );

// bias
float b1 [] = { -4,5,2 };
Vector b(b1, _countof(b1));

// Calc with C++ amp.
Vector Y = m.WXplusB( in, b );

float a1 = Y[0]; // 2
float a2 = Y[1]; //-4
float a3 = Y[2]; //3

return 0;
}