183 comments

[ 7.9 ms ] story [ 454 ms ] thread
This is cool and looks like a great way to drain my phone battery :)

I just used the prompt "A person looking at their phone in amazement" and got a good picture.

Beware that on startup the app downloads almost 2 gig of data.

It does warn you on startup about the download if you're not on wifi.
Good time to try 5G ultra capacity if you have it on an unlimited plan - will be faster than most people's wifi.
Pivot alert

I reached 3Gbps over Verizon 5G in San Antonio last year and this year i get about 4Mbps over Verizon 5G in Ohio. It’s so bad I disabled it. I did read an article that iPhone 12 (which is what I have) have some kind of radio issue with 5G. Can anyone in here confirm?

Verizon has been real wonky all over Austin. If there's more than a handful of people in the area, bandwidth just goes to the crapper. I'll go from a couple hundred mbps on a good day with no clouds/wind/holding my phone just perfectly right in the right space, but usually get less than 1mbps on their 5g UW.
Yeah, its really bad. I keep having to disable 5G.
(I have not downloaded it.)

Q: How long does a run typically take? 60 seconds?

From the link:

> It took a minute to summon the picture on the latest and greatest iPhone 14 Pro, uses about 2GiB in-app memory, and requires you to download about 2GiB data to get started. Even though the app itself is rock solid, given these requirements, I would probably call it barely usable.

also

> Even if it took a minute to paint one image, now my Camera Roll is filled with drawings from this app. It is an addictive endeavor. More than that, I am getting better at it. If the face is cropped, now I know how to use the inpainting model to fill it in. If the inpainting model doesn’t do its job, you can always use a paint brush to paint it over and do an image-to-image generation again focused in that area.

Seems very worth a try. I'm downloading the model right now, it's going a bit slow, ~2MB/s.

It would be awesome if it just quickly took a picture from the front camera for that particular request and then just filter it to finish the "in the style of andy warhol"
I have generated some images, I think it only takes less than 1% of the battery for an image, this is already much better than most of the game(for having fun).
It took my battery from 80 to 77% for one generation on the default settings (384^2, 30 iterations). Less than a minute of compute time to complete a generation.

Iphone battery health reports a battery at 100% health. This is an iphone SE3.

Amazing how huge the difference in energy consumption is for the system in standby vs going full throttle.

EDIT: I generated 3 more images; every subsequent generation reduced battery capacity by another 2%. My phone doesn't seem to heat up at all, interestingly.

My iPhone 12 mini dropped from 76% to 71% and got noticeably warmer. Battery health is way worse than yours, 85%.

I wonder if generating a picture uses so much juice that it even drops the percentage while charging...

EDIT: Generating a picture while charging did not drop the percentage.

I generated a bunch of pictures while charging and the percentage still went up (albeit slowly).
Late to the party but depending on your charger voltage, it may be. e.g. I can charge my mbp on a cheap usb-usb-c charger but as soon as I use it _too_ much, it will stall, or worse, lower.
Hahah now I can use my phone as a hand warmer this winter. It's incredible that this is an app!
This is incredible work and a tremendous achievement. Bravo and thanks for sharing.
Could in-memory compression used to bring down the RAM requirements?

There are some performance compressors like Blosch tuned for this:

https://www.blosc.org/pages/blosc-in-depth/

“Faster than memcpy” is the slogan.

MacOS has transparent memory compression. Unclear to me if that's made its way to iPhone, but if it hasn't yet it will sooner or later.
Memory compression? I can't find any good resources to read about it, any hints? I'm having trouble imaging how could it possibly work without totally destroying performance.
On Mac, you can find Compressed memory in Activity monitor.

It’s something similar to swap - apps do not need to have built in support for it.

It segments a certain amount of ram to “swap” to which means compress and store. Normal blue sky ram operations are not compressed on macOS
Oh, yes compressed swap makes much more sense, thanks.
It is not compressed swap, the compressed data is still in RAM. The OS just compresses inactive memory, with a couple of criteria to define “inactive”.
Many operations are actually a lot faster with compressed memory than without. It's all about where the bottleneck is.
It doesn't destroy performance for the simple reason that nowadays memory access is slower than pure compute. If you need to use compute to produce some data to be stored in memory, your overall throughput could very well be faster than without compression.

