Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
f56435a
eagle impl with top-1 proposal
songbell Sep 17, 2025
1d74c03
enable cb benchmark for eagle3
songbell Sep 17, 2025
0b09a65
add benchmarking, apply copilot review comments
songbell Sep 18, 2025
b36ecf7
fix case build failure
songbell Sep 18, 2025
d86e5a7
fix SDL
songbell Sep 18, 2025
f0aa2c7
typo
songbell Sep 18, 2025
bbfa8ad
opt hidden state transfer with ROI tensor
songbell Sep 18, 2025
35e6376
opt roi copy interface
songbell Sep 19, 2025
f6a8872
Merge branch 'master' into bell/eagle_cb_impl
songbell Sep 19, 2025
8a480a4
parse eagle info from draft model
songbell Sep 23, 2025
cd753f6
do not need seperate eagle sample
songbell Sep 23, 2025
6aa4965
opt constructor for eagledecodingimpl
songbell Sep 23, 2025
5efbada
remove hardcoding of eagle layers
songbell Sep 23, 2025
96276fe
apply copilot comment
songbell Sep 30, 2025
146f5c3
Merge branch 'master' of https://github.com/openvinotoolkit/openvino.…
songbell Sep 30, 2025
300996d
Merge branch 'master' into bell/eagle_cb_impl
songbell Oct 10, 2025
6c3876e
share weights, rt info update
songbell Oct 11, 2025
1af6771
Merge branch 'bell/eagle_cb_impl' of https://github.com/songbell/open…
songbell Oct 11, 2025
f33491f
reuse spec app for eagle
songbell Oct 11, 2025
264540f
fix build warning
songbell Oct 11, 2025
cfe77f8
enable test
songbell Oct 13, 2025
2f5d080
skip eagle3 test for now
songbell Oct 14, 2025
70cd1c1
Merge branch 'master' of https://github.com/openvinotoolkit/openvino.…
songbell Oct 15, 2025
ff9b50e
align default num assistant tokens
songbell Oct 15, 2025
723e3f8
udpate test ticket
songbell Oct 15, 2025
8b72711
apply review comment
songbell Oct 16, 2025
b31411a
move eagle3 tests to seperate file
songbell Oct 16, 2025
3a3ad17
refine hs state management
songbell Oct 16, 2025
b333045
apply copilot comment
songbell Oct 17, 2025
7c9cd2b
Merge branch 'master' of https://github.com/openvinotoolkit/openvino.…
songbell Oct 17, 2025
62320a4
fix build failure
songbell Oct 17, 2025
84b589e
fallback unchanged file
songbell Oct 17, 2025
766d72f
Merge branch 'master' into bell/eagle_cb_impl
songbell Oct 20, 2025
baa890b
Update site/docs/supported-models/_components/llm-models-table/models.ts
songbell Oct 20, 2025
c5e474b
apply copilot
songbell Oct 20, 2025
21b4108
Merge branch 'bell/eagle_cb_impl' of https://github.com/songbell/open…
songbell Oct 20, 2025
75ea28e
fix typo for samples
songbell Oct 20, 2025
fdeb3f0
apply review comments part-1, mainly on code
songbell Oct 21, 2025
5fd9b71
Merge branch 'bell/eagle_cb_impl' of https://github.com/songbell/open…
songbell Oct 21, 2025
0931c09
reuse common codes between spec decode and eagle3 decode
songbell Oct 21, 2025
3c97718
add missing default
songbell Oct 21, 2025
5f16e65
enable test interface first
songbell Oct 21, 2025
bb8a39d
apply review comments
songbell Oct 22, 2025
428c25e
enable test for local val first
songbell Oct 22, 2025
efd854b
use warning logger instead of cout
songbell Oct 22, 2025
a9f68db
update per model d2t changes
songbell Oct 23, 2025
15f6a4b
Merge branch 'master' of https://github.com/openvinotoolkit/openvino.…
songbell Oct 23, 2025
3bcdfc3
add missing line for unchanged file
songbell Oct 23, 2025
c4d1b6c
move test
songbell Oct 23, 2025
fc2d11f
try trigger test
songbell Oct 24, 2025
6397b63
Merge branch 'master' of https://github.com/openvinotoolkit/openvino.…
songbell Oct 27, 2025
1903c31
upgrade version
songbell Oct 27, 2025
3e5ec43
apply review comments
songbell Oct 29, 2025
433d8b3
revert the tokenizer params
songbell Oct 30, 2025
27a6b03
Merge branch 'master' of https://github.com/openvinotoolkit/openvino.…
songbell Oct 31, 2025
3898a45
Merge branch 'master' of https://github.com/openvinotoolkit/openvino.…
songbell Nov 10, 2025
b6f5c37
resolve conflict
songbell Nov 10, 2025
66ae01a
apply copilot
songbell Nov 10, 2025
dec0898
Merge branch 'master' into bell/eagle_cb_impl
songbell Nov 10, 2025
b6abe7f
Merge branch 'master' of https://github.com/openvinotoolkit/openvino.…
songbell Nov 12, 2025
ee263f9
Merge branch 'bell/eagle_cb_impl' of https://github.com/songbell/open…
songbell Nov 12, 2025
ad09392
move the def out of class
songbell Nov 12, 2025
a3e431f
With explicit commit id in the ref link.
peterchen-intel Nov 12, 2025
b168f41
formatging
songbell Nov 12, 2025
3af7823
apply review comments
xuchen-intel Nov 19, 2025
e413561
Update tests/python_tests/samples/test_speculative_decoding_lm.py
songbell Nov 19, 2025
1d963cf
Merge branch 'master' of https://github.com/openvinotoolkit/openvino.…
xuchen-intel Nov 21, 2025
bd28b9b
use new logger
xuchen-intel Nov 21, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion samples/cpp/text_generation/CMakeLists.txt
Comment thread
Wovchena marked this conversation as resolved.
Comment thread
songbell marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ set (SAMPLE_LIST
lora_greedy_causal_lm
multinomial_causal_lm
prompt_lookup_decoding_lm
speculative_decoding_lm)
speculative_decoding_lm
eagle_speculative_lm)

