Skip to content

Commit

Permalink
NNUE-HalfKPE9
Browse files Browse the repository at this point in the history
  • Loading branch information
tttak committed Mar 25, 2020
1 parent 30f102d commit d7a58b4
Show file tree
Hide file tree
Showing 15 changed files with 635 additions and 4 deletions.
2 changes: 2 additions & 0 deletions source/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,8 @@ ifeq ($(findstring YANEURAOU_ENGINE_NNUE,$(YANEURAOU_EDITION)),YANEURAOU_ENGINE_
eval/nnue/features/p.cpp \
eval/nnue/features/half_kp.cpp \
eval/nnue/features/half_relative_kp.cpp \
eval/nnue/features/half_kpe9.cpp \
eval/nnue/features/pe9.cpp \
engine/yaneuraou-engine/yaneuraou-search.cpp
endif

Expand Down
6 changes: 6 additions & 0 deletions source/YaneuraOu.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -395,17 +395,20 @@
<ClInclude Include="eval\evaluate_mir_inv_tools.h" />
<ClInclude Include="eval\kppt\evaluate_kppt.h" />
<ClInclude Include="eval\kpp_kkpt\evaluate_kpp_kkpt.h" />
<ClInclude Include="eval\nnue\architectures\halfkpe9_256x2-32-32.h" />
<ClInclude Include="eval\nnue\architectures\halfkp_256x2-32-32.h" />
<ClInclude Include="eval\nnue\architectures\k-p_256x2-32-32.h" />
<ClInclude Include="eval\nnue\evaluate_nnue.h" />
<ClInclude Include="eval\nnue\evaluate_nnue_learner.h" />
<ClInclude Include="eval\nnue\features\features_common.h" />
<ClInclude Include="eval\nnue\features\feature_set.h" />
<ClInclude Include="eval\nnue\features\half_kp.h" />
<ClInclude Include="eval\nnue\features\half_kpe9.h" />
<ClInclude Include="eval\nnue\features\half_relative_kp.h" />
<ClInclude Include="eval\nnue\features\index_list.h" />
<ClInclude Include="eval\nnue\features\k.h" />
<ClInclude Include="eval\nnue\features\p.h" />
<ClInclude Include="eval\nnue\features\pe9.h" />
<ClInclude Include="eval\nnue\layers\affine_transform.h" />
<ClInclude Include="eval\nnue\layers\clipped_relu.h" />
<ClInclude Include="eval\nnue\layers\input_slice.h" />
Expand All @@ -418,6 +421,7 @@
<ClInclude Include="eval\nnue\trainer\features\factorizer.h" />
<ClInclude Include="eval\nnue\trainer\features\factorizer_feature_set.h" />
<ClInclude Include="eval\nnue\trainer\features\factorizer_half_kp.h" />
<ClInclude Include="eval\nnue\trainer\features\factorizer_half_kpe9.h" />
<ClInclude Include="eval\nnue\trainer\trainer.h" />
<ClInclude Include="eval\nnue\trainer\trainer_affine_transform.h" />
<ClInclude Include="eval\nnue\trainer\trainer_clipped_relu.h" />
Expand Down Expand Up @@ -465,9 +469,11 @@
<ClCompile Include="eval\nnue\evaluate_nnue.cpp" />
<ClCompile Include="eval\nnue\evaluate_nnue_learner.cpp" />
<ClCompile Include="eval\nnue\features\half_kp.cpp" />
<ClCompile Include="eval\nnue\features\half_kpe9.cpp" />
<ClCompile Include="eval\nnue\features\half_relative_kp.cpp" />
<ClCompile Include="eval\nnue\features\k.cpp" />
<ClCompile Include="eval\nnue\features\p.cpp" />
<ClCompile Include="eval\nnue\features\pe9.cpp" />
<ClCompile Include="eval\nnue\nnue_test_command.cpp" />
<ClCompile Include="extra\benchmark.cpp" />
<ClCompile Include="extra\bitop.cpp" />
Expand Down
18 changes: 18 additions & 0 deletions source/YaneuraOu.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,18 @@
<ClInclude Include="eval\evalhash.h">
<Filter>リソース ファイル\eval</Filter>
</ClInclude>
<ClInclude Include="eval\nnue\features\half_kpe9.h">
<Filter>リソース ファイル\eval\nnue\features</Filter>
</ClInclude>
<ClInclude Include="eval\nnue\architectures\halfkpe9_256x2-32-32.h">
<Filter>リソース ファイル\eval\nnue\architectures</Filter>
</ClInclude>
<ClInclude Include="eval\nnue\trainer\features\factorizer_half_kpe9.h">
<Filter>リソース ファイル\eval\nnue\trainer\features</Filter>
</ClInclude>
<ClInclude Include="eval\nnue\features\pe9.h">
<Filter>リソース ファイル\eval\nnue\features</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="movegen.cpp">
Expand Down Expand Up @@ -404,6 +416,12 @@
<ClCompile Include="engine\yaneuraou-engine\yaneuraou-search.cpp">
<Filter>リソース ファイル\engine\yaneuraou-engine</Filter>
</ClCompile>
<ClCompile Include="eval\nnue\features\half_kpe9.cpp">
<Filter>リソース ファイル\eval\nnue\features</Filter>
</ClCompile>
<ClCompile Include="eval\nnue\features\pe9.cpp">
<Filter>リソース ファイル\eval\nnue\features</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Text Include="..\docs\USI拡張コマンド.txt">
Expand Down
4 changes: 3 additions & 1 deletion source/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,9 @@

// パラメーターの自動調整絡み
#define USE_GAMEOVER_HANDLER
//#define LONG_EFFECT_LIBRARY

// NNUE-HalfKPE9
#define LONG_EFFECT_LIBRARY

// GlobalOptionsは有効にしておく。
#define USE_GLOBAL_OPTIONS
Expand Down
35 changes: 35 additions & 0 deletions source/eval/nnue/architectures/halfkpe9_256x2-32-32.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// NNUE評価関数で用いる入力特徴量とネットワーク構造の定義

#include "../features/feature_set.h"
#include "../features/half_kpe9.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::HalfKPE9<Features::Side::kFriend>>;

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

namespace Layers {

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

} // namespace Layers

using Network = Layers::OutputLayer;

} // namespace NNUE

} // namespace Eval
5 changes: 4 additions & 1 deletion source/eval/nnue/evaluate_nnue_learner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,16 @@
#include "evaluate_nnue.h"
#include "evaluate_nnue_learner.h"
#include "trainer/features/factorizer_feature_set.h"
#include "trainer/features/factorizer_half_kp.h"
//#include "trainer/features/factorizer_half_kp.h"
#include "trainer/trainer_feature_transformer.h"
#include "trainer/trainer_input_slice.h"
#include "trainer/trainer_affine_transform.h"
#include "trainer/trainer_clipped_relu.h"
#include "trainer/trainer_sum.h"

