Как я засунул Stable Diffusion XL в iPhone: 768×768 за 20 секунд, без GPU-серверов и интернета

Народ, привет! В мае 2026 года я выпустил Trazo — приложение для iPhone, которое генерирует картинки прямо на телефоне. Внутри у него Stable Diffusion XL, или коротко SDXL. Один раз скачиваешь модель, пишешь, что хочешь увидеть, нажимаешь «Создать изображение». Можно даже в авиарежиме: для самой генерации интернет не нужен.

На iPhone 15 Pro Max картинка 768×768 получается примерно за 20 секунд, на iPhone 13 Pro — за 30. Это мои замеры при 20 шагах генерации, уже после загрузки модели в память. Запрос и результат остаются на телефоне. А мне не прилетает новый счёт за GPU каждый раз, когда кто-то решил нарисовать ещё одного кота. Красота же.

Но чтобы всё это заработало, пришлось повозиться. Главной головной болью оказалась память. Расскажу, как я уместил SDXL в iPhone, на чём сэкономил и с какими ограничениями пришлось смириться. Без обещаний, что телефон теперь заменяет любую нейросеть в облаке.

Пример генерации в Trazo: рыжий кот на подоконнике в мультяшной стилистике.
Пример генерации в Trazo: рыжий кот на подоконнике в мультяшной стилистике.

Почему вообще не облако

Обычная схема понятна: приложение отправляет запрос на сервер, там нейросеть рисует картинку, а телефон показывает результат. Удобно. Можно использовать тяжёлые модели и поддерживать даже старые смартфоны, потому что всю работу делает сервер. Пользователю не нужно скачивать гигабайты весов.

Но за это удобство приходится платить:

  • промпты и изображения передаются на сервер;
  • без нормального соединения генерация не работает;
  • каждое изображение создаёт переменный расход на GPU;
  • эти расходы нужно чем-то покрывать — подпиской, кредитами, рекламой или другим источником дохода.

А мне было интересно сделать так, чтобы человек скачал модель и дальше пользовался ею без сервера. Да, придётся считаться с возможностями телефона. Зато генерация не зависит от связи, а её себестоимость для меня не растёт с каждой новой картинкой. Ради этого и стоило попробовать.

Сразу скажу: Stable Diffusion на iPhone придумал запускать не я. Есть, например, Draw Things — мощное приложение с локальной генерацией и кучей настроек. Мне хотелось сделать свой вариант попроще: выбираешь стиль, пишешь запрос и получаешь картинку. Без необходимости сначала разбираться, что такое чекпоинт, sampler и CFG.

Главная проблема была не в мощности, а в памяти

SDXL изначально рассчитана на куда более свободные условия, чем приложение на телефоне. Мало скачать файлы модели: во время работы ей нужна оперативная память и для весов, и для промежуточных вычислений. Если памяти не хватает, до готовой картинки дело может просто не дойти. Так что сначала мне пришлось добиться стабильного запуска, а уже потом выжимать скорость.

В iPhone есть Neural Engine — отдельный блок чипа для нейросетевых вычислений. Но наличие этого блока само по себе проблему не решает. Модель нужно подготовить для Core ML, фреймворка Apple для машинного обучения, и подобрать подходящий способ выполнения. Core ML умеет распределять работу между CPU, GPU и Neural Engine; конкретный результат зависит от модели и устройства.

Со старыми iPhone я провозился неделю. Запустить модель один раз — ещё не значит получить приложение, которым нормально пользоваться каждый день. В итоге ограничил список устройств. Не хотелось, чтобы человек установил Trazo и вместо картинок смотрел на бесконечную загрузку.

После сжатия весов пиковое потребление оперативной памяти в моих замерах составило около 2 ГБ. Это память во время работы, а не размер скачиваемой модели. Для приложения важны обе цифры: одна определяет, хватит ли места в хранилище, другая — сможет ли телефон выполнить генерацию.

Как я перенёс SDXL в iPhone

За основу взял открытый проект Apple ml-stable-diffusion. В нём есть инструменты, чтобы перевести модель из PyTorch в Core ML, и Swift-пакет для запуска генерации в приложении. То есть начинать с нуля не пришлось.

Дальше пришлось собрать несколько оптимизаций вместе:

Сжал веса до 6 бит с помощью палетизации. Если по-простому, близкие значения весов собираются в небольшую таблицу, а модель хранит короткие индексы на них. Так она занимает меньше места. При этом сжатие может повлиять на результат, поэтому качество нужно проверять на конкретной модели, а не считать шесть бит гарантией отсутствия потерь.

