2022年12月30日金曜日

libusbをなおす。

 USBのデバイスを制御するライブラリにlibusbというものがあります。

このライブラリを使うと、PCやスマホのUSBのカメラから動画をキャプチャーしたり、iphoneを制御したりできます。


AIの画像認識や組み込みとかでとっても使えるこのライブラリですが、バグでWindowsのコンポジットデバイスのアイソクロナス転送が動かない。

これだとUSBカメラとかUSBオーディオがおじさんの大好きなWindowsで使えないじゃないか。

そしてこのバグを誰も修正してくれない。


https://github.com/libuvc/libuvc/issues/12

このバグ、7年間も放置されています。

世界に80億人もいるのに。

もう誰もWindowsなんか使ってないのね。

最近いろいろなオープンソースでWindowsのバグが修正されていなくて困ります。


誰も修正してくれないので、おじさんが二週間ソースコードを解析してオープンソースを修正してみました。


ソースコードを直すときのメモリリークチェックとかリソースハンドルのクローズ忘れとかのチェックが大変ですね。

だけどとりあえずできた!

ライセンスがLGPLなので、ソースコードを修正すると公開しないといけないです。

https://github.com/yomei-o/libusb-1

これでWindowsでlibusbとlibuvcを使ってUSBカメラを制御できる!

おじさんもちょっと世の中の役に立ったかな。





2022年11月28日月曜日

コルーチンを勉強する

 最近、機械学習系のライブラリとかゲームのライブラリとか動画を扱うライブラリがコルーチンという方法で書かかれているのをよく見ます。

Async/awaitパターンとも言われているそうです。


Async/await

https://ja.wikipedia.org/wiki/Async/await



パイプラインとかのような複雑な非同期非ブロッキングの関数を普通の同期関数と同じように記述できるから便利らしいです。たしかに機械学習の学習とか時間のかかる関数とかを簡単にマルチスレッド化できるし。

気が付けば、C言語も、C++言語も、Pythonも、JavaScriptも、ありとあらゆる言語が、コルーチンをサポートし、いろんなライブラリがそれで書かれている。

基本どのプログラム言語にも、async、awaitってものがあって、promiseというものに結果を格納するらしい。


しかしこの概念、久々に見た衝撃の難しさ。

いろいろな説明ページ見ても何言ってんの?っていうくらい難しい。

日本語でC++で正しく書かれているサイトないし。

年取るとこういう概念にとっさについていけない。

そもそもプロミスって最短30分くらいで簡単にお借入れできなかったっけ?

朝から夜まで一週間くらいずっと眺めて、やっとさっき主要な言語のpromiseの仕組みがわかかった。



C++のサンプル

-----------------------------------------

#include <coroutine>

#include <iostream>

#include <stdexcept>

#include <thread>


auto switch_to_new_thread(std::jthread& out) {

    struct awaitable {

        std::jthread* p_out;

        bool await_ready() { return false; }

        void await_suspend(std::coroutine_handle<> h) {

            std::jthread& out = *p_out;

            if (out.joinable())

                throw std::runtime_error("Output jthread parameter not empty");

            out = std::jthread([h] { h.resume(); });

            //潜在的な未定義の動作:潜在的に破壊された*thisへのアクセス

            // std :: cout << "新しいスレッドID:" << p_out-> get_id()<<'\ n';

            std::cout << "New thread ID: " << out.get_id() << '\n'; // これで結構です

        }

        void await_resume() {}

    };

    return awaitable{ &out };

}


struct task {

    struct promise_type {

        task get_return_object() { return {}; }

        std::suspend_never initial_suspend() { return {}; }

        std::suspend_never final_suspend() noexcept { return {}; }

        void return_void() {}

        void unhandled_exception() {}

    };

};


task resuming_on_new_thread(std::jthread& out) {

    std::cout << "Coroutine started on thread: " << std::this_thread::get_id() << '\n';

    co_await switch_to_new_thread(out);

    //ここでウェイターが破壊されました

    std::cout << "Coroutine resumed on thread: " << std::this_thread::get_id() << '\n';

}


int main() {

    std::jthread out;

    resuming_on_new_thread(out);

}

-----------------------------------------






2022年10月21日金曜日

ブラウザでC/C++のプログラムを動かす

 最近、TensorFlow.jsとかOnnxRuntimeなど、C/C++言語で書かれた機械学習のライブラリが何故かブラウザで動きます。

調べてみると、emscriptenを使ってC/C++のソースをコンパイルすると、WebAssemblyのバイナリーができて、C/C++等で書かれたプログラムがブラウザで動くようです。

ブラウザはJavaScriptしか動かないと思っていたら、いつの間にかブラウザで動くすごいアプリはみんなC/C++で書かれている・・・。

おじさんの大好きなC/C++で書かれている。


PythonもOpenCVもffmpegもみんなWebAssemblyで動くようにコンパイルされたバイナリーがあります。

それをHTMLに組み込むと、ブラウザでPythonもOpenCVもffmpegも動くのね。

ゲームのエミュレータやLinuxなどのOSもWebAssemblyで動くようです。


すげー。


https://dev.classmethod.jp/articles/cpp-webassembly-emscripten/


とってもすごいんだけど、emscriptenのインストールとか開発環境がとっても不便。

でもこれでプログラムを作れば、スマホやPCなど、すべてのデバイスでプログラムが動く。


ぼくもとりあえずhello.cppを作ってみました。

2022年10月5日水曜日

AIでプログラムしてみた。

最近はAIがプログラムしてくれるようになったらしいです。

おじさんのような人がコードを書かなくてもAIが自動でコードを書いてくれるらしいです。

おじさんがコード書いたことにしてお金もらえないかなぁ。


前からやってみたかったのですが、プログラムするAIを学習させるのがとても大変で誰かやってくれないかなぁとおもっていたら、やってくれた人がいました。




https://aiprogrammer.hashlab.jp/


--------------------

nまでの素数を求めるプログラム

--------------------

#include <iostream>

#include <math.h>


using namespace std;


int main()

{

int i, j;

int n;

int prime;


cout << "nを入力してください:";

cin >> n;


for (i = 2; i <= n; i++) {

prime = 1;

for (j = 2; j <= sqrt(i); j++) {

if (i%j == 0) {

prime = 0;

break;

}

}

if (prime == 1) {

cout << i << " ";

}

}


cout << endl;


return 0;

}

--------------------

おーあってる。
ちゃんとコンパイルして動くし。


--------------------

高速にnまでの素数を求めるプログラム

--------------------

#include <iostream>

#include <vector>


using namespace std;


vector<int> primeNumbers(int n) {

vector<int> res;


for (int i = 2; i <= n; i++) {

bool isPrime = true;

for (int j = 2; j * j <= i; j++) {

if (i % j == 0) {

isPrime = false;

break;

}

}

if (isPrime) res.push_back(i);

}


return res;

}


int main() {

int n;

cin >> n;

vector<int> res = primeNumbers(n);

for (int i = 0; i < res.size(); i++) {

cout << res[i] << endl;

}


return 0;

}

--------------------


おーこれもあっている。
しかも高速に求めてるし。
ニュートン法とかいけるのかな?


--------------------

ニュートン法で平方根を求めるプログラム

--------------------

#include <iostream>

#include <cmath>

using namespace std;