There have been a large amount of innovation on fast compression and fast decompression in recent years. Traditional compression tools like gzip or xz are geared towards higher compression ratio, but memory compression tends to favor speed. Check out those algorithms:

* lz4: https://lz4.github.io/lz4/

* Google's snappy: https://github.com/google/snappy

* Facebook's zstd in fast mode: http://facebook.github.io/zstd/#benchmarks

My guess is that iPhone is purely “kill app” instead of “compress memory / swap” OOM model. This makes more sense for mobile.
IIRC from WWDC they said that inactive/suspended apps get their memory compressed to free up memory for the current active/foreground app.

Seems to mesh well with the iOS idea of using a single app at a time and minimizing background processing in apps that you aren't actively using.

In an out of memory situation I think apps just get killed as you suggest.

Memory compression is a generalization of swap, which is only for dynamic memory; files on disk don't need it because you can just read them off the disk.

The problem is that GPUs don't support virtual memory paging, so they can't read files nor decompress nor swap anything unless you write it yourself, which is a lot slower.

Also, ML models (probably) can't be compressed because they already are compressed; learning and compression are the same thing!

Wait. This comment just blew my mind. Does that imply that you might be able to measure the efficiency of a model by it's compressibility? Note, I'm trying to recognize efficient and accurate are not the same. One could imagine evaluating a model on a 2d performance and compression map somehow.
> Also, ML models (probably) can't be compressed because they already are compressed; learning and compression are the same thing!

I feel like they're kind of two sides of the same coin: learning is about putting more information in the same data, while compression is about putting the same information in less data.

I'm wondering if some lossy floating-point compressor (such as zfp) would work.

> I'm wondering if some lossy floating-point compressor (such as zfp) would work.

Well apparently this can work; StableDiffusion comes as 32-bit and 16-bit float versions. I'm kind of surprised they both work, but that's lossy compression.

Sure, but 16-bit float is pretty primitive compression, as it does not exploit any redundancy in the input. zfp groups numbers together in chunks, which means that correlated numbers can be represented more precisely. Its algorithm is described here: https://zfp.readthedocs.io/en/release1.0.0/algorithm.html#lo...

I would like to see if the zfp can be applied to something like Stable Diffusion (or other ML models) and give better results than regular floats at the same size.

In-memory compression means the memory is inherently dirty memory

On Apple platforms if you mmap a read-only file into the process address space, then it is "clean" memory. It is clean because the kernel can drop it at any time because it already exists on disk. You essentially can offload the memory management to the kernel page cache.

The downside is that if you run up to the limit and the "working set" can't fit entirely in memory, then you run into page faults which incur an I/O cost.

The advantage is that the kernel will drop the page cache before it considers killing your process to reclaim memory.

That said, I don't know the typical access patterns for neural network inference, so I don't know how the page faults would effect performance

No. The memory usage is due to huge series of floating point numbers without much redundancy that you could squeeze out with a compressor.
zfp compression might be an interesting thing to try. In fixed rate mode, it supports random access too.
Should be doable for parameters but at that point, you don't need compression rather just LLM.Int8 tricks would be sufficient. For activations, I wrote about it a while back: https://liuliu.me/eyes/reduce-another-70-memory-usage-for-de...

It is not as useful for this case (inference) because the activations holds long (UNet holds downsampling passes' activations and use that for upsampling) is not that much of a memory (in the range of a few megabytes). If it is for training, it is probably more useful.

This is absolutely incredible. It takes about 45 seconds to generate a whole image on my iPhone SE3 - which is about as fast as my M1 Pro macbook was doing it with the original version!
SE 3rd Gen has 4GiB RAM, therefore the app defaults to 384x384 size. This is about 1/2 computation of your normal run (512x512) and the original version uses PLMS sampler, which defaults to 50 steps, while this one uses the newer DPM++ 2M Karras sampler, that defaults to 30 steps. All in all, your M1 Pro MBP is still 4x of your SE 3rd Gen in raw performance (although my implementation should be faster than PyTorch at about 2x on M1 chips)
> although my implementation should be faster than PyTorch at about 2x on M1 chips

Do you plan to make a macOS version of your app also? Hope you will :)

