egbbdll is very easy to use because it was designed for probing endgame bitbases originally.
You could essentially do probe(FEN_string) and get value and policy results.
How and where it is evaluated the user doesn't need to know, but ofcourse it can use both CPU/GPU.
Both Tensorflow & TensoRT are supported which can use cuDNN so ofcourse it can use CUDA too.
Lc0 explicitly wrote cuda code for the backend but I am getting equal nps using TenorRT.
Moreover, one can use INT8 and maybe INT4. So writing backend code when there is a flora of deep learning
libraries is a futile endevour IMHO.
This is the actual code I use for probing bitbases and neural network. It has become a little cumbersome
after I added policy head but still easy to use. You populate your pieces, and feed history info (for lczero nets)
and just probe. The egbbdll takes care of "batching" with multi-thread approach, and caching as well.
Code: Select all
/*
Probe:
Change interanal scorpio board representaion to [A1 = 0 ... H8 = 63]
board representation and then probe bitbase.
*/
void SEARCHER::fill_list(int& count, int* piece, int* square) {
PLIST current;
#define ADD_PIECE(list,type) { \
current = list; \
while(current) { \
piece[count] = type; \
square[count] = SQ8864(current->sq); \
count++; \
current = current->next; \
} \
};
ADD_PIECE(plist[wking],_WKING);
ADD_PIECE(plist[bking],_BKING);
ADD_PIECE(plist[wqueen],_WQUEEN);
ADD_PIECE(plist[bqueen],_BQUEEN);
ADD_PIECE(plist[wrook],_WROOK);
ADD_PIECE(plist[brook],_BROOK);
ADD_PIECE(plist[wbishop],_WBISHOP);
ADD_PIECE(plist[bbishop],_BBISHOP);
ADD_PIECE(plist[wknight],_WKNIGHT);
ADD_PIECE(plist[bknight],_BKNIGHT);
ADD_PIECE(plist[wpawn],_WPAWN);
ADD_PIECE(plist[bpawn],_BPAWN);
piece[count] = _EMPTY;
square[count] = SQ8864(epsquare);
count++;
}
int SEARCHER::probe_bitbases(int& score) {
#ifdef EGBB
int piece[MAX_PIECES],square[MAX_PIECES],count = 0;
fill_list(count,piece,square);
score = probe_egbb(player,piece,square);
if(score != _NOTFOUND)
return true;
#endif
return false;
}
int SEARCHER::probe_neural(bool hard_probe) {
#ifdef EGBB
UBMP64 hkey = ((player == white) ? hash_key :
(hash_key ^ UINT64(0x2bc3964f82352234)));
int moves[3*MAX_MOVES];
int *s = moves;
for(int i = 0; i < pstack->count; i++) {
MOVE& m = pstack->move_st[i];
int from = m_from(m), to = m_to(m);
if(is_castle(m)) {
if(to > from) to++;
else to -= 2;
}
*s++ = SQ8864(from);
*s++ = SQ8864(to);
*s++ = m_promote(m);
}
*s++ = -1;
nnecalls++;
if(nn_type == 0) {
int piece[33],square[33],isdraw[1];
int count = 0, hist = 1;
fill_list(count,piece,square);
return probe_nn(player,castle,fifty,hist,isdraw,piece,square,moves,
(float*)pstack->score_st,pstack->count,hkey,hard_probe);
} else {
int piece[8*33],square[8*33],isdraw[8];
int count = 0, hist = 0, phply = hply;
for(int i = 0; i < 8; i++) {
isdraw[hist++] = draw();
fill_list(count,piece,square);
if(hply > 0 && hstack[hply - 1].move)
POP_MOVE();
else break;
}
count = phply - hply;
for(int i = 0; i < count; i++)
PUSH_MOVE(hstack[hply].move);
if(isdraw[0])
hkey ^= UINT64(0xc7e9153edee38dcb);
hkey ^= fifty_hkey[fifty];
return probe_nn(player,castle,fifty,hist,isdraw,piece,square,moves,
(float*)pstack->score_st,pstack->count,hkey,hard_probe);
}
#endif
return 0;
}
void PROCESSOR::set_num_searchers() {
#ifdef EGBB
if(SEARCHER::use_nn && set_num_active_searchers) {
int n_searchers = n_processors - n_idle_processors;
set_num_active_searchers(n_searchers);
}
#endif
}
Daniel