Автор статьи рассказывает, как за неделю создал Text2Art.com — генератор изображений на основе VQGAN+CLIP, способный рисовать пиксель-арт и живопись, а также изображать то, что вы напишете в текстовом поле.

Для интерфейса используется Gradio, модель работает на сервере FastAPI, а системой очереди сообщений служит Firebase. Подробностями делимся к старту курса по ML и DL.


Галерея Text2Art
Галерея Text2Art

Если вам понравился проект, вы можете проголосовать за него здесь.

Введение

Не так давно генеративные картины и NFT штурмом захватили мир. Это стало возможным после значительного прогресса OpenAI в генерации изображения из текста. Ранее в этом году OpenAI анонсировал DALL-E, мощный генератор изображений из текстов.

Чтобы проиллюстрировать, насколько хорошо работает DALL-E, посмотрите рисунки, сгенерированные DALL-E по запросу "a professional high quality illustration of a giraffe dragon chimera, "a giraffe imitating a dragon", "a giraffe made of dragon".

Изображения по запросу "a professional high quality illustration of a giraffe dragon chimera, "a giraffe imitating a dragon", "a giraffe made of dragon".
Изображения по запросу "a professional high quality illustration of a giraffe dragon chimera, "a giraffe imitating a dragon", "a giraffe made of dragon".

К сожалению, DALL-E не был выпущен в массы. Вместо него была опубликована модель, которая творит магию DALL-E, — CLIP. CLIP или Contrastive Image-Language Pretraining — это мультимодальная сеть, объединяющая текст и изображения.

Одним словом, CLIP способен оценить, насколько хорошо изображение соответствует надписи или наоборот.

Это крайне полезно в управлении генератором, чтобы создать изображение, точно соответствующее введённому тексту. В фильме "DALL-E"  CLIP используется, чтобы ранжировать сгенерированные изображения и входные изображения с наивысшим баллом (самые похожие на тектовый запрос).

Через несколько месяцев после анонса фильма DALL-E был опубликован новый генератор изображений-трансформеров под названием VQGAN (Vector Quantized GAN). Сочетание VQGAN с CLIP даёт качество, аналогичное DALL-E. С момента обнародования предварительно обученной модели VQGAN сообщество создало множество удивительных картин.

Вот примеры:

Я был поражён результатами и захотел поделиться ими со своими друзьями. Но, поскольку не так много людей готовы погрузиться в код ради генерации картин, я решил сделать Text2Art.com — сайт, где любой может просто ввести подсказку и сгенерировать нужное изображение, не сталкиваясь с кодом воочию.

Как это работает

Итак, как работает VQGAN+CLIP? VQGAN генерирует изображение, а CLIP измеряет, насколько оно соответствует запросу. Затем генератор использует обратную связь от модели CLIP, чтобы сгенерировать более точные изображения. Процедура повторяется, пока оценка CLIP не станет достаточно высокой.

VQGAN генерирует изображения, пока CLIP направляет процесс. Чем больше итераций, тем точнее изображение [источник: иллюстрированный VQGAN от LJ Miranda]
VQGAN генерирует изображения, пока CLIP направляет процесс. Чем больше итераций, тем точнее изображение [источник: иллюстрированный VQGAN от LJ Miranda]

Я не буду рассказывать о внутренней работе VQGAN или CLIP. Но, если вы хотите получить более глубокие объяснения VQGAN, CLIP или DALL-E, обратитесь к этим удивительным ресурсам, которые я нашёл:

X + CLIP

VQGAN+CLIP — это только пример того, на что способно объединение генератора изображений с CLIP. Однако вы можете заменить VQGAN на любой генератор. Появилось много вариантов X + CLIP, таких как StyleCLIP (StyleGAN + CLIP), CLIPDraw (векторный генератор), BigGAN + CLIP и многие другие, даже AudioCLIP, который работает со звуком, а не изображениями.

Редактирование изображений при помощи StyleCLIP [работа о StyleCLIP]
Редактирование изображений при помощи StyleCLIP [работа о StyleCLIP]

Код

