22// Licensed under the MIT License.
33
44#pragma once
5+
56#include " core/common/common.h"
67#include " core/providers/common.h"
8+ #include " core/providers/cpu/llm/rotary_embedding_int32_utils.h"
79
810namespace onnxruntime {
911namespace contrib {
1012namespace rotary_embedding_helper {
1113
14+ namespace detail {
15+ using onnxruntime::rotary_embedding_int32_utils::CheckedMulToInt32;
16+ using onnxruntime::rotary_embedding_int32_utils::NarrowNonNegativeToInt32;
17+ } // namespace detail
18+
1219// Parameters deduced from node attributes and inputs/outputs.
1320struct RotaryParameters {
1421 int batch_size; // Batch size used by input
@@ -73,20 +80,52 @@ Status CheckInputs(const T* input,
7380 }
7481
7582 // Get attributes from inputs
76- int batch_size = static_cast <int >(input_dims[0 ]);
77- int sequence_length = static_cast <int >(input_dims[1 ]);
78- int hidden_size = static_cast <int >(input_dims[2 ]);
83+ int batch_size = 0 ;
84+ int sequence_length = 0 ;
85+ int hidden_size = 0 ;
86+ int head_size = 0 ;
87+
88+ ORT_RETURN_IF_ERROR (detail::NarrowNonNegativeToInt32 (input_dims[0 ], " batch_size" , batch_size));
89+ ORT_RETURN_IF_ERROR (detail::NarrowNonNegativeToInt32 (input_dims[1 ], " sequence_length" , sequence_length));
90+ ORT_RETURN_IF_ERROR (detail::NarrowNonNegativeToInt32 (input_dims[2 ], " hidden_size" , hidden_size));
7991
8092 bool transposed = false ;
8193 if (input_dims.size () == 4 ) {
8294 // input is [batch, num_heads, seq, head_size]
83- sequence_length = static_cast <int >(input_dims[2 ]);
84- hidden_size = static_cast <int >(input_dims[1 ]) * static_cast <int >(input_dims[3 ]);
95+ ORT_RETURN_IF_ERROR (detail::NarrowNonNegativeToInt32 (input_dims[2 ], " sequence_length" , sequence_length));
96+ ORT_RETURN_IF_ERROR (detail::NarrowNonNegativeToInt32 (input_dims[1 ], " num_heads" , num_heads));
97+ ORT_RETURN_IF_ERROR (detail::NarrowNonNegativeToInt32 (input_dims[3 ], " head_size" , head_size));
98+ ORT_RETURN_IF_ERROR (detail::CheckedMulToInt32 (num_heads, head_size, " hidden_size" , hidden_size));
8599 transposed = true ;
100+ } else if (num_heads > 0 ) {
101+ if (hidden_size % num_heads != 0 ) {
102+ return ORT_MAKE_STATUS (ONNXRUNTIME , INVALID_ARGUMENT ,
103+ " RotaryEmbedding: hidden_size=" , hidden_size,
104+ " must be divisible by num_heads=" , num_heads,
105+ " for rank-3 input" );
106+ }
107+ head_size = static_cast <int >(hidden_size / num_heads);
108+ if (batch_size > 0 && sequence_length > 0 && hidden_size > 0 && head_size <= 0 ) {
109+ return ORT_MAKE_STATUS (ONNXRUNTIME , INVALID_ARGUMENT ,
110+ " RotaryEmbedding: head_size must be greater than 0 for non-empty rank-3 input" );
111+ }
112+ }
113+ int max_sequence_length = 0 ;
114+ ORT_RETURN_IF_ERROR (detail::NarrowNonNegativeToInt32 (cos_cache_dims[0 ], " max_sequence_length" , max_sequence_length));
115+ if (rotary_embedding_dim == 0 ) {
116+ int cache_width = 0 ;
117+ ORT_RETURN_IF_ERROR (detail::NarrowNonNegativeToInt32 (cos_cache_dims[1 ], " cache_width" , cache_width));
118+ if (head_size == 0 ) {
119+ ORT_RETURN_IF_ERROR (detail::CheckedMulToInt32 (cache_width, 2 , " head_size" , head_size));
120+ }
121+ } else {
122+ if (!transposed) {
123+ if (num_heads <= 0 ) {
124+ return ORT_MAKE_STATUS (ONNXRUNTIME , INVALID_ARGUMENT ,
125+ " RotaryEmbedding: num_heads must be greater than 0 for rank-3 input" );
126+ }
127+ }
86128 }
87- int max_sequence_length = static_cast <int >(cos_cache_dims[0 ]);
88- int head_size = rotary_embedding_dim == 0 ? static_cast <int >(cos_cache_dims[1 ]) * 2
89- : static_cast <int >(hidden_size / num_heads);
90129 if (rotary_embedding_dim > 0 && rotary_embedding_dim > head_size) {
91130 return ORT_MAKE_STATUS (ONNXRUNTIME , INVALID_ARGUMENT , " rotary_embedding_dim must be less than or equal to " ,
92131 " head_size" );
@@ -96,11 +135,16 @@ Status CheckInputs(const T* input,
96135
97136 // Check position_ids input shapes
98137 if (!onnxruntime::IsScalarOr1ElementVector (position_ids)) {
99- if (batch_size != static_cast <int >(position_ids_dims[0 ])) {
138+ int position_ids_batch = 0 ;
139+ int position_ids_sequence = 0 ;
140+ ORT_RETURN_IF_ERROR (detail::NarrowNonNegativeToInt32 (position_ids_dims[0 ], " position_ids_dim0" , position_ids_batch));
141+ ORT_RETURN_IF_ERROR (detail::NarrowNonNegativeToInt32 (position_ids_dims[1 ], " position_ids_dim1" , position_ids_sequence));
142+
143+ if (batch_size != position_ids_batch) {
100144 return ORT_MAKE_STATUS (ONNXRUNTIME , INVALID_ARGUMENT , " Input 'position_ids' dimension 0 should be of size " ,
101145 " batch_size, got " , position_ids_dims[0 ]);
102146 }
103- if (sequence_length != static_cast < int >(position_ids_dims[ 1 ]) ) {
147+ if (sequence_length != position_ids_sequence ) {
104148 return ORT_MAKE_STATUS (ONNXRUNTIME , INVALID_ARGUMENT , " Input 'position_ids' dimension 1 should be of size " ,
105149 " sequence_length, got " , position_ids_dims[1 ]);
106150 }
@@ -114,26 +158,44 @@ Status CheckInputs(const T* input,
114158 return ORT_MAKE_STATUS (ONNXRUNTIME , INVALID_ARGUMENT , " Input 'cos_cache' dimension 0 should be same as " ,
115159 " max_sequence_length, got " , cos_cache_dims[0 ]);
116160 }
117- if ((head_size / 2 ) != static_cast <int >(cos_cache_dims[1 ]) && (rotary_embedding_dim > 0 && (rotary_embedding_dim / 2 ) != static_cast <int >(cos_cache_dims[1 ]))) {
161+ if ((head_size / 2 ) != static_cast <int >(cos_cache_dims[1 ]) &&
162+ (rotary_embedding_dim <= 0 || (rotary_embedding_dim / 2 ) != static_cast <int >(cos_cache_dims[1 ]))) {
118163 return ORT_MAKE_STATUS (ONNXRUNTIME , INVALID_ARGUMENT , " Input 'cos_cache' dimension 1 should be same as " ,
119164 " head_size / 2 or rotary_embedding_dim / 2, got " , cos_cache_dims[1 ]);
120165 }
121166
122- num_heads = num_heads > 0 ? num_heads : static_cast <int >(hidden_size / head_size);
167+ if (num_heads <= 0 ) {
168+ if (head_size == 0 ) {
169+ if (batch_size == 0 || sequence_length == 0 || hidden_size == 0 ) {
170+ num_heads = 0 ;
171+ } else {
172+ return ORT_MAKE_STATUS (ONNXRUNTIME , INVALID_ARGUMENT ,
173+ " RotaryEmbedding: head_size must be greater than 0 when inferring num_heads" );
174+ }
175+ } else {
176+ if (hidden_size % head_size != 0 ) {
177+ return ORT_MAKE_STATUS (ONNXRUNTIME , INVALID_ARGUMENT ,
178+ " RotaryEmbedding: hidden_size=" , hidden_size,
179+ " must be divisible by inferred head_size=" , head_size,
180+ " when inferring num_heads" );
181+ }
182+ num_heads = static_cast <int >(hidden_size / head_size);
183+ }
184+ }
123185 // Calculate stride values
124186 int head_stride;
125187 int seq_stride;
126188 int batch_stride;
127189 if (transposed) {
128190 // Transposed input tensor shape is [batch, n_heads, seq_len, head_size]
129191 seq_stride = head_size;
130- head_stride = sequence_length * seq_stride;
131- batch_stride = num_heads * head_stride;
192+ ORT_RETURN_IF_ERROR ( detail::CheckedMulToInt32 ( sequence_length, seq_stride, " head_stride " , head_stride)) ;
193+ ORT_RETURN_IF_ERROR ( detail::CheckedMulToInt32 ( num_heads, head_stride, " batch_stride " , batch_stride)) ;
132194 } else {
133195 // Default input tensor shape is [batch, seq_len, hidden_size]
134196 head_stride = head_size;
135- seq_stride = num_heads * head_stride;
136- batch_stride = sequence_length * seq_stride;
197+ ORT_RETURN_IF_ERROR ( detail::CheckedMulToInt32 ( num_heads, head_stride, " seq_stride " , seq_stride)) ;
198+ ORT_RETURN_IF_ERROR ( detail::CheckedMulToInt32 ( sequence_length, seq_stride, " batch_stride " , batch_stride)) ;
137199 }
138200
139201 // Set rotary parameters
0 commit comments