@@ -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,13 @@ Result<uint64_t> read_sampled_token(
98101 static_cast <int >(output.scalar_type ()));
99102 return Error::InvalidArgument;
100103#else
104+ if (use_sampling) {
105+ ET_CHECK_OR_RETURN_ERROR (
106+ output.scalar_type () == executorch::aten::ScalarType::Long,
107+ InvalidProgram,
108+ " read_sampled_token: use_sampling set but forward output is not Long" );
109+ return static_cast <uint64_t >(output.const_data_ptr <int64_t >()[0 ]);
110+ }
101111 return static_cast <uint64_t >(
102112 logits_to_token (output, temperature < 0 .0f ? 0 .0f : temperature));
103113#endif
@@ -291,6 +301,19 @@ class Gemma4_31BSession : public LLMSession {
291301 auto temp_host =
292302 from_blob (&temp_val_, {1 }, executorch::aten::ScalarType::Float);
293303 temp_tensor_dev_ = clone_tensor_ptr_to (temp_host, cuda_device_);
304+ #endif
305+ #ifdef EXECUTORCH_BUILD_MLX
306+ if (auto it = metadata_.find (kUseSampling ); it != metadata_.end ()) {
307+ use_sampling_ = it->second != 0 ;
308+ }
309+ temp_tensor_mlx_ =
310+ from_blob (&temp_val_mlx_, {}, executorch::aten::ScalarType::Float);
311+ top_k_tensor_ =
312+ from_blob (&top_k_val_, {}, executorch::aten::ScalarType::Long);
313+ top_p_tensor_ =
314+ from_blob (&top_p_val_, {}, executorch::aten::ScalarType::Float);
315+ seed_tensor_ =
316+ from_blob (&seed_val_, {}, executorch::aten::ScalarType::Long);
294317#endif
295318 }
296319
@@ -312,15 +335,25 @@ class Gemma4_31BSession : public LLMSession {
312335 }
313336 float first_token_temp = temperature_;
314337 if (initial_sampling != nullptr ) {
315- if (initial_sampling->top_p != 1 .0f || initial_sampling->top_k != 0 ||
316- initial_sampling->seed != 0 ) {
338+ if (!use_sampling_ &&
339+ (initial_sampling->top_k != 0 || initial_sampling->top_p != 1 .0f ||
340+ initial_sampling->seed != 0 )) {
317341 ET_LOG (
318342 Error,
319- " Gemma4_31BSession: only temperature is supported; top_p/top_k/seed "
320- " are not implemented " );
343+ " prefill_tokens: top_k/top_p/seed require a sampling model "
344+ " (export with --sample); only temperature is supported otherwise " );
321345 return Error::NotSupported;
322346 }
323347 first_token_temp = initial_sampling->temperature ;
348+ if (use_sampling_) {
349+ if (!valid_top_p (initial_sampling->top_p )) {
350+ ET_LOG (Error, " prefill_tokens: top_p must be in (0, 1]" );
351+ return Error::InvalidArgument;
352+ }
353+ top_k_ = initial_sampling->top_k ;
354+ top_p_ = initial_sampling->top_p ;
355+ seed_ = initial_sampling->seed ;
356+ }
324357 }
325358 if (!valid_temperature (first_token_temp)) {
326359 ET_LOG (Error, " prefill_tokens: temperature must be -1 or in [0, 2]" );
@@ -360,15 +393,21 @@ class Gemma4_31BSession : public LLMSession {
360393 offset += chunk;
361394 }
362395 prev_decode_token_ = tokens.back ();
396+ #ifdef EXECUTORCH_BUILD_MLX
397+ if (use_sampling_) {
398+ seed_ += 1 ;
399+ }
400+ #endif
363401 return Error::Ok;
364402 }
365403
366404 Result<DecodeResult> decode_one (const SamplingConfig& sampling) override {
367- if (sampling.top_p != 1 .0f || sampling.top_k != 0 || sampling.seed != 0 ) {
405+ if (!use_sampling_ &&
406+ (sampling.top_k != 0 || sampling.top_p != 1 .0f || sampling.seed != 0 )) {
368407 ET_LOG (
369408 Error,
370- " Gemma4_31BSession: only temperature is supported; top_p/top_k/seed "
371- " are not implemented " );
409+ " Gemma4_31BSession: top_k/top_p/seed require a sampling model "
410+ " (export with --sample); only temperature is supported otherwise " );
372411 return Error::NotSupported;
373412 }
374413 if (!valid_temperature (sampling.temperature )) {
@@ -380,6 +419,14 @@ class Gemma4_31BSession : public LLMSession {
380419 InvalidState,
381420 " decode_one requires a pending token; call prefill_tokens() first" );
382421 temperature_ = sampling.temperature ;
422+ if (use_sampling_) {
423+ if (!valid_top_p (sampling.top_p )) {
424+ ET_LOG (Error, " decode_one: top_p must be in (0, 1]" );
425+ return Error::InvalidArgument;
426+ }
427+ top_k_ = sampling.top_k ;
428+ top_p_ = sampling.top_p ;
429+ }
383430
384431 if (stop_.load (std::memory_order_relaxed)) {
385432 return DecodeResult{0 , " " , /* is_eos=*/ false , /* is_terminal=*/ true };
@@ -427,13 +474,27 @@ class Gemma4_31BSession : public LLMSession {
427474#else
428475 inputs.push_back (EValue (decode_tokens_));
429476 inputs.push_back (EValue (decode_pos_));
477+ #ifdef EXECUTORCH_BUILD_MLX
478+ if (use_sampling_) {
479+ set_sampling_inputs (temperature_, top_k_, top_p_, seed_);
480+ inputs.push_back (EValue (temp_tensor_mlx_));
481+ inputs.push_back (EValue (top_k_tensor_));
482+ inputs.push_back (EValue (top_p_tensor_));
483+ inputs.push_back (EValue (seed_tensor_));
484+ }
485+ #endif
430486#endif
431487 auto sampled =
432488 run_locked (kDecodeMethod , inputs, temperature_, /* sync_after=*/ false );
433489 ET_CHECK_OK_OR_RETURN_ERROR (sampled.error ());
434490 pending_ = sampled.get ();
435491 prev_decode_token_ = token;
436492 pos_ += 1 ;
493+ #ifdef EXECUTORCH_BUILD_MLX
494+ if (use_sampling_) {
495+ seed_ += 1 ;
496+ }
497+ #endif
437498 return DecodeResult{
438499 token, std::move (text_piece), /* is_eos=*/ false , /* is_terminal=*/ false };
439500 }
@@ -459,6 +520,20 @@ class Gemma4_31BSession : public LLMSession {
459520 return temperature == -1 .0f || (temperature >= 0 .0f && temperature <= 2 .0f );
460521 }
461522
523+ static bool valid_top_p (float top_p) {
524+ return top_p > 0 .0f && top_p <= 1 .0f ;
525+ }
526+
527+ #ifdef EXECUTORCH_BUILD_MLX
528+ void
529+ set_sampling_inputs (float temp, int64_t top_k, float top_p, uint64_t seed) {
530+ temp_val_mlx_ = (temp < 0 .0f ) ? 0 .0f : temp;
531+ top_k_val_ = (top_k <= 0 ) ? INT64_MAX : top_k; // 0/neg = keep all
532+ top_p_val_ = top_p;
533+ seed_val_ = static_cast <int64_t >(seed);
534+ }
535+ #endif
536+
462537 Result<uint64_t >
463538 run_prefill_chunk (const uint64_t * tokens, int64_t T, float temperature) {
464539 std::vector<int64_t > token_data (tokens, tokens + T);
@@ -491,6 +566,15 @@ class Gemma4_31BSession : public LLMSession {
491566 (T >= min_prefill_chunk_) ? kPrefillMethod : kDecodeMethod ;
492567#else
493568 const char * method = kPrefillMethod ;
569+ #endif
570+ #ifdef EXECUTORCH_BUILD_MLX
571+ if (use_sampling_) {
572+ set_sampling_inputs (temperature, top_k_, top_p_, seed_);
573+ inputs.push_back (EValue (temp_tensor_mlx_));
574+ inputs.push_back (EValue (top_k_tensor_));
575+ inputs.push_back (EValue (top_p_tensor_));
576+ inputs.push_back (EValue (seed_tensor_));
577+ }
494578#endif
495579 return run_locked (method, inputs, temperature, /* sync_after=*/ true );
496580 }
@@ -594,7 +678,7 @@ class Gemma4_31BSession : public LLMSession {
594678 : module_->execute (method, inputs);
595679 ET_CHECK_OK_OR_RETURN_ERROR (res.error ());
596680 const auto & out_tensor = res.get ()[0 ].toTensor ();
597- auto sampled = read_sampled_token (out_tensor, temperature);
681+ auto sampled = read_sampled_token (out_tensor, temperature, use_sampling_ );
598682 ET_CHECK_OK_OR_RETURN_ERROR (sampled.error ());
599683#ifdef EXECUTORCH_BUILD_CUDA
600684 ET_CHECK_OK_OR_RETURN_ERROR (
@@ -626,6 +710,11 @@ class Gemma4_31BSession : public LLMSession {
626710 float temperature_ = -1 .0f ;
627711 std::atomic<bool > stop_{false };
628712
713+ bool use_sampling_ = false ;
714+ int64_t top_k_ = 0 ; // 0 = off (keep all); mapped to INT64_MAX on-device
715+ float top_p_ = 1 .0f ;
716+ uint64_t seed_ = 0 ;
717+
629718 int64_t decode_token_data_[1 ] = {0 };
630719 int64_t decode_pos_data_[1 ] = {0 };
631720 TensorPtr decode_tokens_;
@@ -643,6 +732,16 @@ class Gemma4_31BSession : public LLMSession {
643732 TensorPtr decode_pos_dev_;
644733 TensorPtr temp_tensor_dev_;
645734#endif
735+ #ifdef EXECUTORCH_BUILD_MLX
736+ float temp_val_mlx_ = 0 .0f ;
737+ int64_t top_k_val_ = INT64_MAX ;
738+ float top_p_val_ = 1 .0f ;
739+ int64_t seed_val_ = 0 ;
740+ TensorPtr temp_tensor_mlx_;
741+ TensorPtr top_k_tensor_;
742+ TensorPtr top_p_tensor_;
743+ TensorPtr seed_tensor_;
744+ #endif
646745};
647746
648747} // namespace
@@ -689,6 +788,12 @@ Result<std::unique_ptr<Gemma4_31BEngine>> Gemma4_31BEngine::create(
689788 metadata[kMaxPrefillChunk ] = max_prefill_chunk;
690789 }
691790
791+ #ifdef EXECUTORCH_BUILD_MLX
792+ if (auto get_result = meta_module->get (kUseSampling ); get_result.ok ()) {
793+ metadata[kUseSampling ] = get_result->toScalar ().to <int64_t >();
794+ }
795+ #endif
796+
692797 int64_t min_prefill_chunk = 1 ;
693798#ifdef EXECUTORCH_BUILD_CUDA
694799 min_prefill_chunk = 5 ;
0 commit comments