2020年8月15日土曜日

TensorflowのC++APIで学習をする

ここ数日暑い、暑すぎる。

あまりにも外が暑いので家でプログラムをします。


TensorflowのC++APIはあまりマニュアルが整備されていないため、ソースコードがほとんどありません。

その中でも特にC++APIを使った学習に関するサンプルはGoogleが作った簡単なもの以外まったくない。

一番ありそうなMNISTの学習サンプルもないのです。

なんで?


世の中でまだ誰もTensorflowのC++APIを使ったMNISTの学習サンプルがないので作ってみました。


作っている途中でわかったのですが、TensorflowのC++APIにはオプティマイザーとか最急降下法の便利な関数がありません。

手動でネットワークの微分とかバックプロパゲーションをしないといけないみたいです。

だからMNISTのC++の学習サンプルがないのか!


微分とか言っても高校生でできる程度の簡単なものだし、行列の演算も内積と四則演算と転置くらいしかありません。

バックプロパゲーションって結果を使って計算するだけならばそんな難しくなです。


バックプロパゲーションを理解する

https://postd.cc/2015-08-backprop/


いまさらMNIST分類器を自前実装する

https://qiita.com/soramimi_jp/items/d557d2d7adf8cc555d8b


上記のサイトを参考にしてTensorflowのC++APIでMNISTを実装してみました。


全ソースコードはこちら

https://drive.google.com/file/d/1bqBK5B8xTR0K_0C1z7yOg5yKk-teq-9I/view?usp=sharing

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

#define NOMINMAX

#define WIN32_LEAN_AND_MEAN


#include <iostream>

#include <fstream>

#include <vector>

#include "mnistutil.h"


#include <tensorflow_cc_client_client_session.h>

#include <tensorflow_cc_ops_standard_ops.h>

#include <tensorflow_core_framework_tensor.h>

#include <tensorflow_cc_framework_gradients.h>

#include <tensorflow_core_platform_init_main.h>


#ifdef _MSC_VER

#pragma comment(lib,"ws2_32.lib")

#endif


#define tf tensorflow



void print_tensor(const char* tt,tf::Tensor& out)

{

int sz,i,w=1,h;

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

sz = out.dims();

printf("dims()=%d\n", sz);

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

w *= out.dim_size(i);

printf("dim_size(%d)=%d\n",i,out.dim_size(i));

}

if (w > 10)w = 10;

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

float* p = (float*)out.data();

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

}

if (sz > 1) {

h = out.dim_size(0);

if (h > 10)h = 10;


for (i = 1; i < h; i++) {

float* p = (float*)out.data();

printf("data(%d)=%f \n", i * out.dim_size(1), p[i * out.dim_size(1)]);

}

}

printf("\n");

}



int main(int argc, char** argv)

