From b6ecdd80251e8974197a313856f41f827c11e0e5 Mon Sep 17 00:00:00 2001 From: lemonsqueeze Date: Mon, 28 Mar 2016 19:23:51 +0200 Subject: [PATCH] caffe dcnn support --- Makefile | 21 ++++++++++++ board.h | 2 ++ dcnn.cpp | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ dcnn.h | 30 +++++++++++++++++ pachi.c | 2 ++ uct/uct.c | 2 ++ 6 files changed, 169 insertions(+) create mode 100644 dcnn.cpp create mode 100644 dcnn.h diff --git a/Makefile b/Makefile index 39ba633..b7201bc 100644 --- a/Makefile +++ b/Makefile @@ -19,6 +19,13 @@ # MAC=1 +# Compile Pachi with dcnn support ? +# You'll need to install Boost and Caffe libraries. +# If Caffe is in a custom directory you can set it here. + +#DCNN=1 +#CAFFE_LIB=/usr/local/lib + # By default, Pachi uses low-precision numbers within the game tree to # conserve memory. This can become an issue with playout counts >1M, # e.g. with extremely long thinking times or massive parallelization; @@ -52,6 +59,7 @@ BINDIR=$(PREFIX)/bin # (N.B. -ffast-math breaks us; -fomit-frame-pointer is added below # unless PROFILING=gprof.) CUSTOM_CFLAGS?=-Wall -ggdb3 -O3 -std=gnu99 -frename-registers -pthread -Wsign-compare -D_GNU_SOURCE +CUSTOM_CXXFLAGS?=-Wall -ggdb3 -O3 ### CONFIGURATION END @@ -72,6 +80,16 @@ else endif endif +ifdef CAFFE_LIB + SYS_LDFLAGS+=-L$(CAFFE_LIB) +endif + +ifdef DCNN + CUSTOM_CFLAGS+=-DDCNN + CUSTOM_CXXFLAGS+=-DDCNN + SYS_LIBS:=-lcaffe -lboost_system -lstdc++ $(SYS_LIBS) +endif + ifdef DOUBLE CUSTOM_CFLAGS+=-DDOUBLE endif @@ -105,6 +123,9 @@ INCLUDES=-I. OBJS=board.o gtp.o move.o ownermap.o pattern3.o pattern.o patternsp.o patternprob.o playout.o probdist.o random.o stone.o timeinfo.o network.o fbook.o chat.o +ifdef DCNN + OBJS+=dcnn.o +endif SUBDIRS=random replay patternscan patternplay joseki montecarlo uct uct/policy playout tactics t-unit distributed all: all-recursive pachi diff --git a/board.h b/board.h index e6363d2..faec55d 100644 --- a/board.h +++ b/board.h @@ -269,9 +269,11 @@ struct board { /* Avoid unused variable warnings */ #define board_size(b_) (((b_) == (b_)) ? BOARD_SIZE + 2 : 0) #define board_size2(b_) (board_size(b_) * board_size(b_)) +#define real_board_size(b_) (((b_) == (b_)) ? BOARD_SIZE : 0) #else #define board_size(b_) ((b_)->size) #define board_size2(b_) ((b_)->size2) +#define real_board_size(b_) ((b_)->size - 2) #endif /* This is a shortcut for taking different action on smaller diff --git a/dcnn.cpp b/dcnn.cpp new file mode 100644 index 0000000..56b36c5 --- /dev/null +++ b/dcnn.cpp @@ -0,0 +1,112 @@ +#define DEBUG +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CPU_ONLY 1 +#include +using namespace caffe; + +extern "C" { +#include "debug.h" +#include "board.h" +#include "dcnn.h" + + +static shared_ptr > net; + +bool +using_dcnn(struct board *b) +{ + return (real_board_size(b) == 19 && net); +} + +/* Make caffe quiet */ +void +dcnn_quiet_caffe(int argc, char *argv[]) +{ + if (DEBUGL(7) || getenv("GLOG_minloglevel")) + return; + + setenv("GLOG_minloglevel", "2", 1); + execvp(argv[0], argv); /* Sucks that we have to do this */ +} + +void +dcnn_init() +{ + if (net) + return; + + struct stat s; + const char *model_file = "movepredict.prototxt"; + const char *trained_file = "movepredict.caffemodel"; + if (stat(model_file, &s) != 0 || stat(trained_file, &s) != 0) { + if (DEBUGL(1)) + fprintf(stderr, "No dcnn files found, will not use dcnn code.\n"); + return; + } + + Caffe::set_mode(Caffe::CPU); + + /* Load the network. */ + net.reset(new Net(model_file, TEST)); + net->CopyTrainedLayersFrom(trained_file); + + if (DEBUGL(1)) + fprintf(stderr, "Initialized dcnn.\n"); +} + +void +dcnn_get_moves(struct board *b, enum stone color, float result[]) +{ + assert(real_board_size(b) == 19); + int size = 19; + float *data = new float[2 * size * size]; + + if (color == S_BLACK) + for (int j = 0; j < size; j++) + for (int k = 0; k < size; k++) { + coord_t c = coord_xy(b, j + 1, k + 1); + int offsetb = j * size + k; + int offsetw = size * size + size * j + k; + data[offsetb] = (board_at(b, c) == S_BLACK ? 1.0 : 0.0); + data[offsetw] = (board_at(b, c) == S_WHITE ? 1.0 : 0.0); + } + + if (color == S_WHITE) { + for (int j = 0; j < size; j++) + for (int k = 0; k < size; k++) { + coord_t c = coord_xy(b, j + 1, k + 1); + int offsetb = j * size + k; + int offsetw = size * size + size * j + k; + data[offsetb] = (board_at(b, c) == S_WHITE ? 1.0 : 0.0); + data[offsetw] = (board_at(b, c) == S_BLACK ? 1.0 : 0.0); + } + } + + Blob *blob = new Blob(1,2,size,size); + blob->set_cpu_data(data); + vector*> bottom; + bottom.push_back(blob); + assert(net); + const vector*>& rr = net->Forward(bottom); + + for (int i = 0; i < size * size; i++) { + result[i] = rr[0]->cpu_data()[i]; + if (result[i] < 0.00001) + result[i] = 0.00001; + } + delete[] data; + delete blob; +} + + +} /* extern "C" */ + diff --git a/dcnn.h b/dcnn.h new file mode 100644 index 0000000..7a1170c --- /dev/null +++ b/dcnn.h @@ -0,0 +1,30 @@ + +#ifndef PACHI_DCNN_H +#define PACHI_DCNN_H + +#ifdef __cplusplus +extern "C" { +#endif + + +#ifdef DCNN + +void dcnn_get_moves(struct board *b, enum stone color, float result[]); +bool using_dcnn(struct board *b); +void dcnn_quiet_caffe(int argc, char *argv[]); +void dcnn_init(); + +#else + +#define using_dcnn(b) 0 +#define dcnn_quiet_caffe(argc, argv) +#define dcnn_init() + +#endif + + +#ifdef __cplusplus +} +#endif + +#endif /* PACHI_DCNN_H */ diff --git a/pachi.c b/pachi.c index 3bc8993..334aaee 100644 --- a/pachi.c +++ b/pachi.c @@ -25,6 +25,7 @@ #include "random.h" #include "version.h" #include "network.h" +#include "dcnn.h" int debug_level = 3; bool debug_boardprint = true; @@ -167,6 +168,7 @@ int main(int argc, char *argv[]) } } + dcnn_quiet_caffe(argc, argv); if (log_port) open_log_port(log_port); diff --git a/uct/uct.c b/uct/uct.c index fc42a9a..f2a0e49 100644 --- a/uct/uct.c +++ b/uct/uct.c @@ -13,6 +13,7 @@ #include "chat.h" #include "move.h" #include "mq.h" +#include "dcnn.h" #include "joseki/base.h" #include "playout.h" #include "playout/moggy.h" @@ -1277,6 +1278,7 @@ uct_state_init(char *arg, struct board *b) if (u->want_pat && !pat_setup) patterns_init(&u->pat, NULL, false, true); + dcnn_init(); u->ownermap.map = malloc2(board_size2(b) * sizeof(u->ownermap.map[0])); -- 2.11.4.GIT