double NewtonMethod(double x)

{

double result = x;

double prevResult;

double epsilon = 1.0e-6;

int i = 0;

do

{

prevResult = result;

result = result - (result - x / result) / 2;

i++;

} while (fabs(result - prevResult) > epsilon && i < 100);

return result;

}


int main()

{

double input;

cin >> input;

cout << NewtonMethod(input) << endl;

return 0;

}

--------------------


すげー、情報系の大学2年生くらいのレベルはありそうですね。
マクローリン展開とかもできるのでしょうか?


--------------------

マクローリン展開でsinを求めるプログラム

--------------------

#include <iostream>

#include <cmath>


using namespace std;


int main()

{

double x;

cin >> x;


double result = 0;

for (int i = 0; i < 10; i++)

{

result += pow(-1, i) * pow(x, 2 * i + 1) / (2 * i + 1);

}


cout << result << endl;


return 0;

}

--------------------

マクローリン展開もできてる。
あらーすごい。
これは大学のレポート作成にもってこいだわ。
海外の大学だとアルバイトにお金払えば大学の宿題とかレポートやってくれるんですが、お金払わなくていいじゃん!



だけど、まだオープンソースとか作れるプロのプログラマーレベルではないみたい。
数値計算はとっても得意だけれどエスケープ処理とか文字列とかの細かい処理が苦手?


2022年9月5日月曜日

PytorchのC++のライブラリlibtorchを使う2022

最近AI囲碁や将棋、たんぱく質の構造推定などあらゆるAIでResNetが使われています。

ResNetって画像分類以外のこともできるようです。

ResNetくらいなら簡単なものならおじさんの個人所有のGPUでもなんとか学習ができそう。

C++でやってみたい・・・・



c++でResNetができるフレームワークを探すと、Pytorchがでてきます。

Pytorchはもともとコア部分がlibtorchにまとまっていてc++から使えるようになっているし、Android版はNewralNetworkAPIなどに対応しており、GPUを使って高速に演算ができるようです。

 最近、GoogleのTensorFlow、マイクロソフトのonnxruntime、FacebookのPytorchなど、いろいろな機械学習フレームワークが続々とONNX対応、c++対応やスマホ対応になってきています。

Pytorchのようなスマホ対応のフレームワークを使えば、フルセットのPytorchがスマホでも動き、GPU付きのPCで学習させてスマホでその結果を利用することもできるようです。

いろいろなOSで動いて、学習データの再利用ができてほんとうに便利ねー。


そこで、本日は最新のPytorch 1.12.1のc++ライブラリlibtorchをビルドして動かしてみたいと思います。


ビルド方法はドキュメントに書かれている通りでとっても簡単

以前の自分のブログに書いてある通りでビルドできます。

http://yomeiotani.blogspot.com/2019/04/windowslibtorch.html


--------------------

cd <pytorch_root>\tools

mkdir build

cd build

python ..\build_libtorch.py

--------------------

上記のように打つだけ。
Windowsでのビルドは、公式にはVisualStudio 2017にしか対応していないようですが、コンパイラのバージョンをチェックしている部分を直せばVisualStudio 2022でもビルドできるようです。
外部依存ライブラリが前回より変わっています。
演算をより高速にするためにいろいろな機能を追加しているみたいですね。

PyTorchのexample/cppフォルダにはc++のサンプルがあります。
このなかに定番の文字認識「MNIST」のlibtorch版、mnist.cppがあります。


とりあえずビルドして動かしてみました。
----------------------------
Training on CPU.
Train Epoch: 1 [59584/60000] Loss: 0.2362
Test set: Average loss: 0.2119 | Accuracy: 0.935
Train Epoch: 2 [59584/60000] Loss: 0.1365
Test set: Average loss: 0.1301 | Accuracy: 0.959
Train Epoch: 3 [59584/60000] Loss: 0.1805
Test set: Average loss: 0.1069 | Accuracy: 0.965
Train Epoch: 4 [59584/60000] Loss: 0.1147
Test set: Average loss: 0.0899 | Accuracy: 0.970
Train Epoch: 5 [59584/60000] Loss: 0.1017
Test set: Average loss: 0.0834 | Accuracy: 0.974
Train Epoch: 6 [59584/60000] Loss: 0.0549
Test set: Average loss: 0.0725 | Accuracy: 0.976
Train Epoch: 7 [59584/60000] Loss: 0.0657
Test set: Average loss: 0.0697 | Accuracy: 0.979
Train Epoch: 8 [59584/60000] Loss: 0.0832
Test set: Average loss: 0.0639 | Accuracy: 0.980
Train Epoch: 9 [59584/60000] Loss: 0.0523
Test set: Average loss: 0.0609 | Accuracy: 0.982
Train Epoch: 10 [59584/60000] Loss: 0.0504
Test set: Average loss: 0.0559 | Accuracy: 0.983
----------------------------

なんかあってそう。
とりあえずlibtorchのカスタムビルドができたから次はResNetでいろいろ遊ぼうっと。
android版のビルドもしてみたいなぁ。

2022年2月22日火曜日

株価指数を計算する。

 おじさん、今週は株価指数を計算するライブラリを作成しています。


株価指数って、まずTOPIXが基本らしい。

株系のWebページって結構みんな読まれるためか、いろいろな人がいろいろなことを書いているのですが、結構適当な記事が多いです。


ある経済ライターさんのページには以下のように書かれています。

https://seikeidenron.jp/articles/584

------------------

景気を知るためにもう一つ覚えておきたいのが「TOPIX(東証株価指数)」。

こちらは、東証一部に上場しているすべての銘柄の時価総額(株価×発行済株式数)を足して、銘柄数で割ったものだ。

------------------


平均だから銘柄数で割ったら平均になりそうだけどね。

うそつきー。うそのこと書くなよ!

景気を知る前に株価指数のこと知れよ!!!!



おじさんがプログラムで計算した式は、


(今の浮遊株時価総額)÷(昔の浮遊株時価総額)×(100または1000)

(浮遊株時価総額)=(浮遊株数)×(終値)


だぞ!


おじさんも二週間、朝から晩までプログラム書いて株価指数の計算方法がわかったので、こういう嘘のことを書いているのがわかるようになりました。

おじさんの勉強では平均株価ってだいたい「浮動株基準時価総額加重平均型株価」って方法で計算するらしい。


https://ja.wikipedia.org/wiki/%E6%99%82%E4%BE%A1%E7%B7%8F%E9%A1%8D%E5%8A%A0%E9%87%8D%E5%B9%B3%E5%9D%87%E5%9E%8B%E6%A0%AA%E4%BE%A1%E6%8C%87%E6%95%B0


でもこの株価指数の計算ってなかなか大変。

浮遊株数とか基準時時価総額とかの具体的な計算例や一覧データはどこにもフリーのデータがありません。

東証から月3300円で入手しないといけないっぽいです。

10年分とると40万円いるじゃないか!

うそ書いてるやると金とるやつしかいない・・・・。

なんという厳しい世界。


TOPIXでさえ、株価指数の計算の仕方が正確に書かれていないので、おじさんきちんとTOPIXを求めてみました。

浮遊株数ってどうやって計算するんだろ?

おじさん頑張ってフリーのデータから基準時時価総額と浮遊株数を計算する方法を見つけました。



