Как я засунул 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, на чём сэкономил и с какими ограничениями пришлось смириться. Без обещаний, что телефон теперь заменяет любую нейросеть в облаке.
Почему вообще не облако
Обычная схема понятна: приложение отправляет запрос на сервер, там нейросеть рисует картинку, а телефон показывает результат. Удобно. Можно использовать тяжёлые модели и поддерживать даже старые смартфоны, потому что всю работу делает сервер. Пользователю не нужно скачивать гигабайты весов.
Но за это удобство приходится платить:
- промпты и изображения передаются на сервер;
- без нормального соединения генерация не работает;
- каждое изображение создаёт переменный расход на 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 — для мультяшных. Пользователю не обязательно запоминать эти названия: в приложении он просто выбирает нужный стиль.
Для меня это больше работы с подготовкой и доставкой моделей. Зато человеку проще начать: хочет аниме — выбирает аниме, хочет реалистичную картинку — выбирает реализм. Я как раз и хотел убрать из этого процесса лишнюю возню с настройками.
Что здесь на самом деле означает «офлайн»
Для первого запуска интернет понадобится: нужно установить приложение и скачать выбранную модель. Лучше сделать это заранее по Wi-Fi. Когда загрузка закончилась, файлы лежат на телефоне, и для генерации связь уже не нужна.
Проверить это легко: скачали модель, отключили Wi-Fi и мобильную сеть, попробовали создать картинку. Сам запрос обрабатывается на устройстве, результат тоже остаётся там. Для меня именно в этом смысл офлайна: генерация продолжает работать, даже когда связи вообще нет.
За автономность платим местом в хранилище. Само приложение в описываемой версии занимает около 135 МБ, а модели скачиваются дополнительно. В карточках трёх моделей указано по 2,3 ГБ. Качать все сразу не обязательно: можно выбрать нужную, а ненужные потом удалить. Для повторной загрузки удалённой модели снова понадобится интернет.
Что получилось
Мой рабочий режим сейчас — 768×768 и 20 шагов. Шаги — это последовательные проходы, за которые модель превращает шум в картинку. На 15 Pro Max у меня выходит около 20 секунд, на 13 Pro — около 30. Первая генерация может идти дольше, потому что модель ещё нужно загрузить в память. Нагрев телефона и нагрузка от других приложений тоже влияют на время.
Есть и локальное увеличение ×4: из 768×768 получается файл 3072×3072, в моих тестах примерно за 5–10 секунд. Тут важно не путать размер с детализацией. Текущий апскейл увеличивает картинку и немного повышает чёткость, но не дорисовывает новые детали. Четыре пальца в пять правильных он, увы, не превратит.
Для аватарок, иллюстраций к постам и набросков идей результат уже вполне годится. Но руки, надписи и сцены с кучей персонажей могут получаться криво. Иногда хороший вариант приходится поискать за несколько попыток. Поэтому мне сейчас интереснее улучшать качество на обычных запросах людей, чем просто добавлять побольше пикселей.
Цена офлайна — скорость и совместимость
20–30 секунд на картинку — это ощутимое ожидание, особенно когда хочется перебрать десяток вариантов. Облачный сервис может быть быстрее, но время зависит от модели, разрешения, загрузки серверов и очереди. Поэтому сравнивать стоит конкретные режимы и качество результата, а не обещать, что любое облако всегда справится за пять секунд.
У локальной генерации свои расходы: она занимает память, нагружает телефон и тратит заряд. Облачная снимает основную вычислительную нагрузку с устройства, зато требует связи и зависит от условий сервиса. Так что выбирать тут стоит под свою задачу.
Если нужно быстро перебрать много вариантов или взять самую тяжёлую свежую модель, я бы смотрел на облачные инструменты. Если хочется рисовать без сети и не отправлять запросы на сервер, локальный вариант уже имеет смысл. Готовы ли вы ждать полминуты ради этого — вопрос ваших привычек, а не универсальный ответ для всех.
Почему офлайн — это ещё и другая экономика
Теперь про деньги. Для меня как для соло-разработчика это одна из самых интересных частей. В облачном генераторе активность пользователей означает дополнительную нагрузку на GPU. Хорошо, когда приложением пользуются. Чуть менее весело, когда вместе с этим быстро растёт счёт за вычисления.
В Trazo я не оплачиваю серверные вычисления для каждой картинки: считает телефон пользователя, он же расходует заряд. Конечно, само приложение от этого не становится бесплатным в разработке и поддержке. Остаются доставка моделей, комиссия App Store и другие расходы. Но отдельного GPU-счёта за генерации нет.
Простой пример, не статистика Trazo: 1000 человек делают по 20 картинок в день. За 30 дней получается 600 тысяч изображений. В облаке все эти вычисления нужно обеспечить на сервере. У меня они распределяются по телефонам пользователей. Масштаб тот же, а забота о серверных мощностях совсем другая.
Это даёт больше свободы в выборе оплаты. Например, проще предложить разовую покупку: не нужно заранее угадывать, сколько серверных вычислений человек потратит за несколько лет.
Если выбирать подписку, её доход можно направлять на новые функции, модели и поддержку, не закладывая в каждую картинку оплату облачного GPU.
С бесплатным режимом та же история: активный пользователь не сжигает мой бюджет на генерацию. Это возможности такой архитектуры, а не описание конкретного тарифа. Актуальные условия оплаты нужно смотреть в самом приложении.
При этом рост аудитории всё равно может увеличить расходы на скачивание моделей и поддержку. Я убрал из уравнения именно серверную генерацию. Все остальные заботы разработчика остались со мной, тут без чудес.
Зато мне не нужно поднимать новые GPU-серверы при росте нагрузки и разбираться с очередью генераций. Для проекта, который я делаю сам, это заметно упрощает жизнь.
Освободившееся время я могу тратить на то, что человек видит в приложении: картинки, скорость, удобство. Распространять Trazo помогает App Store, а вычислительная мощность уже есть у пользователя в кармане. Мне такой подход нравится.
Когда on-device AI действительно имеет смысл
Если вы тоже делаете приложение с локальной нейросетью, я бы начал с четырёх вопросов. Помещается ли модель в память нужных устройств? Готов ли пользователь столько ждать? Важны ли ему автономность и обработка данных на телефоне? И сколько вы действительно сэкономите на облаке при ожидаемой частоте использования?
Я бы проверял это на самом слабом устройстве, которое собираюсь поддерживать: отдельно первый запуск и несколько генераций подряд. Так быстрее станет понятно, где заканчивается красивое демо и начинаются реальные ограничения. Если нужны старые телефоны, тяжёлые модели и частая их замена, серверный вариант вполне может оказаться удобнее.
У меня этот эксперимент превратился в работающий продукт. Со своими ограничениями, но уже с понятной пользой: можно рисовать без сети, а мне не нужно оплачивать каждую попытку пользователя. Теперь хочется сделать всё это быстрее и удобнее.
Дальше хочу попробовать few-step distillation — подходы, которые позволяют модели получать картинку за меньшее число шагов. Цель — приблизиться к десяти секундам, сохранив приемлемое качество. Пока это план, а не готовый результат. Ещё хочу подтянуть лица, руки и сложные сцены. А потом уже думать о более высоком исходном разрешении.
Trazo в App Store: https://apps.apple.com/app/trazo-ai-art-offline/id6765913692
Если попробуете Trazo — напишите, на каком iPhone запускали, что получилось и чего не хватает. Я свои проекты развиваю в том числе по таким отзывам, так что замечания очень пригодятся. И отдельно интересно: где вам реально нужна генерация без интернета? Вопросы по технической части тоже несите в комментарии, обсудим.