@@ -54,12 +54,15 @@ constexpr const char* kDecodeMethod = "decode";
5454
5555constexpr const char * kMaxPrefillChunk = " get_max_prefill_chunk" ;
5656constexpr const char * kMinPrefillChunk = " get_min_prefill_chunk" ;
57+ constexpr const char * kUseSampling = " use_sampling" ;
5758
5859Result<uint64_t > read_sampled_token (
5960 const executorch::aten::Tensor& output,
60- float temperature) {
61+ float temperature,
62+ bool use_sampling) {
6163#ifdef EXECUTORCH_BUILD_CUDA
6264 (void )temperature;
65+ (void )use_sampling;
6366 const void * ptr = output.const_data_ptr ();
6467 cudaPointerAttributes attrs{};
6568 const bool on_device = cudaPointerGetAttributes (&attrs, ptr) == cudaSuccess &&
@@ -98,6 +101,9 @@ Result<uint64_t> read_sampled_token(
98101 static_cast <int >(output.scalar_type ()));
99102 return Error::InvalidArgument;
100103#else
104+ if (use_sampling) {
105+ return static_cast <uint64_t >(output.const_data_ptr <int64_t >()[0 ]);
106+ }
101107 return static_cast <uint64_t >(
102108 logits_to_token (output, temperature < 0 .0f ? 0 .0f : temperature));
103109#endif
@@ -257,6 +263,17 @@ class Gemma4_31BSession : public LLMSession {
257263 auto temp_host =
258264 from_blob (&temp_val_, {1 }, executorch::aten::ScalarType::Float);
259265 temp_tensor_dev_ = clone_tensor_ptr_to (temp_host, cuda_device_);
266+ #endif
267+ #ifdef EXECUTORCH_BUILD_MLX
268+ if (auto it = metadata_.find (kUseSampling ); it != metadata_.end ()) {
269+ use_sampling_ = it->second != 0 ;
270+ }
271+ temp_tensor_mlx_ =
272+ from_blob (&temp_val_mlx_, {}, executorch::aten::ScalarType::Float);
273+ top_p_tensor_ =
274+ from_blob (&top_p_val_, {}, executorch::aten::ScalarType::Float);
275+ seed_tensor_ =
276+ from_blob (&seed_val_, {}, executorch::aten::ScalarType::Long);
260277#endif
261278 }
262279
@@ -278,15 +295,27 @@ class Gemma4_31BSession : public LLMSession {
278295 }
279296 float first_token_temp = temperature_;
280297 if (initial_sampling != nullptr ) {
281- if (initial_sampling->top_p != 1 .0f || initial_sampling->top_k != 0 ||
282- initial_sampling->seed != 0 ) {
298+ if (initial_sampling->top_k != 0 ) {
299+ ET_LOG (Error, " prefill_tokens: top_k is not implemented" );
300+ return Error::NotSupported;
301+ }
302+ if (!use_sampling_ &&
303+ (initial_sampling->top_p != 1 .0f || initial_sampling->seed != 0 )) {
283304 ET_LOG (
284305 Error,
285- " Gemma4_31BSession: only temperature is supported; top_p/top_k/seed "
286- " are not implemented " );
306+ " prefill_tokens: top_p/seed require a sampling model "
307+ " (export with --sample); only temperature is supported otherwise " );
287308 return Error::NotSupported;
288309 }
289310 first_token_temp = initial_sampling->temperature ;
311+ if (use_sampling_) {
312+ if (!valid_top_p (initial_sampling->top_p )) {
313+ ET_LOG (Error, " prefill_tokens: top_p must be in (0, 1]" );
314+ return Error::InvalidArgument;
315+ }
316+ top_p_ = initial_sampling->top_p ;
317+ seed_ = initial_sampling->seed ;
318+ }
290319 }
291320 if (!valid_temperature (first_token_temp)) {
292321 ET_LOG (Error, " prefill_tokens: temperature must be -1 or in [0, 2]" );
@@ -326,15 +355,24 @@ class Gemma4_31BSession : public LLMSession {
326355 offset += chunk;
327356 }
328357 prev_decode_token_ = tokens.back ();
358+ #ifdef EXECUTORCH_BUILD_MLX
359+ if (use_sampling_) {
360+ seed_ += 1 ;
361+ }
362+ #endif
329363 return Error::Ok;
330364 }
331365
332366 Result<DecodeResult> decode_one (const SamplingConfig& sampling) override {
333- if (sampling.top_p != 1 .0f || sampling.top_k != 0 || sampling.seed != 0 ) {
367+ if (sampling.top_k != 0 ) {
368+ ET_LOG (Error, " Gemma4_31BSession: top_k is not implemented" );
369+ return Error::NotSupported;
370+ }
371+ if (!use_sampling_ && (sampling.top_p != 1 .0f || sampling.seed != 0 )) {
334372 ET_LOG (
335373 Error,
336- " Gemma4_31BSession: only temperature is supported; top_p/top_k/seed "
337- " are not implemented " );
374+ " Gemma4_31BSession: top_p/seed require a sampling model "
375+ " (export with --sample); only temperature is supported otherwise " );
338376 return Error::NotSupported;
339377 }
340378 if (!valid_temperature (sampling.temperature )) {
@@ -346,6 +384,13 @@ class Gemma4_31BSession : public LLMSession {
346384 InvalidState,
347385 " decode_one requires a pending token; call prefill_tokens() first" );
348386 temperature_ = sampling.temperature ;
387+ if (use_sampling_) {
388+ if (!valid_top_p (sampling.top_p )) {
389+ ET_LOG (Error, " decode_one: top_p must be in (0, 1]" );
390+ return Error::InvalidArgument;
391+ }
392+ top_p_ = sampling.top_p ;
393+ }
349394
350395 if (stop_.load (std::memory_order_relaxed)) {
351396 return DecodeResult{0 , " " , /* is_eos=*/ false , /* is_terminal=*/ true };
@@ -393,13 +438,26 @@ class Gemma4_31BSession : public LLMSession {
393438#else
394439 inputs.push_back (EValue (decode_tokens_));
395440 inputs.push_back (EValue (decode_pos_));
441+ #ifdef EXECUTORCH_BUILD_MLX
442+ if (use_sampling_) {
443+ set_sampling_inputs (temperature_, top_p_, seed_);
444+ inputs.push_back (EValue (temp_tensor_mlx_));
445+ inputs.push_back (EValue (top_p_tensor_));
446+ inputs.push_back (EValue (seed_tensor_));
447+ }
448+ #endif
396449#endif
397450 auto sampled =
398451 run_locked (kDecodeMethod , inputs, temperature_, /* sync_after=*/ false );
399452 ET_CHECK_OK_OR_RETURN_ERROR (sampled.error ());
400453 pending_ = sampled.get ();
401454 prev_decode_token_ = token;
402455 pos_ += 1 ;
456+ #ifdef EXECUTORCH_BUILD_MLX
457+ if (use_sampling_) {
458+ seed_ += 1 ;
459+ }
460+ #endif
403461 return DecodeResult{
404462 token, std::move (text_piece), /* is_eos=*/ false , /* is_terminal=*/ false };
405463 }
@@ -425,6 +483,18 @@ class Gemma4_31BSession : public LLMSession {
425483 return temperature == -1 .0f || (temperature >= 0 .0f && temperature <= 2 .0f );
426484 }
427485
486+ static bool valid_top_p (float top_p) {
487+ return top_p > 0 .0f && top_p <= 1 .0f ;
488+ }
489+
490+ #ifdef EXECUTORCH_BUILD_MLX
491+ void set_sampling_inputs (float temp, float top_p, uint64_t seed) {
492+ temp_val_mlx_ = (temp < 0 .0f ) ? 0 .0f : temp;
493+ top_p_val_ = top_p;
494+ seed_val_ = static_cast <int64_t >(seed);
495+ }
496+ #endif
497+
428498 Result<uint64_t >
429499 run_prefill_chunk (const uint64_t * tokens, int64_t T, float temperature) {
430500 std::vector<int64_t > token_data (tokens, tokens + T);
@@ -457,6 +527,14 @@ class Gemma4_31BSession : public LLMSession {
457527 (T >= min_prefill_chunk_) ? kPrefillMethod : kDecodeMethod ;
458528#else
459529 const char * method = kPrefillMethod ;
530+ #endif
531+ #ifdef EXECUTORCH_BUILD_MLX
532+ if (use_sampling_) {
533+ set_sampling_inputs (temperature, top_p_, seed_);
534+ inputs.push_back (EValue (temp_tensor_mlx_));
535+ inputs.push_back (EValue (top_p_tensor_));
536+ inputs.push_back (EValue (seed_tensor_));
537+ }
460538#endif
461539 return run_locked (method, inputs, temperature, /* sync_after=*/ true );
462540 }
@@ -560,7 +638,7 @@ class Gemma4_31BSession : public LLMSession {
560638 : module_->execute (method, inputs);
561639 ET_CHECK_OK_OR_RETURN_ERROR (res.error ());
562640 const auto & out_tensor = res.get ()[0 ].toTensor ();
563- auto sampled = read_sampled_token (out_tensor, temperature);
641+ auto sampled = read_sampled_token (out_tensor, temperature, use_sampling_ );
564642 ET_CHECK_OK_OR_RETURN_ERROR (sampled.error ());
565643#ifdef EXECUTORCH_BUILD_CUDA
566644 ET_CHECK_OK_OR_RETURN_ERROR (
@@ -592,6 +670,10 @@ class Gemma4_31BSession : public LLMSession {
592670 float temperature_ = -1 .0f ;
593671 std::atomic<bool > stop_{false };
594672
673+ bool use_sampling_ = false ;
674+ float top_p_ = 1 .0f ;
675+ uint64_t seed_ = 0 ;
676+
595677 int64_t decode_token_data_[1 ] = {0 };
596678 int64_t decode_pos_data_[1 ] = {0 };
597679 TensorPtr decode_tokens_;
@@ -609,6 +691,14 @@ class Gemma4_31BSession : public LLMSession {
609691 TensorPtr decode_pos_dev_;
610692 TensorPtr temp_tensor_dev_;
611693#endif
694+ #ifdef EXECUTORCH_BUILD_MLX
695+ float temp_val_mlx_ = 0 .0f ;
696+ float top_p_val_ = 1 .0f ;
697+ int64_t seed_val_ = 0 ;
698+ TensorPtr temp_tensor_mlx_;
699+ TensorPtr top_p_tensor_;
700+ TensorPtr seed_tensor_;
701+ #endif
612702};
613703
614704} // namespace
@@ -655,6 +745,12 @@ Result<std::unique_ptr<Gemma4_31BEngine>> Gemma4_31BEngine::create(
655745 metadata[kMaxPrefillChunk ] = max_prefill_chunk;
656746 }
657747
748+ #ifdef EXECUTORCH_BUILD_MLX
749+ if (auto get_result = meta_module->get (kUseSampling ); get_result.ok ()) {
750+ metadata[kUseSampling ] = get_result->toScalar ().to <int64_t >();
751+ }
752+ #endif
753+
658754 int64_t min_prefill_chunk = 1 ;
659755#ifdef EXECUTORCH_BUILD_CUDA
660756 min_prefill_chunk = 5 ;
0 commit comments