Задействовал Neural Engine через Core ML. На него приходится основная тяжёлая работа в моей реализации. CPU тоже участвует: управляет последовательностью вычислений и выполняет вспомогательные задачи. Полностью «выключить процессор» тут, конечно, не получится.

Ограничил поддержку конкретными устройствами. Самый старый iPhone в моём списке — 13 Pro. Это не обещание поддержки любого телефона с A15: одного названия чипа недостаточно, важны ещё память и стабильность работы. Перед установкой стоит проверить совместимость своего устройства в App Store.

Подобрал три модели под разные стили. Animagine XL 4.0 — для аниме, RealVisXL V5.0 — для реалистичных картинок, RealCartoon XL V6 — для мультяшных. Пользователю не обязательно запоминать эти названия: в приложении он просто выбирает нужный стиль.

Для меня это больше работы с подготовкой и доставкой моделей. Зато человеку проще начать: хочет аниме — выбирает аниме, хочет реалистичную картинку — выбирает реализм. Я как раз и хотел убрать из этого процесса лишнюю возню с настройками.

Ещё один результат Trazo: кот на подоконнике в реалистичной стилистике. Примеры показывают разные варианты результата, а не сравнение моделей на одинаковых настройках.
Ещё один результат Trazo: кот на подоконнике в реалистичной стилистике. Примеры показывают разные варианты результата, а не сравнение моделей на одинаковых настройках.

Что здесь на самом деле означает «офлайн»

Для первого запуска интернет понадобится: нужно установить приложение и скачать выбранную модель. Лучше сделать это заранее по Wi-Fi. Когда загрузка закончилась, файлы лежат на телефоне, и для генерации связь уже не нужна.

Проверить это легко: скачали модель, отключили Wi-Fi и мобильную сеть, попробовали создать картинку. Сам запрос обрабатывается на устройстве, результат тоже остаётся там. Для меня именно в этом смысл офлайна: генерация продолжает работать, даже когда связи вообще нет.

За автономность платим местом в хранилище. Само приложение в описываемой версии занимает около 135 МБ, а модели скачиваются дополнительно. В карточках трёх моделей указано по 2,3 ГБ. Качать все сразу не обязательно: можно выбрать нужную, а ненужные потом удалить. Для повторной загрузки удалённой модели снова понадобится интернет.

Менеджер моделей Trazo. На этом телефоне загружены все три, а общий счётчик занятого места показывает 7,86 ГБ. Можно оставить только ту модель, которой пользуешься.
Менеджер моделей Trazo. На этом телефоне загружены все три, а общий счётчик занятого места показывает 7,86 ГБ. Можно оставить только ту модель, которой пользуешься.

Что получилось

Мой рабочий режим сейчас — 768×768 и 20 шагов. Шаги — это последовательные проходы, за которые модель превращает шум в картинку. На 15 Pro Max у меня выходит около 20 секунд, на 13 Pro — около 30. Первая генерация может идти дольше, потому что модель ещё нужно загрузить в память. Нагрев телефона и нагрузка от других приложений тоже влияют на время.

Есть и локальное увеличение ×4: из 768×768 получается файл 3072×3072, в моих тестах примерно за 5–10 секунд. Тут важно не путать размер с детализацией. Текущий апскейл увеличивает картинку и немного повышает чёткость, но не дорисовывает новые детали. Четыре пальца в пять правильных он, увы, не превратит.

После HD-увеличения приложение показывает 3072×3072. Размер файла в пикселях вырос, но новых деталей текущий апскейл не дорисовывает.
После HD-увеличения приложение показывает 3072×3072. Размер файла в пикселях вырос, но новых деталей текущий апскейл не дорисовывает.

Для аватарок, иллюстраций к постам и набросков идей результат уже вполне годится. Но руки, надписи и сцены с кучей персонажей могут получаться криво. Иногда хороший вариант приходится поискать за несколько попыток. Поэтому мне сейчас интереснее улучшать качество на обычных запросах людей, чем просто добавлять побольше пикселей.

Цена офлайна — скорость и совместимость

20–30 секунд на картинку — это ощутимое ожидание, особенно когда хочется перебрать десяток вариантов. Облачный сервис может быть быстрее, но время зависит от модели, разрешения, загрузки серверов и очереди. Поэтому сравнивать стоит конкретные режимы и качество результата, а не обещать, что любое облако всегда справится за пять секунд.

