Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,17 @@ public actor CoreAIDiffusionModelFunction {
return result
}
}

/// Infer the sequence length from the first input's shape (dim 1).
/// Returns nil if the model isn't loaded or has no rank-2 input.
public func inferSequenceLength() async throws -> Int? {
let descs = try await inputDescriptors
guard let desc = descs.values.first, desc.shape.count >= 2 else {
return nil
}
let dim = desc.shape[1]
return dim > 0 ? dim : nil
}
}

// MARK: - Errors
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,13 +113,15 @@ extension PipelineDescriptor {
throw PipelineLoadError.missingComponent("text_encoder")
}

let textEncoderSeqLength = try await textEncoderFunction.inferSequenceLength() ?? 77

let textEncoder = CoreAITextEncoder(
function: textEncoderFunction,
tokenize: { text in
let (_, ids) = tokenizer.tokenize(input: text, minCount: 77)
let (_, ids) = tokenizer.tokenize(input: text, minCount: textEncoderSeqLength)
return ids.map(Int32.init)
},
maxLength: 77
maxLength: textEncoderSeqLength
)

let denoiser = CoreAIDenoiser(function: unetFunction)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,9 +172,10 @@ public struct StableDiffusionPipeline: DiffusionPipeline {
// MARK: - Private Helpers

private func encodeText(_ text: String) async throws -> [Float] {
let tokenize = components.textEncoder.tokenize
let ids = tokenize(text)
return try await components.textEncoder.function.run(intInputs: [(ids, [1, ids.count])])
let output = try await components.textEncoder.encode(text)
let shape = output.hiddenStates.shape
let count = shape.reduce(1, *)
return readNDArray(output.hiddenStates, as: Float.self, count: count)
}

private func runDenoiser(
Expand Down
33 changes: 33 additions & 0 deletions swift/Tests/DiffusionPipelineTests/DiffusionPipelineTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,36 @@ struct DiffusionPipelineTests {
}
}
}

@Suite("TextEncoder tokenize padding")
struct TextEncoderTokenizeTests {
@Test("Tokenize closure pads short input to maxLength")
func padsShortInput() {
let maxLength = 77
let tokenize: @Sendable (String) -> [Int32] = { _ in
var ids = [Int32](1...10)
if ids.count < maxLength {
ids += [Int32](repeating: 0, count: maxLength - ids.count)
}
return ids
}
let ids = tokenize("short prompt")
#expect(ids.count == 77)
#expect(ids.last == 0)
}

@Test("Tokenize closure truncates long input to maxLength")
func truncatesLongInput() {
let maxLength = 77
let tokenize: @Sendable (String) -> [Int32] = { _ in
var ids = [Int32](1...100)
if ids.count > maxLength {
ids = Array(ids.prefix(maxLength))
}
return ids
}
let ids = tokenize("very long prompt that produces many tokens")
#expect(ids.count == 77)
#expect(ids[76] == 77)
}
}