diff --git a/Package.resolved b/Package.resolved index b689a691..0b86bc46 100644 --- a/Package.resolved +++ b/Package.resolved @@ -19,6 +19,15 @@ "version" : "1.3.1" } }, + { + "identity" : "llama.swift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/mattt/llama.swift", + "state" : { + "revision" : "716419d4d7aa542fce301e809cde7234c68ddbc6", + "version" : "2.10549.0" + } + }, { "identity" : "partialjsondecoder", "kind" : "remoteSourceControl", diff --git a/Sources/AnyLanguageModel/Models/LlamaLanguageModel.swift b/Sources/AnyLanguageModel/Models/LlamaLanguageModel.swift index 6bcd8045..fc73ea50 100644 --- a/Sources/AnyLanguageModel/Models/LlamaLanguageModel.swift +++ b/Sources/AnyLanguageModel/Models/LlamaLanguageModel.swift @@ -192,6 +192,25 @@ import Foundation /// The path to the GGUF model file. public let modelPath: String + /// The number of model layers to offload to the GPU. + /// + /// A negative value offloads all layers, and `0` runs entirely on the CPU. + public let gpuLayers: Int32 + + /// The default GPU layer count for the current platform. + /// + /// All layers are offloaded by default: the prebuilt llama.cpp binaries + /// ship with Metal enabled and the shader library embedded. The simulator + /// defaults to CPU-only execution, which remains the reliable + /// configuration there. + public static var defaultGPULayerCount: Int32 { + #if targetEnvironment(simulator) + return 0 + #else + return -1 + #endif + } + /// The context size for the model. /// /// - Important: This property is deprecated. @@ -425,8 +444,11 @@ import Foundation /// /// - Parameters: /// - modelPath: The path to the GGUF model file. - public init(modelPath: String) { + /// - gpuLayers: The number of model layers to offload to the GPU. + /// Defaults to ``defaultGPULayerCount``. + public init(modelPath: String, gpuLayers: Int32 = LlamaLanguageModel.defaultGPULayerCount) { self.modelPath = modelPath + self.gpuLayers = gpuLayers self.legacyDefaults = ResolvedGenerationOptions() } @@ -668,13 +690,10 @@ import Foundation private func createModelParams() -> llama_model_params { var params = llama_model_default_params() - - // Force CPU-only execution to avoid Metal GPU issues - params.n_gpu_layers = 0 + params.n_gpu_layers = gpuLayers // Try to reduce memory usage - params.use_mmap = true - params.use_mlock = false + params.load_mode = LLAMA_LOAD_MODE_MMAP return params } @@ -829,6 +848,7 @@ import Foundation llama_sampler_chain_add( samplerPtr, llama_sampler_init_penalties( + llama_vocab_n_tokens(vocab), effectiveRepeatLastN, effectiveRepeatPenalty, effectiveFrequencyPenalty, @@ -958,6 +978,7 @@ import Foundation llama_sampler_chain_add( samplerPointer, llama_sampler_init_penalties( + llama_vocab_n_tokens(vocab), options.repeatLastN, options.repeatPenalty, options.frequencyPenalty, @@ -1197,6 +1218,7 @@ import Foundation llama_sampler_chain_add( samplerPtr, llama_sampler_init_penalties( + llama_vocab_n_tokens(vocab), effectiveRepeatLastN, effectiveRepeatPenalty, effectiveFrequencyPenalty, diff --git a/Tests/AnyLanguageModelTests/LlamaLanguageModelTests.swift b/Tests/AnyLanguageModelTests/LlamaLanguageModelTests.swift index 3d9e32c7..08efc898 100644 --- a/Tests/AnyLanguageModelTests/LlamaLanguageModelTests.swift +++ b/Tests/AnyLanguageModelTests/LlamaLanguageModelTests.swift @@ -17,6 +17,10 @@ import Testing @Test func initialization() { let customModel = LlamaLanguageModel(modelPath: "/path/to/model.gguf") #expect(customModel.modelPath == "/path/to/model.gguf") + #expect(customModel.gpuLayers == LlamaLanguageModel.defaultGPULayerCount) + + let cpuOnlyModel = LlamaLanguageModel(modelPath: "/path/to/model.gguf", gpuLayers: 0) + #expect(cpuOnlyModel.gpuLayers == 0) #expect(customModel.contextSize == 2048) #expect(customModel.batchSize == 512) #expect(customModel.threads == Int32(ProcessInfo.processInfo.processorCount))