Я воспользуюсь кодом из репозитория clipit от dribnet, этот код генерирует изображения при помощи VQGAN+CLIP в несколько простых строк (обновление: clipit мигрировал на pixray). Его рекомендуется запускать на Google Colab: VQGAN+CLIP требует много памяти GPU. Вот блокнот Colab.

Прежде всего, если вы работаете на Colab, убедитесь, что вы изменили тип рантайма на GPU, вот так:

Установим кодовую базу и зависимости:

from IPython.utils import io
with io.capture_output() as captured:
  !git clone https://github.com/openai/CLIP
  # !pip install taming-transformers
  !git clone https://github.com/CompVis/taming-transformers.git
  !rm -Rf clipit
  !git clone https://github.com/mfrashad/clipit.git
  !pip install ftfy regex tqdm omegaconf pytorch-lightning
  !pip install kornia
  !pip install imageio-ffmpeg   
  !pip install einops
  !pip install torch-optimizer
  !pip install easydict
  !pip install braceexpand
  !pip install git+https://github.com/pvigier/perlin-numpy

  # ClipDraw deps
  !pip install svgwrite
  !pip install svgpathtools
  !pip install cssutils
  !pip install numba
  !pip install torch-tools
  !pip install visdom

  !pip install gradio

  !git clone https://github.com/BachiLi/diffvg
  %cd diffvg
  # !ls
  !git submodule update --init --recursive
  !python setup.py install
  %cd ..
  
  !mkdir -p steps
  !mkdir -p models

"!" — это специальная команда в Google Colab, которая означает, что команда будет запущена в bash, а не в python.

После установки библиотек мы можем просто импортировать clipit и запустить эти несколько строк кода для генерации картины с помощью VQGAN+CLIP.

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

Вот код генерации:

import sys
sys.path.append("clipit")
import clipit

# To reset settings to default
clipit.reset_settings()

# You can use "|" to separate multiple prompts
prompts = "underwater city"

# You can trade off speed for quality: draft, normal, better, best
quality = "normal"

# Aspect ratio: widescreen, square
aspect = "widescreen"

# Add settings
clipit.add_settings(prompts=prompts, quality=quality, aspect=aspect)

# Apply these settings and run
settings = clipit.apply_settings()
clipit.do_init(settings)
cliptit.do_run(settings)

Когда вы запустите код, он сгенерирует изображение. На каждой итерации сгенерированное изображение будет приближаться к тексту, который вы ввели.

Итерации по заросу “underwater city”
Итерации по заросу “underwater city”

Количество итераций

Вот так можно установить количество итераций, им управляет iterations:

clipit.add_settings(iterations=500)

Генерация видео

В любом случае нужно генерировать изображение для каждой итерации, поэтому можно сохранить эти изображения и создать анимацию самой генерации. Для этого добавьте make_video=True перед применением настроек.

clipit.add_settings(make_video=True)

Получится этот ролик:

Сгенерированный подводный город, запрос “Underwater City”
Сгенерированный подводный город, запрос “Underwater City”

Управление размером изображений

Размер изображения устанавливается опцией size=(width, height). Сенерируем баннерное изображение с разрешением 800x200. Обратите внимание, что более высокое разрешение требует большего объёма памяти GPU.

clipit.add_settings(size=(800, 200))
Баннер 800x200 по запросу “Fantasy Kingdom #artstation”
Баннер 800x200 по запросу “Fantasy Kingdom #artstation”

Генерация пиксель-арта

Можно генерировать и пиксель-арт. Для этого используется рендерер CLIPDraw за сценой с некоторыми инженерными решениями, такими как ограничение цветов палитры, пикселизация и т.д. Просто включите опцию use_pixeldraw=True.

clipit.add_settings(use_pixeldraw=True)
Изображение по запросу “Knight in armor #pixelart”
Изображение по запросу “Knight in armor #pixelart”
Изображение по запросу “A world of chinese fantasy video game #pixelart”
Изображение по запросу “A world of chinese fantasy video game #pixelart”

VQGAN+CLIP модификатор ключевых слов

Из-за смещения в CLIP добавление определённых ключевых слов к подсказке может придать определённый эффект генерируемому изображению. Например, добавление слова "unreal engine"  к текстовой подсказке, как правило, создаёт реалистичное изображение или HD стиль. Добавление определённых названий сайтов, таких как "deviantart", "artstation"  или "flickr", обычно делает результаты более эстетичными. Мне больше всего нравится использовать ключевое слово "artstation”, так как я считаю, что помогает создать лучшие картины.