For what it's worth, you can decrease resolution and use the sampler mentioned on the pytorch versions. The AUTOMATIC web UI supports this, for instance.

I would also welcome the additional optimizations, however.

hey. 9th gen ipad 10.9, i think it has 3GB ram so it will never work on it?
I'm downloading it now. This should be fun.
works really well thank you!
Fantastic! Can it be made available for iPad?
It works on the iPad, but it uses the iPhone UI. But it works just as well
This looks so cool! Unfortunately, my 16.1 11pro is crashing before an image can be generated, let me know if I can do anything to debug/test this.
Which generation of iPad is that? Honestly I haven't tested iPad yet, still in designing phase.
My bad I wasn't clear, iPhone 11 Pro on iOS 16.1
It’s working fine on my iPhone 11 Pro / iOS 16.1 with all default settings. Just generated an image of an astronaut skiing that looks pretty good!
Aww man, no ipad version? Tsk what did I get this 16gb of ram for?
Given couple of weeks. Still playing to see what's the optimal UI looks like for such large screen. 16GiB should be able to generate several images to select from at once.
Crashes every time... am I doing something wrong? iPhone 11 Pro.
Does it crash upon downloading models, or generating? I haven't tested on all the devices, but 11 Pro seems have 4GiB RAM, and should run with 384x384 resolution (check if that is the selected resolution at top right).

There are reports that iOS is not happy with how I computing SHA256 for downloaded model file by loading them all in memory for Xr (3GiB RAM). If this is happening for other devices, I may need to do streaming hash computing and put up a bugfix.

It _might_ be easier just to use mmio and save any futzing around rewriting the actual code.
Yeah, I thought Data(contentsOf:) already do that, but it appears not (tested, indeed allocated all the memory to load the data). Adding `mapIfSafe` in the reading options solved this.
I have an iPhone 11 and it works for me. Had to keep the app in focus until all the downloading completed.
I can also confirm it works (for me) on iPhone 11 Pro.
Meh… 2gb download only to try “image of unicorn pooping” to get the lamest results ever. If I can’t amuse my 5 yr old with this AI it’s nonsense.

It transcribed as “image of unicorn poo ping” in tags :(

small add. display multiple examples while it's downloading the model. Its a long time to stare at an astronaut on a horse in space
here's a direct app store link, if anyone wants to try the iPhone app immediately: https://apps.apple.com/us/app/draw-things-ai-generation/id64...

congratulations to liuliu on the launch!

Crashes on my iPhone SE 2. Gen which was to be expected :-(
(comment deleted)
Crashes on my 13 Mini, which is unexpected! Anything we need to do to prep the phones?
I think that probably is to be expected, unfortunately. The model is 2GB; per the article iOS will kill apps that use 2GB on 4GB RAM devices (and the 13 Mini is 4GB).
It works just fine on my iPhone 12 Mini, which has (basically) the same RAM, so it seems like it's something else. They're basically the same phone in general though, so I would be surprised if it was a hardware issue.
(comment deleted)
It's running on my 13 Mini (so far).

I did have trouble closing the "adjustments" dialog (upper-right button) due to its close button being underneath the status bar, but found that I could just drag the dialog down to the bottom and it closed.

Hmmm, my ipad keeps crashing and redownloading the sd_v1.4_f16.ckpt file.
(comment deleted)
Yeah, seems iPad has bunch of issues (curiously most of it related to how I translate tensor back to CGImage ...) stay tuned.
On my iPad mini 5th generation with A12 the download is fast and fine. But with standard settings it first warns “Device capability warning” and then indeed crashes every time. Is there a way to solve this? A12 chip should work, no?
I just tried it works beautifully! I suggest defaulting to lower resolution 384 X 384 since it will speed up.
Did you try using Core ML for inference?
This is super cool. I just tried the default prompt on my iPhone 13 with the image size set to 768x512 and using the 3D Model (Redshift v1) and it just crashed the whole phone and restarted. Just like when I get BSOD's at work on my Windows GPU desktop :)
(comment deleted)
You should see a warning when selecting that size? 4GiB model cannot run at that resolution until someone implemented FlashAttention on Metal :)
Nice work :)

