Skip to content

Commit e6a33c2

Browse files
authored
Merge branch 'main' into sukru/input-handler-protocol
2 parents 7b614e8 + b736767 commit e6a33c2

10 files changed

Lines changed: 35 additions & 126 deletions

File tree

swift/Sources/CoreAIDiffusionPipeline/Pipelines/Flux2Pipeline.swift

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ public struct Flux2Pipeline: DiffusionPipeline {
3737
private static let latentChannels = 128
3838
private static let textSeqLen = 512
3939
private static let defaultRopeTheta: Float = 2000.0
40+
private static let qwen3PadTokenId = 151643
4041

4142
/// FLUX.2 flow-matching timestep shift.
4243
///
@@ -113,6 +114,12 @@ public struct Flux2Pipeline: DiffusionPipeline {
113114
self.batchNormMean = batchNormMean
114115
self.batchNormVar = batchNormVar
115116
self.batchNormEps = batchNormEps
117+
118+
if tokenizer.convertTokenToId("<|endoftext|>") == nil {
119+
CLILogger.log(
120+
"⚠️ Flux2Pipeline: tokenizer has no <|endoftext|> token, using Qwen3 fallback pad ID",
121+
component: "Diffusion")
122+
}
116123
}
117124

118125
// MARK: - ResourceManaging
@@ -353,7 +360,7 @@ public struct Flux2Pipeline: DiffusionPipeline {
353360
// (diffusers 0.37.1, pipeline_flux2_klein.py `_get_qwen3_prompt_embeds`),
354361
// which uses pad_token. These ~490 padding tokens are fed to the DiT
355362
// UNMASKED, so the id must match the reference exactly.
356-
let padTokenId = tokenizer.convertTokenToId("<|endoftext|>") ?? 151643
363+
let padTokenId = tokenizer.convertTokenToId("<|endoftext|>") ?? Self.qwen3PadTokenId
357364

358365
while ids.count < seqLen {
359366
ids.append(padTokenId)

swift/Sources/CoreAILanguageModels/InferenceEngines/CoreAIPipelinedEngine.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -688,6 +688,7 @@ private struct EngineImpl: ~Copyable {
688688
// MARK: - Sampler
689689

690690
private mutating func getOrCreateSampler(for config: SamplingConfiguration) throws -> any MPSGraphSampler {
691+
let config = config.normalized()
691692
let temperature = config.temperature
692693

693694
if let existingSampler = cachedSampler, let existingTemp = cachedSamplerTemperature {

swift/Sources/CoreAILanguageModels/InferenceEngines/CoreAISequentialEngine.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -538,7 +538,7 @@ extension CoreAISequentialEngine.GenerationSequence {
538538
generationToken: GenerationToken
539539
) {
540540
self.engine = engine
541-
self.samplingConfiguration = samplingConfiguration
541+
self.samplingConfiguration = samplingConfiguration.normalized()
542542
self.returnsLogits = inferenceOptions.includeLogits
543543
self.forcedContinuation = inferenceOptions.forcedContinuation
544544
self.stopReasonStore = stopReasonStore

swift/Sources/CoreAILanguageModels/InferenceEngines/CoreAISequentialVLMEngine.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1009,7 +1009,7 @@ extension CoreAISequentialVLMEngine.GenerationSequence {
10091009
generationToken: GenerationToken
10101010
) {
10111011
self.engine = engine
1012-
self.samplingConfiguration = samplingConfiguration
1012+
self.samplingConfiguration = samplingConfiguration.normalized()
10131013
self.returnsLogits = inferenceOptions.includeLogits
10141014
self.forcedContinuation = inferenceOptions.forcedContinuation
10151015
self.stopReasonStore = stopReasonStore

swift/Sources/CoreAILanguageModels/ModelShapeConfig.swift

Lines changed: 0 additions & 106 deletions
This file was deleted.

swift/Sources/CoreAILanguageModels/Output/LogitsWriter.swift

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -308,31 +308,28 @@ public struct LogitsWriter {
308308
/// Handle all logits output based on provided options
309309
/// - Parameters:
310310
/// - logits: Array of logits for each generated token
311-
/// - generatedText: The generated text
311+
/// - generatedTokenIds: Token IDs produced during generation (one per logits vector)
312312
/// - tokenizer: Tokenizer for decoding token IDs
313313
/// - saveLogitsLength: Specifies whether to save top-K or full logits
314314
/// - saveJsonPath: Optional path to save logits as JSON
315315
/// - printToConsole: Whether to print top-5 to console
316316
public static func handleOutput<T: BinaryFloatingPoint>(
317317
logits: [[T]],
318-
generatedText: String,
318+
generatedTokenIds: [Int],
319319
tokenizer: any Tokenizer,
320320
saveLogitsLength: LogitsLength,
321321
saveJsonPath: String?,
322322
printToConsole: Bool
323323
) throws {
324-
// Decode generated text to get token IDs
325-
let generatedTokens = tokenizer.encode(text: generatedText)
326-
327324
// Token count must match logits count - each generation step produces one token and one logits vector
328-
guard generatedTokens.count == logits.count else {
325+
guard generatedTokenIds.count == logits.count else {
329326
throw LogitsWriterError.tokenCountMismatch(
330-
tokenCount: generatedTokens.count,
327+
tokenCount: generatedTokenIds.count,
331328
logitsCount: logits.count
332329
)
333330
}
334331

335-
let tokenCount = generatedTokens.count
332+
let tokenCount = generatedTokenIds.count
336333

337334
// Only build top-K array if we need it for printing or saving top-K
338335
let needsTopKArray = printToConsole || !saveLogitsLength.isFull
@@ -343,7 +340,7 @@ public struct LogitsWriter {
343340
if let jsonPath = saveJsonPath {
344341
try saveFullJSON(
345342
logits: logits,
346-
generatedTokens: generatedTokens,
343+
generatedTokens: generatedTokenIds,
347344
tokenizer: tokenizer,
348345
path: jsonPath
349346
)
@@ -355,8 +352,8 @@ public struct LogitsWriter {
355352
let topK = saveLogitsLength.topKForConsole
356353
for index in 0..<tokenCount {
357354
let logitVector = logits[index]
358-
let tokenId = Int32(generatedTokens[index])
359-
let tokenText = tokenizer.decode(tokens: [generatedTokens[index]])
355+
let tokenId = Int32(generatedTokenIds[index])
356+
let tokenText = tokenizer.decode(tokens: [generatedTokenIds[index]])
360357

361358
// Extract top-K logits
362359
let topLogits = extractTopK(

swift/Sources/CoreAILanguageModels/Samplers/SamplingConfiguration.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,14 @@ public struct SamplingConfiguration: Sendable, Equatable, Hashable {
226226
///
227227
/// - Returns: A new configuration with redundant settings removed.
228228
public func normalized() -> SamplingConfiguration {
229+
// topK=1 with temperature>0 is equivalent to greedy — promote it
230+
if let k = topK, k == 1, temperature > 0 {
231+
CLILogger.log(
232+
"⚠️ SamplingConfiguration: topK=1 normalized to greedy (temperature=0)",
233+
component: "Sampling")
234+
return .greedy
235+
}
236+
229237
let effectiveTopK: Int?
230238
let effectiveTopP: Double?
231239
let effectiveMinP: Double?

swift/Sources/CoreAILanguageModels/TextGeneration/TextGenerator.swift

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,13 +65,14 @@ public class TextGenerator {
6565
/// - prompt: Input text prompt
6666
/// - maxTokens: Maximum number of tokens to generate
6767
/// - stopSequences: Stop token sequences that halt generation. If nil, uses tokenizer's EOS tokens and common fallbacks.
68-
/// - Returns: Tuple containing generated text and array of logits for each token
68+
/// - Returns: Tuple containing generated text, token IDs, and array of logits for each token
6969
public func generateWithLogits(
7070
input: Input,
7171
maxTokens: Int = 50,
7272
stopSequences: StopSequences? = nil
73-
) async throws -> (text: String, logits: [[LogitsScalarType]]) {
73+
) async throws -> (text: String, tokenIds: [Int], logits: [[LogitsScalarType]]) {
7474
var textParts: [String] = []
75+
var allTokenIds: [Int] = []
7576
var allLogits: [[LogitsScalarType]] = []
7677

7778
// Use provided stop sequences, or create default ones from tokenizer
@@ -89,11 +90,12 @@ public class TextGenerator {
8990
for try await result in resultStream {
9091
textParts.append(result.text)
9192
if let logits = result.rawLogits {
93+
allTokenIds.append(Int(result.tokenId))
9294
allLogits.append(logits)
9395
}
9496
}
9597

96-
return (text: textParts.joined(), logits: allLogits)
98+
return (text: textParts.joined(), tokenIds: allTokenIds, logits: allLogits)
9799
}
98100

99101
/// Evaluate continuation probability (no generation)

swift/Sources/CoreAISpeech/MelSpectrogram.swift

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@ public struct MelConfig: Sendable {
1818
public let nMelBins: Int
1919
public let nFrames: Int
2020

21-
public var nSamples: Int { Int(sampleRate) * (nFrames * hopLength / Int(sampleRate / 100)) }
22-
2321
/// Whisper / Parakeet shared parameters.
2422
public static let whisper = MelConfig(
2523
sampleRate: 16_000, nFFT: 400, hopLength: 160, nMelBins: 128, nFrames: 3_000)

swift/Sources/Tools/llm-runner/LLMRunnerMain.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -637,6 +637,7 @@ struct LLMRunner: AsyncParsableCommand, Sendable {
637637
let needsLogits = saveLogits != nil || printLogits
638638
let generatedText: String
639639
var allLogits: [[LogitsScalarType]] = []
640+
var allTokenIds: [Int] = []
640641

641642
if needsLogits {
642643
// Generate with logits
@@ -646,6 +647,7 @@ struct LLMRunner: AsyncParsableCommand, Sendable {
646647
stopSequences: stopSequences
647648
)
648649
generatedText = result.text
650+
allTokenIds = result.tokenIds
649651
allLogits = result.logits
650652
} else {
651653
// Standard generation without logits
@@ -681,7 +683,7 @@ struct LLMRunner: AsyncParsableCommand, Sendable {
681683
if needsLogits && !allLogits.isEmpty {
682684
try LogitsWriter.handleOutput(
683685
logits: allLogits,
684-
generatedText: generatedOnly,
686+
generatedTokenIds: allTokenIds,
685687
tokenizer: tokenizer,
686688
saveLogitsLength: saveLogitsLength,
687689
saveJsonPath: saveLogits,

0 commit comments

Comments
 (0)