Сравнение ключевых слов
Сравнение ключевых слов

Кроме того, вы можете использовать ключевые слова, чтобы обусловить художественный стиль: "pencil sketch”, "low poly" или даже имя художника — "Thomas Kinkade" или "James Gurney”.

Ключевые слова стиля — сравнение
Ключевые слова стиля — сравнение

Чтобы узнать больше о влиянии различных ключевых слов, вы можете ознакомиться с изображением, которое показывает более 200 слов на 4 темы.

UI на Gradio

Gradio — это библиотека Python, которая упрощает построение демонстраций ML до нескольких строк кода. Демоверсия требует меньше 10 минут работы. Кроме того, вы можете запустить Gradio в Colab, и он сгенерирует ссылку для совместного использования на домене Gradio. Ссылкой можно поделиться.

Gradio имеет некоторые ограничения, но я считаю, что это самая подходящая библиотека, когда вы просто хотите продемонстрировать одну функцию.

Ниже код простого пользовательского интерфейса для приложения Text2Art. Думаю, что он достаточно понятен, но, если вам нужно больше объяснений, смотрите документацию Gradio.

import gradio as gr
import torch
import clipit

# Define the main function
def generate(prompt, quality, style, aspect):
    torch.cuda.empty_cache()
    clipit.reset_settings()
    
    use_pixeldraw = (style == 'pixel art')
    use_clipdraw = (style == 'painting')
    clipit.add_settings(prompts=prompt,
                        aspect=aspect,
                        quality=quality,
                        use_pixeldraw=use_pixeldraw,
                        use_clipdraw=use_clipdraw,
                        make_video=True)
  
    settings = clipit.apply_settings()
    clipit.do_init(settings)
    clipit.do_run(settings)

    return 'output.png', 'output.mp4'

# Create the UI
prompt = gr.inputs.Textbox(default="Underwater city", label="Text Prompt")
quality = gr.inputs.Radio(choices=['draft', 'normal', 'better'], label="Quality")
style = gr.inputs.Radio(choices=['image', 'painting','pixel art'], label="Type")
aspect = gr.inputs.Radio(choices=['square', 'widescreen','portrait'], label="Size")

# Launch the demo
iface = gr.Interface(generate, inputs=[prompt, quality, style, aspect], outputs=['image', 'video'], enable_queue=True, live=False)
iface.launch(debug=True)

Как только вы запустите эту программу в Google Colab или локально, она создаст ссылку, которой можно поделиться, демонстрация будет общедоступной. Не нужно использовать туннелирование SSH вроде ngrok. Кроме того, Gradio также предлагает хостинг за 7 долларов в месяц.

Ссылка в демо, которой можно поделиться.
Ссылка в демо, которой можно поделиться.

Однако Gradio хорошо подходит только для демонстрации одной функции. Создание кастомного сайта с дополнительными функциями, такими как галерея, вход в систему или даже просто пользовательский CSS, довольно ограничено или вообще невозможно.

Одно быстрое решение — создать демонстрационный сайт отдельно от пользовательского интерфейса Gradio, затем — встроить интерфейс Gradio через iframe.

Я попробовал этот метод, но осознал один важный недостаток: я не могу персонализировать части, которые должны взаимодействовать с самим приложением ML: валидацию ввода, пользовательский прогресс-бар и т. д., невозможны с iframe. И я решил создать API.

FastAPI для модели

Чтобы сделать API быстрее, вместо Flask я воспользовался FastAPI. Кода меньше, а ещё он автоматически генерирует документацию со Swagger UI, что позволяет тестировать API с помощью простого пользовательского интерфейса.

Кроме того, FastAPI поддерживает асинхронные функции и, как утверждается, он быстрее, чем Flask.

Добавляем /docs/ в URL, чтобы увидеть Swagger
Добавляем /docs/ в URL, чтобы увидеть Swagger
Тестируем API в UI Swagger
Тестируем API в UI Swagger

Вот код, который я написал для выполнения функции ML на сервере FastAPI:

import clipit
import torch
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi import FastAPI, File, UploadFile, Form, BackgroundTasks
from fastapi.responses import FileResponse

app = FastAPI()

app.add_middleware(
    CORSMiddleware,
    allow_origins=['*'],
    allow_credentials=True,
    allow_methods=['*'],
    allow_headers=['*'],
)

@app.get('/')
async def root():
    return {'hello': 'world'}

@app.post("/generate")
async def generate(
        seed: int = Form(None),
        iterations: int = Form(None),
        prompts: str = Form("Underwater City"),
        quality: str = Form("draft"),
        aspect: str = Form("square"),
        scale: float = Form(2.5),
        style: str = Form('image'),
        make_video: bool = Form(False),      
    ):
    torch.cuda.empty_cache()
    clipit.reset_settings()

    use_pixeldraw = (style == 'Pixel Art')
    use_clipdraw = (style == 'Painting')
    clipit.add_settings(prompts=prompts,
                        seed=seed,
                        iterations=iterations,
                        aspect=aspect,
                        quality=quality,
                        scale=scale,
                        use_pixeldraw=use_pixeldraw,
                        use_clipdraw=use_clipdraw,
                        make_video=make_video)
    
    settings = clipit.apply_settings()
    clipit.do_init(settings)
    clipit.do_run(settings)

    return FileResponse('output.png', media_type="image/png")

После определения сервера мы можем запустить его с помощью uvicorn. Кроме того, поскольку Google Colab предоставляет доступ к своему серверу только через интерфейс Colab, мы должны использовать Ngrok, чтобы сделать сервер FastAPI публичным.

Код для запуска и демонстрации сервера:

import nest_asyncio
from pyngrok import ngrok
import uvicorn

ngrok_tunnel = ngrok.connect(8000)
print('Public URL:', ngrok_tunnel.public_url)
print('Doc URL:', ngrok_tunnel.public_url+'/docs')
nest_asyncio.apply()
uvicorn.run(app, port=8000)

Запустив сервер, мы можем перейти к Swagger UI (добавив /docs в сгенерированный ngrok URL) и протестировать API.

Генерация подводного замка при помощи FastAPI Swagger UI
Генерация подводного замка при помощи FastAPI Swagger UI

При тестировании API я понял, что вывод может занять от 3 до 20 минут в зависимости от качества/итераций. Три минуты само по себе уже считается очень долгим для HTTP-запроса, и пользователи могут не захотеть ждать так долго.

Я решил, что установка вывода в качестве фоновой задачи и отправка пользователю электронного письма после получения результата лучше подходят для этой задачи.

Теперь, когда мы определились с планом, напишем функцию для отправки письма. Сначала я использовал почтовый API SendGrid, но после исчерпания квоты бесплатного использования (100 писем в день) перешёл на API Mailgun, который входит в пакет GitHub Student Developer Pack, разрешая студентам отправлять 20 000 писем в месяц.

Вот код для отправки электронного письма с вложением изображения с помощью API Mailgun:

import requests
def email_results_mailgun(email, prompt):
    return requests.post("https://api.mailgun.net/v3/text2art.com/messages",
        auth=("api", "YOUR_MAILGUN_API_KEY"),
        files=[("attachment",("output.png", open("output.png", "rb").read() )),
               ("attachment", ("output.mp4", open("output.mp4", "rb").read() ))],
        data={"from": "Text2Art <YOUR_EMAIL>",
              "to": email,
              "subject": "Your Artwork is ready!",
              "text": f'Your generated arts using the prompt "{prompt}".',
              "html": f'Your generated arts using the prompt <strong>"{prompt}"</strong>.'})

Далее мы изменим код нашего сервера, чтобы использовать фоновые задачи в FastAPI и отправить результат по электронной почте в фоновом режиме.

Код сервера
#@title API Functions
import clipit
import torch
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi import FastAPI, File, UploadFile, Form, BackgroundTasks
from fastapi.responses import FileResponse

app = FastAPI()

app.add_middleware(
    CORSMiddleware,
    allow_origins=['*'],
    allow_credentials=True,
    allow_methods=['*'],
    allow_headers=['*'],
)