まず、東京証券取引所からTOPIXの銘柄別のウェイト情報を入手

https://www.jpx.co.jp/markets/indices/topix/index.html

構成銘柄別ウエイト一覧


つぎに、年末の浮遊株時価総額と基準時時価総額を入手。

https://www.jpx.co.jp/markets/indices/related/value/index.html

2021年12月末現在



上記の二個のファイルから、TOPIX時価総額にウェイトをかけて各銘柄の浮遊株時価総額を計算。

浮遊株時価総額をその日の終値で割って、浮遊株式数を逆計算で取得。

浮遊株式数から株価指数を計算。


さらに実際には、銘柄変更、上場廃止、一時取引停止、株式分割などいろいろなイベントが毎週あるので、これらのイベントに対応し計算しないといけないためかなりめんどくさい。


でもこの方法で業種別の株価指数を計算できるようになりました。

これでただで業種別株価指数を使ってAIで株価分析してやる。



ソースはこちら。

https://github.com/yomei-o/Protra_cpp





2022年2月16日水曜日

33業種データベースを作る。

 おじさん、以下のサイトで株価はマーケットや業種ごとに傾向がことなることを勉強しました。

https://qiita.com/blog_UKI/items/25dc1c2559c61890a449

なるほど、ウイリアム・シャープっていうノーベル賞を受賞したおちゃんが言っているのね。

https://ja.wikipedia.org/wiki/%E8%B3%87%E6%9C%AC%E8%B3%87%E7%94%A3%E4%BE%A1%E6%A0%BC%E3%83%A2%E3%83%87%E3%83%AB


何言ってるのかよくわからん。

けど、機械学習とかって論文や資料が全部英語なんだけど、金融経済分野って資料が全部日本語に翻訳されている・・・。

きっとこの分野、お金が有り余ってるに違いない。


株のリターンを計算するには、上場企業の「業種」やどのマーケットに上場しているのかのデータが必要らしいです。

Protraの上場企業データベースには、上場しているマーケット情報はあるのですが、業種のデータベースがありません。なので、本日は上場企業の業種のデータベースを作ろうと思ういます。


上場企業の業種の一覧ってどこにあるんだろ?

調べてみると、東京証券取引所にあるみたい。



https://www.jpx.co.jp/markets/statistics-equities/misc/01.html

ここにいろんな企業の株に関するデータがありました。

ここの東証上場銘柄一覧というエクセルの中に業種があるのね。


しかしこのエクセル、「食品    」のように業種の文字のあとにスペースが入ってる・・・。

たしかに見た感じわかんないひっかけだけど、微妙に間違ってるのね。

金融とか証券ってこういうの間違っちゃいけないと思うんだけど・・・。

きっと誰もこのエクセル使っていないのね。


エクセルを見ると、「17業種コード」と「33業種コード」があるらしい。

「17業種コード」は1から連番なのですが、「33業種コード」は7250とか意味不明な数字が・・・

図書館の本の分類の日本十進分類だって連番なのに、Kaggleのようにあちこちにいろんな罠があります。

https://ja.wikipedia.org/wiki/%E6%97%A5%E6%9C%AC%E5%8D%81%E9%80%B2%E5%88%86%E9%A1%9E%E6%B3%95


こういう不連続なデータをきちんと機械学習できるように連番にしていきます。

データを正確に分類するのって結構大変なのね。


ということで、いろいろ罠があり時間がかかってしまいましたが、上場企業の業種のライブラリができた!


https://github.com/yomei-o/Protra_cpp/blob/main/src/Industory.h




2022年2月14日月曜日

ローソク足を表示する

 おじさん、今日はどうやってJavaScriptで株価のローソク足を描画するのか調べています。

日経平均株価のリアルタイム表示サイトとかで使われている赤と緑のグラフのやつね。

デフォルトのChart.jsだとローソク足表示はできないらしい。

だけど、なかなかあれと同じようなちょうどいいライブラリがないねぇ。


いろいろ試してみると、このライブラリが一番きれいにローソク足が表示できそう。

https://github.com/chartjs/chartjs-chart-financial/tree/master/docs

Chart.jsのプラグインになっているようです。



思う通りの日経平均株価のローソク足表示ができた。
おじさんシステムトレードのプログラム作るより、証券会社のWebページを作った方が儲かるんじゃないかと思えてきました。
自分で作って分かったのですが、証券会社のWebページって結構製作難易度高いように思ういます。
みんなどのように作っているのでしょうね?

ソースコードはこちら

2022年2月10日木曜日

残差プロットをする。

おじさん、先日作ったlightgbmの住宅価格の予想プログラムを任意のCSVファイルを読めるように少し改造してました。

あとモデルデータの保存と読み込みもできるようにしました。

でもどうしても学習の結果が正しいかどうかなかなかわからない。

プログラムにバグがないことを確認することはほんと至難の業。


いろいろ考えた結果、よく知られているデータの学習結果を残差プロット表示すればわかるんじゃないかと思いつきました。

PandasやR言語でグラフ表示すると結局別のプログラムしないといけないし。

よく考えて、今週は機械学習のデータのグラフ表示のJavascriptライブラリを作ってみました。

いつものようにC++からJavaScriptを生成。

全部C++で行います。


JavaScriptで計算すると遅いのかと思ったのですが、ChromeのJavaScriptってめちゃくちゃ高速なのね。

あまりの速さにびっくり。

相関係数とか行列操作のJavaScriptrの統計ライブラリも作ったので、ブラウザでさくさくCSVファイルを読み込んで相関行列とか残差プロットとかが表示できるようになりました。



先日作った、おじさんのlightgbmのプログラムの、ボストンの住宅価格の残差プロットを作ってみました。
おー、ネットに落っこちている図と同じになった。
右下の部分にある謎の直線上の点が同じ。

ということは、先日作ったおじさんのlightgbmのプログラムや今週作ったJavaScriptの統計ライブラリは正しいっぽい。
モデルデータの保存と読み込みやCSVファイルの処理もあってそう。
しかもおじさんの方が右下部分の点の数が少ないからある意味正確??
おじさんのデータだと10以上外したの二つしかないし。

学習アルゴリズムが多少違っても、どちらもある程度正しく学習できていれば、残差プロットの特徴ってだいたい一致するのね。


残差プロットってこういう具合にプログラムにバグがないかを判断するのにも使えるのね。

勉強になるねぇ。

これで、いろんな株価の特徴データのCSVファイルを作れば、ブラウザベースで株価のAIデータ解析ができて、学習が正しいかわかるはず。

ソースコードはこちら

https://github.com/yomei-o/Protra_cpp/tree/main/server/scatter_plot

2022年2月6日日曜日

c++でデータマイニングをする。

 おじさん、先週は勾配ブーストの機械学習ライブラリの使い方がわかったので、今週はデータマイニングのやり方を勉強します。


データマイニングって意味がよくわからないし。日本語で言うと統計解析?

統計解析とデータマイニングは違うといってる人もいるし。

データマイニングとは、上の図のように相関行列を求めたりしてデータの中から意味のある情報を取りだすことらしいです。

そしてその手法が統計解析っぽいです。

PythonのPandasなどの統計解析のライブラリを使うと上の図のような相関行列を簡単に作り出せます。

なんかデータマイニングしてる感じが出てかっこいいね。