foreach(sample IN LISTS SAMPLE_LIST)
add_sample_executable(${sample})
Expand Down
114 changes: 114 additions & 0 deletions samples/cpp/text_generation/eagle_speculative_lm.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
// Copyright (C) 2023-2025 Intel Corporation
// SPDX-License-Identifier: Apache-2.0

#include <chrono>
#include <openvino/openvino.hpp>

#include "openvino/genai/llm_pipeline.hpp"
#include "openvino/genai/speculative_decoding/perf_metrics.hpp"

template <typename T>
void print_perf_metrics(T& perf_metrics, std::string model_name) {
std::cout << "\n" << model_name << std::endl;
auto generation_duration = perf_metrics.get_generate_duration().mean;
std::cout << " Generate time: " << generation_duration << " ms" << std::endl;
std::cout << " TTFT: " << perf_metrics.get_ttft().mean << " ± " << perf_metrics.get_ttft().std << " ms"
<< std::endl;
std::cout << " TPOT: " << perf_metrics.get_tpot().mean << " ± " << perf_metrics.get_tpot().std << " ms/token"
<< std::endl;
std::cout << " Num generated token: " << perf_metrics.get_num_generated_tokens() << " tokens" << std::endl;
if (model_name == "Total") {
std::cout << " Total iteration number: " << perf_metrics.raw_metrics.m_new_token_times.size() << std::endl;
} else {
std::cout << " Total iteration number: " << perf_metrics.raw_metrics.m_durations.size() << std::endl;
}
if (perf_metrics.get_num_input_tokens() > 0) {
std::cout << " Input token size: " << perf_metrics.get_num_input_tokens() << std::endl;
}
}

int main(int argc, char* argv[]) try {
if (4 != argc) {
throw std::runtime_error(std::string{"Usage: "} + argv[0] + " <MODEL_DIR> <EAGLE_MODEL_DIR> '<PROMPT>'");
}

std::string main_model_path = argv[1];
std::string eagle_model_path = argv[2];
Comment thread
songbell marked this conversation as resolved.
Outdated
std::string prompt = argv[3];

// Configure devices - can run main and eagle models on different devices
std::string main_device = "GPU", eagle_device = "GPU"; // CPU can bse used as well
Comment thread
songbell marked this conversation as resolved.
Outdated
Comment thread
songbell marked this conversation as resolved.
Outdated

// Eagle Speculative settings
ov::genai::GenerationConfig config = ov::genai::greedy();
config.max_new_tokens = 100;
config.num_assistant_tokens = 5;

ov::genai::SchedulerConfig scheduler_config;
scheduler_config.dynamic_split_fuse = false; // Eagle speculative decoding does not support dynamic_split_fuse mode
// Create pipeline with eagle speculative enabled
ov::genai::LLMPipeline pipe(
main_model_path,
main_device,
ov::genai::draft_model(eagle_model_path, eagle_device),
ov::genai::scheduler_config(scheduler_config),
ov::genai::eagle3_mode(true)
Comment thread
songbell marked this conversation as resolved.
Outdated
);
// Setup performance measurement
auto start_time = std::chrono::high_resolution_clock::now();

// Optional: Create a streaming callback for real-time token display
auto streamer = [](std::string subword) {
std::cout << subword << std::flush;
return ov::genai::StreamingStatus::RUNNING;
};

// Run generation with eagle speculative decoding
std::cout << "Generating with Eagle Speculative decoding:" << std::endl;
auto result = pipe.generate(prompt, config, streamer);
std::cout << std::endl;

// Calculate and display performance metrics
auto end_time = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end_time - start_time);
std::cout << "\nGeneration completed in " << duration.count() << " ms" << std::endl;
Comment thread
songbell marked this conversation as resolved.
Outdated

