mirror of
https://github.com/official-stockfish/Stockfish.git
synced 2026-07-22 20:57:10 +00:00
Remove small net
Failed VVLTC non-regression https://tests.stockfishchess.org/tests/view/69d562b84088e069540a2288 LLR: -2.96 (-2.94,2.94) <-1.75,0.25> Total: 386998 W: 99181 L: 99760 D: 188057 Ptnml(0-2): 35, 35792, 122429, 35203, 40 Failed STC non-regression https://tests.stockfishchess.org/tests/view/69f3c6601e5788938e86a99e LLR: -2.93 (-2.94,2.94) <-1.75,0.25> Total: 33696 W: 8492 L: 8795 D: 16409 Ptnml(0-2): 124, 4209, 8504, 3868, 143 Many thanks to Dubslow, Torom, ces42, Shawn, vondele, Disservin and others for discussion. ## Summary The venerable small net has been around for quite some time now, and while the big net architecture has substantially advanced with TI, the small net has stayed with plain HalfKA. It therefore presents a few burdens: multiple net architectures to maintain, multiple nets to train, and a whole lot of templates to deal with the variable L1 size. Locally I measure a slowdown of -2.5% in NPS with this branch – and it's probably more on non-AVX512 architectures – but a pure slowdown of that magnitude would lead to more dramatic losses (even at VVLTC) than exhibited in the above tests, suggesting that the small net's lower eval quality is deleterious. Bonus: Shawn found this interesting PGN among the VVLTC games: https://lichess.org/study/hvo8jflc/OeTOityv `master` seems to misevaluate the fortress because all positions go to small net (the material difference is larger than the threshold). closes https://github.com/official-stockfish/Stockfish/pull/6796 Bench: 2877007
This commit is contained in:
committed by
Joost VandeVondele
parent
dc1686345c
commit
ab8f901d25
+36
-104
@@ -44,52 +44,21 @@
|
||||
// const unsigned int gEmbeddedNNUESize; // the size of the embedded file
|
||||
// Note that this does not work in Microsoft Visual Studio.
|
||||
#if !defined(UNIVERSAL_BINARY) && !defined(_MSC_VER) && !defined(NNUE_EMBEDDING_OFF)
|
||||
INCBIN(EmbeddedNNUEBig, EvalFileDefaultNameBig);
|
||||
INCBIN(EmbeddedNNUESmall, EvalFileDefaultNameSmall);
|
||||
INCBIN(EmbeddedNNUE, EvalFileDefaultName);
|
||||
#elif defined(UNIVERSAL_BINARY)
|
||||
// When building for the universal binary, use C++26 #embed with weak symbols so that a
|
||||
// separate, non-LTO nnue_embed.o (with strong symbols) can override them during the LTO link,
|
||||
// (INCBIN can't deduplicate.)
|
||||
#define WEAK_SYM __attribute__((weak))
|
||||
extern const unsigned char gEmbeddedNNUEBigData[] WEAK_SYM = {
|
||||
#embed EvalFileDefaultNameBig
|
||||
extern const unsigned char gEmbeddedNNUEData[] WEAK_SYM = {
|
||||
#embed EvalFileDefaultName
|
||||
};
|
||||
extern const unsigned int gEmbeddedNNUEBigSize WEAK_SYM = sizeof(gEmbeddedNNUEBigData);
|
||||
extern const unsigned char gEmbeddedNNUESmallData[] WEAK_SYM = {
|
||||
#embed EvalFileDefaultNameSmall
|
||||
};
|
||||
extern const unsigned int gEmbeddedNNUESmallSize WEAK_SYM = sizeof(gEmbeddedNNUESmallData);
|
||||
extern const unsigned int gEmbeddedNNUESize WEAK_SYM = sizeof(gEmbeddedNNUEData);
|
||||
#else
|
||||
const unsigned char gEmbeddedNNUEBigData[1] = {0x0};
|
||||
const unsigned int gEmbeddedNNUEBigSize = 1;
|
||||
const unsigned char gEmbeddedNNUESmallData[1] = {0x0};
|
||||
const unsigned int gEmbeddedNNUESmallSize = 1;
|
||||
const unsigned char gEmbeddedNNUEData[1] = {0x0};
|
||||
const unsigned int gEmbeddedNNUESize = 1;
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
struct EmbeddedNNUE {
|
||||
EmbeddedNNUE(const unsigned char* embeddedData, const unsigned int embeddedSize) :
|
||||
data(embeddedData),
|
||||
end(embeddedData + embeddedSize),
|
||||
size(embeddedSize) {}
|
||||
const unsigned char* data;
|
||||
const unsigned char* end;
|
||||
const unsigned int size;
|
||||
};
|
||||
|
||||
using namespace Stockfish::Eval::NNUE;
|
||||
|
||||
EmbeddedNNUE get_embedded(EmbeddedNNUEType type) {
|
||||
if (type == EmbeddedNNUEType::BIG)
|
||||
return EmbeddedNNUE(gEmbeddedNNUEBigData, gEmbeddedNNUEBigSize);
|
||||
else
|
||||
return EmbeddedNNUE(gEmbeddedNNUESmallData, gEmbeddedNNUESmallSize);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
namespace Stockfish::Eval::NNUE {
|
||||
|
||||
|
||||
@@ -116,8 +85,7 @@ bool write_parameters(std::ostream& stream, const T& reference) {
|
||||
|
||||
} // namespace Detail
|
||||
|
||||
template<typename Arch, typename Transformer>
|
||||
void Network<Arch, Transformer>::load(const std::string& rootDirectory, std::string evalfilePath) {
|
||||
void Network::load(const std::string& rootDirectory, std::string evalfilePath) {
|
||||
#if defined(DEFAULT_NNUE_DIRECTORY)
|
||||
std::vector<std::string> dirs = {"<internal>", "", rootDirectory,
|
||||
stringify(DEFAULT_NNUE_DIRECTORY)};
|
||||
@@ -146,8 +114,7 @@ void Network<Arch, Transformer>::load(const std::string& rootDirectory, std::str
|
||||
}
|
||||
|
||||
|
||||
template<typename Arch, typename Transformer>
|
||||
bool Network<Arch, Transformer>::save(const std::optional<std::string>& filename) const {
|
||||
bool Network::save(const std::optional<std::string>& filename) const {
|
||||
std::string actualFilename;
|
||||
std::string msg;
|
||||
|
||||
@@ -177,16 +144,13 @@ bool Network<Arch, Transformer>::save(const std::optional<std::string>& filename
|
||||
}
|
||||
|
||||
|
||||
template<typename Arch, typename Transformer>
|
||||
NetworkOutput
|
||||
Network<Arch, Transformer>::evaluate(const Position& pos,
|
||||
AccumulatorStack& accumulatorStack,
|
||||
AccumulatorCaches::Cache<FTDimensions>& cache) const {
|
||||
NetworkOutput Network::evaluate(const Position& pos,
|
||||
AccumulatorStack& accumulatorStack,
|
||||
AccumulatorCaches& cache) const {
|
||||
|
||||
constexpr uint64_t alignment = CacheLineSize;
|
||||
|
||||
alignas(alignment)
|
||||
TransformedFeatureType transformedFeatures[FeatureTransformer<FTDimensions>::BufferSize];
|
||||
alignas(alignment) TransformedFeatureType transformedFeatures[FeatureTransformer::BufferSize];
|
||||
|
||||
ASSERT_ALIGNED(transformedFeatures, alignment);
|
||||
|
||||
@@ -198,9 +162,8 @@ Network<Arch, Transformer>::evaluate(const Position& pos
|
||||
}
|
||||
|
||||
|
||||
template<typename Arch, typename Transformer>
|
||||
void Network<Arch, Transformer>::verify(std::string evalfilePath,
|
||||
const std::function<void(std::string_view)>& f) const {
|
||||
void Network::verify(std::string evalfilePath,
|
||||
const std::function<void(std::string_view)>& f) const {
|
||||
if (evalfilePath.empty())
|
||||
evalfilePath = evalFile.defaultName;
|
||||
|
||||
@@ -229,9 +192,9 @@ void Network<Arch, Transformer>::verify(std::string
|
||||
|
||||
if (f)
|
||||
{
|
||||
size_t size = sizeof(featureTransformer) + sizeof(Arch) * LayerStacks;
|
||||
size_t size = sizeof(featureTransformer) + sizeof(NetworkArchitecture) * LayerStacks;
|
||||
f("NNUE evaluation using " + evalfilePath + " (" + std::to_string(size / (1024 * 1024))
|
||||
+ "MiB, (" + std::to_string(featureTransformer.TotalInputDimensions) + ", "
|
||||
+ "MiB, (" + std::to_string(featureTransformer.InputDimensions) + ", "
|
||||
+ std::to_string(network[0].TransformedFeatureDimensions) + ", "
|
||||
+ std::to_string(network[0].FC_0_OUTPUTS) + ", " + std::to_string(network[0].FC_1_OUTPUTS)
|
||||
+ ", 1))");
|
||||
@@ -239,16 +202,13 @@ void Network<Arch, Transformer>::verify(std::string
|
||||
}
|
||||
|
||||
|
||||
template<typename Arch, typename Transformer>
|
||||
NnueEvalTrace
|
||||
Network<Arch, Transformer>::trace_evaluate(const Position& pos,
|
||||
AccumulatorStack& accumulatorStack,
|
||||
AccumulatorCaches::Cache<FTDimensions>& cache) const {
|
||||
NnueEvalTrace Network::trace_evaluate(const Position& pos,
|
||||
AccumulatorStack& accumulatorStack,
|
||||
AccumulatorCaches& cache) const {
|
||||
|
||||
constexpr uint64_t alignment = CacheLineSize;
|
||||
|
||||
alignas(alignment)
|
||||
TransformedFeatureType transformedFeatures[FeatureTransformer<FTDimensions>::BufferSize];
|
||||
alignas(alignment) TransformedFeatureType transformedFeatures[FeatureTransformer::BufferSize];
|
||||
|
||||
ASSERT_ALIGNED(transformedFeatures, alignment);
|
||||
|
||||
@@ -268,9 +228,7 @@ Network<Arch, Transformer>::trace_evaluate(const Position&
|
||||
}
|
||||
|
||||
|
||||
template<typename Arch, typename Transformer>
|
||||
void Network<Arch, Transformer>::load_user_net(const std::string& dir,
|
||||
const std::string& evalfilePath) {
|
||||
void Network::load_user_net(const std::string& dir, const std::string& evalfilePath) {
|
||||
std::ifstream stream(dir + evalfilePath, std::ios::binary);
|
||||
auto description = load(stream);
|
||||
|
||||
@@ -282,8 +240,7 @@ void Network<Arch, Transformer>::load_user_net(const std::string& dir,
|
||||
}
|
||||
|
||||
|
||||
template<typename Arch, typename Transformer>
|
||||
void Network<Arch, Transformer>::load_internal() {
|
||||
void Network::load_internal() {
|
||||
// C++ way to prepare a buffer for a memory stream
|
||||
class MemoryBuffer: public std::basic_streambuf<char> {
|
||||
public:
|
||||
@@ -293,10 +250,8 @@ void Network<Arch, Transformer>::load_internal() {
|
||||
}
|
||||
};
|
||||
|
||||
const auto embedded = get_embedded(embeddedType);
|
||||
|
||||
MemoryBuffer buffer(const_cast<char*>(reinterpret_cast<const char*>(embedded.data)),
|
||||
size_t(embedded.size));
|
||||
MemoryBuffer buffer(const_cast<char*>(reinterpret_cast<const char*>(gEmbeddedNNUEData)),
|
||||
size_t(gEmbeddedNNUESize));
|
||||
|
||||
std::istream stream(&buffer);
|
||||
auto description = load(stream);
|
||||
@@ -309,16 +264,12 @@ void Network<Arch, Transformer>::load_internal() {
|
||||
}
|
||||
|
||||
|
||||
template<typename Arch, typename Transformer>
|
||||
void Network<Arch, Transformer>::initialize() {
|
||||
initialized = true;
|
||||
}
|
||||
void Network::initialize() { initialized = true; }
|
||||
|
||||
|
||||
template<typename Arch, typename Transformer>
|
||||
bool Network<Arch, Transformer>::save(std::ostream& stream,
|
||||
const std::string& name,
|
||||
const std::string& netDescription) const {
|
||||
bool Network::save(std::ostream& stream,
|
||||
const std::string& name,
|
||||
const std::string& netDescription) const {
|
||||
if (name.empty() || name == "None")
|
||||
return false;
|
||||
|
||||
@@ -326,8 +277,7 @@ bool Network<Arch, Transformer>::save(std::ostream& stream,
|
||||
}
|
||||
|
||||
|
||||
template<typename Arch, typename Transformer>
|
||||
std::optional<std::string> Network<Arch, Transformer>::load(std::istream& stream) {
|
||||
std::optional<std::string> Network::load(std::istream& stream) {
|
||||
initialize();
|
||||
std::string description;
|
||||
|
||||
@@ -335,8 +285,7 @@ std::optional<std::string> Network<Arch, Transformer>::load(std::istream& stream
|
||||
}
|
||||
|
||||
|
||||
template<typename Arch, typename Transformer>
|
||||
std::size_t Network<Arch, Transformer>::get_content_hash() const {
|
||||
std::size_t Network::get_content_hash() const {
|
||||
if (!initialized)
|
||||
return 0;
|
||||
|
||||
@@ -345,15 +294,11 @@ std::size_t Network<Arch, Transformer>::get_content_hash() const {
|
||||
for (auto&& layerstack : network)
|
||||
hash_combine(h, layerstack);
|
||||
hash_combine(h, evalFile);
|
||||
hash_combine(h, static_cast<int>(embeddedType));
|
||||
return h;
|
||||
}
|
||||
|
||||
// Read network header
|
||||
template<typename Arch, typename Transformer>
|
||||
bool Network<Arch, Transformer>::read_header(std::istream& stream,
|
||||
std::uint32_t* hashValue,
|
||||
std::string* desc) const {
|
||||
bool Network::read_header(std::istream& stream, std::uint32_t* hashValue, std::string* desc) const {
|
||||
std::uint32_t version, size;
|
||||
|
||||
version = read_little_endian<std::uint32_t>(stream);
|
||||
@@ -368,10 +313,9 @@ bool Network<Arch, Transformer>::read_header(std::istream& stream,
|
||||
|
||||
|
||||
// Write network header
|
||||
template<typename Arch, typename Transformer>
|
||||
bool Network<Arch, Transformer>::write_header(std::ostream& stream,
|
||||
std::uint32_t hashValue,
|
||||
const std::string& desc) const {
|
||||
bool Network::write_header(std::ostream& stream,
|
||||
std::uint32_t hashValue,
|
||||
const std::string& desc) const {
|
||||
write_little_endian<std::uint32_t>(stream, Version);
|
||||
write_little_endian<std::uint32_t>(stream, hashValue);
|
||||
write_little_endian<std::uint32_t>(stream, std::uint32_t(desc.size()));
|
||||
@@ -380,9 +324,7 @@ bool Network<Arch, Transformer>::write_header(std::ostream& stream,
|
||||
}
|
||||
|
||||
|
||||
template<typename Arch, typename Transformer>
|
||||
bool Network<Arch, Transformer>::read_parameters(std::istream& stream,
|
||||
std::string& netDescription) {
|
||||
bool Network::read_parameters(std::istream& stream, std::string& netDescription) {
|
||||
std::uint32_t hashValue;
|
||||
if (!read_header(stream, &hashValue, &netDescription))
|
||||
return false;
|
||||
@@ -399,9 +341,7 @@ bool Network<Arch, Transformer>::read_parameters(std::istream& stream,
|
||||
}
|
||||
|
||||
|
||||
template<typename Arch, typename Transformer>
|
||||
bool Network<Arch, Transformer>::write_parameters(std::ostream& stream,
|
||||
const std::string& netDescription) const {
|
||||
bool Network::write_parameters(std::ostream& stream, const std::string& netDescription) const {
|
||||
if (!write_header(stream, Network::hash, netDescription))
|
||||
return false;
|
||||
if (!Detail::write_parameters(stream, featureTransformer))
|
||||
@@ -414,12 +354,4 @@ bool Network<Arch, Transformer>::write_parameters(std::ostream& stream,
|
||||
return bool(stream);
|
||||
}
|
||||
|
||||
// Explicit template instantiations
|
||||
|
||||
template class Network<NetworkArchitecture<TransformedFeatureDimensionsBig, L2Big, L3Big>,
|
||||
FeatureTransformer<TransformedFeatureDimensionsBig>>;
|
||||
|
||||
template class Network<NetworkArchitecture<TransformedFeatureDimensionsSmall, L2Small, L3Small>,
|
||||
FeatureTransformer<TransformedFeatureDimensionsSmall>>;
|
||||
|
||||
} // namespace Stockfish::Eval::NNUE
|
||||
|
||||
Reference in New Issue
Block a user