Skip to content

Commit 1c05248

Browse files
authored
add upgrade docs, how to use, how to develop. (#206)
* add upgrade docs, how to use, how to develop. * add macro docs, reference for shortcut * move some documentation from README to upgrade. Prep README for 3.x release
1 parent b331db1 commit 1c05248

9 files changed

Lines changed: 816 additions & 240 deletions

File tree

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# ``MLXHuggingFace``
2+
3+
Macros to assist in adapting HuggingFace Hub and Tokenizer libraries.
4+
5+
## Overview
6+
7+
See [MLXLMCommon](MLXLMCommon) for information about how to use these macros.
8+

Libraries/MLXHuggingFace/Macros.swift

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,133 @@
11
import Foundation
22
import MLXLMCommon
33

4+
/// Wrap a `HubClient` as a `Downloader`.
5+
///
6+
/// ```swift
7+
/// import MLXHuggingFace
8+
/// import HuggingFace
9+
///
10+
/// let model = try await loadModelContainer(
11+
/// from: #hubDownloader(HubClient()),
12+
/// using: #huggingFaceTokenizerLoader(),
13+
/// configuration: modelConfiguration
14+
/// )
15+
/// ```
416
@freestanding(expression)
517
public macro hubDownloader(_ hub: Any) -> MLXLMCommon.Downloader =
618
#externalMacro(module: "MLXHuggingFaceMacros", type: "DownloaderMacro")
719

20+
/// Provide a default `HubClient` as a `Downloader`.
21+
///
22+
/// ```swift
23+
/// import MLXHuggingFace
24+
/// import HuggingFace
25+
///
26+
/// let model = try await loadModelContainer(
27+
/// from: #hubDownloader(),
28+
/// using: #huggingFaceTokenizerLoader(),
29+
/// configuration: modelConfiguration
30+
/// )
31+
/// ```
832
@freestanding(expression)
933
public macro hubDownloader() -> MLXLMCommon.Downloader =
1034
#externalMacro(module: "MLXHuggingFaceMacros", type: "DownloaderMacro")
1135

36+
/// Wrap a `Tokenizers.Tokenizer` in `Tokenizer`.
37+
///
38+
/// This is used internally by ``huggingFaceTokenizerLoader()`` -- typically not used directly.
39+
///
40+
/// ```swift
41+
/// import MLXHuggingFace
42+
/// import Tokenizers
43+
///
44+
/// let t: Tokenizers.Tokenizer
45+
///
46+
/// let tokenizer = #adaptHuggingFaceTokenizer(t)
47+
/// ```
1248
@freestanding(expression)
1349
public macro adaptHuggingFaceTokenizer(_ upstream: Any) -> MLXLMCommon.Tokenizer =
1450
#externalMacro(module: "MLXHuggingFaceMacros", type: "TokenizerAdaptorMacro")
1551

52+
/// Provide a `TokenizerLoader` from `Tokenizers.AutoTokenizer`.
53+
///
54+
/// ```swift
55+
/// import MLXHuggingFace
56+
/// import HuggingFace
57+
///
58+
/// let model = try await loadModelContainer(
59+
/// from: #hubDownloader(),
60+
/// using: #huggingFaceTokenizerLoader(),
61+
/// configuration: modelConfiguration
62+
/// )
63+
/// ```
1664
@freestanding(expression)
1765
public macro huggingFaceTokenizerLoader() -> MLXLMCommon.TokenizerLoader =
1866
#externalMacro(module: "MLXHuggingFaceMacros", type: "TokenizerLoaderMacro")
1967

68+
/// Load a `ModelContainer` using default hub client and tokenizer loader.
69+
///
70+
/// ```swift
71+
/// import MLXHuggingFace
72+
/// import HuggingFace
73+
/// import Tokenizers
74+
///
75+
/// let model = try await huggingFaceLoadModelContainer(
76+
/// configuration: modelConfiguration
77+
/// )
78+
/// ```
2079
@freestanding(expression)
2180
public macro huggingFaceLoadModelContainer(
2281
configuration: ModelConfiguration
2382
) -> ModelContainer =
2483
#externalMacro(module: "MLXHuggingFaceMacros", type: "LoadContainerMacro")
2584

85+
/// Load a `ModelContainer` using default hub client and tokenizer loader with progress.
86+
///
87+
/// ```swift
88+
/// import MLXHuggingFace
89+
/// import HuggingFace
90+
/// import Tokenizers
91+
///
92+
/// let model = try await huggingFaceLoadModelContainer(
93+
/// configuration: modelConfiguration
94+
/// ) { progres in ... }
95+
/// ```
2696
@freestanding(expression)
2797
public macro huggingFaceLoadModelContainer(
2898
configuration: ModelConfiguration,
2999
progressHandler: @Sendable @escaping (Progress) -> Void
30100
) -> ModelContainer =
31101
#externalMacro(module: "MLXHuggingFaceMacros", type: "LoadContainerMacro")
32102

103+
/// Load a `ModelContext` using default hub client and tokenizer loader.
104+
///
105+
/// ```swift
106+
/// import MLXHuggingFace
107+
/// import HuggingFace
108+
/// import Tokenizers
109+
///
110+
/// let modelContext = try await huggingFaceLoadModel(
111+
/// configuration: modelConfiguration
112+
/// )
113+
/// ```
33114
@freestanding(expression)
34115
public macro huggingFaceLoadModel(
35116
configuration: ModelConfiguration
36117
) -> ModelContext =
37118
#externalMacro(module: "MLXHuggingFaceMacros", type: "LoadContextMacro")
38119

120+
/// Load a `ModelContext` using default hub client and tokenizer loader with progress.
121+
///
122+
/// ```swift
123+
/// import MLXHuggingFace
124+
/// import HuggingFace
125+
/// import Tokenizers
126+
///
127+
/// let modelContext = try await huggingFaceLoadModel(
128+
/// configuration: modelConfiguration
129+
/// ) { progres in ... }
130+
/// ```
39131
@freestanding(expression)
40132
public macro huggingFaceLoadModel(
41133
configuration: ModelConfiguration,

Libraries/MLXLLM/Documentation.docc/Documentation.md

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,23 @@ See <doc:evaluation>.
1616
Using LLMs and VLMs is as easy as this:
1717

1818
```swift
19+
import MLXLMCommon
20+
21+
let downloader: any Downloader = ...
22+
let tokenizerLoader: any TokenizerLoader = ...
23+
1924
let model = try await loadModel(
20-
using: TokenizersLoader(),
25+
from: downloader,
26+
using: tokenizerLoader,
2127
id: "mlx-community/Qwen3-4B-4bit"
2228
)
2329
let session = ChatSession(model)
24-
print(try await session.respond(to: "What are two things to see in San Francisco?")
25-
print(try await session.respond(to: "How about a great place to eat?")
30+
print(try await session.respond(to: "What are two things to see in San Francisco?"))
31+
print(try await session.respond(to: "How about a great place to eat?"))
2632
```
2733

34+
See [MLXLMCommon](MLXLMCommon) for information about `Downloader` and `TokenizerLoader`.
35+
2836
More advanced APIs are available for those that need them, see <doc:using-model>.
2937

3038
## Topics

Libraries/MLXLMCommon/Documentation.docc/Documentation.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ Common language model code.
44

55
## Articles
66

7+
- <doc:upgrade>
78
- <doc:wired-memory>
89

910
## Other MLX Libraries Packages
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# Developing mlx-swift-lm
2+
3+
Techniques for developing _in_ mlx-swift-lm.
4+
5+
## Work on Infrastructure
6+
7+
The simplest case for working in mlx-swift-lm is working on
8+
infrastructure, e.g. ``KVCache`` or ``ToolCallParser``.
9+
You can simply fork mlx-swift-lm and modify the files. There are unit
10+
tests that let you exercise the functionality and you can add
11+
more for your specific additions.
12+
13+
The unit tests run without downloading model weights. There
14+
are some tests that exercise the models by using random
15+
weights and mock tokenizers, see EvalTests. This is mostly
16+
useful for testing the generation loop itself rather than
17+
any particular model.
18+
19+
## Work on Models
20+
21+
If you are working on porting or modifying a model you have a few options:
22+
23+
- use `IntegrationTesting/IntegrationTesting.xcodeproj`
24+
- use `llm-tool` from mlx-swift-examples
25+
- use your own application
26+
27+
### IntegrationTesting
28+
29+
`IntegrationTesting.xcodeproj` integrates with the HuggingFace
30+
downloader and tokenizer packages directly and uses [MLXHuggingFace](MLXHuggingFace)
31+
macros to adapt their APIs, see <doc:using> for more information.
32+
This uses code from `IntegrationTestHelpers`
33+
to download weights and run real models. You can easily change which models
34+
it uses or add your own custom tests.
35+
36+
Note: these tests are _not_ run in the CI environment, but are a great way
37+
to test the models in your own development environment.
38+
39+
### mlx-swift-examples / custom application
40+
41+
You can also test your model by integrating it with a tool or application.
42+
This document describes using [`llm-tool`](https://github.com/ml-explore/mlx-swift-examples/blob/main/Tools/llm-tool/README.md) from `mlx-swift-examples`
43+
but the same technique will work with any custom code.
44+
45+
`llm-tool` is a command line tool where you can specify the prompt and the model
46+
as arguments when you run it:
47+
48+
```
49+
--model mlx-community/Mistral-7B-Instruct-v0.3-4bit
50+
--prompt "tell me a story"
51+
```
52+
53+
You will want to have mlx-swift-examples (or your own project) open in
54+
Xcode with a local checkout of mlx-swift-lm (your fork). mlx-swift-examples
55+
will reference a tagged version of mlx-swift-lm and you need to
56+
switch that to reference your local version. There are two basic
57+
methods for doing that (variations on a theme):
58+
59+
- drag the `mlx-swift-lm` _directory_ onto the top item (the mlx-swift-examples project) in the Xcode navigator and chose _reference files in place_
60+
- [Xcode documentation](https://developer.apple.com/documentation/xcode/editing-a-package-dependency-as-a-local-package)
61+
62+
In both cases you will get an override of the mlx-swift-lm dependency for this
63+
project. In addition to using your local copy, you can also _edit_ mlx-swift-lm
64+
at the same time that you use mlx-swift-examples.
65+
66+
For more details on how to configure projects in general, see <doc:using>.

Libraries/MLXLMCommon/Documentation.docc/porting.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ There are a number of ways to implement new models in MLX in Swift:
99

1010
This document talks primarily about the latter.
1111

12+
## Developing mlx-swift-lm
13+
14+
Please see <doc:developing> for more information about how to
15+
do development _in_ mlx-swift-lm.
16+
1217
## Porting Models from MLX in Python
1318

1419
Let's consider a concrete example, [gemma.py](https://github.com/ml-explore/mlx-lm/blob/main/mlx_lm/models/gemma.py). For reference, here is the current port [Gemma.swift](https://github.com/ml-explore/mlx-swift-lm/blob/main/Libraries/MLXLLM/Models/Gemma.swift).

0 commit comments

Comments
 (0)