そもそも統計解析はR言語やPythonを使って行うのが一般的なのですが、R言語とかでやると遅いらしく、海外ではC++で高速に行ったりもしています。

でもC++で統計解析を行っている日本語の記事が一つもない。

どうやってC++で統計解析をやるのか日本語で正しく書かれているサイトがひとつもないのです。

さみしいなぁ。

日本の金融業界とか証券業界ってどうやって統計解析をやっているのでしょうか?

きっと外部に丸投げ?

ということで、今日はC++で統計解析を行って相関係数を求めてみたいと思います。


C++で統計解析を行うには、DataFrameというライブラリを使用します。

https://github.com/hosseinmoein/DataFrame

これ名前がよくなくて、DetaFrameなんていう一般的によく使われる単語の組み合わせなので、なかなか検索で出てきません。

でもこれを使うと簡単に相関係数を求めることができます。


統計解析のライブラリってどれもだいぶ癖が強めです。

というかDetaFrameという概念に癖がありますね。

普通、データをCSVファイルとかで読むときとかは、まず行を読んでそのあと列に分割して処理するのですが、行を中心に行います。

しかし、統計解析って列選択して統計処理を行うので行と列が逆なのです。。

そもそも英語でcolとrowどっちがどっちかわからないし。

年を取ってくると頭が固くなってこういう柔軟な思考に頭が瞬時に追いつかない。

でもDetaFrameの使い方がわかれば、ついでにR言語やPandasの使い方もわかります。


いろいろ書きましたが、C++でDetaFrameのライブラリを使ってボストンの住宅価格の相関行列を求めてみました。



ソースコード

-------------------------------------

#include <stdio.h>

#include <iostream>

#include <stdexcept>


#include <DataFrame_DataFrame.h>


using namespace hmdf;

using MyDataFrame = StdDataFrame<int>;


template<class T> inline std::vector<std::string> split(const std::string& s, const T& separator, bool ignore_empty = 0, bool split_empty = 0) {

struct {

auto len(const std::string& s) { return s.length(); }

auto len(const std::string::value_type* p) { return p ? std::char_traits<std::string::value_type>::length(p) : 0; }

auto len(const std::string::value_type  c) { return c == std::string::value_type() ? 0 : 1; /*return 1;*/ }

} util;


if (s.empty()) { /// empty string ///

if (!split_empty || util.len(separator)) return { "" };

return {};

}


auto v = std::vector<std::string>();

auto n = static_cast<std::string::size_type>(util.len(separator));

if (n == 0) {    /// empty separator ///

if (!split_empty) return { s };

for (auto&& c : s) v.emplace_back(1, c);

return v;

}


auto p = std::string::size_type(0);

while (1) {      /// split with separator ///

auto pos = s.find(separator, p);

if (pos == std::string::npos) {

if (ignore_empty && p - n + 1 == s.size()) break;

v.emplace_back(s.begin() + p, s.end());

break;

}

if (!ignore_empty || p != pos)

v.emplace_back(s.begin() + p, s.begin() + pos);

p = pos + n;

}

return v;

}


struct datapair {

float* data;

float* label;

int rows;

int cols;

};


struct datapair* readboston(const char* fn)

{

FILE* fp;

struct datapair* ret = NULL;

char buf[256];

std::string str;

std::vector<std::string> rows;

std::vector<std::string> cols;

fp = fopen(fn, "rt");

if (fp == NULL)return ret;

while (1) {

buf[0] = 0;

fgets(buf, sizeof(buf), fp);

if (buf[0] == 0)break;

str = buf;

rows.push_back(str);

}

ret = new(struct  datapair);

ret->cols = 13;

ret->rows = rows.size();

ret->data = new float[13 * rows.size()];

ret->label = new float[rows.size()];


for (int i = 0; i < rows.size(); i++) {

cols = split(rows[i], " ", 1, 1);

if (cols.size() < 14)continue;

for (int j = 0; j < 13; j++) {

ret->data[13 * i + j] = std::stod(cols[j]);

}

ret->label[i] = std::stod(cols[13]);

}

return ret;

}


void freedata(struct datapair* d)

{

if (d == nullptr)return;

delete[] d->data;

delete[] d->label;

delete d;

}



int main(int argc, char* argv[])

{

    MyDataFrame df;

    std::vector<int> index;

    std::vector<float> tmp;

    StatsVisitor<float>    stats_visitor;

std::vector<std::string> col_lbl;

char col_name[256];

struct datapair* dp;

int ret;


dp = readboston("housing.data");

for (int j = 0; j < dp->rows; j++) {

index.push_back(j);

}

df.load_index(std::move(index));


for (int j = 0; j < dp->cols; j++) {

sprintf(col_name, "col_%d", j);

tmp.clear();

for (int i = 0; i < dp->rows; i++) {

tmp.push_back(dp->data[j+i*dp->cols]);

}

col_lbl.push_back(col_name);

df.load_column<float>(col_name, std::move(tmp));

}


sprintf(col_name, "col_%d", 24);

tmp.clear();

for (int j = 0; j < dp->rows; j++) {

tmp.push_back(dp->label[j]);

}

df.load_column<float>(col_name, std::move(tmp));

col_lbl.push_back(col_name);


CorrVisitor<float> corr_visitor;

for (int j = 0; j < dp->cols + 1; j++) {

for (int i = 0; i < dp->cols + 1; i++) {

printf("+-----");

}

printf("+\n");

for (int i = 0; i < dp->cols + 1; i++) {

auto fut10 = df.visit<float, float>(col_lbl[i].c_str(), col_lbl[j].c_str(), corr_visitor);

float res = corr_visitor.get_result();

printf("|%5.2f", res);

}

printf("|\n");

}

for (int i = 0; i < dp->cols + 1; i++) {

printf("+-----");

}

printf("+\n");

return 0;

}


-------------------------------------


結果


これでC++を使ってプログラムで自動でデータマイニングができそう。


2022年2月4日金曜日

lightGBMで回帰分析をする。

 おじさん、毎日システムトレードに向けてプログラムを勉強しています。

株価の予想ってたぶん回帰分析なので、本日はlightGBMで回帰分析をしてみます。


回帰分析と言えば、ボストンの住宅価格予想!

アメリカのボストンの住宅のデータをもとにその価格を予想する定番のやつです。

これを住宅データの代わりに株のデータにすれば、株価の予想ができるはず。



むかし、このブログでもタイタニックの生存者の判定とかマンションの価格推定とかをやりました。

混同行列の図を見ればわかりますが、このふざけた複雑な相関関係。

いかにも普通のプログラムでは難しそう。でも原理は全く同じです。


作ってみてわかったのですが、先日作ったlightGBMのMNISTのソースコードをほんの少し直すだけで、住宅価格の回帰分析ができます。

学習の関数に渡すパラメーターを変えるだけでいろんなタイプの学習ができるんですね。

これはすごい。

たぶん、株価の予想もこれを少し直すだけできっとできるようになるんですね。


ネットでも書かれている通り、回帰分析って作ったプログラムの結果が正しいかどうか結果の数値だけからはなかなかわからない。

解けた感が全くありません。

むしろこれが本当に正しいのかという猜疑心が常にわいてきます。

同じデータを別のプログラムでもう一つ作らないと正しいことがわからないのです。