// NNUE-HalfKPE9
#include "trainer/features/factorizer_half_kpe9.h"

namespace Eval {

namespace NNUE {
Expand Down
154 changes: 154 additions & 0 deletions source/eval/nnue/features/half_kpe9.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
// NNUE評価関数の入力特徴量HalfKPE9の定義

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

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

#include "half_kpe9.h"
#include "index_list.h"

namespace Eval {

namespace NNUE {

namespace Features {

inline Square GetSquareFromBonaPiece(BonaPiece p) {
if (p < fe_hand_end) {
return SQ_NB;
}
else {
return static_cast<Square>((p - fe_hand_end) % SQ_NB);
}
}

inline int GetEffectCount(const Position& pos, Square sq_p, Color perspective_org, Color perspective, bool prev_effect) {
if (sq_p == SQ_NB) {
return 0;
}
else {
if (perspective_org == WHITE) {
sq_p = Inv(sq_p);
}

if (prev_effect) {
return std::min(int(pos.board_effect_prev[perspective].effect(sq_p)), 2);
}
else {
return std::min(int(pos.board_effect[perspective].effect(sq_p)), 2);
}
}
}

inline bool IsDirty(const Eval::DirtyPiece& dp, PieceNumber pn) {
for (int i = 0; i < dp.dirty_num; ++i) {
if (pn == dp.pieceNo[i]) {
return true;
}
}
return false;
}

// 玉の位置とBonaPieceと利き数から特徴量のインデックスを求める
template <Side AssociatedKing>
inline IndexType HalfKPE9<AssociatedKing>::MakeIndex(Square sq_k, BonaPiece p, int effect1, int effect2) {
return (static_cast<IndexType>(fe_end) * static_cast<IndexType>(sq_k) + p)
+ (static_cast<IndexType>(fe_end) * static_cast<IndexType>(SQ_NB) * (effect1 * 3 + effect2));
}

// 駒の情報を取得する
template <Side AssociatedKing>
inline void HalfKPE9<AssociatedKing>::GetPieces(
const Position& pos, Color perspective,
BonaPiece** pieces, Square* sq_target_k) {
*pieces = (perspective == BLACK) ?
pos.eval_list()->piece_list_fb() :
pos.eval_list()->piece_list_fw();
const PieceNumber target = (AssociatedKing == Side::kFriend) ?
static_cast<PieceNumber>(PIECE_NUMBER_KING + perspective) :
static_cast<PieceNumber>(PIECE_NUMBER_KING + ~perspective);
*sq_target_k = static_cast<Square>(((*pieces)[target] - f_king) % SQ_NB);
}

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

BonaPiece* pieces;
Square sq_target_k;
GetPieces(pos, perspective, &pieces, &sq_target_k);
auto& board_effect = pos.board_effect;

for (PieceNumber i = PIECE_NUMBER_ZERO; i < PIECE_NUMBER_KING; ++i) {
BonaPiece p = pieces[i];
Square sq_p = GetSquareFromBonaPiece(p);

active->push_back(MakeIndex(sq_target_k, p
, GetEffectCount(pos, sq_p, perspective, perspective, false)
, GetEffectCount(pos, sq_p, perspective, ~perspective, false)
));
}
}

// 特徴量のうち、一手前から値が変化したインデックスのリストを取得する
template <Side AssociatedKing>
void HalfKPE9<AssociatedKing>::AppendChangedIndices(
const Position& pos, Color perspective,
IndexList* removed, IndexList* added) {
BonaPiece* pieces;
Square sq_target_k;
GetPieces(pos, perspective, &pieces, &sq_target_k);
const auto& dp = pos.state()->dirtyPiece;

for (int i = 0; i < dp.dirty_num; ++i) {
if (dp.pieceNo[i] >= PIECE_NUMBER_KING) continue;

const auto old_p = static_cast<BonaPiece>(dp.changed_piece[i].old_piece.from[perspective]);
Square old_sq_p = GetSquareFromBonaPiece(old_p);
removed->push_back(MakeIndex(sq_target_k, old_p
, GetEffectCount(pos, old_sq_p, perspective, perspective, true)
, GetEffectCount(pos, old_sq_p, perspective, ~perspective, true)
));

const auto new_p = static_cast<BonaPiece>(dp.changed_piece[i].new_piece.from[perspective]);
Square new_sq_p = GetSquareFromBonaPiece(new_p);
added->push_back(MakeIndex(sq_target_k, new_p
, GetEffectCount(pos, new_sq_p, perspective, perspective, false)
, GetEffectCount(pos, new_sq_p, perspective, ~perspective, false)
));
}

for (PieceNumber i = PIECE_NUMBER_ZERO; i < PIECE_NUMBER_KING; ++i) {
if (IsDirty(dp, i)) {
continue;
}

BonaPiece p = pieces[i];
Square sq_p = GetSquareFromBonaPiece(p);

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

if ( effectCount_prev_1 != effectCount_now_1
|| effectCount_prev_2 != effectCount_now_2) {
removed->push_back(MakeIndex(sq_target_k, p, effectCount_prev_1, effectCount_prev_2));
added->push_back(MakeIndex(sq_target_k, p, effectCount_now_1, effectCount_now_2));
}
}
}

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

} // namespace Features

} // namespace NNUE

} // namespace Eval

#endif // defined(EVAL_NNUE)
66 changes: 66 additions & 0 deletions source/eval/nnue/features/half_kpe9.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// NNUE評価関数の入力特徴量HalfKPE9の定義

#ifndef _NNUE_FEATURES_HALF_KPE9_H_
#define _NNUE_FEATURES_HALF_KPE9_H_

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

#if defined(EVAL_NNUE)

#include "../../../evaluate.h"
#include "features_common.h"

namespace Eval {

namespace NNUE {

namespace Features {

// 特徴量HalfKPE9:自玉または敵玉の位置と、玉以外の駒の位置と、利き数の組み合わせ
// ・利き数は先後各々最大2までに制限。0~2で3通り。先後で3*3=9通り。なお、持ち駒の場合は利き数0とする。
template <Side AssociatedKing>
class HalfKPE9 {
public:
// 特徴量名
static constexpr const char* kName =
(AssociatedKing == Side::kFriend) ? "HalfKPE9(Friend)" : "HalfKPE9(Enemy)";
// 評価関数ファイルに埋め込むハッシュ値
static constexpr std::uint32_t kHashValue =
0x5D69D5B9u ^ (AssociatedKing == Side::kFriend);
// 特徴量の次元数
static constexpr IndexType kDimensions =
static_cast<IndexType>(SQ_NB) * static_cast<IndexType>(fe_end) * 3 * 3;
// 特徴量のうち、同時に値が1となるインデックスの数の最大値
static constexpr IndexType kMaxActiveDimensions = PIECE_NUMBER_KING;

// 差分計算の代わりに全計算を行うタイミング
static constexpr TriggerEvent kRefreshTrigger =
(AssociatedKing == Side::kFriend) ?
TriggerEvent::kFriendKingMoved : TriggerEvent::kEnemyKingMoved;

// 特徴量のうち、値が1であるインデックスのリストを取得する
static void AppendActiveIndices(const Position& pos, Color perspective,
IndexList* active);

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

// 玉の位置とBonaPieceと利き数から特徴量のインデックスを求める
static IndexType MakeIndex(Square sq_k, BonaPiece p, int effect1, int effect2);

private:
// 駒の情報を取得する
static void GetPieces(const Position& pos, Color perspective,
BonaPiece** pieces, Square* sq_target_k);
};

} // namespace Features

} // namespace NNUE

} // namespace Eval

#endif // defined(EVAL_NNUE)

#endif
Loading

0 comments on commit d7a58b4

Please sign in to comment.