neuroflow-cpp / src /generative_model.cpp
cwenzi's picture
Upload folder using huggingface_hub
26d5b81 verified
Raw
History Blame Contribute Delete
5.57 kB
#include "neuroflow/generative_model.hpp"
#include <algorithm>
#include <cmath>
#include <iostream>
namespace neuroflow {
GenerativeModel::GenerativeModel(const CausalLMConfig& lm_config,
std::unique_ptr<Tokenizer> tokenizer,
NeuroFlowModel* nf_model)
: tokenizer_(std::move(tokenizer)), neuroflow_model_(nf_model) {
lm_head_ = std::make_unique<CausalLMHead>(lm_config);
sampler_ = std::make_unique<TopKSampling>();
}
GenerateOutput GenerativeModel::generate(const std::string& prompt, const GenerateConfig& config) {
GenerateOutput output;
std::vector<size_t> input_ids = tokenizer_->encode(prompt);
std::vector<size_t> generated_ids;
size_t seed = config.random_seed;
if (seed == 0) {
std::random_device rd;
seed = rd();
}
std::mt19937 rng(seed);
lm_head_->clear_cache();
if (input_ids.empty()) {
output.finish_reason = FinishReason::GEN_ERROR;
return output;
}
Tensor logits;
if (input_ids.size() > 1) {
std::vector<size_t> prefix(input_ids.begin(), input_ids.end() - 1);
logits = lm_head_->forward(prefix);
}
size_t last_id = input_ids.back();
for (size_t step = 0; step < config.max_new_tokens; ++step) {
size_t pos = input_ids.size() - 1 + step;
logits = lm_head_->forward_step(last_id, pos);
logits = apply_sn_gating(lm_head_->last_hidden_, logits);
logits = inject_memory(lm_head_->last_hidden_, logits);
logits = apply_repetition_penalty(logits, config, generated_ids);
logits = apply_punct_penalty(logits, config);
Tensor probs = sampler_->apply(logits, config, generated_ids);
size_t next_id = sampler_->sample(probs, rng);
generated_ids.push_back(next_id);
if (next_id == config.eos_id) {
output.finish_reason = FinishReason::EOS_TOKEN;
break;
}
last_id = next_id;
}
if (output.finish_reason != FinishReason::EOS_TOKEN) {
output.finish_reason = FinishReason::MAX_LENGTH;
}
output.token_ids = generated_ids;
output.text = tokenizer_->decode(generated_ids);
output.cache_stats = lm_head_->cache_stats();
return output;
}
Tensor GenerativeModel::apply_sn_gating(const Tensor& hidden, const Tensor& logits) {
if (!neuroflow_model_) return logits;
try {
auto sn_out = neuroflow_model_->sn->forward(hidden);
float ecn_gate = sn_out.gates.as_fp32()[0];
float dmn_gate = sn_out.gates.as_fp32()[1];
if (std::isnan(ecn_gate) || std::isnan(dmn_gate) ||
(ecn_gate == 0.0f && dmn_gate == 0.0f)) {
std::cerr << "Warning: SN gate NaN/zero, falling back to equal weighting" << std::endl;
ecn_gate = 0.5f;
dmn_gate = 0.5f;
}
return logits;
} catch (...) {
return logits;
}
}
Tensor GenerativeModel::inject_memory(const Tensor& query, const Tensor& logits) {
if (!neuroflow_model_) return logits;
try {
auto mem_out = neuroflow_model_->memory->retrieve(query);
const float* mp = mem_out.retrieved.as_fp32();
bool all_zero = true;
for (size_t i = 0; i < mem_out.retrieved.numel(); ++i) {
if (std::abs(mp[i]) > 1e-8f) { all_zero = false; break; }
}
if (all_zero) return logits;
return logits;
} catch (...) {
return logits;
}
}
Tensor GenerativeModel::apply_repetition_penalty(Tensor logits, const GenerateConfig& config,
const std::vector<size_t>& generated) {
if (config.repetition_penalty <= 1.0f || generated.empty()) return logits;
float* data = logits.as_fp32();
size_t n = logits.numel();
size_t window = std::min(generated.size(), static_cast<size_t>(20));
for (size_t i = generated.size() - window; i < generated.size(); ++i) {
size_t tid = generated[i];
if (tid < n) {
if (data[tid] > 0) {
data[tid] /= config.repetition_penalty;
} else {
data[tid] *= config.repetition_penalty;
}
}
}
return logits;
}
Tensor GenerativeModel::apply_punct_penalty(Tensor logits, const GenerateConfig& config) {
if (config.punct_penalty <= 0.0f || config.punct_ids.empty()) return logits;
float* data = logits.as_fp32();
size_t n = logits.numel();
for (size_t pid : config.punct_ids) {
if (pid < n) {
data[pid] -= config.punct_penalty;
}
}
return logits;
}
void GenerativeModel::set_strategy(SamplingStrategyType type) {
switch (type) {
case SamplingStrategyType::GREEDY:
sampler_ = std::make_unique<GreedyDecoding>();
break;
case SamplingStrategyType::TOP_K:
sampler_ = std::make_unique<TopKSampling>();
break;
case SamplingStrategyType::TOP_P:
sampler_ = std::make_unique<TopPSampling>();
break;
case SamplingStrategyType::TOP_K_TOP_P:
sampler_ = std::make_unique<TopKTopPSampling>();
break;
}
}
void GenerativeModel::clear_cache() { lm_head_->clear_cache(); }
CacheStats GenerativeModel::cache_stats() const { return lm_head_->cache_stats(); }
} // namespace neuroflow