ember.cpp 0.1.0
C++ inference engine for Llama-family and paperkiln models (CPU, CUDA, WebAssembly)
Loading...
Searching...
No Matches
tinyllama Namespace Reference

Classes

class  DistributedCoordinator
 Distributed coordinator for multi-node LLM inference. More...
 
class  TinyLlamaSession
 Represents an active TinyLlama session holding the loaded model and tokenizer. More...
 
struct  TtftBreakdown
 Where the time went between generate() being called and its first output token being emitted (docs/TTFT.md). More...
 

Functions

static void log_vector_summary_detailed (const std::string &name, const std::vector< float > &v, int current_pos, int current_layer, int N)
 
static std::string read_file_api (const std::string &path)
 
static int argmax (const std::vector< float > &v)
 
static std::vector< int > prompt_lookup_draft (const std::vector< int > &h, int k)
 
static const ember_draft::DraftTable * corpus_draft_table (int vocab_size)
 
static void apply_repetition_penalty (std::vector< float > &logits, const std::vector< int > &generated, float penalty, size_t window=64)
 
template<class IsStop >
static void apply_contract_penalty (std::vector< float > &lg, const std::vector< int > &a, const std::vector< int > &b, float p, int last_n, IsStop is_stop, std::vector< char > &seen)
 
static void debug_dump_topk (const std::vector< float > &logits)
 
static bool logits_debug_on ()
 
static int sample_top_k_top_p_temperature (const std::vector< float > &logits, float temperature, int top_k, float top_p, std::mt19937 &rng)
 

Function Documentation

◆ apply_contract_penalty()

template<class IsStop >
static void tinyllama::apply_contract_penalty ( std::vector< float > &  lg,
const std::vector< int > &  a,
const std::vector< int > &  b,
float  p,
int  last_n,
IsStop  is_stop,
std::vector< char > &  seen 
)
static

Definition at line 170 of file api.cpp.

171 {
172 if (p == 1.0f || last_n <= 0) return;
173 const size_t na = a.size(), total = na + b.size();
174 const size_t first = total > static_cast<size_t>(last_n) ? total - last_n : 0;
175 seen.assign(lg.size(), 0);
176 for (size_t i = first; i < total; ++i) {
177 const int id = i < na ? a[i] : b[i - na];
178 if (id < 0 || static_cast<size_t>(id) >= lg.size() || seen[id] || is_stop(id)) continue;
179 seen[id] = 1;
180 float& l = lg[id];
181 l = l > 0.0f ? l / p : l * p;
182 }
183}
const float * p[kIrDepthSourcesMax]
std::vector< E > a
size_t j

References a, id, and p.

Referenced by tinyllama::TinyLlamaSession::generate(), and tinyllama::TinyLlamaSession::sample_step().

◆ apply_repetition_penalty()

static void tinyllama::apply_repetition_penalty ( std::vector< float > &  logits,
const std::vector< int > &  generated,
float  penalty,
size_t  window = 64 
)
static

Definition at line 152 of file api.cpp.

154 {
155 if (penalty <= 1.0f || generated.empty()) return;
156 size_t start = generated.size() > window ? generated.size() - window : 0;
157 for (size_t i = start; i < generated.size(); ++i) {
158 int id = generated[i];
159 if (id < 0 || static_cast<size_t>(id) >= logits.size()) continue;
160 float& l = logits[id];
161 l = (l > 0.0f) ? l / penalty : l * penalty;
162 }
163}

References id.

Referenced by tinyllama::TinyLlamaSession::generate().

◆ argmax()

static int tinyllama::argmax ( const std::vector< float > &  v)
static

Definition at line 84 of file api.cpp.

84 {
85 if (v.empty()) {
86 Logger::error("Cannot perform argmax on empty vector");
87 return -1;
88 }
89
90 return std::distance(v.begin(), std::max_element(v.begin(), v.end()));
91}
static void error(const std::string &message)
Definition logger.cpp:143
std::vector< float > v

References Logger::error(), and v.

◆ corpus_draft_table()

static const ember_draft::DraftTable * tinyllama::corpus_draft_table ( int  vocab_size)
static

Definition at line 109 of file api.cpp.

109 {
111 static bool ok = false;
112 static int vocab_read = 0;
113 static std::once_flag once;
114 std::call_once(once, [&] {
115 const char* path = std::getenv("EMBER_DRAFT_TABLE");
116 std::string why = "EMBER_DRAFT_TABLE is not set";
117 ok = path && table.load(path, vocab_size, &why);
118 vocab_read = vocab_size;
119 if (ok)
120 Logger::info("EMBER_DRAFT=table: " + std::string(path) + ", " + std::to_string(table.entries()) +
121 " entries over orders 1-" + std::to_string(table.orders()));
122 else
123 Logger::warning("EMBER_DRAFT=table: no corpus table (" + why + "); prompt-lookup drafts only.");
124 });
125 return ok && vocab_size == vocab_read ? &table : nullptr;
126}
static void warning(const std::string &message)
Definition logger.cpp:139
static void info(const std::string &message)
Definition logger.cpp:135
std::string why
Definition graph_ir.cpp:280