auto sd_perf_metrics = std::dynamic_pointer_cast<ov::genai::SDPerModelsPerfMetrics>(result.extended_perf_metrics);
if (sd_perf_metrics) {
print_perf_metrics(result.perf_metrics, "Total");
print_perf_metrics(sd_perf_metrics->main_model_metrics, "MAIN MODEL");
std::cout << " accepted token: " << sd_perf_metrics->get_num_accepted_tokens() << " tokens" << std::endl;
std::cout << " compress rate: "
<< sd_perf_metrics->main_model_metrics.get_num_generated_tokens() * 1.0f /
sd_perf_metrics->main_model_metrics.raw_metrics.m_durations.size()
<< std::endl;
print_perf_metrics(sd_perf_metrics->draft_model_metrics, "DRAFT MODEL");
}
std::cout << std::endl;

// Run without Eagle for comparison
std::cout << "\n-----------------------------" << std::endl;
std::cout << "Generating without Eagle Speculative decoding:" << std::endl;

// Disable Eagle mode
/*config.eagle_model = false;

start_time = std::chrono::high_resolution_clock::now();
pipe.generate(prompt, config, streamer);
std::cout << std::endl;
*/
end_time = std::chrono::high_resolution_clock::now();
duration = std::chrono::duration_cast<std::chrono::milliseconds>(end_time - start_time);
std::cout << "\nStandard generation completed in " << duration.count() << " ms" << std::endl;
Comment thread
songbell marked this conversation as resolved.
Outdated

} catch (const std::exception& error) {
try {
std::cerr << error.what() << '\n';
} catch (const std::ios_base::failure&) {}
return EXIT_FAILURE;
} catch (...) {
try {
std::cerr << "Non-exception object thrown\n";
} catch (const std::ios_base::failure&) {}
return EXIT_FAILURE;
}
2 changes: 1 addition & 1 deletion samples/cpp/text_generation/greedy_causal_lm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ int main(int argc, char* argv[]) try {

std::string models_path = argv[1];
std::string prompt = argv[2];
std::string device = "CPU"; // GPU can be used as well
Comment thread
peterchen-intel marked this conversation as resolved.
std::string device = "GPU"; // GPU can be used as well
Comment thread
songbell marked this conversation as resolved.
Outdated

ov::genai::LLMPipeline pipe(models_path, device);
ov::genai::GenerationConfig config;
Expand Down
67 changes: 67 additions & 0 deletions samples/python/text_generation/eagle_speculative_lm.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#!/usr/bin/env python3
# Copyright (C) 2024 Intel Corporation
# SPDX-License-Identifier: Apache-2.0

import argparse
import openvino_genai
import queue

def streamer(subword):
print(subword, end='', flush=True)
# Return flag corresponds whether generation should be stopped.
return openvino_genai.StreamingStatus.RUNNING

def main():
parser = argparse.ArgumentParser()
parser.add_argument('model_dir')
parser.add_argument('draft_model_dir')
parser.add_argument('prompt')
args = parser.parse_args()

# User can run main and draft model on different devices.
# Please, set device for main model in `openvino_genai.LLMPipeline` constructor and in openvino_genai.draft_model` for draft.
main_device = 'GPU' # CPU can be used as well
draft_device = 'GPU'
scheduler_config = openvino_genai.SchedulerConfig()
scheduler_config.dynamic_split_fuse = False # Eagle speculative decoding does not support dynamic_split_fuse mode
draft_model = openvino_genai.draft_model(args.draft_model_dir, draft_device)

pipe = openvino_genai.LLMPipeline(args.model_dir, main_device, scheduler_config = scheduler_config, draft_model=draft_model, eagle3_mode = True)

config = openvino_genai.GenerationConfig()
config.max_new_tokens = 100
# Speculative decoding generation parameters like `num_assistant_tokens` and `assistant_confidence_threshold` are mutually excluded
# add parameter to enable speculative decoding to generate `num_assistant_tokens` candidates by draft_model per iteration
config.num_assistant_tokens = 5
# add parameter to enable speculative decoding to generate candidates by draft_model while candidate probability is higher than `assistant_confidence_threshold`
# config.assistant_confidence_threshold = 0.4

# Since the streamer is set, the results will be printed
# every time a new token is generated and put into the streamer queue.
res = pipe.generate([args.prompt], config, streamer)
print()
if (res.extended_perf_metrics):
main_model_metrics = res.extended_perf_metrics.main_model_metrics
print(f"MAIN MODEL")
print(f" Generate time: {main_model_metrics.get_generate_duration().mean:.2f} ms" )
print(f" TTFT: {main_model_metrics.get_ttft().mean:.2f} ± {main_model_metrics.get_ttft().std:.2f} ms" )
print(f" TTST: {main_model_metrics.get_ttst().mean:.2f} ± {main_model_metrics.get_ttst().std:.2f} ms/token")
print(f" TPOT: {main_model_metrics.get_tpot().mean:.2f} ± {main_model_metrics.get_tpot().std:.2f} ms/iteration")
print(f" AVG Latency: {main_model_metrics.get_latency().mean:.2f} ± {main_model_metrics.get_latency().std:.2f} ms/token")
print(f" Num generated token: {main_model_metrics.get_num_generated_tokens()} tokens")
print(f" Total iteration number: {len(main_model_metrics.raw_metrics.m_durations)}")
print(f" Num accepted token: {res.extended_perf_metrics.get_num_accepted_tokens()} tokens")

draft_model_metrics = res.extended_perf_metrics.draft_model_metrics
print(f"DRAFT MODEL" )
print(f" Generate time: {draft_model_metrics.get_generate_duration().mean:.2f} ms" )
print(f" TTFT: {draft_model_metrics.get_ttft().mean:.2f} ms")
print(f" TTST: {draft_model_metrics.get_ttst().mean:.2f} ms/token")
print(f" TPOT: {draft_model_metrics.get_tpot().mean:.2f} ± {draft_model_metrics.get_tpot().std:.2f} ms/token")
print(f" AVG Latency: {draft_model_metrics.get_latency().mean:.2f} ± {draft_model_metrics.get_latency().std:.2f} ms/iteration")
print(f" Num generated token: {draft_model_metrics.get_num_generated_tokens()} tokens")
print(f" Total iteration number: {len(draft_model_metrics.raw_metrics.m_durations)}")
print()

if '__main__' == __name__:
main()
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,18 @@ class OPENVINO_GENAI_EXPORTS ContinuousBatchingPipeline {
class ContinuousBatchingImpl;

class ContinuousBatchingForSpeculativeDecodingImpl;
class ContinuousBatchingForEagleDecodingImpl;
class ContinuousBatchingForPromptLookupImpl;
class SpeculativeDecodingImpl;
class EagleDecodingImpl;
class PromptLookupImpl;

friend class ContinuousBatchingForSpeculativeDecodingImpl;

friend class ContinuousBatchingForPromptLookupImpl;
friend class ContinuousBatchingForEagleDecodingImpl;
Comment thread
songbell marked this conversation as resolved.
Outdated
friend class SpeculativeDecodingImpl;
friend class EagleDecodingImpl;
friend class PromptLookupImpl;

std::shared_ptr<IContinuousBatchingPipeline> m_impl;
Expand Down
6 changes: 6 additions & 0 deletions src/cpp/include/openvino/genai/llm_pipeline.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,12 @@ static constexpr ov::Property<bool> prompt_lookup{"prompt_lookup"};
*/
static constexpr ov::Property<bool> enable_save_ov_model{"enable_save_ov_model"};

/**
* @brief enable eagle3_mode property serves to activate eagle3 speculative decoding.
* Set `true` to activate this mode.
* And create LLMPipeline instance with this config.
*/
static constexpr ov::Property<bool> eagle3_mode{"eagle3_mode"};

} // namespace genai
} // namespace ov
2 changes: 1 addition & 1 deletion src/cpp/include/openvino/genai/perf_metrics.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ struct OPENVINO_GENAI_EXPORTS PerfMetrics {
MeanStdPair detokenization_duration = {-1.0f, -1.0f};

size_t num_generated_tokens;
size_t num_input_tokens;
size_t num_input_tokens = 0;

float get_load_time(); // Load time in ms.
size_t get_num_generated_tokens();
Expand Down
Loading
Loading