Porting FlashAttention to Metal will be quite hard. Because for performance reasons, they did a lot of shenanigans to respect the memory hierarchy.

Thankfully, you can probably do something slower but more adapted to your memory constraints.

If you relax this need for performance and allow some re-computations, you can write a qkvatt function which takes q,k,v and a buffer to store the resulting attention, and compute without needing any extra memory.

The algorithm is still quadratic in time with respect to the attention horizon (although with a bigger constant (2x or 3x) due to the re computation). But it doesn't need any extra memory allocation which makes it easy to parallelize.

Alternatively you can use an O(attention horizon * number of thread in parallel) (like flash attention) extra memory buffer to avoid the re-computation.

Concerning the backward pass, that's the same thing, you don't need extra memory if you are willing to do some re-computation, or linear in attention horizon to not do re-computation.

One interesting thing to notice in the backward pass, is that it doesn't use the attn of the forward pass, so it doesn't need to be kept preserved (only need to preserve Q,K,V).

One little caveat of the backward pass (which you only need for training) is that it needs atomic_add to be easy to parallelize. This mean, it will be hard on Metal (afaik they don't have atomics for floats though they do have atomics for integer so you can probably use fixed points numbers).

(comment deleted)
I did, it's fully my fault, I just wanted to see what would happen.

Love the work, really great job!

I wonder if any of these tricks would be applicable to make a version of Stable Diffusion which could run on the Steam Deck.
cant you just run it the regular way? it's a pc.
It doesn't have enough VRAM to load the regular model; it ends up triggering the OOM killer.
I dont think the Steam Deck is powerful enough. It might be possible but it will take hours.
Apple's mobile processors (especially the M1) are waaay faster than a steam deck. Even with the optimizations, it would take like half an hour to run I bet.
liuliu has always been a fucking god
(comment deleted)
This is some impressive work.

You might like to look at the work HuggingFace has been doing (on non-iOS versions). They can run it in under 1GB RAM:

> If is also possible to chain it with attention slicing for minimal memory consumption, running it in as little as < 800mb of GPU vRAM

https://huggingface.co/docs/diffusers/optimization/fp16#offl...

CPU offloading doesn't work because Apple has shared memory arch already. The head slicing is similar to https://machinelearning.apple.com/research/neural-engine-tra... I think it is quite practical only if MPSGraph less mysterious about its allocation strategy. It is not the ideal way though. Ideally, FlashAttention / XFormer is the way to go.
the developer is about to have a MASSIVE hosting bill

the download restarts from 0% if the app is sent to the background, as there does not seem to be a download manager. This is especially problematic for the large 1.5gb file.

I am using Cloudflare R2, which doesn't have egress fee and I am getting about 5k Class B operations right now. Unless Cloudflare changes their end of the deal, I think it is OK.
great to hear! please consider introducing a mechanism to suspend the download vs restarting, this may be especially valuable for those with a slower connection. With the traffic growth you'll be seeing chances are Cloudflare's enterprise team will soon be in-touch ;)
I wonder why the file can’t be distributed inside the app on the App Store. That way downloads would be much more convenient.
Is P2P torrent type of sharing the load possible under AppStore guidelines (be they iOS or Android)? I've honestly never even thought about this being a thing, but with large shared data that doesn't change, why not?
P2P, as in hosted from other people's phones? I think the issue is that people generally wouldn't be happy with P2P data uploads from their phones (compared to P2P on desktop, where internet is cheaper/faster, and battery isn't an issue).
They are banned on iOS but not on Android.
Kinda ironic that this links to a site that is almost unreadable on an iPhone (14 pro max if you’re wondering).
I frequently see such comments about sites not loading fine on iPhone 13/14, while they continue to load just fine on for me on a 4 year old Android device (not pixel / Samsung).

I wonder if it's the hardware or just the blockers that i use. Might be worth trying using blockers to see if it makes the general browsing experience better on Apple devices

The site works just fine on an iPhone 7
(comment deleted)
It loads fine on an iPhone 14 Pro Max, it just has a very small font. Reader mode works great though.
The site loads fine but the font size is a little small for mobile. It reads fine if you rotate to landscape, though.