おじさんもネットに落ちていたPythonのlightGBMのボストンの住宅価格のプログラムの結果と比較して自分のプログラムが正しいことを確かめました。

いろいろ勉強になるね。


ソースコード

---------------------------------

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <string>

#include <vector>

#include "LightGBM/c_api.h"



template<class T> inline std::vector<std::string> split(const std::string& s, const T& separator, bool ignore_empty = 0, bool split_empty = 0) {

struct {

auto len(const std::string& s) { return s.length(); }

auto len(const std::string::value_type* p) { return p ? std::char_traits<std::string::value_type>::length(p) : 0; }

auto len(const std::string::value_type  c) { return c == std::string::value_type() ? 0 : 1; /*return 1;*/ }

} util;


if (s.empty()) { /// empty string ///

if (!split_empty || util.len(separator)) return { "" };

return {};

}


auto v = std::vector<std::string>();

auto n = static_cast<std::string::size_type>(util.len(separator));

if (n == 0) {    /// empty separator ///

if (!split_empty) return { s };

for (auto&& c : s) v.emplace_back(1, c);

return v;

}


auto p = std::string::size_type(0);

while (1) {      /// split with separator ///

auto pos = s.find(separator, p);

if (pos == std::string::npos) {

if (ignore_empty && p - n + 1 == s.size()) break;

v.emplace_back(s.begin() + p, s.end());

break;

}

if (!ignore_empty || p != pos)

v.emplace_back(s.begin() + p, s.begin() + pos);

p = pos + n;

}

return v;

}


struct datapair {

float* data;

float* label;

int rows;

int cols;

};


struct datapair* readboston(const char* fn)

{

FILE* fp;

struct datapair * ret = NULL;

char buf[256];

std::string str;

std::vector<std::string> rows;

std::vector<std::string> cols;

fp = fopen(fn, "rt");

if (fp == NULL)return ret;

while (1) {

buf[0] = 0;

fgets(buf, sizeof(buf), fp);

if (buf[0] == 0)break;

str = buf;

rows.push_back(str);

}

ret = new(struct  datapair);

ret->cols = 13;

ret->rows = rows.size();

ret->data = new float[13*rows.size()];

ret->label = new float[rows.size()];


for(int i=0;i<rows.size();i++){

cols=split(rows[i], " ", 1, 1);

if (cols.size() < 14)continue;

for (int j = 0; j < 13; j++) {

ret->data[13*i+j]=std::stod(cols[j]);

}

ret->label[i]= std::stod(cols[13]);

}

return ret;

}


void freedata(struct datapair*d)

{

if (d == nullptr)return;

delete[] d->data;

delete[] d->label;

delete d;

}


int main(int argc, char* argv[])

{

int ret;


DatasetHandle hx_train, hx_test;

struct datapair* dp;



dp=readboston("housing.data");

int pos = dp->rows * 0.8;

int n = dp->rows - pos;


#if 0

for (int i = 0; i < pos; i++) {

printf("%d ",i);

for (int j = 0; j < 13; j++)printf("%f ",dp->data[i*13+j]);

printf(">>%f\n",dp->label[i]);

}

#endif


ret = LGBM_DatasetCreateFromMat(dp->data, C_API_DTYPE_FLOAT32, pos,

dp->cols, 1, "", nullptr, &hx_train);

if (ret) {

printf("Error: LGBM_DatasetCreateFromMat()\n");

return 1;

}

ret = LGBM_DatasetSetField(hx_train, "label", dp->label, pos, C_API_DTYPE_FLOAT32);

if (ret) {

printf("Error: LGBM_DatasetSetField()\n");

return 1;

}


ret = LGBM_DatasetCreateFromMat(&dp->data[dp->cols*pos], C_API_DTYPE_FLOAT32, n,

dp->cols, 1, "", hx_train, &hx_test);

if (ret) {

printf("Error: LGBM_DatasetCreateFromMat()\n");

return 1;

}

ret = LGBM_DatasetSetField(hx_test, "label", &dp->label[pos], n, C_API_DTYPE_FLOAT32);

if (ret) {

printf("Error: LGBM_DatasetSetField()\n");

return 1;

}


printf("Create Data OK!!\n");


BoosterHandle bh;

ret = LGBM_BoosterCreate(hx_train, "objective=regression "

"metric=rmse", &bh);

if (ret) {

printf("Error: LGBM_BoosterCreate()\n");

return 1;

}


ret = LGBM_BoosterAddValidData(bh, hx_test);

if (ret) {

printf("Error: LGBM_BoosterAddValidData()\n");

return 1;

}


int is_finished = 0;

for (int i = 0; i < 100; i++) {

double d = 0;

ret = LGBM_BoosterUpdateOneIter(bh, &is_finished);

if (ret) {

printf("Error: LGBM_BoosterUpdateOneIter()\n");

return 1;

}

int out_len = 10;

ret = LGBM_BoosterGetEval(bh, 1, &out_len, &d);

if (ret) {

printf("Error: LGBM_BoosterGetEval()\n");

return 1;

}

printf("%d %f\n",i,d);

}


printf("Update OK!!\n");


long long d_len = 1;

double d;


ret = LGBM_BoosterPredictForMat(bh, &dp->data[dp->cols * pos], C_API_DTYPE_FLOAT32, 1, 13,

1, C_API_PREDICT_NORMAL, 0, -1, "", &d_len, &d);

if (ret) {

printf("Error: LGBM_BoosterPredictForMat()\n");

return 1;

}

printf("input\n");

for (int i = 0; i < 13; i++) {

printf("%d  %f\n",i, dp->data[dp->cols * pos+i]);

}

printf("predict\n");

printf("d=%f\n", d);


LGBM_BoosterFree(bh);

LGBM_DatasetFree(hx_train);

LGBM_DatasetFree(hx_test);


freedata(dp);


return 0;

}

---------------------------------



結果

---------------------------------

Create Data OK!!
[LightGBM] [Warning] Auto-choosing row-wise multi-threading, the overhead of testing was 0.000566 seconds.
You can set `force_row_wise=true` to remove the overhead.
And if memory is not enough, you can set `force_col_wise=true`.
[LightGBM] [Info] Total Bins 1028
[LightGBM] [Info] Number of data points in the train set: 404, number of used features: 13
[LightGBM] [Info] Start training from score 24.175743
[LightGBM] [Warning] No further splits with positive gain, best gain: -inf
0 8.902198
[LightGBM] [Warning] No further splits with positive gain, best gain: -inf
1 8.128168
...
[LightGBM] [Warning] No further splits with positive gain, best gain: -inf
99 5.225559
Update OK!!
input
0  41.529202
1  0.000000
2  18.100000
3  0.000000
4  0.693000
5  5.531000
6  85.400002
7  1.607400
8  24.000000
9  666.000000
10  20.200001
11  329.459991
12  27.379999
predict
d=9.342857

---------------------------------



2022年2月3日木曜日

XGBoostでMNISTをする。

 おじさん、lightGBMでMNISTができたので、今度はもう一つの勾配ブースト木ライブラリのxgboostも試してみたくなりました。

ということで、今日はXGBoostでMNISTをします。



昨日の深夜にXGBoostがビルドできたので、今日は朝5時からXGBoostの使い方を勉強。