References ember_draft::DraftTable::entries(), Logger::info(), ember_draft::DraftTable::load(), ember_draft::DraftTable::orders(), Logger::warning(), and why.

Referenced by tinyllama::TinyLlamaSession::generate().

◆ debug_dump_topk()

static void tinyllama::debug_dump_topk ( const std::vector< float > &  logits)
static

Definition at line 188 of file api.cpp.

188 {
189 // TINYLLAMA_LOGITS_DUMP=<path>: append the FULL logit vector at every
190 // sampled position (one space-joined line each). The engine half of the
191 // golden-batch GGUF-parity test — compare against the trainer's
192 // golden_batch_test --dump rows with compare_golden_logits.py. Nine significant digits, so each
193 // value reads back as the same float32 (bit-for-bit comparisons of two dumps).
194 static const char* dump_path = std::getenv("TINYLLAMA_LOGITS_DUMP");
195 if (dump_path) {
196 std::ofstream f(dump_path, std::ios::app);
197 f << std::setprecision(9);
198 for (size_t i = 0; i < logits.size(); ++i) f << (i ? " " : "") << logits[i];
199 f << "\n";
200 }
201 static const bool on = std::getenv("TINYLLAMA_TOPK_DEBUG") != nullptr;
202 if (!on) return;
203 std::vector<int> idx(logits.size());
204 for (size_t i = 0; i < idx.size(); ++i) idx[i] = static_cast<int>(i);
205 std::partial_sort(idx.begin(), idx.begin() + std::min<size_t>(10, idx.size()),
206 idx.end(), [&](int a, int b) { return logits[a] > logits[b]; });
207 std::ostringstream os;
208 os << "[TOPK]";
209 for (size_t r = 0; r < std::min<size_t>(10, idx.size()); ++r)
210 os << " " << idx[r] << ":" << logits[idx[r]];
211 fprintf(stderr, "%s\n", os.str().c_str());
212}

References a.

Referenced by tinyllama::TinyLlamaSession::generate().

◆ log_vector_summary_detailed()

static void tinyllama::log_vector_summary_detailed ( const std::string &  name,
const std::vector< float > &  v,
int  current_pos,
int  current_layer,
int  N 
)
static

Definition at line 43 of file api.cpp.

46 {
47 if (v.empty()) {
48 Logger::info(name + " (pos=" + std::to_string(current_pos) + ", layer=" +
49 std::to_string(current_layer) + "): EMPTY VECTOR");
50 return;
51 }
52 std::stringstream ss;
53 ss << name << " (pos=" << std::to_string(current_pos)
54 << ", layer=" << std::to_string(current_layer) << "): size=" << v.size();
55 ss << ", first " << N << ": [";
56 for (int i = 0; i < N && i < v.size(); ++i) {
57 ss << std::fixed << std::setprecision(4) << v[i]
58 << (i == N - 1 || i == v.size() - 1 ? "" : ", ");
59 }
60 ss << "]";
61 float min_val = v[0], max_val = v[0], sum = 0.0f;
62 bool all_finite = true;
63 for (float val : v) {
64 if (val < min_val) min_val = val;
65 if (val > max_val) max_val = val;
66 sum += val;
67 if (!std::isfinite(val)) all_finite = false;
68 }
69 ss << ", min=" << std::fixed << std::setprecision(4) << min_val;
70 ss << ", max=" << std::fixed << std::setprecision(4) << max_val;
71 ss << ", mean=" << std::fixed << std::setprecision(4) << (sum / v.size());
72 ss << ", finite=" << (all_finite ? "yes" : "no");
73 Logger::info(ss.str());
74}
const char * name

References Logger::info(), name, and v.

Referenced by tinyllama::TinyLlamaSession::generate().

◆ logits_debug_on()

static bool tinyllama::logits_debug_on ( )
static

Definition at line 216 of file api.cpp.

216 {
217 static const bool on = std::getenv("TINYLLAMA_LOGITS_DUMP") != nullptr ||
218 std::getenv("TINYLLAMA_TOPK_DEBUG") != nullptr;
219 return on;
220}

Referenced by tinyllama::TinyLlamaSession::generate().

◆ prompt_lookup_draft()

static std::vector< int > tinyllama::prompt_lookup_draft ( const std::vector< int > &  h,
int  k 
)
static

Definition at line 96 of file api.cpp.

96 {
97 const int n = static_cast<int>(h.size());
98 for (int g = std::min(3, n - 1); g >= 2; --g) {
99 for (int s = n - g - 1; s >= 0; --s) {
100 if (std::equal(h.begin() + s, h.begin() + s + g, h.end() - g))
101 return std::vector<int>(h.begin() + s + g, h.begin() + std::min(n, s + g + k));
102 }
103 }
104 return {};
105}
int n

References k, and n.

