v2: add defer enc.endEncoding() to all Metal encoders
This commit is contained in:
@@ -106,24 +106,32 @@ public final class EmbeddingGemmaModel: @unchecked Sendable {
|
|||||||
guard !tokens.isEmpty else { return [] }
|
guard !tokens.isEmpty else { return [] }
|
||||||
|
|
||||||
let seqLen = tokens.count, hs = config.hiddenSize
|
let seqLen = tokens.count, hs = config.hiddenSize
|
||||||
|
print(" embed: seqLen=\(seqLen)")
|
||||||
|
|
||||||
// Use single command buffer for entire forward pass
|
// Use single command buffer for entire forward pass
|
||||||
let cmdBuf = engine.commandQueue.makeCommandBuffer()!
|
let cmdBuf = engine.commandQueue.makeCommandBuffer()!
|
||||||
|
|
||||||
// Embedding lookup
|
// Embedding lookup
|
||||||
|
print(" embed: lookupEmbeddings")
|
||||||
let inputBuf = try lookupEmbeddings(tokens: tokens, cmdBuf: cmdBuf)
|
let inputBuf = try lookupEmbeddings(tokens: tokens, cmdBuf: cmdBuf)
|
||||||
|
print(" embed: lookupEmbeddings done")
|
||||||
|
|
||||||
// Forward through layers
|
// Forward through layers
|
||||||
var hidden = inputBuf
|
var hidden = inputBuf
|
||||||
for idx in 0..<config.numHiddenLayers {
|
for idx in 0..<config.numHiddenLayers {
|
||||||
|
if idx % 6 == 0 { print(" embed: layer \(idx)/\(config.numHiddenLayers)") }
|
||||||
hidden = try forwardLayer(hidden: hidden, layerIdx: idx, seqLen: seqLen, cmdBuf: cmdBuf)
|
hidden = try forwardLayer(hidden: hidden, layerIdx: idx, seqLen: seqLen, cmdBuf: cmdBuf)
|
||||||
}
|
}
|
||||||
|
print(" embed: all layers done")
|
||||||
|
|
||||||
// Final norm
|
// Final norm
|
||||||
|
print(" embed: final norm")
|
||||||
let output = try applyRmsNorm(input: hidden, weight: finalNorm, count: seqLen * hs, cmdBuf: cmdBuf)
|
let output = try applyRmsNorm(input: hidden, weight: finalNorm, count: seqLen * hs, cmdBuf: cmdBuf)
|
||||||
|
print(" embed: committing")
|
||||||
|
|
||||||
cmdBuf.commit()
|
cmdBuf.commit()
|
||||||
cmdBuf.waitUntilCompleted()
|
cmdBuf.waitUntilCompleted()
|
||||||
|
print(" embed: completed")
|
||||||
|
|
||||||
// Readback
|
// Readback
|
||||||
let data = engine.readFloats(from: output, count: seqLen * hs)
|
let data = engine.readFloats(from: output, count: seqLen * hs)
|
||||||
@@ -171,6 +179,7 @@ public final class EmbeddingGemmaModel: @unchecked Sendable {
|
|||||||
let seqLen = tokens.count, hs = config.hiddenSize
|
let seqLen = tokens.count, hs = config.hiddenSize
|
||||||
let buf = engine.device.makeBuffer(length: seqLen * hs * 4)!
|
let buf = engine.device.makeBuffer(length: seqLen * hs * 4)!
|
||||||
let enc = cmdBuf.makeComputeCommandEncoder()!
|
let enc = cmdBuf.makeComputeCommandEncoder()!
|
||||||
|
defer { enc.endEncoding() }
|
||||||
let pso = try engine.pipeline(named: "lookup_embeddings")
|
let pso = try engine.pipeline(named: "lookup_embeddings")
|
||||||
enc.setComputePipelineState(pso)
|
enc.setComputePipelineState(pso)
|
||||||
enc.setBuffer(embedTokens, offset: 0, index: 0)
|
enc.setBuffer(embedTokens, offset: 0, index: 0)
|
||||||
@@ -182,13 +191,13 @@ public final class EmbeddingGemmaModel: @unchecked Sendable {
|
|||||||
enc.setBytes(&v, length: 4, index: 5)
|
enc.setBytes(&v, length: 4, index: 5)
|
||||||
enc.dispatchThreads(MTLSize(width: seqLen, height: 1, depth: 1),
|
enc.dispatchThreads(MTLSize(width: seqLen, height: 1, depth: 1),
|
||||||
threadsPerThreadgroup: MTLSize(width: min(256, seqLen), height: 1, depth: 1))
|
threadsPerThreadgroup: MTLSize(width: min(256, seqLen), height: 1, depth: 1))
|
||||||
enc.endEncoding()
|
|
||||||
return buf
|
return buf
|
||||||
}
|
}
|
||||||
|
|
||||||
private func applyRmsNorm(input: MTLBuffer, weight: MTLBuffer, count: Int, cmdBuf: MTLCommandBuffer) throws -> MTLBuffer {
|
private func applyRmsNorm(input: MTLBuffer, weight: MTLBuffer, count: Int, cmdBuf: MTLCommandBuffer) throws -> MTLBuffer {
|
||||||
let output = engine.device.makeBuffer(length: count * 4)!
|
let output = engine.device.makeBuffer(length: count * 4)!
|
||||||
let enc = cmdBuf.makeComputeCommandEncoder()!
|
let enc = cmdBuf.makeComputeCommandEncoder()!
|
||||||
|
defer { enc.endEncoding() }
|
||||||
let pso = try engine.pipeline(named: "rms_norm")
|
let pso = try engine.pipeline(named: "rms_norm")
|
||||||
enc.setComputePipelineState(pso)
|
enc.setComputePipelineState(pso)
|
||||||
enc.setBuffer(input, offset: 0, index: 0)
|
enc.setBuffer(input, offset: 0, index: 0)
|
||||||
@@ -199,12 +208,12 @@ public final class EmbeddingGemmaModel: @unchecked Sendable {
|
|||||||
enc.setBytes(&e, length: 4, index: 4)
|
enc.setBytes(&e, length: 4, index: 4)
|
||||||
enc.dispatchThreads(MTLSize(width: count, height: 1, depth: 1),
|
enc.dispatchThreads(MTLSize(width: count, height: 1, depth: 1),
|
||||||
threadsPerThreadgroup: MTLSize(width: min(256, count), height: 1, depth: 1))
|
threadsPerThreadgroup: MTLSize(width: min(256, count), height: 1, depth: 1))
|
||||||
enc.endEncoding()
|
|
||||||
return output
|
return output
|
||||||
}
|
}
|
||||||
|
|
||||||
private func matmulSeq(input: MTLBuffer, weight: MTLBuffer, output: MTLBuffer, m: Int, k: Int, n: Int, cmdBuf: MTLCommandBuffer) throws {
|
private func matmulSeq(input: MTLBuffer, weight: MTLBuffer, output: MTLBuffer, m: Int, k: Int, n: Int, cmdBuf: MTLCommandBuffer) throws {
|
||||||
let enc = cmdBuf.makeComputeCommandEncoder()!
|
let enc = cmdBuf.makeComputeCommandEncoder()!
|
||||||
|
defer { enc.endEncoding() }
|
||||||
let pso = try engine.pipeline(named: "matmul_f32")
|
let pso = try engine.pipeline(named: "matmul_f32")
|
||||||
enc.setComputePipelineState(pso)
|
enc.setComputePipelineState(pso)
|
||||||
for i in 0..<m {
|
for i in 0..<m {
|
||||||
@@ -220,11 +229,11 @@ public final class EmbeddingGemmaModel: @unchecked Sendable {
|
|||||||
enc.dispatchThreads(MTLSize(width: n, height: 1, depth: 1),
|
enc.dispatchThreads(MTLSize(width: n, height: 1, depth: 1),
|
||||||
threadsPerThreadgroup: MTLSize(width: min(256, n), height: 1, depth: 1))
|
threadsPerThreadgroup: MTLSize(width: min(256, n), height: 1, depth: 1))
|
||||||
}
|
}
|
||||||
enc.endEncoding()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func eltwiseAdd(a: MTLBuffer, b: MTLBuffer, output: MTLBuffer, count: Int, cmdBuf: MTLCommandBuffer) throws {
|
private func eltwiseAdd(a: MTLBuffer, b: MTLBuffer, output: MTLBuffer, count: Int, cmdBuf: MTLCommandBuffer) throws {
|
||||||
let enc = cmdBuf.makeComputeCommandEncoder()!
|
let enc = cmdBuf.makeComputeCommandEncoder()!
|
||||||
|
defer { enc.endEncoding() }
|
||||||
let pso = try engine.pipeline(named: "eltwise_add")
|
let pso = try engine.pipeline(named: "eltwise_add")
|
||||||
enc.setComputePipelineState(pso)
|
enc.setComputePipelineState(pso)
|
||||||
enc.setBuffer(a, offset: 0, index: 0)
|
enc.setBuffer(a, offset: 0, index: 0)
|
||||||
@@ -234,11 +243,11 @@ public final class EmbeddingGemmaModel: @unchecked Sendable {
|
|||||||
enc.setBytes(&c, length: 4, index: 3)
|
enc.setBytes(&c, length: 4, index: 3)
|
||||||
enc.dispatchThreads(MTLSize(width: count, height: 1, depth: 1),
|
enc.dispatchThreads(MTLSize(width: count, height: 1, depth: 1),
|
||||||
threadsPerThreadgroup: MTLSize(width: min(256, count), height: 1, depth: 1))
|
threadsPerThreadgroup: MTLSize(width: min(256, count), height: 1, depth: 1))
|
||||||
enc.endEncoding()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func geluMul(gate: MTLBuffer, up: MTLBuffer, output: MTLBuffer, count: Int, cmdBuf: MTLCommandBuffer) throws {
|
private func geluMul(gate: MTLBuffer, up: MTLBuffer, output: MTLBuffer, count: Int, cmdBuf: MTLCommandBuffer) throws {
|
||||||
let enc = cmdBuf.makeComputeCommandEncoder()!
|
let enc = cmdBuf.makeComputeCommandEncoder()!
|
||||||
|
defer { enc.endEncoding() }
|
||||||
let pso = try engine.pipeline(named: "gelu_mul_kernel")
|
let pso = try engine.pipeline(named: "gelu_mul_kernel")
|
||||||
enc.setComputePipelineState(pso)
|
enc.setComputePipelineState(pso)
|
||||||
enc.setBuffer(gate, offset: 0, index: 0)
|
enc.setBuffer(gate, offset: 0, index: 0)
|
||||||
@@ -248,11 +257,11 @@ public final class EmbeddingGemmaModel: @unchecked Sendable {
|
|||||||
enc.setBytes(&c, length: 4, index: 3)
|
enc.setBytes(&c, length: 4, index: 3)
|
||||||
enc.dispatchThreads(MTLSize(width: count, height: 1, depth: 1),
|
enc.dispatchThreads(MTLSize(width: count, height: 1, depth: 1),
|
||||||
threadsPerThreadgroup: MTLSize(width: min(256, count), height: 1, depth: 1))
|
threadsPerThreadgroup: MTLSize(width: min(256, count), height: 1, depth: 1))
|
||||||
enc.endEncoding()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func applyRoPE(q: MTLBuffer, k: MTLBuffer, seqLen: Int, headDim: Int, numHeads: Int, cmdBuf: MTLCommandBuffer) throws {
|
private func applyRoPE(q: MTLBuffer, k: MTLBuffer, seqLen: Int, headDim: Int, numHeads: Int, cmdBuf: MTLCommandBuffer) throws {
|
||||||
let enc = cmdBuf.makeComputeCommandEncoder()!
|
let enc = cmdBuf.makeComputeCommandEncoder()!
|
||||||
|
defer { enc.endEncoding() }
|
||||||
let pso = try engine.pipeline(named: "apply_rope")
|
let pso = try engine.pipeline(named: "apply_rope")
|
||||||
enc.setComputePipelineState(pso)
|
enc.setComputePipelineState(pso)
|
||||||
enc.setBuffer(q, offset: 0, index: 0)
|
enc.setBuffer(q, offset: 0, index: 0)
|
||||||
@@ -265,11 +274,11 @@ public final class EmbeddingGemmaModel: @unchecked Sendable {
|
|||||||
enc.setBytes(&rt, length: 4, index: 5)
|
enc.setBytes(&rt, length: 4, index: 5)
|
||||||
enc.dispatchThreads(MTLSize(width: numHeads * headDim / 2, height: 1, depth: 1),
|
enc.dispatchThreads(MTLSize(width: numHeads * headDim / 2, height: 1, depth: 1),
|
||||||
threadsPerThreadgroup: MTLSize(width: min(256, numHeads * headDim / 2), height: 1, depth: 1))
|
threadsPerThreadgroup: MTLSize(width: min(256, numHeads * headDim / 2), height: 1, depth: 1))
|
||||||
enc.endEncoding()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func bidirectionalAttention(q: MTLBuffer, k: MTLBuffer, v: MTLBuffer, output: MTLBuffer, seqLen: Int, cmdBuf: MTLCommandBuffer) throws {
|
private func bidirectionalAttention(q: MTLBuffer, k: MTLBuffer, v: MTLBuffer, output: MTLBuffer, seqLen: Int, cmdBuf: MTLCommandBuffer) throws {
|
||||||
let enc = cmdBuf.makeComputeCommandEncoder()!
|
let enc = cmdBuf.makeComputeCommandEncoder()!
|
||||||
|
defer { enc.endEncoding() }
|
||||||
let pso = try engine.pipeline(named: "bidirectional_sliding_attn")
|
let pso = try engine.pipeline(named: "bidirectional_sliding_attn")
|
||||||
enc.setComputePipelineState(pso)
|
enc.setComputePipelineState(pso)
|
||||||
enc.setBuffer(q, offset: 0, index: 0)
|
enc.setBuffer(q, offset: 0, index: 0)
|
||||||
@@ -289,7 +298,6 @@ public final class EmbeddingGemmaModel: @unchecked Sendable {
|
|||||||
enc.setThreadgroupMemoryLength(tgMem, index: 0)
|
enc.setThreadgroupMemoryLength(tgMem, index: 0)
|
||||||
enc.dispatchThreads(MTLSize(width: seqLen * config.numAttentionHeads, height: 1, depth: 1),
|
enc.dispatchThreads(MTLSize(width: seqLen * config.numAttentionHeads, height: 1, depth: 1),
|
||||||
threadsPerThreadgroup: MTLSize(width: min(256, seqLen * config.numAttentionHeads), height: 1, depth: 1))
|
threadsPerThreadgroup: MTLSize(width: min(256, seqLen * config.numAttentionHeads), height: 1, depth: 1))
|
||||||
enc.endEncoding()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func forwardLayer(hidden: MTLBuffer, layerIdx: Int, seqLen: Int, cmdBuf: MTLCommandBuffer) throws -> MTLBuffer {
|
private func forwardLayer(hidden: MTLBuffer, layerIdx: Int, seqLen: Int, cmdBuf: MTLCommandBuffer) throws -> MTLBuffer {
|
||||||
|
|||||||
Reference in New Issue
Block a user