朝8時ごろにXGBoostのMNISTができました。

その後学習をしている時間にこのブログを書いています。


XGBoostは入門者やC言語のドキュメントがしっかりしているので、ほとんど何も問題なくMNISTを作ることができました。

はじめにlightGBMよりこっちを勉強すればよかった。


だけれど、やっぱりネットに書かてれいる通り、学習が遅い。

数分で終わるlightGBMに比べてこちらは1/3のイテレーションでも学習に30分以上かかります。

最初止まっているんじゃないないかと思ったくらい。

とても150回イテレーションを回す気がしない。

50回だと判別間違ってるし。

これでは、遅すぎて耐えられない。

プログラムやデータ分析をする気がなくなる。



ソースコード

-------------------------------

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include "xgboost_c_api.h"


#define TRAIN_IMAGE "train-images-idx3-ubyte"

#define TRAIN_LABEL "train-labels-idx1-ubyte"

#define TEST_IMAGE "t10k-images-idx3-ubyte"

#define TEST_LABEL "t10k-labels-idx1-ubyte"


float data[] = {


0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,


0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,


0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,


0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,


0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,


0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,


0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,


0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,


0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,


0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,


0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,


0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,


0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,


0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,


0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,


0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,


0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,


0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,


0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,


0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,


0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,


0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,


0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,


0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,


0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,


0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,


0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,


0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,


};




struct tensor {

float* data;

int cols;

int rows;

};


static struct tensor* create_tensor(int rows, int cols) {

struct tensor* ret;

ret = (struct tensor*)malloc(sizeof(struct tensor));

ret->data = (float*)malloc(sizeof(float) * rows * cols);

memset(ret->data, 0, sizeof(float) * rows * cols);

ret->cols = cols; ret->rows = rows;

return ret;

}

static void free_tensor(struct tensor* t)

{

if (t && t->data)free(t->data);

if (t)free(t);

}




static int buf2int(char* buf_) {

int ret;

unsigned char* buf = (unsigned char*)buf_;


ret = buf[0]; ret <<= 8; ret |= buf[1]; ret <<= 8;

ret |= buf[2]; ret <<= 8; ret |= buf[3];

return ret;

}

static struct tensor* load_image_file(const char* fn)

{

struct tensor* ret = NULL;

FILE* fp;

int sz, t, w, h, n, i, j;

char buf[4];


fp = fopen(fn, "rb");

if (fp == NULL)goto end;

fseek(fp, 0, SEEK_END);

sz = ftell(fp);

fseek(fp, 0, SEEK_SET);


fread(buf, 1, 4, fp);

t = buf2int(buf);

if (t != 0x803)goto end;


fread(buf, 1, 4, fp);

n = buf2int(buf);

fread(buf, 1, 4, fp);

w = buf2int(buf);

fread(buf, 1, 4, fp);

h = buf2int(buf);

if (h * w != 784)goto end;


ret = create_tensor(n, 784);

for (i = 0; i < n; i++) {

for (j = 0; j < 784; j++) {

fread(buf, 1, 1, fp);

ret->data[i * 784 + j] = (float)(buf[0] & 255);

}

}

end:

if (fp)fclose(fp);

return ret;

}



static struct tensor* load_label_file(const char* fn)

{

struct tensor* ret = NULL;

FILE* fp;

int sz, t, n, i, j;

char buf[4];


fp = fopen(fn, "rb");

if (fp == NULL)goto end;

fseek(fp, 0, SEEK_END);

sz = ftell(fp);

fseek(fp, 0, SEEK_SET);


fread(buf, 1, 4, fp);

t = buf2int(buf);

if (t != 0x801)goto end;


fread(buf, 1, 4, fp);

n = buf2int(buf);

ret = create_tensor(n, 1);

for (i = 0; i < n; i++) {

fread(buf, 1, 1, fp);

ret->data[i] = (float)buf[0];

}

end:

if (fp)fclose(fp);

return ret;

}




int main(int argc, char *argv[])

{

struct tensor* x_train, * x_test;

struct tensor* y_train, * y_test;


x_train = load_image_file(TRAIN_IMAGE);

y_train = load_label_file(TRAIN_LABEL);

x_test = load_image_file(TEST_IMAGE);

y_test = load_label_file(TEST_LABEL);


int ret;

DMatrixHandle hx_train;

DMatrixHandle hx_test;

DMatrixHandle h_test;

BoosterHandle booster;


ret = XGDMatrixCreateFromMat(x_train->data, x_train->rows, x_train->cols, -1, &hx_train);

if (ret) {

printf("Error: XGDMatrixCreateFromMat()\n");

return 1;

}

ret = XGDMatrixSetFloatInfo(hx_train, "label", y_train->data, y_train->rows);

if (ret) {

printf("Error: XGDMatrixSetFloatInfo()\n");

return 1;

}


ret = XGDMatrixCreateFromMat(x_test->data, x_test->rows, x_test->cols, -1, &hx_test);

if (ret) {

printf("Error: XGDMatrixCreateFromMat()\n");

return 1;

}

ret = XGDMatrixSetFloatInfo(hx_test, "label", y_test->data, y_test->rows);

if (ret) {

printf("Error: XGDMatrixSetFloatInfo()\n");

return 1;

}

ret = XGDMatrixCreateFromMat(data, 1,784, -1, &h_test);

if (ret) {

printf("Error: XGDMatrixCreateFromMat()\n");

return 1;

}


const int eval_dmats_size = 2;

DMatrixHandle eval_dmats[eval_dmats_size] = { hx_train, hx_test };

ret=XGBoosterCreate(eval_dmats, eval_dmats_size, &booster);

if (ret) {

printf("Error: XGBoosterCreate()\n");

return 1;

}

ret = XGBoosterSetParam(booster, "objective", "multi:softprob");

if (ret) {

printf("Error: XGBoosterSetParam()\n");

return 1;

}

ret = XGBoosterSetParam(booster, "num_class", "10");

if (ret) {

printf("Error: XGBoosterSetParam()\n");

return 1;

}


int num_of_iterations = 50;

const char* eval_names[eval_dmats_size] = { "train", "test" };

const char* eval_result = NULL;

for (int i = 0; i < num_of_iterations; ++i) {

ret=XGBoosterUpdateOneIter(booster, i, hx_train);

if (ret) {

printf("Error: XGBoosterUpdateOneIter()\n");

return 1;

}

ret=XGBoosterEvalOneIter(booster, i, eval_dmats, eval_names, eval_dmats_size, &eval_result);

if (ret) {

printf("Error: XGBoosterEvalOneIter()\n");

return 1;

}

printf("%s\n", eval_result);

}


bst_ulong output_length=0;

const float* output_result=NULL;

ret=XGBoosterPredict(booster, h_test, 0, 0,0, &output_length, &output_result);

for (unsigned int i = 0; i < output_length; i++) {

printf("prediction[%i] = %f \n", i, output_result[i]);

}


XGBoosterFree(booster);

XGDMatrixFree(hx_train);

XGDMatrixFree(hx_test);

free_tensor(x_train); free_tensor(y_train);

free_tensor(x_test); free_tensor(y_test);


return 0;

}

-------------------------------



結果

-------------------------------