# define function to be run as background tasks
def generate(email, settings):
    clipit.do_init(settings)
    clipit.do_run(settings)

    prompt = " | ".join(settings.prompts)

    email_results_mailgun(email, prompt)

@app.get('/')
async def root():
    return {'hello': 'world'}

@app.post("/generate")
async def add_task(
        email: str,
        background_tasks: BackgroundTasks,
        seed: int = Form(None),
        iterations: int = Form(None),
        prompts: str = Form("Underwater City"),
        quality: str = Form("draft"),
        aspect: str = Form("square"),
        scale: float = Form(2.5),
        style: str = Form('image'),
        make_video: bool = Form(False),      
    ):
    torch.cuda.empty_cache()
    clipit.reset_settings()

    use_pixeldraw = (style == 'Pixel Art')
    use_clipdraw = (style == 'Painting')
    clipit.add_settings(prompts=prompts,
                        seed=seed,
                        iterations=iterations,
                        aspect=aspect,
                        quality=quality,
                        scale=scale,
                        use_pixeldraw=use_pixeldraw,
                        use_clipdraw=use_clipdraw,
                        make_video=make_video)
    
    settings = clipit.apply_settings()

    # Run function as background task
    background_tasks.add_task(generate, email, settings)

    return {"message": "Task is processed in the background"}
  

С помощью приведённого выше кода сервер быстро ответит на запрос сообщением "Task is processed in the background" вместо того, чтобы ждать завершения генерации и ответа с изображением. Когда генерация завершится, сервер по электронной почте отправит пользователю результат.

Изображение и видеозапись отправляются пользователю по электронной почте
Изображение и видеозапись отправляются пользователю по электронной почте

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

Когда второй пользователь делает запрос на сервер, в то время как первая задача всё ещё обрабатывается, вторая задача каким-то образом завершает текущий процесс, вместо того чтобы создать параллельный процесс или очередь.

Не было уверенности, что вызвало проблему, возможно, это было использование глобальных переменных в коде clipit, а возможно, нет. Я быстро понял, что мне нужно реализовать систему очереди сообщений.

По результатам поисков в Google большинство рекомендует RabbitMQ или Redis. Однако я не был уверен, можно ли установить RabbitMQ или Redis на Google Colab: для этого, похоже, требуется разрешение sudo.

В конце концов, я решил использовать Google Firebase, потому что хотел закончить проект как можно скорее, а с Firebase я знаком лучше всего.

В основном, когда пользователь пытается сгенерировать рисунок во фронтенде, он добавляет запись в queue, которая описывает задачу (введённый текст, тип изображения, размер и т. д.).

С другой стороны, мы запустим сценарий на Google Colab, который будет постоянно прослушивать новую запись в очереди и обрабатывать задания одно за другим.

Код бэкенда, который обрабатывает задание и постоянно прослушивает очередь
import torch
import clipit
import time
from datetime import datetime
import firebase_admin
from firebase_admin import credentials, firestore, storage

if not firebase_admin._apps:
    cred = credentials.Certificate("YOUR_CREDENTIAL_FILE")
    firebase_admin.initialize_app(cred, {
        'storageBucket': 'YOUR_BUCKET_URL'
    })

db = firestore.client()
bucket = storage.bucket()

def generate(doc_id, prompt, quality, style, aspect, email):
    torch.cuda.empty_cache()
    clipit.reset_settings()

    use_pixeldraw = (style == 'pixel art')
    use_clipdraw = (style == 'painting')
    clipit.add_settings(prompts=prompt,
                        seed=seed,
                        aspect=aspect,
                        quality=quality,
                        use_pixeldraw=use_pixeldraw,
                        use_clipdraw=use_clipdraw,
                        make_video=True)
    
    settings = clipit.apply_settings()
    clipit.do_init(settings)
    clipit.do_run(settings)

    data = {
        "seed": seed,
        "prompt": prompt,
        "quality": quality,
        "aspect": aspect,
        "type": style,
        "user": email,
        "created_at": datetime.now()
    }
    db.collection('generated_images').document(doc_id).set(data)
    email_results_mailgun(email, prompt)

transaction = db.transaction()

