Skip to content

Commit 5cf3709

Browse files
author
Aegis-AI
committed
feat: expose embedTokens, lmHead, callCapturing for DFlash conformance on Llama/Qwen3/Qwen3MoE
Enables Sources/SwiftLM/{Llama,Qwen3,Qwen3MoE}+DFlash.swift to conform to DFlashTargetModel by exposing: - LlamaModelInner.embedTokens (public) - LlamaModel.lmHead (public) - LlamaModel.callCapturing(_:cache:captureLayerIDs:) - Qwen3ModelInner.embedTokens + layers (public) - Qwen3Model.lmHead (public) - Qwen3Model.callCapturing(_:cache:captureLayerIDs:) - Qwen3MoEModelInner.embedTokens + layers (public) - Qwen3MoEModel.lmHead (public) - Qwen3MoEModel.callCapturing(_:cache:captureLayerIDs:) Authored by: 0xClandestine (original design in unreachable commit b5762584)
1 parent ef3318e commit 5cf3709

3 files changed

Lines changed: 53 additions & 8 deletions

File tree

Libraries/MLXLLM/Models/Llama.swift

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ class LlamaTransformerBlock: Module {
120120

121121
public class LlamaModelInner: Module, LayerPartitionable {
122122

123-
@ModuleInfo(key: "embed_tokens") var embedTokens: Embedding
123+
@ModuleInfo(key: "embed_tokens") public var embedTokens: Embedding
124124

125125
let layers: [LlamaTransformerBlock]
126126
let norm: RMSNorm
@@ -162,7 +162,7 @@ public class LlamaModel: Module, LLMModel, KVCacheDimensionProvider {
162162

163163
public let model: LlamaModelInner
164164

165-
@ModuleInfo(key: "lm_head") var lmHead: Linear?
165+
@ModuleInfo(key: "lm_head") public var lmHead: Linear?
166166

167167
public init(_ args: LlamaConfiguration) {
168168
self.vocabularySize = args.vocabularySize
@@ -182,6 +182,21 @@ public class LlamaModel: Module, LLMModel, KVCacheDimensionProvider {
182182
}
183183
}
184184

185+
public func callCapturing(
186+
_ inputs: MLXArray, cache: [KVCache?]? = nil, captureLayerIDs: Set<Int>
187+
) -> (MLXArray, [Int: MLXArray]) {
188+
var h = model.embedTokens(inputs)
189+
let kvCache = cache?.compactMap { $0 }
190+
let mask = createAttentionMask(h: h, cache: kvCache?.first)
191+
var captured: [Int: MLXArray] = [:]
192+
for (i, layer) in model.layers.enumerated() {
193+
h = layer(h, mask: mask, cache: kvCache?[i])
194+
if captureLayerIDs.contains(i) { captured[i] = h }
195+
}
196+
h = model.norm(h)
197+
return (h, captured)
198+
}
199+
185200
public func sanitize(weights: [String: MLXArray]) -> [String: MLXArray] {
186201
// Remove unused precomputed rotary frequencies
187202
weights.filter {

Libraries/MLXLLM/Models/Qwen3.swift

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -145,9 +145,9 @@ public class Qwen3ModelInner: Module, LayerPartitionable {
145145
// LayerPartitionable
146146
public var gpuLayerCount: Int?
147147
public var totalLayerCount: Int { layers.count }
148-
@ModuleInfo(key: "embed_tokens") var embedTokens: Embedding
148+
@ModuleInfo(key: "embed_tokens") public var embedTokens: Embedding
149149

150-
fileprivate let layers: [Qwen3TransformerBlock]
150+
public let layers: [Qwen3TransformerBlock]
151151
let norm: RMSNorm
152152

153153
public init(_ args: Qwen3Configuration) {
@@ -185,7 +185,7 @@ public class Qwen3Model: Module, LLMModel, KVCacheDimensionProvider {
185185
public let model: Qwen3ModelInner
186186
let configuration: Qwen3Configuration
187187

188-
@ModuleInfo(key: "lm_head") var lmHead: Linear?
188+
@ModuleInfo(key: "lm_head") public var lmHead: Linear?
189189

190190
public init(_ args: Qwen3Configuration) {
191191
self.configuration = args
@@ -208,6 +208,21 @@ public class Qwen3Model: Module, LLMModel, KVCacheDimensionProvider {
208208
return out
209209
}
210210

211+
public func callCapturing(
212+
_ inputs: MLXArray, cache: [KVCache?]? = nil, captureLayerIDs: Set<Int>
213+
) -> (MLXArray, [Int: MLXArray]) {
214+
var h = model.embedTokens(inputs)
215+
let kvCache = cache?.compactMap { $0 }
216+
let mask = createAttentionMask(h: h, cache: kvCache?.first)
217+
var captured: [Int: MLXArray] = [:]
218+
for (i, layer) in model.layers.enumerated() {
219+
h = layer(h, mask: mask, cache: kvCache?[i])
220+
if captureLayerIDs.contains(i) { captured[i] = h }
221+
}
222+
h = model.norm(h)
223+
return (h, captured)
224+
}
225+
211226
public func sanitize(weights: [String: MLXArray]) -> [String: MLXArray] {
212227
var weights = weights
213228

Libraries/MLXLLM/Models/Qwen3MoE.swift

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -196,9 +196,9 @@ public class Qwen3MoEModelInner: Module, LayerPartitionable, StreamableMoE {
196196
// StreamableMoE
197197
public var streamExperts: Bool = false
198198

199-
@ModuleInfo(key: "embed_tokens") var embedTokens: Embedding
199+
@ModuleInfo(key: "embed_tokens") public var embedTokens: Embedding
200200

201-
fileprivate let layers: [Qwen3MoeDecoderLayer]
201+
public let layers: [Qwen3MoeDecoderLayer]
202202
let norm: RMSNorm
203203
let args: Qwen3MoEConfiguration
204204

@@ -238,7 +238,7 @@ public class Qwen3MoEModel: Module, LLMModel, KVCacheDimensionProvider {
238238
public let model: Qwen3MoEModelInner
239239
let configuration: Qwen3MoEConfiguration
240240

241-
@ModuleInfo(key: "lm_head") var lmHead: Linear?
241+
@ModuleInfo(key: "lm_head") public var lmHead: Linear?
242242

243243
public init(_ args: Qwen3MoEConfiguration) {
244244
self.configuration = args
@@ -261,6 +261,21 @@ public class Qwen3MoEModel: Module, LLMModel, KVCacheDimensionProvider {
261261
return out
262262
}
263263

264+
public func callCapturing(
265+
_ inputs: MLXArray, cache: [KVCache?]? = nil, captureLayerIDs: Set<Int>
266+
) -> (MLXArray, [Int: MLXArray]) {
267+
var h = model.embedTokens(inputs)
268+
let kvCache = cache?.compactMap { $0 }
269+
let mask = createAttentionMask(h: h, cache: kvCache?.first)
270+
var captured: [Int: MLXArray] = [:]
271+
for (i, layer) in model.layers.enumerated() {
272+
h = layer(h, mask: mask, cache: kvCache?[i])
273+
if captureLayerIDs.contains(i) { captured[i] = h }
274+
}
275+
h = model.norm(h)
276+
return (h, captured)
277+
}
278+
264279
public func sanitize(weights: [String: MLXArray]) -> [String: MLXArray] {
265280
var sanitizedWeights = weights
266281

0 commit comments

Comments
 (0)