[07:53:35] WARNING: C:\trash\lightgbm\xgboost_mnist\src\learner.cc:1115: Starting in XGBoost 1.3.0, the default evaluation metric used with the objective 'multi:softprob' was changed from 'merror' to 'mlogloss'. Explicitly set eval_metric if you'd like to restore the old behavior.

[0]     train-mlogloss:1.356904 test-mlogloss:1.367719

[1]     train-mlogloss:1.026020 test-mlogloss:1.046251

...

[19]    train-mlogloss:0.089134 test-mlogloss:0.156737


prediction[0] = 0.027325

prediction[1] = 0.038958

prediction[2] = 0.124319

prediction[3] = 0.109822

prediction[4] = 0.223622

prediction[5] = 0.294601

prediction[6] = 0.042664

prediction[7] = 0.056748

prediction[8] = 0.043369

prediction[9] = 0.038572

-------------------------------


2022年2月1日火曜日

lightGBMでMNISTをする。

おじさん、今月はシステムトレードの計算ができるようにするため、lightGBMの使い方を勉強し始めました。

ネットの情報ではlightGBMでMNISTができるらしい。

決定木でニューラルネットワークのようなことができるのね。

これは面白そう。

ということで、lightGBMの最初のプログラムでMNISTをやってみました。



しかし、Pythonのコードはたくさん落っこちているのですが、c++のサンプルコードはどこにも落ちていません。

マイクロソフトの公式サイトにもC++のサンプルがありません。

これ本当にC++でできんの?


一日中いろいろ試して、どうにか学習と予測のところまでC++でできました。

だけれど、C++だと学習がちょうどいいところで自動で終わってくれない。

このハイパーパラメータを自分で計算しないといけないっぽいです。

どうやって計算するんだ?


でもとりあえずできた。

実際にやってみてわかったのですが、lightGBMは他の機械学習のライブラリと比べてビルド時間や学習にかかる時間が圧倒的に速い。

調べてみると、MNISTもニューラルネットワークと比べて8倍くらい早いらしいです。

しかもMNISTのようにたくさんの次元をいれても高速。

これくらいさくさく学習できると、ストレスなくいろんな特徴量をいれることができますね。

Kaglleとかでみんなが使う理由がよくわかります。



ソースコード

--------------------------


#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include "LightGBM/c_api.h"


#define TRAIN_IMAGE "train-images-idx3-ubyte"

#define TRAIN_LABEL "train-labels-idx1-ubyte"

#define TEST_IMAGE "t10k-images-idx3-ubyte"

#define TEST_LABEL "t10k-labels-idx1-ubyte"


float data[]={


0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,


0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,


0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,


0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,


0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,


0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,


0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,


0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,


0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,


0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,


0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,


0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,


0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,


0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,


0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,


0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,


0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,


0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,


0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,


0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,


0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,


0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,


0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,


0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,


0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,


0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,


0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,


0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,


};




struct tensor {

float* data;

int cols;

int rows;

};


static struct tensor* create_tensor(int rows, int cols) {

struct tensor* ret;

ret = (struct tensor*)malloc(sizeof(struct tensor));

ret->data = (float*)malloc(sizeof(float) * rows * cols);

memset(ret->data, 0, sizeof(float) * rows * cols);

ret->cols = cols; ret->rows = rows;

return ret;

}

static void free_tensor(struct tensor* t)

{

if (t && t->data)free(t->data);

if (t)free(t);

}




static int buf2int(char* buf_) {

int ret;

unsigned char* buf = (unsigned char*)buf_;


ret = buf[0]; ret <<= 8; ret |= buf[1]; ret <<= 8;

ret |= buf[2]; ret <<= 8; ret |= buf[3];

return ret;

}

static struct tensor* load_image_file(const char* fn)

{

struct tensor* ret = NULL;

FILE* fp;

int sz, t, w, h, n, i, j;

char buf[4];


fp = fopen(fn, "rb");

if (fp == NULL)goto end;

fseek(fp, 0, SEEK_END);

sz = ftell(fp);

fseek(fp, 0, SEEK_SET);


fread(buf, 1, 4, fp);

t = buf2int(buf);

if (t != 0x803)goto end;


fread(buf, 1, 4, fp);

n = buf2int(buf);

fread(buf, 1, 4, fp);

w = buf2int(buf);

fread(buf, 1, 4, fp);

h = buf2int(buf);

if (h * w != 784)goto end;


ret = create_tensor(n, 784);

for (i = 0; i < n; i++) {

for (j = 0; j < 784; j++) {

fread(buf, 1, 1, fp);

ret->data[i * 784 + j] = (float)(buf[0] & 255);

}

}

end:

if (fp)fclose(fp);

return ret;

}



static struct tensor* load_label_file(const char* fn)

{

struct tensor* ret = NULL;

FILE* fp;

int sz, t, n, i, j;

char buf[4];


fp = fopen(fn, "rb");

if (fp == NULL)goto end;

fseek(fp, 0, SEEK_END);

sz = ftell(fp);

fseek(fp, 0, SEEK_SET);


fread(buf, 1, 4, fp);

t = buf2int(buf);

if (t != 0x801)goto end;


fread(buf, 1, 4, fp);

n = buf2int(buf);

ret = create_tensor(n, 1);

for (i = 0; i < n; i++) {

fread(buf, 1, 1, fp);

ret->data[i] = (float)buf[0];

}

end:

if (fp)fclose(fp);

return ret;

}



int main(int argc, char* argv[])

{

int ret;


DatasetHandle hx_train, hx_test;


struct tensor* x_train, * x_test;

struct tensor* y_train, * y_test;


x_train = load_image_file(TRAIN_IMAGE);

y_train = load_label_file(TRAIN_LABEL);

x_test = load_image_file(TEST_IMAGE);

y_test = load_label_file(TEST_LABEL);



ret = LGBM_DatasetCreateFromMat(x_train->data, C_API_DTYPE_FLOAT32, x_train->rows,

x_train->cols, 1, "", nullptr, &hx_train);

if (ret) {

printf("Error: LGBM_DatasetCreateFromMat()\n");

return 1;

}

ret = LGBM_DatasetSetField(hx_train, "label", y_train->data, y_train->rows, C_API_DTYPE_FLOAT32);

if (ret) {

printf("Error: LGBM_DatasetSetField()\n");

return 1;

}


ret = LGBM_DatasetCreateFromMat(x_test->data, C_API_DTYPE_FLOAT32, x_test->rows,

x_test->cols, 1, "", hx_train, &hx_test);

if (ret) {

printf("Error: LGBM_DatasetCreateFromMat()\n");

return 1;

}

ret = LGBM_DatasetSetField(hx_test, "label", y_test->data, y_test->rows, C_API_DTYPE_FLOAT32);

if (ret) {

printf("Error: LGBM_DatasetSetField()\n");

return 1;

}


printf("Create Data OK!!\n");


BoosterHandle bh;

ret = LGBM_BoosterCreate(hx_train, "objective=multiclass "

"num_class=10 num_boost_round=300 "

"early_stopping_round=5", &bh);

if (ret) {

printf("Error: LGBM_BoosterCreate()\n");

return 1;

}


ret = LGBM_BoosterAddValidData(bh, hx_test);

if (ret) {

printf("Error: LGBM_BoosterAddValidData()\n");

return 1;

}


int is_finished = 0;

double d_min = 10;

int ct_min=0;

for (int i = 0; i < 300; i++) {

double d = 0;

ret = LGBM_BoosterUpdateOneIter(bh, &is_finished);

if (ret) {

printf("Error: LGBM_BoosterUpdateOneIter()\n");

return 1;

}

int out_len = 10;

ret = LGBM_BoosterGetEval(bh, 1, &out_len, &d);

if (ret) {

printf("Error: LGBM_BoosterGetEval()\n");

return 1;

}

printf("%d %f\n",i,d);

if (d < d_min) {

d_min = d;

ct_min = 0;

}

else {

ct_min++;

if (ct_min >= 5)break;

}

}


printf("Update OK!!\n");


long long d_len = 10;

double d[10];

for (int j = 0; j < 784; j++) {

data[j] = data[j] * 255;

}

ret = LGBM_BoosterPredictForMat(bh, data, C_API_DTYPE_FLOAT32, 1, 784,

1, C_API_PREDICT_NORMAL, 0, -1, "", &d_len, d);

if (ret) {

printf("Error: LGBM_BoosterPredictForMat()\n");

return 1;

}

for (int i = 0; i < 10; i++) {

printf("d[%d]=%f\n", i, d[i]);

}


LGBM_BoosterFree(bh);

LGBM_DatasetFree(hx_train);

LGBM_DatasetFree(hx_test);

        free_tensor(x_train); free_tensor(y_train);

free_tensor(x_test); free_tensor(y_test);

return 0;

}