@firestore.transactional
def claim_task(transaction, queue_objects_ref):
    # query firestore
    queue_objects = queue_objects_ref.stream(transaction=transaction)

    # pull the document from the iterable
    next_item = None
    for doc in queue_objects:
        next_item = doc

    # if queue is empty return status code of 2
    if not next_item:
        return {"status": 2}

    # get information from the document 
    next_item_data = next_item.to_dict()
    next_item_data["status"] = 0
    next_item_data['id'] = next_item.id

    # delete the document and return the information
    transaction.delete(next_item.reference)
    return next_item_data

# initialize query
queue_objects_ref = (
    db.collection("queue")
    .order_by("created_at", direction="ASCENDING")
    .limit(1)
)

transaction_attempts = 0
while True:
    try:
        # apply transaction
        next_item_data = claim_task(transaction, queue_objects_ref)
        if next_item_data['status'] == 0:
            generate(next_item_data['id'],
                     next_item_data['prompt'],
                     next_item_data['quality'],
                     next_item_data['type'],
                     next_item_data['aspect'],
                     next_item_data['email'])
            print(f"Generated {next_item_data['prompt']} for {next_item_data['email']}")

    except Exception as e:
        print(f"Could not apply transaction. Error: {e}")
        time.sleep(5)
        transaction_attempts += 1
        if transaction_attempts > 20:
            db.collection("errors").add({
                "exception": f"Could not apply transaction. Error: {e}",
                "time": str(datetime.now())
            })
            exit()

На фронте нужно только добавить новую задачу в очередь. Убедитесь, что правильно настроили Firebase на фронтенде:

db.collection("queue").add({
        prompt: prompt,
        email: email,
        quality: quality,
        type: type,
        aspect: aspect,
        created_at: firebase.firestore.FieldValue.serverTimestamp(),
})

Мы сделали это! Теперь, когда пользователь попытается создать рисунок на фронтенде, он добавит новую задачу в очередь. Затем рабочий скрипт на сервере Colab обработает задания в очереди, одно за другим. Вы можете заглянуть в репозиторий GitHub, чтобы увидеть весь код.

Лучше понять нейросети и научиться решать проблемы бизнеса с их помощью вы сможете на наших курсах:

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

Ссылки статьи

[1] DALL-E

[2] CLIP

[3] CLIP-VQGAN

[4] StyleCLIP

[5] Flask против FastAPI

Профессии и курсы

