おじさん、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
-------------------------------
0 件のコメント:
コメントを投稿