--------------------------


結果

--------------------------

[LightGBM] [Info] Load from binary file x_train

Create Data OK!!

[LightGBM] [Warning] Auto-choosing col-wise multi-threading, the overhead of testing was 1.095544 seconds.

You can set `force_col_wise=true` to remove the overhead.

[LightGBM] [Info] Total Bins 109606

[LightGBM] [Info] Number of data points in the train set: 60000, number of used features: 629

[LightGBM] [Info] Start training from score -2.315501

[LightGBM] [Info] Start training from score -2.185988

[LightGBM] [Info] Start training from score -2.309610

[LightGBM] [Info] Start training from score -2.280987

[LightGBM] [Info] Start training from score -2.329271

[LightGBM] [Info] Start training from score -2.404064

[LightGBM] [Info] Start training from score -2.316346

[LightGBM] [Info] Start training from score -2.259366

[LightGBM] [Info] Start training from score -2.327732

[LightGBM] [Info] Start training from score -2.311121

0 1.679374

1 1.373263

2 1.159687

...

...

149 0.000824


Update OK!!


d[0]=0.000818

d[1]=0.000104

d[2]=0.236144

d[3]=0.014695

d[4]=0.573232

d[5]=0.003431

d[6]=0.016848

d[7]=0.002404

d[8]=0.142658

d[9]=0.009667

--------------------------


おー、なんかあってる。
でもCPPでlightGBMつかうの大変ね。


2022年1月27日木曜日

システムトレードのWebサイトを作ってみた。

おじさん、オミクロン株の流行で外へ出かけられないので、毎日家に引きこもりです。

家でやることがないので、システムトレードのシミュレーターを作ってみました。

前回Protra言語のインタープリタを作ったことをブログに書いたのですが、

こういうのをブログに書くと、「副業で儲ける方法」とか「株で1億円儲けられる」とか「仮想通貨で夢の生活」とか怪しいメールがたくさん来るようになってしまいました。

世の中ほんと人の欲に付け入る悪い人ばかりだなぁ。

そんな簡単にもうかるんだったらこんなツールつくらないっつーの。


システムトレードのソフトウェアって、スクリプト言語の実装、株価情報の取得更新、損益計算、グラフ表示、データ変換、Webサーバ構築、セキュリティー対策、クライアントUXページ作成、JavaScriptr作成、ソースコード公開などいろんなことをやらないといけないので、結構大変。毎日深夜まで、仕事以外の空き時間を1か月全力投入でやっとここまで完成。

これは会社とかグループで作るもので、ひとりで作るものじゃないな。


日本の株価のデータも1Gバイトくらいあり、結構でかい。

これを高速で処理しないとシミュレーション結果がすぐにでないので、C++で実装しないとだめ。

最初、年末年始の一週間くらいでできないかなぁと思っていたのですが、一か月くらいかかってしました。


やっと動くようになっただけでまだまだ機能が貧弱ですが、どうにかWebでシステムトレードのシミュレーションが動くところまでできた。

 http://one.agolamusic.com/htdocs_protra/main.html



こんな感じでグラフも表示できます。

ソースコードはこちら、

https://github.com/yomei-o/Protra_cpp


おじさん、いつもスマートフォンやタブレットでもきちんと動くようにWebサイトを作るので、このシステムを使えば通勤電車のなかとかいつでもどこでもトレードのシミュレーションを行うこともできます。

コアの計算部分以外のグラフ表示とかは全部クライアントのブラウザで処理をしているのですが、最近のスマホのブラウザって本当にすごいねぇ。なんでもできちゃうのね。


来週からは、lightGBMのディープラーニングエンジンを追加しようと思っていますが、

これも結構時間かかりそう。

外に出れない間の暇つぶしにはちょうどいいかなぁ。


2022年1月12日水曜日

Protra言語のインタープリタを実装してみた。

 おじさん、毎年年末年始は、なにかお金儲けでがきそうなライブラリを作ることにしています。

今年は何を作ろうか考えた結果、Protra言語のインタープリタを作ることにしました。

https://ja.osdn.net/projects/protra/wiki/FrontPage



ここに書かれているとおり、Protraとはシステムトレードをするソフトです。

コンピュータのプログラムが儲かりそうな株を分析してくれるのがシステムトレードソフト。そのプログラムの分析の通り株を買うと株で儲かるはず・・・・。

https://ja.wikipedia.org/wiki/%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%83%88%E3%83%AC%E3%83%BC%E3%83%89

このシステムトレードをするソフトのなかでオープンソースのものがProtraなのです。

このProtoraを改造して、ディープライニングのLightGBMなどと連携させると、最新のシステムトレードソフトになるらしい。

https://ja.wikipedia.org/wiki/LightGBM


LightGBMのプログラムを書ける人がシステムトレードの上位にはいれるのか!

https://nehori.com/nikki/2021/11/27/post-33741/


これは、お金儲けできそう。

しかし、なぜかオリジナルのProtoraはC#で書かれているため、他のライブラリと連携できないため、おじさんのMacやPythonからも使えないのです。


なるほど、ここにProtraの問題点があるんですね。

これはなんとかしなければ。

ということで、まずはProtraインタープリタをC++で実装してみました。

https://github.com/yomei-o/Protra_cpp


年末年始に実装できたのはProtra言語のインタープリタ部分だけなのですが、とりあえずこれでProtra言語がLinuxやMacでも動くし、LightGBMとも連携させられそうだし、簡単にPythonからもProtoraを使うことができそうです。

あと株価系のビルトイン関数とPythonとのインタフェースを作れば、システムトレードのシミュレーションをすることができるはず。


今年中にある程度完成できればいいなぁ。

ソフトが完成したら誰かお金投資してくれないかなぁ。

そしたら以下のようなお金のむしり取り合いに参加できるんだけどなぁ。

https://nehori.com/nikki/2021/12/16/post-11240/