Skip to content

Commit ffd119c

Browse files
authored
Merge pull request #1 from EthanLipnik/main
Fix iOS support, update Readme, and fix gitignore
2 parents 4a638f8 + b90f6bf commit ffd119c

File tree

6 files changed

+63
-29
lines changed

6 files changed

+63
-29
lines changed

.gitignore

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,19 @@ maple-diffusion/bins/*.txt
22
maple-diffusion/bins/*.bin
33
xcuserdata/
44
.DS_Store
5+
.build
6+
DerivedData
7+
/.previous-build
8+
xcuserdata
9+
*~
10+
\#*
11+
.\#*
12+
.*.sw[nop]
13+
*.xcscmblueprint
14+
/default.profraw
15+
Utilities/Docker/*.tar.gz
16+
.swiftpm
17+
Package.resolved
18+
/build
19+
*.pyc
20+
.docc-build

MapleDiffusion/.swiftpm/xcode/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist

Lines changed: 0 additions & 8 deletions
This file was deleted.

Package.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import PackageDescription
55

66
let package = Package(
77
name: "MapleDiffusion",
8-
platforms: [ .macOS(.v12) ],
8+
platforms: [.iOS(.v15), .macOS(.v12)],
99

1010
products: [
1111
// Products define the executables and libraries a package produces, and make them visible to other packages.

README.md

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,30 +4,57 @@ Maple Diffusion runs Stable Diffusion models **locally** on macOS / iOS devices,
44

55
![](demonstration.jpg)
66

7-
Maple Diffusion should be capable of generating a reasonable image in a minute or two on a recent iPhone (I get around ~2.3s / step on an iPhone 13 Pro).
7+
Maple Diffusion should be capable of generating a reasonable image [in a minute or two](https://twitter.com/madebyollin/status/1579213789823893504) on a recent iPhone (I get around ~2.3s / step on an iPhone 13 Pro).
88

99
To attain usable performance without tripping over iOS's 4GB memory limit, Maple Diffusion relies internally on FP16 (NHWC) tensors, operator fusion from MPSGraph, and a truly pitiable degree of swapping models to device storage.
1010

1111
On macOS, Maple Diffusion uses slightly more memory (~6GB), to reach <1s / step.
1212

1313
![](screenshot.jpg)
1414

15+
# Projects using Maple Diffusion
16+
17+
* https://github.com/mortenjust/maple-diffusion/ is a fork with several improvements
18+
19+
# Device Requirements
20+
21+
Maple Diffusion should run on any Apple Silicon Mac (M1, M2, etc.). Intel macs seem to not support Float16 or something.
22+
23+
Maple Diffusion should run on any iOS device with [sufficient RAM](https://blakespot.com/ios_device_specifications_grid.html) (≥6144MB RAM definitely works; 4096MB *might* but I wouldn't bet on it; anything lower than that won't work). Recent iPads should work out of the box; recent iPhones should work if you can get the `Increase Memory Limit` capability working (to unlock 4GB of RAM).
24+
25+
iOS 16.1 (beta) is reportedly broken and always generating a gray image :(
26+
1527
# Usage
1628

1729
To build and run Maple Diffusion:
1830

19-
1. Download a Stable Diffusion model checkpoint ([`sd-v1-4.ckpt`](https://huggingface.co/CompVis/stable-diffusion-v1-4), or some derivation thereof)
31+
1. Download a Stable Diffusion PyTorch model checkpoint ([`sd-v1-4.ckpt`](https://huggingface.co/CompVis/stable-diffusion-v1-4), or some derivation thereof)
2032

2133
2. Download this repo
2234

2335
```bash
2436
git clone https://github.com/madebyollin/maple-diffusion.git && cd maple-diffusion
2537
```
2638

27-
3. Convert the model into a bunch of fp16 binary blobs. You might need to install PyTorch and stuff.
39+
3. Setup & install Python with PyTorch, if you haven't already.
40+
41+
```bash
42+
# may need to install conda first https://github.com/conda-forge/miniforge#homebrew
43+
conda deactivate
44+
conda remove -n maple-diffusion --all
45+
conda create -n maple-diffusion python=3.10
46+
conda activate maple-diffusion
47+
pip install torch typing_extensions numpy Pillow requests pytorch_lightning
48+
```
49+
50+
4. Convert the PyTorch model checkpoint into a bunch of fp16 binary blobs.
2851

2952
```bash
3053
./maple-convert.py ~/Downloads/sd-v1-4.ckpt
3154
```
3255

33-
4. Open, build, and run the `maple-diffusion` Xcode project. You might need to set up code signing and stuff
56+
5. Open the `maple-diffusion` Xcode project. Select the device you want to run on from the `Product > Destination` menu.
57+
58+
6. [Manually add](https://github.com/madebyollin/maple-diffusion/issues/5#issuecomment-1279111878) the `Increased Memory Limit` capability to the `maple-diffusion` target (this step might not be needed on iPads, but it's definitely needed on iPhones - the default limit is 3GB).
59+
60+
7. Build & run the project on your device with the `Product > Run` menu.

Sources/MapleDiffusion/Functions.swift

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ func makeUpsampleNearest(graph: MPSGraph, xIn: MPSGraphTensor, scaleFactor: Int=
4444
return graph.resize(xIn, size: [NSNumber(value:xIn.shape![1].intValue * scaleFactor), NSNumber(value:xIn.shape![2].intValue * scaleFactor)], mode: MPSGraphResizeMode.nearest, centerResult: true, alignCorners: false, layout: MPSGraphTensorNamedDataLayout.NHWC, name: nil)
4545
}
4646

47-
@available(macOS 12.3, *)
47+
@available(iOS 15.4, macOS 12.3, *)
4848
func makeGroupNorm(graph: MPSGraph, xIn: MPSGraphTensor, name: String) -> MPSGraphTensor {
4949
var x = xIn
5050
if (xIn.shape!.count == 3) {
@@ -66,12 +66,12 @@ func makeSwish(graph: MPSGraph, xIn: MPSGraphTensor) -> MPSGraphTensor {
6666
return graph.multiplication(xIn, graph.sigmoid(with: xIn, name: nil), name: nil)
6767
}
6868

69-
@available(macOS 12.3, *)
69+
@available(iOS 15.4, macOS 12.3, *)
7070
func makeGroupNormSwish(graph: MPSGraph, xIn: MPSGraphTensor, name: String) -> MPSGraphTensor {
7171
return makeSwish(graph: graph, xIn: makeGroupNorm(graph: graph, xIn: xIn, name: name))
7272
}
7373

74-
@available(macOS 12.3, *)
74+
@available(iOS 15.4, macOS 12.3, *)
7575
func makeDecoderResBlock(graph: MPSGraph, xIn: MPSGraphTensor, name: String, outChannels: NSNumber) -> MPSGraphTensor {
7676
var x = xIn
7777
x = makeGroupNormSwish(graph: graph, xIn: x, name: name + ".norm1")
@@ -85,7 +85,7 @@ func makeDecoderResBlock(graph: MPSGraph, xIn: MPSGraphTensor, name: String, out
8585
return graph.addition(x, xIn, name: "skip")
8686
}
8787

88-
@available(macOS 12.3, *)
88+
@available(iOS 15.4, macOS 12.3, *)
8989
func makeDecoderAttention(graph: MPSGraph, xIn: MPSGraphTensor, name: String) -> MPSGraphTensor {
9090
var x = makeGroupNorm(graph: graph, xIn: xIn, name: name + ".norm")
9191
let c = x.shape![3]
@@ -113,7 +113,7 @@ func makeByteConverter(graph: MPSGraph, xIn: MPSGraphTensor) -> MPSGraphTensor {
113113
return graph.concatTensors([x, alpha], dimension: 3, name: nil)
114114
}
115115

116-
@available(macOS 12.3, *)
116+
@available(iOS 15.4, macOS 12.3, *)
117117
func makeDecoder(graph: MPSGraph, xIn: MPSGraphTensor) -> MPSGraphTensor {
118118
var x = xIn
119119
let name = "first_stage_model.decoder"
@@ -185,7 +185,7 @@ func makeTimeEmbed(graph: MPSGraph, xIn: MPSGraphTensor, name: String) -> MPSGra
185185
return makeLinear(graph: graph, xIn: x, name: name + ".2", outChannels: 1280)
186186
}
187187

188-
@available(macOS 12.3, *)
188+
@available(iOS 15.4, macOS 12.3, *)
189189
func makeUNetResBlock(graph: MPSGraph, xIn: MPSGraphTensor, embIn: MPSGraphTensor, name: String, inChannels: NSNumber, outChannels: NSNumber) -> MPSGraphTensor {
190190
var x = xIn
191191
x = makeGroupNormSwish(graph: graph, xIn: x, name: name + ".in_layers.0")
@@ -286,7 +286,7 @@ func makeBasicTransformerBlock(graph: MPSGraph, xIn: MPSGraphTensor, name: Strin
286286
return graph.addition(ff, x, name: nil)
287287
}
288288

289-
@available(macOS 12.3, *)
289+
@available(iOS 15.4, macOS 12.3, *)
290290
func makeSpatialTransformerBlock(graph: MPSGraph, xIn: MPSGraphTensor, name: String, contextIn: MPSGraphTensor, saveMemory: Bool) -> MPSGraphTensor {
291291
let n, h, w, c: NSNumber
292292
(n, h, w, c) = (xIn.shape![0], xIn.shape![1], xIn.shape![2], xIn.shape![3])
@@ -300,7 +300,7 @@ func makeSpatialTransformerBlock(graph: MPSGraph, xIn: MPSGraphTensor, name: Str
300300
return graph.addition(x, xIn, name: nil)
301301
}
302302

303-
@available(macOS 12.3, *)
303+
@available(iOS 15.4, macOS 12.3, *)
304304
func makeOutputBlock(graph: MPSGraph, xIn: MPSGraphTensor, embIn: MPSGraphTensor, condIn: MPSGraphTensor, inChannels: NSNumber, outChannels: NSNumber, dHead: NSNumber, name: String, saveMemory: Bool, spatialTransformer: Bool = true, upsample: Bool = false) -> MPSGraphTensor {
305305
var x = xIn
306306
x = makeUNetResBlock(graph: graph, xIn: x, embIn: embIn, name: name + ".0", inChannels: inChannels, outChannels: outChannels)
@@ -315,7 +315,7 @@ func makeOutputBlock(graph: MPSGraph, xIn: MPSGraphTensor, embIn: MPSGraphTensor
315315
}
316316

317317

318-
@available(macOS 12.3, *)
318+
@available(iOS 15.4, macOS 12.3, *)
319319
func makeUNetAnUnexpectedJourney(graph: MPSGraph, xIn: MPSGraphTensor, tembIn: MPSGraphTensor, condIn: MPSGraphTensor, name: String, saveMemory: Bool = true) -> [MPSGraphTensor] {
320320
let emb = makeTimeEmbed(graph: graph, xIn: tembIn, name: name + ".time_embed")
321321

@@ -382,7 +382,7 @@ func makeUNetAnUnexpectedJourney(graph: MPSGraph, xIn: MPSGraphTensor, tembIn: M
382382
return savedInputs + [emb] + [x]
383383
}
384384

385-
@available(macOS 12.3, *)
385+
@available(iOS 15.4, macOS 12.3, *)
386386
func makeUNetTheDesolationOfSmaug(graph: MPSGraph, savedInputsIn: [MPSGraphTensor], name: String, saveMemory: Bool = true) -> [MPSGraphTensor] {
387387
var savedInputs = savedInputsIn
388388
let condIn = savedInputs.popLast()!
@@ -408,7 +408,7 @@ func makeUNetTheDesolationOfSmaug(graph: MPSGraph, savedInputsIn: [MPSGraphTenso
408408
return savedInputs + [emb] + [x]
409409
}
410410

411-
@available(macOS 12.3, *)
411+
@available(iOS 15.4, macOS 12.3, *)
412412
func makeUNetTheBattleOfTheFiveArmies(graph: MPSGraph, savedInputsIn: [MPSGraphTensor], name: String, saveMemory: Bool = true) -> MPSGraphTensor {
413413
var savedInputs = savedInputsIn
414414
let condIn = savedInputs.popLast()!
@@ -456,7 +456,7 @@ func makeSqrtOneMinus(graph: MPSGraph, xIn: MPSGraphTensor) -> MPSGraphTensor {
456456
return graph.squareRoot(with: graph.subtraction(graph.constant(1.0, dataType: MPSDataType.float16), xIn, name: nil), name: nil)
457457
}
458458

459-
@available(macOS 12.3, *)
459+
@available(iOS 15.4, macOS 12.3, *)
460460
func makeDiffusionStep(graph: MPSGraph, xIn: MPSGraphTensor, etaUncondIn: MPSGraphTensor, etaCondIn: MPSGraphTensor, tIn: MPSGraphTensor, tPrevIn: MPSGraphTensor, guidanceScaleIn: MPSGraphTensor) -> MPSGraphTensor {
461461

462462
// superconditioning
@@ -530,7 +530,7 @@ func makeTextEncoder(graph: MPSGraph, xIn: MPSGraphTensor, name: String) -> MPSG
530530
return x
531531
}
532532

533-
@available(macOS 12.3, *)
533+
@available(iOS 15.4, macOS 12.3, *)
534534
func makeTextEmbeddings(graph: MPSGraph, xIn: MPSGraphTensor, name: String) -> MPSGraphTensor {
535535
var tokenEmbeddings = loadConstant(graph: graph, name: name + ".token_embedding.weight", shape: [1, 49408, 768])
536536
tokenEmbeddings = graph.broadcast(tokenEmbeddings, shape: [2, 49408, 768], name: nil)
@@ -540,7 +540,7 @@ func makeTextEmbeddings(graph: MPSGraph, xIn: MPSGraphTensor, name: String) -> M
540540
return graph.addition(embeddings, positionEmbeddings, name: nil)
541541
}
542542

543-
@available(macOS 12.3, *)
543+
@available(iOS 15.4, macOS 12.3, *)
544544
func makeTextGuidance(graph: MPSGraph, xIn: MPSGraphTensor, name: String) -> MPSGraphTensor {
545545
var x = makeTextEmbeddings(graph: graph, xIn: xIn, name: name + ".embeddings")
546546
x = makeTextEncoder(graph: graph, xIn: x, name: name + ".encoder")

Sources/MapleDiffusion/MapleDiffusion.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11

22
import MetalPerformanceShadersGraph
33
import Foundation
4-
import AppKit
54
import Combine
65

76

@@ -34,7 +33,7 @@ public struct ProgressMonitor : Equatable {
3433

3534
}
3635

37-
@available(macOS 12.3, *)
36+
@available(iOS 15.4, macOS 12.3, *)
3837
public class MapleDiffusion : ObservableObject {
3938
@Published public var isModelLoaded = false
4039

0 commit comments

Comments
 (0)