Referenced by tinyllama::TinyLlamaSession::generate().

◆ read_file_api()

static std::string tinyllama::read_file_api ( const std::string &  path)
static

Definition at line 76 of file api.cpp.

76 {
77 std::filesystem::path fs_path(path);
78 std::ifstream file(fs_path, std::ios::binary);
79 if (!file) throw std::runtime_error("Failed to open file: " + path);
80 return std::string((std::istreambuf_iterator<char>(file)),
81 std::istreambuf_iterator<char>());
82}

◆ sample_top_k_top_p_temperature()

static int tinyllama::sample_top_k_top_p_temperature ( const std::vector< float > &  logits,
float  temperature,
int  top_k,
float  top_p,
std::mt19937 &  rng 
)
static

Definition at line 222 of file api.cpp.

224 {
225 if (logits.empty()) {
226 throw std::runtime_error("Cannot sample from empty logits.");
227 }
228
229 // If temperature is very low, fall back to greedy sampling
230 if (temperature < 0.05f) {
231 return std::distance(logits.begin(), std::max_element(logits.begin(), logits.end()));
232 }
233
234 int vocab_size = logits.size();
235
236 top_k = (std::min)(top_k, vocab_size);
237 if (top_k <= 0) top_k = vocab_size;
238
239 std::vector<float> scaled_logits(vocab_size);
240 float max_logit = -std::numeric_limits<float>::infinity();
241 for (float logit : logits) max_logit = (std::max)(max_logit, logit);
242
243 // Scale logits to avoid numerical instability
244 const float scale = 1.0f / temperature;
245 for (int i = 0; i < vocab_size; ++i) {
247 }
248
249 std::vector<double> probs_double(vocab_size);
250 double sum_exp = 0.0;
251 for (int i = 0; i < vocab_size; ++i) {
252 probs_double[i] = std::exp(static_cast<double>(scaled_logits[i]));
254 }
255
256 // Pure temperature (top_k <= 0 or >= vocab, top_p >= 1): draw from the
257 // whole double-precision distribution, no sort and no float cumulative sum
258 // that can reach 1.0 early and drop the tail. Same distribution as
259 // paperkiln's sample_pure (charter 0001 §4); the RNG stream differs.
260 if (top_k >= vocab_size && top_p >= 1.0f && sum_exp > 0.0) {
261 std::discrete_distribution<int> pure(probs_double.begin(), probs_double.end());
262 return pure(rng);
263 }
264
265 // Normalize probabilities
266 if (sum_exp > 0.0) {
267 for (int i = 0; i < vocab_size; ++i) {
269 }
270 } else {
271 // If all probabilities are zero, fall back to uniform distribution
272 for (int i = 0; i < vocab_size; ++i) {
273 probs_double[i] = 1.0 / vocab_size;
274 }
275 }
276
277 std::vector<std::pair<float, int>> prob_idx(vocab_size);
278 for (int i = 0; i < vocab_size; ++i) {
279 prob_idx[i] = {static_cast<float>(probs_double[i]), i};
280 }
281
282 // Only the top_k head is used, so sort just that head: the same elements
283 // in the same order as a full sort (pairs are distinct, so the order is
284 // total), without sorting the whole vocabulary on every token.
285 if (top_k < vocab_size) {
286 std::partial_sort(prob_idx.begin(), prob_idx.begin() + top_k, prob_idx.end(),
287 std::greater<std::pair<float, int>>());
288 prob_idx.resize(top_k);
289 } else {
290 std::sort(prob_idx.begin(), prob_idx.end(), std::greater<std::pair<float, int>>());
291 }
292
293 float cumulative_prob = 0.0f;
294 int last_idx = 0;
295 for (int i = 0; i < prob_idx.size(); ++i) {
296 cumulative_prob += prob_idx[i].first;
297 last_idx = i;
298 if (cumulative_prob >= top_p) {
299 break;
300 }
301 }
302 prob_idx.resize(last_idx + 1);
303
304 float final_sum = 0.0f;
305 for (const auto& pi : prob_idx) {
306 final_sum += pi.first;
307 }
308
309 // Renormalize probabilities after top-k and top-p filtering
310 std::vector<float> final_probs(prob_idx.size());
311 if (final_sum > 0.0f) {
312 for (size_t i = 0; i < prob_idx.size(); ++i) {
313 final_probs[i] = prob_idx[i].first / final_sum;
314 }
315 } else {
316 // If all probabilities are zero after filtering, use uniform distribution
317 float uniform_prob = 1.0f / prob_idx.size();
318 std::fill(final_probs.begin(), final_probs.end(), uniform_prob);
319 }
320
321 std::discrete_distribution<int> dist(final_probs.begin(), final_probs.end());
323
324 return prob_idx[sampled_idx_in_filtered].second;
325}
node scale

References scale.

Referenced by tinyllama::TinyLlamaSession::generate(), tinyllama::TinyLlamaSession::generate_batch(), and tinyllama::TinyLlamaSession::sample_step().