Комментарии (22)


  1. Areso
    07.10.2021 22:50

    Предположим, я гейм-девелопер. Я плохо умею в код, но совсем не умею в картинки.

    Захожу на такой сайт (или любой другой), вбиваю ключевые слова, с какой-то попытки получаю результат, достаточный, чтобы вставить в игру.

    Вопрос: кто является владельцем прав на картинку? ИИ? Но это программа. Авторы модели или моделей, потому что тут их две? Или владелец сервера-сервиса? Или я, потому что я написал описание и долго вылавливал среди случайных артефактов тот самый. Знаете, как коллекционирование минералов - можно собирать десятки лет камни, но лишь энный окажется божественно красив. Слепая воля случая, которая подарит конкретному булыжнику красивый узор.


    1. RigelNM
      07.10.2021 22:56

      "Знаете, как коллекционирование минералов - можно собирать десятки лет камни, но лишь энный окажется божественно красив. Слепая воля случая, которая подарик конкретному булыжнику красивый узор."

      Точно так-же как с произведением искусства, музыкант или художник делает десятки и даже сотни произведений и только одно из них ему не стыдно показать и возможно даже именно оно станет общепризнанным шедевром.

      Часто вижу такой аргумент насчет "ненастоящести" творения ИИ (дескать человек выбирает что-то хорошее. из рандома, который создал ИИ). Ну дак и среди людей-творцов мы так-же сами выбираем то что нам нравится из точно такого же хаоса.

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


      1. Areso
        07.10.2021 23:06

        А где есть описания лицензионного соглашения на эту программу или на модели? Они как-то вообще лицензируются?

        Ну вот я каждый день использую в корыстных целях кучу софта. Но это законно. Где это незаконно - либо мне это покупают (я наемный рабочий на дневной работе), либо я это не использую, как правило.

        Вопрос не досужий - генерация ассетов вполне себе рабочий вариант, но надо учитывать подводные камни (в т.ч. лицензию) и стоимость (условно-бесплатный хостинг, свое оборудование, аренда игровых машин в облаке, аренда серверов с ГПУ - вариантов много).


      1. Areso
        07.10.2021 23:11

        Конкретно SpeedTree включен как плагин в состав Unity, а Unity (в определенных пределах) можно использовать бесплатно, в т.ч. в коммерческих целях.

        Вот статья https://habr.com/ru/post/538874/

        Значит, я могу использовать SpeedTree в составе этой поставки. По крайней мере, я делаю такой вывод.


      1. Alexey2005
        08.10.2021 00:14
        +2

        думаю если разработчик ИИ пойдет в суд с жалобой, то суд встанет на его сторону.
        Сильно в том сомневаюсь. Во-первых, код для работы с моделью (CLIP) опубликован под лицензией MIT. А вот является ли объектом авторского права сама модель, полученная в результате работы данного кода (полностью автоматического! Человек после запуска ни во что не вмешивался!) — до сих пор идут споры.
        И даже если является, то разработчик вряд ли наберётся наглости, чтобы пойти в суд и потребовать роялти со всех пользователей, потому что тогда ему сразу зададут очень неудобный вопрос — «а те 400 миллионов картинок, которые вы собрали со всего Интернета для тренировки сети — у вас на них есть права? Это вообще Fair Use?».
        Поэтому шанс, что разработчик CLIP пойдёт с вами судиться, равен нулю. И в любом случае исход тех судов будет очень мутным и неопределённым.

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


        1. major-general_Kusanagi
          08.10.2021 07:50

          Фиг с этим копирайтом!
          Меня больше заботит, что это способно привести к тому, что книжные полки будут забиты макулатурой сгенерерированнной нейросетями, и теперь ещё и со сгенерированными иллюстрациями. :(
          И аналогично может получиться и с играми, и с кино-мультифильмами. :(


          1. inkelyad
            08.10.2021 09:24
            +1

            Меня больше заботит, что это способно привести к тому, что книжные полки будут забиты макулатурой сгенерерированнной нейросетями, и теперь ещё и со сгенерированными иллюстрациями. :(

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


            1. perfect_genius
              29.10.2021 14:29

              Вот-вот, т.е. будет удовлетворён каждый из нас.


    1. GospodinKolhoznik
      07.10.2021 23:27

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

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

      Ладно, сам себе в качестве контрпримера приведу игру Hylics, в которой графику делал живой человек, но выглядит она дурнее нейросетевой. И вроде даже игра имеет какой то небольшой успех в узких кругах за свой крезёвый психоделизм. В общем можно попробовать повторить его скромный успех с помощью нейросети, но затея очень уж рисковая.


      1. JustDont
        08.10.2021 10:57

        Тут даже не в абстракциях дело, а в том, что графика игр всегда состоит из множества кусочков, которые всё-таки надо сделать в одном и том же стиле (иначе это никто не купит). А нейросетка не умеет рисовать в одном стиле, куда минимум функции съехал, то и будет. Даже если это вывод, "уточненный" ключевыми словами описания стиля.


        Ну и да, с самим содержимым картинок — огромная проблема, ключевым словам они соответствуют только в случае "глянуть быстро с расстояния и не вглядываться". Если начать вглядываться, то 99.99% вывода нейросетки сразу же превращаются в абстрактную мазню.


        Я бы сказал, что для геймдева будет куда перспективнее сделать такую штуку, которая стиль одного изображения будет сводить к стилю другого изображения (базиса, нарисованного человеком) с минимумом изменений.


        1. Alexey2005
          08.10.2021 12:09

          Нейросетки отлично способны переносить стиль. Причём для этого даже не надо чего-то навороченного вроде CLIP, справляется и простенькая CycleGAN, способная работать в реальном времени:

          стилизация потока с вебкамеры


        1. Alexey2005
          08.10.2021 13:48

          Если начать вглядываться, то 99.99% вывода нейросетки сразу же превращаются в абстрактную мазню.
          Нейросетью, как и любым другим инструментом, тоже нужно уметь пользоваться. Если это просто «скачал код, даже не понимая, что там под капотом, и сгенерировал Hello World в пять строчек кода», то и получится рисунок уровня Hello World.
          А вот например подборка персонажей поттерианы, сгенерированная в Artbreeder, просто смешиванием рефов и переносом стилей:
          согласитесь, уже не совсем мазня
          Вернон Дурсль:


          Петуния Дурсль:


          Дадли Дурсль:


          Люциус Малфой:


          Драко Малфой:


          Сириус Блэк:


          Беллатриса Лестрейндж:


          1. JustDont
            08.10.2021 13:55

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


            А вот например подборка персонажей поттерианы, сгенерированная в Artbreeder, просто смешиванием рефов и переносом стилей

            Собственно, отчетливо видно, что если эти портреты разложить рядом, то они будут выглядеть крайне разнородно ("нарисовано разными людьми разными приемами с разным уровнем детализации и проработки").


            1. inkelyad
              08.10.2021 14:02

              И не выгоднее ли в итоге таки нанять художника, вместо того, чтоб тратить время программиста.

              А так же не выгодней ли нанять художника, который Artbreeder-ом пользоваться умеет и поэтому будет выдавать результат раз в n быстрее того, кто все рисует ручками.


              1. Alexey2005
                08.10.2021 14:08

                Прям так и вижу объявление:
                «Требуется художник-фуллстек. Владение Artbreeder, Topaz Gigapixel, StyleGAN2+ADA, глубокие знания VQGAN+CLIP, уверенное владение Google Colab.»


                1. inkelyad
                  08.10.2021 14:10

                  Именно так. И рядом — еще писатель с навыком владения всеми этими GPT генераторами текстов


                  1. major-general_Kusanagi
                    08.10.2021 14:12

                    рядом — еще писатель с навыком владения всеми этими GPT генераторами текстов

                    … и автор для Хабры, использующий неросети для генерации статей. :)


        1. GospodinKolhoznik
          08.10.2021 14:26

          Да, во всем согласен. Я сам давно ещё об этом думал, и даже пытался делать кое что.

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

          Ну я пытался, пытался, потратил некоторое время. В 3д моделирование я не умею, я делал сцены в воксельных редакторах (этому любой ребенок может научиться за 2 часа) и на эти сценки натравливал нейросеть. Кое что даже было вроде ничего. Но проблемы были. Во первых все таки эффекта "вау как круто" мне не удалось достигнуть. Было интересно, прикольно, забавно, странно, но прям круто не было. Во вторых то, что хорошо работает на одном изображении ужасно работает на другом. Ну и всякие уродливые артефакты то и дело лезли. Добиться какого то прямо универсального стиля, который бы одинаково хорошо работал на всех изображениях мне не удалось. Либо это был слишком психоделический стиль, либо совсем легкая обработка, которую можно и в фотошопе или гимпе получить ихними фильтрами.


          1. GospodinKolhoznik
            08.10.2021 14:39

            Например вот, что получалось.

            Вот кораблик, который я сделал в воксельном редакторе за пару часов.

            А вот он же после нейро-обработки под византийскую мозаику

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

            Ну вроде ничего так, но чтобы прям вау-обалдеть, такого нет.

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


            1. Alexey2005
              08.10.2021 15:39

              Так а цель-то ваша в чём заключалась? Что именно вы хотели получить? Если просто сделать кораблик менее пластиковым с помощью нейронки, то

              это возможно

              Если же сгенерировать «настоящий» кораблик на основе вашего квадратного, то
              уже гораздо сложнее



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


              1. GospodinKolhoznik
                08.10.2021 16:05
                +1

                Цель была получить инструмент для создания красивой пререндеренной графики на не очень красивых 3д моделях. А именно: во первых сделать красивее*, чем в оригинале, во вторых чтобы был универсальный способ из самых разных исходных изображений получать стилистически одинаковый результат и в третьих, чтобы не было бросающихся в глаза артефактов.

                *красивее по моему личному ощущению.

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


    1. inkelyad
      08.10.2021 09:23

      Вопрос: кто является владельцем прав на картинку?

      Вроде бы правами на результаты работы инструмента практически всегда является тот, кто инструмент применил, а не тот, кто инструмент изготовил.