Skip to content

Commit

Permalink
HalfKP-KSDG_512x2-8-96.20240706
Browse files Browse the repository at this point in the history
  • Loading branch information
tttak committed Jul 6, 2024
1 parent 1f25a5c commit fb214f7
Show file tree
Hide file tree
Showing 7 changed files with 393 additions and 4 deletions.
5 changes: 3 additions & 2 deletions source/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@
# ビルドを確認したDocker image → nvcr.io/nvidia/tensorrt:22.12-py3


YANEURAOU_EDITION = YANEURAOU_ENGINE_NNUE
#YANEURAOU_EDITION = YANEURAOU_ENGINE_NNUE
#YANEURAOU_EDITION = YANEURAOU_ENGINE_NNUE_KP256
#YANEURAOU_EDITION = YANEURAOU_ENGINE_NNUE_HALFKPE9
YANEURAOU_EDITION = YANEURAOU_ENGINE_NNUE_HALFKPE9
#YANEURAOU_EDITION = YANEURAOU_ENGINE_NNUE_HALFKP_512X2_16_32
#YANEURAOU_EDITION = YANEURAOU_ENGINE_NNUE_HALFKP_1024X2_8_32
#YANEURAOU_EDITION = YANEURAOU_ENGINE_NNUE_HALFKP_1024X2_8_64
Expand Down Expand Up @@ -501,6 +501,7 @@ ifneq (,$(findstring YANEURAOU_ENGINE_NNUE,$(YANEURAOU_EDITION)))
eval/nnue/features/half_relative_kp.cpp \
eval/nnue/features/half_kpe9.cpp \
eval/nnue/features/pe9.cpp \
eval/nnue/features/king_safety_distinguishgolds.cpp \
engine/yaneuraou-engine/yaneuraou-search.cpp

ifneq (,$(findstring em++,$(COMPILER)))
Expand Down
2 changes: 1 addition & 1 deletion source/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@
// 評価関数で金と小駒の成りを区別する
// 駒の特徴量はBonaPiece。これはBonanzaに倣っている。
// このオプションを有効化すると、金と小駒の成りを区別する。(Bonanzaとは異なる特徴量になる)
// #define DISTINGUISH_GOLDS
#define DISTINGUISH_GOLDS

// エンジンオプションをコンパイル時に指定したい時に用いる。
// ";"で区切って複数指定できる。
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// NNUE評価関数で用いる入力特徴量とネットワーク構造の定義

#include "../features/feature_set.h"
#include "../features/half_kp.h"
#include "../features/king_safety_distinguishgolds.h"

#include "../layers/input_slice.h"
#include "../layers/affine_transform.h"
#include "../layers/clipped_relu.h"

namespace Eval {

namespace NNUE {

// 評価関数で用いる入力特徴量
using RawFeatures = Features::FeatureSet<
Features::HalfKP<Features::Side::kFriend>, Features::KingSafety_DistinguishGolds<Features::Side::kFriend>>;

// 変換後の入力特徴量の次元数
constexpr IndexType kTransformedFeatureDimensions = 512;

namespace Layers {

// ネットワーク構造の定義
using InputLayer = InputSlice<kTransformedFeatureDimensions * 2>;
using HiddenLayer1 = ClippedReLU<AffineTransform<InputLayer, 8>>;
using HiddenLayer2 = ClippedReLU<AffineTransform<HiddenLayer1, 96>>;
using OutputLayer = AffineTransform<HiddenLayer2, 1>;

} // namespace Layers

using Network = Layers::OutputLayer;

} // namespace NNUE

} // namespace Eval
257 changes: 257 additions & 0 deletions source/eval/nnue/features/king_safety_distinguishgolds.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,257 @@
// NNUE評価関数の入力特徴量KingSafety_DistinguishGoldsの定義

#include "../../../config.h"

#if defined(EVAL_NNUE) && defined(LONG_EFFECT_LIBRARY) && defined(USE_BOARD_EFFECT_PREV) && defined(DISTINGUISH_GOLDS)

#include "king_safety_distinguishgolds.h"
#include "index_list.h"

