介紹
在 SwiftUI-MLX本地大模型開發一文中,我們已經詳細講了如何利用 MLX 進行本地大模型的開發。但是通過案例可以發現 2 個問題:
- MLX 內置的大模型數量有限。
- 每次大模型都需要從 HuggingFace 下載。
如何解決這 2 個問題,方案是:定制大模型與使用離線大模型。
定制大模型
- 通過擴展
MLXLLM.ModelRegistry
實現模型的定制。 - 可以在 Hugging Face 模型搜索地址 中搜索需要的 MLX 大模型。
// MARK: - 注冊自定義模型,模型必須為MLX格式
extension MLXLLM.ModelRegistry {
public static let llama3_2_3B_4bit = ModelConfiguration(
id: "mlx-community/Llama-3.2-3B-Instruct-4bit", // Hugging Face上模型的倉庫路徑
overrideTokenizer: "PreTrainedTokenizer" // 分詞器
)
}
使用離線大模型
- 每次都從 HuggingFace 在線下載模型非常麻煩,如果已經離線下載了模型到本地,可以通過指定路徑的方式加載模型。
- 可以在 Model Scope 模型搜索地址 中搜索并下載需要的 MLX 大模型。
extension MLXLLM.ModelRegistry {
public static let localModel = ModelConfiguration(
directory: URL(fileURLWithPath: "/Users/yangfan/Documents/modelscope/Llama-3.2-3B-Instruct"), // 本地模型的路徑
overrideTokenizer: "PreTrainedTokenizer"
)
}
使用
struct ContentView: View {
// 提示詞
@State private var prompt: String = "什么是SwiftUI?"
// 輸出結果
@State private var response: String = ""
@State private var isLoading: Bool = false
var body: some View {
VStack(spacing: 16) {
// 頂部輸入區域
HStack {
TextField("輸入提示詞...", text: $prompt)
.textFieldStyle(.roundedBorder)
.font(.system(size: 16))
Button {
response = ""
Task {
do {
try await generate()
} catch {
debugPrint(error)
}
}
} label: {
Text("生成")
.foregroundStyle(.white)
.padding(.horizontal, 16)
.padding(.vertical, 8)
.background(prompt.isEmpty ? Color.gray : Color.blue)
.cornerRadius(8)
}
.buttonStyle(.borderless)
.disabled(prompt.isEmpty || isLoading)
}
.padding(.horizontal)
.padding(.top)
// 分隔線
Rectangle()
.fill(Color.gray.opacity(0.2))
.frame(height: 1)
// 響應展示區域
if response != "" {
ResponseBubble(text: response)
}
Spacer()
}
if isLoading {
ProgressView()
.progressViewStyle(.circular)
.padding()
}
}
}
extension ContentView {
// MARK: 文本生成
func generate() async throws {
isLoading = true
// 加載模型
// let modelConfiguration = ModelRegistry.llama3_2_3B_4bit
let modelConfiguration = ModelRegistry.localModel
let modelContainer = try await LLMModelFactory.shared.loadContainer(configuration: modelConfiguration) { progress in
print("正在下載 \(modelConfiguration.name),當前進度 \(Int(progress.fractionCompleted * 100))%")
}
// 生成結果
let _ = try await modelContainer.perform { [prompt] context in
let input = try await context.processor.prepare(input: .init(prompt: prompt))
let result = try MLXLMCommon.generate(input: input, parameters: .init(), context: context) { tokens in
let text = context.tokenizer.decode(tokens: tokens)
Task { @MainActor in
self.response = text
self.isLoading = false
}
return .more
}
return result
}
}
}
struct ResponseBubble: View {
let text: String
var body: some View {
ScrollView {
VStack(alignment: .leading, spacing: 8) {
Text("AI")
.font(.system(size: 16))
.foregroundColor(.gray)
Text(text)
.font(.system(size: 16))
.lineSpacing(4)
.padding()
.background(Color.blue.opacity(0.1))
.cornerRadius(12)
}
}
.padding(.horizontal)
}
}
效果
- 定制大模型。
定制大模型.gif
- 使用離線大模型。
使用離線大模型.gif