our_knp/examples/knp/base-framework/impl/model_executor.cpp
int 8f43927575 Initial import: KNP experiments (examples, viz, cats-dogs, reports)
examples/ is based on KasperskyLab/knp at 55470ed6 with local changes
to the mnist-learn altai/blifat models, cuda-backend CMake and model_loader.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 18:17:15 +03:00

151 lines
4.4 KiB
C++

/**
* @file model_executor.cpp
* @brief Model executor class implementation.
* @kaspersky_support Artiom N.
* @date 21.04.2023
* @license Apache 2.0
* @copyright © 2024 AO Kaspersky Lab
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <knp/framework/model_executor.h>
#include <spdlog/spdlog.h>
namespace knp::framework
{
class ModelExecutor::SpikeMessageHandler
{
public:
using MessageIn = knp::core::messaging::SpikeMessage;
using MessageData = knp::core::messaging::SpikeData;
using FunctionType = std::function<MessageData(std::vector<MessageIn> &)>;
SpikeMessageHandler(FunctionType &&function, knp::core::MessageEndpoint &&endpoint, const knp::core::UID &uid = {})
: message_handler_function_(std::move(function)), endpoint_(std::move(endpoint)), base_{uid}
{
}
SpikeMessageHandler(SpikeMessageHandler &&other) noexcept = default;
SpikeMessageHandler(const SpikeMessageHandler &) = delete;
void subscribe(const std::vector<core::UID> &entities) { endpoint_.subscribe<MessageIn>(base_.uid_, entities); }
void update(size_t step);
[[nodiscard]] knp::core::UID get_uid() const { return base_.uid_; };
~SpikeMessageHandler() = default;
private:
FunctionType message_handler_function_;
knp::core::MessageEndpoint endpoint_;
knp::core::BaseData base_;
};
void ModelExecutor::SpikeMessageHandler::update(size_t step)
{
endpoint_.receive_all_messages();
auto incoming_messages = endpoint_.unload_messages<MessageIn>(base_.uid_);
knp::core::messaging::SpikeMessage outgoing_message = {
{base_.uid_, step}, message_handler_function_(incoming_messages)};
if (!(outgoing_message.neuron_indexes_.empty()))
{
endpoint_.send_message(outgoing_message);
}
}
ModelExecutor::ModelExecutor(
knp::framework::Model &model, std::shared_ptr<core::Backend> backend, ModelLoader::InputChannelMap i_map)
: loader_(backend, i_map)
{
loader_.load(model);
}
ModelExecutor::~ModelExecutor() = default;
void ModelExecutor::start()
{
start([](knp::core::Step) { return true; });
}
void ModelExecutor::start(core::Backend::RunPredicate run_predicate)
{
SPDLOG_INFO("Starting model execution...");
get_backend()->start(
[this, run_predicate](knp::core::Step step)
{
// Sending inputs from the channels.
for (auto &i_ch : loader_.get_inputs())
{
i_ch.send(step);
}
// Run user predicate.
return run_predicate(step);
},
[this](knp::core::Step)
{
// Loading spikes into output channels.
for (auto &o_ch : loader_.get_outputs())
{
o_ch.update();
}
// Running handlers
for (auto &handler : message_handlers_)
{
handler->update(get_backend()->get_step());
}
// Run monitoring observers.
for (auto &observer : observers_)
{
std::visit([](auto &entity) { entity.update(); }, observer);
}
return true;
});
SPDLOG_INFO("Model execution stopped.");
}
void ModelExecutor::stop()
{
get_backend()->stop();
}
void ModelExecutor::add_spike_message_handler(
typename SpikeMessageHandler::FunctionType &&message_handler_function, const std::vector<core::UID> &senders,
const std::vector<core::UID> &receivers, const knp::core::UID &uid)
{
knp::core::MessageEndpoint endpoint = get_backend()->get_message_bus().create_endpoint();
message_handlers_.emplace_back(
std::make_unique<SpikeMessageHandler>(std::move(message_handler_function), std::move(endpoint), uid));
message_handlers_.back()->subscribe(senders);
for (const knp::core::UID &rec_uid : receivers)
{
get_backend()->subscribe<knp::core::messaging::SpikeMessage>(rec_uid, {uid});
}
}
} // namespace knp::framework