{

int batch_num = 100;

int epoch_num = 10000;

float rate = 0.1;

int i;


tf::Scope root=tf::Scope::NewRootScope();

tf::ClientSession session{ root };


tf::Output x = tf::ops::Placeholder(root, tf::DataType::DT_FLOAT);

tf::Output t = tf::ops::Placeholder(root, tf::DataType::DT_FLOAT);


tf::Output w1 = tf::ops::Variable(root, {784,50}, tf::DataType::DT_FLOAT);

auto assign_w1 = tf::ops::Assign(root, w1, tf::ops::RandomNormal(root, { 784,50 }, tf::DataType::DT_FLOAT));


tf::Output b1 = tf::ops::Variable(root, { 50 }, tf::DataType::DT_FLOAT);

auto assign_b1 = tf::ops::Assign(root, b1, tf::ops::RandomNormal(root, { 50 }, tf::DataType::DT_FLOAT));


tf::Output w2 = tf::ops::Variable(root, { 50,10 }, tf::DataType::DT_FLOAT);

auto assign_w2 = tf::ops::Assign(root, w2, tf::ops::RandomNormal(root, { 50,10 }, tf::DataType::DT_FLOAT));


tf::Output b2 = tf::ops::Variable(root, { 10 }, tf::DataType::DT_FLOAT);

auto assign_b2 = tf::ops::Assign(root, b2, tf::ops::RandomNormal(root, { 10 }, tf::DataType::DT_FLOAT));


auto a1=tf::ops::Add(root,tf::ops::MatMul(root, x, w1),b1);


auto z1 = tf::ops::Sigmoid(root,a1);

auto a2 = tf::ops::Add(root, tf::ops::MatMul(root, z1, w2), b2);

auto y = tf::ops::Softmax(root,a2);


tf::Tensor x_data;

tf::Tensor t_data;


auto dy = tf::ops::Div(root, tf::ops::Sub(root, y, t), {(float)batch_num});


auto z1t = tf::ops::Transpose(root, z1, {1,0});

auto w2_ = tf::ops::MatMul(root, z1t, dy);

auto b2_ = tf::ops::Sum(root, dy, {0});


auto w2t = tf::ops::Transpose(root, w2, { 1,0 });

auto dz1 = tf::ops::MatMul(root,dy,w2t);

auto dsg = tf::ops::Mul(root, tf::ops::Sub(root, {(float)1}, tf::ops::Sigmoid(root, a1)), tf::ops::Sigmoid(root, a1));

auto da1 = tf::ops::Mul(root,dsg,dz1);


auto xt = tf::ops::Transpose(root, x, { 1,0 });

auto w1_= tf::ops::MatMul(root,xt,da1);

auto b1_ = tf::ops::Sum(root, da1, { 0 });

 

auto w1_g = tf::ops::Mul(root, w1_, {(float)rate});

auto w2_g = tf::ops::Mul(root, w2_, { (float)rate });

auto b1_g = tf::ops::Mul(root, b1_, { (float)rate });

auto b2_g = tf::ops::Mul(root, b2_, { (float)rate });


auto w1_n = tf::ops::Sub(root, w1, w1_g);

auto w2_n = tf::ops::Sub(root, w2, w2_g);

auto b1_n = tf::ops::Sub(root, b1, b1_g);

auto b2_n = tf::ops::Sub(root, b2, b2_g);


auto a_w1 = tf::ops::Assign(root, w1, w1_n);

auto a_w2 = tf::ops::Assign(root, w2, w2_n);

auto a_b1 = tf::ops::Assign(root, b1, b1_n);

auto a_b2 = tf::ops::Assign(root, b2, b2_n);


std::vector<tf::Tensor> outputs {};


//init

auto ret1 = session.Run({ assign_w1,assign_w2,assign_b1,assign_b2 }, nullptr);


std::vector<float> train_img, test_img, train_lbl, test_lbl,bat_img,bat_lbl;

load_image_file(TRAIN_IMAGE, train_img);

load_label_file(TRAIN_LABEL, train_lbl);

load_image_file(TEST_IMAGE, test_img);

load_label_file(TEST_LABEL, test_lbl);




//train

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


create_batch(batch_num, train_img, train_lbl, bat_img, bat_lbl);


tf::Tensor x_data(tf::DT_FLOAT, tf::TensorShape({ batch_num,784 }));

auto dst_x_data = x_data.flat<float>().data();

memcpy(dst_x_data, bat_img.data(), sizeof(float)*bat_img.size());


tf::Tensor t_data(tf::DT_FLOAT, tf::TensorShape({ batch_num,10 }));

auto dst_t_data = t_data.flat<float>().data();

memcpy(dst_t_data, bat_lbl.data(), sizeof(float) * bat_lbl.size());


//ok  auto ret0 = session.Run({ { x, x_data },{ t, t_data } }, { y }, &outputs);

//print_tensor("y", outputs[0]);

//break;


auto ret2 = session.Run({ { x, x_data },{ t, t_data } }, { a_w1, a_b1, a_w2, a_b2 }, nullptr); 

}


// predict

create_batch(1, test_img, test_lbl, bat_img, bat_lbl);


tf::Tensor xt_data(tf::DT_FLOAT, tf::TensorShape({ 1,784 }));

auto dst_xt_data = xt_data.flat<float>().data();

memcpy(dst_xt_data, bat_img.data(), sizeof(float) * bat_img.size());


tf::Tensor tt_data(tf::DT_FLOAT, tf::TensorShape({ 1,10 }));

auto dst_tt_data = tt_data.flat<float>().data();

memcpy(dst_tt_data, bat_lbl.data(), sizeof(float) * bat_lbl.size());


auto ret3 = session.Run({ { x, xt_data },{ t, tt_data } }, { y }, &outputs);


float* pc = (float*)(outputs[0].data());

print_image(bat_img.data());

print_label(pc);


return 0;

}

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


結果はこちら

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

2020-08-14 14:07:44.312280: I C:\trash\mnist\tensorflow_2_2_mnist_001\src_core\tensorflow_core_platform_cpu_feature_guard.cc:143] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX AVX2

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

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

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

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

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

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

----------------------------------------11111111--------

--------------111111------------------1111111111--------

--------------111111----------------111111111111--------

------------11111111----------------1111111111----------

------------11111111----------------1111111111----------

----------11111111--------------111111111111------------

----------11111111--------------1111111111--------------

----------11111111--------------1111111111--------------

----------1111111111------------11111111----------------

------------1111111111111111111111111111----------------

----------------111111111111111111111111----------------

------------------1111111111111111111111----------------

--------------------111111111111111111------------------

----------------------------1111111111------------------

------------------------------11111111------------------

----------------------------11111111--------------------

----------------------------11111111--------------------

----------------------------11111111--------------------

----------------------------111111----------------------

----------------------------111111----------------------

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

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


0: 0.000000

1: 0.000000

2: 0.000014

3: 0.000000

4: 0.997556

5: 0.000003

6: 0.000017

7: 0.000059

8: 0.000143

9: 0.002207


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


できた!

バックプロパゲーションとかも誤差関数固定ならば数時間で作れるんですね。


0 件のコメント:

コメントを投稿