namespace Eval {

namespace NNUE {

namespace Features {

// 盤上の駒のBonaPieceからPieceへの変換配列
Piece sqBonaPieceToPiece[] = {B_PAWN, W_PAWN, B_LANCE, W_LANCE, B_KNIGHT, W_KNIGHT, B_SILVER, W_SILVER, B_GOLD, W_GOLD
, B_BISHOP, W_BISHOP, B_HORSE, W_HORSE, B_ROOK, W_ROOK, B_DRAGON, W_DRAGON
, B_PRO_PAWN, W_PRO_PAWN, B_PRO_LANCE, W_PRO_LANCE, B_PRO_KNIGHT, W_PRO_KNIGHT, B_PRO_SILVER, W_PRO_SILVER
, B_KING, W_KING };

// BonaPieceからSquareとPieceを取得する
// ・持ち駒の場合は「SQ_NB、NO_PIECE」を返す。本来は持ち駒のPieceを正確に算出することもできるが、この評価関数では不要なので。
template <Side AssociatedKing>
inline void KingSafety_DistinguishGolds<AssociatedKing>::GetSquarePieceFromBonaPiece(BonaPiece bp, Square &sq, Piece &pc) {
// 持ち駒の場合
if (bp < fe_hand_end) {
sq = SQ_NB;
pc = NO_PIECE;
}
// 盤上の駒の場合
else {
sq = static_cast<Square>((bp - fe_hand_end) % SQ_NB);
pc = sqBonaPieceToPiece[(bp - fe_hand_end) / SQ_NB];
}
}

// Squareのdirty判定
template <Side AssociatedKing>
inline bool KingSafety_DistinguishGolds<AssociatedKing>::IsDirty(Square dirty_sq24[], int dirty_sq24_count, Square sq) {
for (int i = 0; i < dirty_sq24_count; ++i) {
if (dirty_sq24[i] == sq) {
return true;
}
}
return false;
}

// Effect24::Directの算出
template <Side AssociatedKing>
inline Effect24::Direct KingSafety_DistinguishGolds<AssociatedKing>::CalcDirect(Square sq_king, Square sq) {
int file_diff = file_of(sq) - file_of(sq_king);
int rank_diff = rank_of(sq) - rank_of(sq_king);
int calc = file_diff * 5 + rank_diff + 12;

return Effect24::Direct(calc < 12 ? calc : calc - 1);
}

// 利き数の取得
template <Side AssociatedKing>
inline int KingSafety_DistinguishGolds<AssociatedKing>::GetEffectCount(const Position& pos, Square sq, Color perspective, bool prev_effect) {
if (sq == SQ_NB) {
return 0;
}
else {
if (prev_effect) {
return std::min(int(pos.board_effect_prev[perspective].effect(sq)), 3);
}
else {
return std::min(int(pos.board_effect[perspective].effect(sq)), 3);
}
}
}

// Pieceの先後反転
template <Side AssociatedKing>
inline Piece KingSafety_DistinguishGolds<AssociatedKing>::Inv(Piece pc) {
if (pc == NO_PIECE) {
return NO_PIECE;
}
else if (pc == PIECE_WALL) {
return PIECE_WALL;
}
else {
return make_piece(~color_of(pc), type_of(pc));
}
}

// Effect24::Directの先後反転
template <Side AssociatedKing>
inline Effect24::Direct KingSafety_DistinguishGolds<AssociatedKing>::Inv(Effect24::Direct dir) {
return Effect24::DIRECT_NB - static_cast<Effect24::Direct>(1) - dir;
}

// 特徴量のインデックスを求める
template <Side AssociatedKing>
inline IndexType KingSafety_DistinguishGolds<AssociatedKing>::MakeIndex(Color perspective, Effect24::Direct dir, Piece pc, int effect1, int effect2) {
if (perspective == WHITE) {
pc = Inv(pc);
dir = Inv(dir);
}

return ((static_cast<IndexType>(dir)
* static_cast<IndexType>(PIECE_WALL_NB) + static_cast<IndexType>(pc))
* 4 + effect1)
* 4 + effect2;
}

// 特徴量のうち、値が1であるインデックスのリストを取得する
template <Side AssociatedKing>
void KingSafety_DistinguishGolds<AssociatedKing>::AppendActiveIndices(
const Position& pos, Color perspective, IndexList* active) {
// コンパイラの警告を回避するため、配列サイズが小さい場合は何もしない
if (RawFeatures::kMaxActiveDimensions < kMaxActiveDimensions) return;

// perspective側の玉のマス(先手目線)
SquareWithWall sqww_king = to_sqww(pos.king_square(perspective));

// 24近傍をループ
for (Effect24::Direct dir : Effect24::Direct()) {
SquareWithWall sqww = sqww_king + DirectToDeltaWW(dir);

// 盤内の場合
if (is_ok(sqww)) {
Square sq = sqww_to_sq(sqww);
active->push_back(MakeIndex(perspective, dir, pos.piece_on(sq)
, GetEffectCount(pos, sq, perspective, false)
, GetEffectCount(pos, sq, ~perspective, false)
));
}

// 盤外の場合
else {
active->push_back(MakeIndex(perspective, dir, PIECE_WALL, 0, 0));
}
}
}

// 特徴量のうち、一手前から値が変化したインデックスのリストを取得する
template <Side AssociatedKing>
void KingSafety_DistinguishGolds<AssociatedKing>::AppendChangedIndices(
const Position& pos, Color perspective,
IndexList* removed, IndexList* added) {

// perspective側の玉のマス(先手目線)
Square sq_king = pos.king_square(perspective);
SquareWithWall sqww_king = to_sqww(sq_king);

// pieces(先手目線)
BonaPiece* pieces = pos.eval_list()->piece_list_fb();
const auto& dp = pos.state()->dirtyPiece;

// 玉の24近傍でdirtyなマス
Square dirty_sq24[4] = {SQ_NB, SQ_NB, SQ_NB, SQ_NB};
int dirty_sq24_count = 0;

for (int i = 0; i < dp.dirty_num; ++i) {
// old_piece(先手目線)
const auto old_piece = static_cast<BonaPiece>(dp.changed_piece[i].old_piece.from[BLACK]);
Square old_sq;
Piece old_pc;
GetSquarePieceFromBonaPiece(old_piece, old_sq, old_pc);

// old_pieceのマスが玉の24近傍の場合
if (old_sq != SQ_NB && dist(sq_king, old_sq) <= 2) {
dirty_sq24[dirty_sq24_count] = old_sq;
++dirty_sq24_count;

Effect24::Direct dir = CalcDirect(sq_king, old_sq);

removed->push_back(MakeIndex(perspective, dir, old_pc
, GetEffectCount(pos, old_sq, perspective, true)
, GetEffectCount(pos, old_sq, ~perspective, true)
));

// iが0以外の場合(iが1の場合)は取られた駒なので除外
if (i == 0) {
added->push_back(MakeIndex(perspective, dir, NO_PIECE
, GetEffectCount(pos, old_sq, perspective, false)
, GetEffectCount(pos, old_sq, ~perspective, false)
));
}
}

// new_piece(先手目線)
const auto new_piece = static_cast<BonaPiece>(dp.changed_piece[i].new_piece.from[BLACK]);
Square new_sq;
Piece new_pc;
GetSquarePieceFromBonaPiece(new_piece, new_sq, new_pc);

// new_pieceのマスが玉の24近傍の場合
if (new_sq != SQ_NB && dist(sq_king, new_sq) <= 2) {
dirty_sq24[dirty_sq24_count] = new_sq;
++dirty_sq24_count;

Effect24::Direct dir = CalcDirect(sq_king, new_sq);

// 「dp.dirty_num == 2 && i == 0)」の場合は除外
if ( (dp.dirty_num == 1 && i == 0)
|| (dp.dirty_num == 2 && i == 1)) {
removed->push_back(MakeIndex(perspective, dir, NO_PIECE
, GetEffectCount(pos, new_sq, perspective, true)
, GetEffectCount(pos, new_sq, ~perspective, true)
));
}

added->push_back(MakeIndex(perspective, dir, new_pc
, GetEffectCount(pos, new_sq, perspective, false)
, GetEffectCount(pos, new_sq, ~perspective, false)
));
}
}

// 24近傍をループ
for (Effect24::Direct dir : Effect24::Direct()) {
SquareWithWall sqww = sqww_king + DirectToDeltaWW(dir);

// 盤内の場合
if (is_ok(sqww)) {
Square sq = sqww_to_sq(sqww);

// dirtyな場合は既に処理済み
if (IsDirty(dirty_sq24, dirty_sq24_count, sq)) {
continue;
}

int effectCount_prev_1 = GetEffectCount(pos, sq, perspective, true);
int effectCount_prev_2 = GetEffectCount(pos, sq, ~perspective, true);
int effectCount_now_1 = GetEffectCount(pos, sq, perspective, false);
int effectCount_now_2 = GetEffectCount(pos, sq, ~perspective, false);

// 利き数に変化があった場合
if ( effectCount_prev_1 != effectCount_now_1
|| effectCount_prev_2 != effectCount_now_2) {
Piece pc = pos.piece_on(sq);
removed->push_back(MakeIndex(perspective, dir, pc, effectCount_prev_1, effectCount_prev_2));
added->push_back(MakeIndex(perspective, dir, pc, effectCount_now_1, effectCount_now_2));
}
}

// 盤外の場合
else {
// 何もしない
}
}
}

template class KingSafety_DistinguishGolds<Side::kFriend>;
template class KingSafety_DistinguishGolds<Side::kEnemy>;

} // namespace Features

} // namespace NNUE

} // namespace Eval

#endif // defined(EVAL_NNUE)
Loading

0 comments on commit fb214f7

Please sign in to comment.