У локальной генерации свои расходы: она занимает память, нагружает телефон и тратит заряд. Облачная снимает основную вычислительную нагрузку с устройства, зато требует связи и зависит от условий сервиса. Так что выбирать тут стоит под свою задачу.

Если нужно быстро перебрать много вариантов или взять самую тяжёлую свежую модель, я бы смотрел на облачные инструменты. Если хочется рисовать без сети и не отправлять запросы на сервер, локальный вариант уже имеет смысл. Готовы ли вы ждать полминуты ради этого — вопрос ваших привычек, а не универсальный ответ для всех.

Почему офлайн — это ещё и другая экономика

Теперь про деньги. Для меня как для соло-разработчика это одна из самых интересных частей. В облачном генераторе активность пользователей означает дополнительную нагрузку на GPU. Хорошо, когда приложением пользуются. Чуть менее весело, когда вместе с этим быстро растёт счёт за вычисления.

В Trazo я не оплачиваю серверные вычисления для каждой картинки: считает телефон пользователя, он же расходует заряд. Конечно, само приложение от этого не становится бесплатным в разработке и поддержке. Остаются доставка моделей, комиссия App Store и другие расходы. Но отдельного GPU-счёта за генерации нет.

Простой пример, не статистика Trazo: 1000 человек делают по 20 картинок в день. За 30 дней получается 600 тысяч изображений. В облаке все эти вычисления нужно обеспечить на сервере. У меня они распределяются по телефонам пользователей. Масштаб тот же, а забота о серверных мощностях совсем другая.

Это даёт больше свободы в выборе оплаты. Например, проще предложить разовую покупку: не нужно заранее угадывать, сколько серверных вычислений человек потратит за несколько лет.

Если выбирать подписку, её доход можно направлять на новые функции, модели и поддержку, не закладывая в каждую картинку оплату облачного GPU.

С бесплатным режимом та же история: активный пользователь не сжигает мой бюджет на генерацию. Это возможности такой архитектуры, а не описание конкретного тарифа. Актуальные условия оплаты нужно смотреть в самом приложении.

При этом рост аудитории всё равно может увеличить расходы на скачивание моделей и поддержку. Я убрал из уравнения именно серверную генерацию. Все остальные заботы разработчика остались со мной, тут без чудес.

Зато мне не нужно поднимать новые GPU-серверы при росте нагрузки и разбираться с очередью генераций. Для проекта, который я делаю сам, это заметно упрощает жизнь.

Освободившееся время я могу тратить на то, что человек видит в приложении: картинки, скорость, удобство. Распространять Trazo помогает App Store, а вычислительная мощность уже есть у пользователя в кармане. Мне такой подход нравится.

Когда on-device AI действительно имеет смысл

Если вы тоже делаете приложение с локальной нейросетью, я бы начал с четырёх вопросов. Помещается ли модель в память нужных устройств? Готов ли пользователь столько ждать? Важны ли ему автономность и обработка данных на телефоне? И сколько вы действительно сэкономите на облаке при ожидаемой частоте использования?

Я бы проверял это на самом слабом устройстве, которое собираюсь поддерживать: отдельно первый запуск и несколько генераций подряд. Так быстрее станет понятно, где заканчивается красивое демо и начинаются реальные ограничения. Если нужны старые телефоны, тяжёлые модели и частая их замена, серверный вариант вполне может оказаться удобнее.

У меня этот эксперимент превратился в работающий продукт. Со своими ограничениями, но уже с понятной пользой: можно рисовать без сети, а мне не нужно оплачивать каждую попытку пользователя. Теперь хочется сделать всё это быстрее и удобнее.

Дальше хочу попробовать few-step distillation — подходы, которые позволяют модели получать картинку за меньшее число шагов. Цель — приблизиться к десяти секундам, сохранив приемлемое качество. Пока это план, а не готовый результат. Ещё хочу подтянуть лица, руки и сложные сцены. А потом уже думать о более высоком исходном разрешении.

Если попробуете Trazo — напишите, на каком iPhone запускали, что получилось и чего не хватает. Я свои проекты развиваю в том числе по таким отзывам, так что замечания очень пригодятся. И отдельно интересно: где вам реально нужна генерация без интернета? Вопросы по технической части тоже несите в комментарии, обсудим.

11