@@ -266,17 +266,22 @@ trtllmGenContextPreprocess(torch::Tensor qkv_input, torch::Tensor workspace, tor
266266 int64_t const position_embedding_type, double const bmm1_scale, double const bmm2_scale,
267267 int64_t const attention_chunk_size, bool const fp8_context_fmha, bool const paged_context_fmha,
268268 bool const is_mla_enable, int64_t const multi_processor_count, int64_t const total_num_blocks,
269- int64_t const kv_factor, bool const need_build_kv_cache_metadata)
269+ int64_t const kv_factor, bool const need_build_kv_cache_metadata, std::optional<torch::Tensor> cross_kv,
270+ bool const cross_attention)
270271{
271272 (void ) bmm2_scale;
272273 TORCH_CHECK (host_kv_cache_pool_pointers.has_value (), " host_kv_cache_pool_pointers is required." );
273274 TORCH_CHECK (host_kv_cache_pool_mapping.has_value (), " host_kv_cache_pool_mapping is required." );
274275 TORCH_CHECK (kv_cache_block_offsets.has_value (), " kv_cache_block_offsets is required." );
276+ TORCH_CHECK (!cross_attention || !is_mla_enable, " trtllm-gen cross attention does not support MLA." );
275277
276- bool const separateQKvOutput = paged_context_fmha || fp8_context_fmha;
278+ bool const separateQKvOutput = paged_context_fmha || fp8_context_fmha || cross_attention ;
277279 auto const qkvScalarType = qkv_input.scalar_type ();
278280 auto const qkvElementSize = static_cast <size_t >(qkv_input.element_size ());
279281 auto const quantMode = tensorrt_llm::common::QuantMode (static_cast <uint32_t >(kv_cache_quant_mode));
282+ int64_t const effectiveMaxAttentionWindowSize = cross_attention ? max_past_kv_length : max_attention_window_size;
283+ int64_t const effectiveCyclicAttentionWindowSize
284+ = cross_attention ? max_past_kv_length : cyclic_attention_window_size;
280285 auto const views = [&]
281286 {
282287 auto const layout = TrtllmAttentionWorkspaceManager::buildContextLayout (
@@ -307,8 +312,8 @@ trtllmGenContextPreprocess(torch::Tensor qkv_input, torch::Tensor workspace, tor
307312 decoderInfoParams.fmhaBmm2Scale = ptrs.fmhaBmm2ScalePtr ;
308313 decoderInfoParams.batchSize = static_cast <int >(batch_size);
309314 decoderInfoParams.maxQSeqLength = static_cast <int >(input_seq_length);
310- decoderInfoParams.maxEncoderQSeqLength = 0 ;
311- decoderInfoParams.attentionWindowSize = static_cast <int >(cyclic_attention_window_size );
315+ decoderInfoParams.maxEncoderQSeqLength = cross_attention ? static_cast < int >(max_past_kv_length) : 0 ;
316+ decoderInfoParams.attentionWindowSize = static_cast <int >(effectiveCyclicAttentionWindowSize );
312317 decoderInfoParams.numTokens = static_cast <int >(num_tokens);
313318 decoderInfoParams.removePadding = true ;
314319 decoderInfoParams.attentionMaskType = static_cast <AttentionMaskType>(mask_type);
@@ -333,12 +338,13 @@ trtllmGenContextPreprocess(torch::Tensor qkv_input, torch::Tensor workspace, tor
333338 {
334339 return buildPagedKvCacheBuffers (kv_cache_block_offsets, host_kv_cache_pool_pointers,
335340 host_kv_cache_pool_mapping, quantMode, layer_idx, batch_size, tokens_per_block, num_kv_heads, head_size,
336- cyclic_attention_window_size, max_attention_window_size, 0 , 0 , is_mla_enable, qkvElementSize);
341+ effectiveCyclicAttentionWindowSize, effectiveMaxAttentionWindowSize, 0 , 0 , is_mla_enable,
342+ qkvElementSize);
337343 }();
338344
339345 QKVPreprocessingParams<void , KVBlockArray> qkvParams{};
340346 qkvParams.qkv_input = qkv_input.data_ptr ();
341- qkvParams.cross_kv_input = nullptr ;
347+ qkvParams.cross_kv_input = optPtr< void >(cross_kv) ;
342348 qkvParams.quantized_qkv_output = nullptr ;
343349 qkvParams.q_output = ptrs.qBufPtr ;
344350 qkvParams.kv_cache_buffer = kvArrays.kvCacheBuffer ;
@@ -353,8 +359,9 @@ trtllmGenContextPreprocess(torch::Tensor qkv_input, torch::Tensor workspace, tor
353359 qkvParams.logn_scaling = nullptr ;
354360 qkvParams.tokens_info = ptrs.tokensInfoPtr ;
355361 qkvParams.seq_lens = static_cast <int *>(context_lengths.data_ptr ());
356- qkvParams.cache_seq_lens = static_cast <int *>(sequence_lengths.data_ptr ());
357- qkvParams.encoder_seq_lens = nullptr ;
362+ qkvParams.cache_seq_lens = cross_attention ? static_cast <int *>(context_lengths.data_ptr ())
363+ : static_cast <int *>(sequence_lengths.data_ptr ());
364+ qkvParams.encoder_seq_lens = cross_attention ? static_cast <int *>(sequence_lengths.data_ptr ()) : nullptr ;
358365 qkvParams.cu_seq_lens = ptrs.cuQSeqlensPtr ;
359366 qkvParams.cu_kv_seq_lens = ptrs.cuKvSeqlensPtr ;
360367 qkvParams.sparse_kv_offsets = nullptr ;
@@ -367,11 +374,11 @@ trtllmGenContextPreprocess(torch::Tensor qkv_input, torch::Tensor workspace, tor
367374 qkvParams.batch_size = static_cast <int >(batch_size);
368375 qkvParams.max_input_seq_len = static_cast <int >(input_seq_length);
369376 qkvParams.max_kv_seq_len = static_cast <int >(max_past_kv_length);
370- qkvParams.cyclic_kv_cache_len = static_cast <int >(cyclic_attention_window_size );
377+ qkvParams.cyclic_kv_cache_len = static_cast <int >(effectiveCyclicAttentionWindowSize );
371378 qkvParams.token_num = static_cast <int >(num_tokens);
372379 qkvParams.remove_padding = true ;
373380 qkvParams.is_last_chunk = attention_chunk_size == 0 || input_seq_length == max_past_kv_length;
374- qkvParams.cross_attention = false ;
381+ qkvParams.cross_attention = cross_attention ;
375382 qkvParams.head_num = static_cast <int >(num_heads);
376383 qkvParams.kv_head_num = static_cast <int >(num_kv_heads);
377384 qkvParams.qheads_per_kv_head = static_cast <int >(num_heads / num_kv_heads);
@@ -438,7 +445,9 @@ trtllmGenContextPreprocess(torch::Tensor qkv_input, torch::Tensor workspace, tor
438445
439446 // FlashInfer paged context launches trtllm-gen with multi-CTA-KV mode disabled, so it does not
440447 // consume the counter slab reserved at the head of the workspace.
441- auto const windowLeft = computeWindowLeft (cyclic_attention_window_size, max_past_kv_length, attention_chunk_size);
448+ auto const windowLeft = cross_attention
449+ ? int64_t {-1 }
450+ : computeWindowLeft (cyclic_attention_window_size, max_past_kv_length, attention_chunk_size);
442451 return {qProcessed, kvPool, blockTables, kvScalePool, views.fmhaBmm1Scale , views.fmhaBmm2Scale ,
443452 views.trtllmGenWorkspace , views.cuQSeqlens , views.cuKvSeqlens , input_seq_length, max_past_kv_length,
444453 windowLeft};
@@ -577,17 +586,22 @@ trtllmGenGenerationPreprocess(torch::Tensor qkv_input, torch::Tensor workspace,
577586 int64_t const rotary_embedding_max_positions, int64_t const position_embedding_type, double const bmm1_scale,
578587 double const bmm2_scale, bool const fp8_context_fmha, int64_t const predicted_tokens_per_seq,
579588 int64_t const attention_chunk_size, int64_t const multi_processor_count, int64_t const total_num_blocks,
580- int64_t const kv_factor, bool const need_build_kv_cache_metadata)
589+ int64_t const kv_factor, bool const need_build_kv_cache_metadata, bool const cross_attention )
581590{
582591 TORCH_CHECK (host_kv_cache_pool_pointers.has_value (), " host_kv_cache_pool_pointers is required." );
583592 TORCH_CHECK (host_kv_cache_pool_mapping.has_value (), " host_kv_cache_pool_mapping is required." );
584593 TORCH_CHECK (kv_cache_block_offsets.has_value (), " kv_cache_block_offsets is required." );
585594 (void ) bmm2_scale;
586595
587596 bool const isMultiTokenGen = spec_decoding_generation_lengths.has_value () && predicted_tokens_per_seq > 1 ;
597+ TORCH_CHECK (
598+ !cross_attention || !isMultiTokenGen, " trtllm-gen cross attention does not support multi-token generation." );
588599 auto const qkvScalarType = qkv_input.scalar_type ();
589600 auto const qkvElementSize = static_cast <size_t >(qkv_input.element_size ());
590601 auto const quantMode = tensorrt_llm::common::QuantMode (static_cast <uint32_t >(kv_cache_quant_mode));
602+ int64_t const effectiveMaxAttentionWindowSize = cross_attention ? max_past_kv_length : max_attention_window_size;
603+ int64_t const effectiveCyclicAttentionWindowSize
604+ = cross_attention ? max_past_kv_length : cyclic_attention_window_size;
591605 auto const views = [&]
592606 {
593607 auto const layout = TrtllmAttentionWorkspaceManager::buildGenerationLayout (
@@ -617,7 +631,7 @@ trtllmGenGenerationPreprocess(torch::Tensor qkv_input, torch::Tensor workspace,
617631 decoderInfoParams.fmhaBmm2Scale = nullptr ;
618632 decoderInfoParams.batchSize = static_cast <int >(batch_beam);
619633 decoderInfoParams.maxQSeqLength = static_cast <int >(input_seq_length);
620- decoderInfoParams.maxEncoderQSeqLength = 0 ;
634+ decoderInfoParams.maxEncoderQSeqLength = cross_attention ? static_cast < int >(max_past_kv_length) : 0 ;
621635 decoderInfoParams.attentionWindowSize = 0 ;
622636 decoderInfoParams.sinkTokenLength = 0 ;
623637 decoderInfoParams.numTokens = static_cast <int >(num_tokens);
@@ -655,7 +669,8 @@ trtllmGenGenerationPreprocess(torch::Tensor qkv_input, torch::Tensor workspace,
655669 {
656670 return buildPagedKvCacheBuffers (kv_cache_block_offsets, host_kv_cache_pool_pointers,
657671 host_kv_cache_pool_mapping, quantMode, layer_idx, batch_beam, tokens_per_block, num_kv_heads, head_size,
658- cyclic_attention_window_size, max_attention_window_size, 1 , seq_offset, false , qkvElementSize);
672+ effectiveCyclicAttentionWindowSize, effectiveMaxAttentionWindowSize, 1 , seq_offset, false ,
673+ qkvElementSize);
659674 }();
660675
661676 QKVPreprocessingParams<void , KVBlockArray> qkvParams{};
@@ -676,7 +691,7 @@ trtllmGenGenerationPreprocess(torch::Tensor qkv_input, torch::Tensor workspace,
676691 qkvParams.tokens_info = isMultiTokenGen ? views.tokensInfoPtr : nullptr ;
677692 qkvParams.seq_lens = isMultiTokenGen ? optPtr<int >(spec_decoding_generation_lengths) : nullptr ;
678693 qkvParams.cache_seq_lens = static_cast <int *>(sequence_lengths.data_ptr ());
679- qkvParams.encoder_seq_lens = nullptr ;
694+ qkvParams.encoder_seq_lens = cross_attention ? static_cast < int *>(sequence_lengths. data_ptr ()) : nullptr ;
680695 qkvParams.cu_seq_lens = buildDecoderInfoNeeded ? views.cuSeqlensPtr : nullptr ;
681696 qkvParams.cu_kv_seq_lens = buildDecoderInfoNeeded ? views.cuKvSeqlensPtr : nullptr ;
682697 qkvParams.sparse_kv_offsets = nullptr ;
@@ -690,11 +705,11 @@ trtllmGenGenerationPreprocess(torch::Tensor qkv_input, torch::Tensor workspace,
690705 qkvParams.batch_size = static_cast <int >(batch_beam);
691706 qkvParams.max_input_seq_len = static_cast <int >(input_seq_length);
692707 qkvParams.max_kv_seq_len = static_cast <int >(max_past_kv_length);
693- qkvParams.cyclic_kv_cache_len = static_cast <int >(cyclic_attention_window_size );
708+ qkvParams.cyclic_kv_cache_len = static_cast <int >(effectiveCyclicAttentionWindowSize );
694709 qkvParams.token_num = static_cast <int >(num_tokens);
695710 qkvParams.remove_padding = true ;
696711 qkvParams.is_last_chunk = false ;
697- qkvParams.cross_attention = false ;
712+ qkvParams.cross_attention = cross_attention ;
698713 qkvParams.head_num = static_cast <int >(num_heads);
699714 qkvParams.kv_head_num = static_cast <int >(num_kv_heads);
700715 qkvParams.qheads_per_kv_head = static_cast <int >(num_heads / num_kv_heads);
@@ -751,7 +766,9 @@ trtllmGenGenerationPreprocess(torch::Tensor qkv_input, torch::Tensor workspace,
751766
752767 auto qProcessed = views.qBuf .view ({num_tokens, num_heads, head_size});
753768
754- auto const windowLeft = computeWindowLeft (cyclic_attention_window_size, max_past_kv_length, attention_chunk_size);
769+ auto const windowLeft = cross_attention
770+ ? int64_t {-1 }
771+ : computeWindowLeft (cyclic_attention_window_size, max_past_kv_length, attention_chunk_size);
755772 return {qProcessed, kvPool, blockTables, kvScalePool, views.bmm1Scale , views.bmm2Scale , views.trtllmGenWorkspace ,
756773 cuSeqlens, input_seq_length, max_past_kv_length, windowLeft, isMultiTokenGen};
757774}
0 commit comments