@@ -80,17 +80,29 @@ public struct ObjectDetector {
8080
8181 // MARK: - Inference
8282
83- /// Warm up the backend (e.g. trigger Metal kernel compilation) with a dummy pass.
84- public func warmup( ) async throws {
83+ /// Warm up the backend (e.g. trigger Metal kernel compilation) with a dummy
84+ /// pass at the same `(B, H, W)` that subsequent `detect()` calls will use.
85+ /// For static-shape models the arguments are ignored — `planBatch` falls
86+ /// back to the descriptor's fixed dims.
87+ public func warmup( imageCount: Int = 1 , parameters: DetectionParameters = . default) async throws {
8588 guard case . ndArray( let imageDescriptor) = functionDescriptor. inputDescriptor ( of: imageInputName) else {
8689 throw DetectionRuntimeError . invalidConfiguration (
8790 " No array descriptor for image input ' \( imageInputName) ' "
8891 )
8992 }
90- let defaults = DetectionParameters ( )
91- let warmupShape = zip ( imageDescriptor. shape, [ 1 , 3 , defaults. inputHeight, defaults. inputWidth] )
92- . map { actual, fallback in actual >= 0 ? actual : fallback }
93- let resolved = imageDescriptor. resolvingDynamicDimensions ( warmupShape)
93+ let expectedShape = imageDescriptor. shape
94+ guard expectedShape. count == 4 else {
95+ throw DetectionRuntimeError . invalidConfiguration (
96+ " Expected 4-dimensional input shape, got \( expectedShape. count) "
97+ )
98+ }
99+ let plan = try Self . planBatch (
100+ expectedShape: expectedShape,
101+ imageCount: imageCount,
102+ parameters: parameters
103+ )
104+ let resolved = imageDescriptor. resolvingDynamicDimensions (
105+ [ plan. batch, 3 , plan. height, plan. width] )
94106 _ = try await function. run ( inputs: [ imageInputName: NDArray ( descriptor: resolved) ] )
95107 }
96108
@@ -142,7 +154,7 @@ public struct ObjectDetector {
142154
143155 let plan = try Self . planBatch (
144156 expectedShape: expectedShape,
145- imageSizes : images. map { CGSize ( width : $0 . width , height : $0 . height ) } ,
157+ imageCount : images. count ,
146158 parameters: parameters
147159 )
148160
@@ -249,29 +261,28 @@ public struct ObjectDetector {
249261
250262 /// Resolve the concrete `(B, H, W)` to bind the model with, given the
251263 /// model's expected shape (which may contain `-1` for dynamic dims), the
252- /// list of input image sizes , and the user's parameter overrides.
264+ /// number of input images , and the user's parameter overrides.
253265 ///
254266 /// Resolution rules:
255- /// - **Batch**: always `images.count `. A static-batch model must match.
267+ /// - **Batch**: always `imageCount `. A static-batch model must match.
256268 /// - **Spatial dims**: a dynamic `-1` dim is filled from
257269 /// `parameters.inputHeight` / `inputWidth`. A static dim is taken
258270 /// from the model descriptor (the parameters' values are ignored for
259271 /// that axis).
260272 static func planBatch(
261273 expectedShape: [ Int ] ,
262- imageSizes : [ CGSize ] ,
274+ imageCount : Int ,
263275 parameters: DetectionParameters
264276 ) throws -> BatchPlan {
265- guard !imageSizes . isEmpty else {
266- throw DetectionRuntimeError . invalidConfiguration ( " planBatch requires at least one image " )
277+ guard imageCount >= 1 else {
278+ throw DetectionRuntimeError . invalidConfiguration ( " planBatch requires imageCount >= 1 " )
267279 }
268280
269- // Resolve batch from image count; verify it matches a static batch dim.
270- let targetBatch = imageSizes. count
281+ // Verify image count matches a static batch dim.
271282 let batchExpected = expectedShape [ 0 ]
272- if batchExpected >= 0 && batchExpected != targetBatch {
283+ if batchExpected >= 0 && batchExpected != imageCount {
273284 throw DetectionRuntimeError . invalidConfiguration (
274- " Model expects fixed batch= \( batchExpected) but caller supplied \( targetBatch ) image(s) "
285+ " Model expects fixed batch= \( batchExpected) but caller supplied \( imageCount ) image(s) "
275286 )
276287 }
277288
@@ -280,7 +291,7 @@ public struct ObjectDetector {
280291 let height = heightExpected < 0 ? parameters. inputHeight : heightExpected
281292 let width = widthExpected < 0 ? parameters. inputWidth : widthExpected
282293
283- return BatchPlan ( batch: targetBatch , height: height, width: width)
294+ return BatchPlan ( batch: imageCount , height: height, width: width)
284295 }
285296
286297 // MARK: - Name Discovery
0 commit comments