Рубрики
Без рубрики

Передача нервного стиля самым простым способом

Алгоритм передачи нервного стиля в последнее время был в очень популярной позиции. Если мы посмотрим на … с меткой машинного обучения, глубокого обучения, информатики, Python.

Алгоритм передачи нервного стиля в последнее время был в очень популярной позиции. Если мы посмотрим на ускорение алгоритмов «глубокого обучения» за последние 5 лет, то, похоже, алгоритмы передачи нервного стиля будут сохранять эту популярность в течение длительного времени, улучшая себя с новыми подходами каждый день. В дополнение к этому, с пониманием искусства киберпанка на платформах NFT, мы заставили компьютеры рисовать больше картинок, чем раньше, какая ирония, верно? 🦾

Что такое «передача нервного стиля»?

Согласно Википедии: Передача нейронного стиля (NST) относится к классу алгоритмов программного обеспечения, которые манипулируют цифровыми изображениями или видео, чтобы принять внешний вид или визуальный стиль другого изображения. Алгоритмы NST характеризуются их использованием глубоких нейронных сетей ради трансформации изображения. Общим применением NST является создание искусственных произведений искусства из фотографий, например, путем переноса появления знаменитых картин на представленные пользователем фотографии. Несколько известных мобильных приложений используют NST методы для этой цели, включая Deedart и Prisma. Этот метод использовался художниками и дизайнерами по всему миру для разработки новых произведений искусства, основанных на существующем стиле. Статья Википедии о передаче нервного стиля

Хорошо. Википедия знает, что это такое, так что мы должны понимать об этом чертовом абзаце: Хорошо, ладно, не сердись. Я постараюсь все объяснить. Да, Википедия знает, что это такое, и объяснила это. Что «мы» должны понимать из этого, мы можем просто сказать это так: алгоритм «переноса нейронного стиля» делает 2 фотографии в качестве ввода, одну, чтобы сосредоточиться на формах, а другая, чтобы сосредоточиться на текстуре изображения. Затем он создает новую фотографию, создав синтез этих двух фотографий.

Да я вижу! Просто позвольте мне увидеть код.

Хорошо, я позволю вам увидеть код за секунду Но я хочу дать несколько инструкций перед началом. Я буду продолжать объяснять реализацию «передача нейронного стиля», которую я сделал ( Вы можете получить доступ к кодам по этой ссылке ). Мы продолжим с кодами и математическим фоном алгоритма одновременно. Так что не путайте! Пожалуйста, оставайтесь на правильном пути, сэр!

Давайте начнем – построить модель! 🔬

Во -первых, как и почти все Компьютерное зрение Приложение, нам понадобится Экстрактор функции Модель для доступа к более подробным функциям на наших изображениях. С помощью модели экстрактора функции мы проанализируем Особенности из изображений, которые у нас есть, а затем делаем различные вычисления по этим функциям. На этом этапе я создал 3 разных моделя. ( Все модели )

Когда мы изучаем модели, вы должны были заметить, что 2 модели включают предварительно обученный VGG19 Модель и одна модель была написана полностью с нуля. На этом этапе нам нужно знать, что предварительно обученные модели предварительно обучены с различными большими наборами данных (здесь мы предпочитаем набор данных ImageNet По этим причинам vgg_extractor_model Может дать нам лучшее выступление здесь. vgg_extractor_model Похоже, это:

@classmethod
def vgg_extractor_model(cls):
  vgg_model = tf.keras.applications.VGG19(include_top = False,
                                          weights = "imagenet")

  style_conv_blocks = [f"block{i}_conv1" for i in range(1, 6)]
  content_conv_block = ["block5_conv2"]
  all_activation_layers = style_conv_blocks + content_conv_block

  input_layer = vgg_model.inputs
  output_layers = [vgg_model.get_layer(i).output for i in all_activation_layers]

  model = tf.keras.models.Model(inputs = input_layer,
                                outputs = output_layers,
                                name = "vgg19_extractor")

  return model

На этом этапе есть часть, к которой я хотел бы привлечь ваше внимание. Если вы посмотрите внимательно, из vgg_extractor_model Мы создали, что содержит предварительно обученный VGG19 модель, мы вернули только несколько слоев свертки, а не всю структуру:

style_conv_blocks = [f"block{i}_conv1" for i in range(1, 6)]
content_conv_block = ["block5_conv2"]
all_activation_layers = style_conv_blocks + content_conv_block

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

На один шаг дальше – расчет значений потерь! 📉

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

  • Граманская матрица (или грамм -матрица)
  • Потеря стиля
  • Потеря содержания

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

@classmethod
def gram_matrix(cls, arr):
  """Gramian matrix for calculating style loss"""
  x = tf.transpose(arr, (2, 0, 1))
  features = tf.reshape(x, (tf.shape(x)[0], -1))
  gram = tf.matmul(features, tf.transpose(features))

  return gram

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

@classmethod
def style_loss(cls, style, generated):
  style_gram = cls.gram_matrix(style)
  generated_gram = cls.gram_matrix(generated)

  style_loss = tf.reduce_mean(tf.square(generated_gram - style_gram))

  return style_loss

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

@classmethod
def content_loss(cls, content, generated):
  """1/2 * sum of (generated - original) ** 2"""
  content_loss = tf.reduce_sum(tf.square((generated - content)))

  return content_loss * 5e-1

Давайте все сложим – последний шаг! 🤖

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

class Constants(object):
  CONTENT_WEIGHT = 2e-5
  STYLE_WEIGHT = 1e-4


class Train(Loss, FeatureExtractor):

  @classmethod
  def calculate_step_loss(cls, model, content, style, generated):
    tensor = tf.concat([content, style, generated], axis = 0)
    features = cls.extract(image_stack = tensor, model = model)
    content_act, style_act = cls.get_layers(features)

    content_loss = cls.content_loss(content_act[0], content_act[-1])

    style_loss = 0.
    for layer in style_act:
      layer_loss = cls.style_loss(layer[1], layer[-1])
      style_loss += layer_loss

    loss = (content_loss * Constants.CONTENT_WEIGHT) \
           + (style_loss * Constants.STYLE_WEIGHT)

    return loss

Вот что мы делаем; Во -первых, мы рассчитываем карты функций с нашей моделью «экстрактора функций». После этого мы рассчитываем Потеря стиля и Потеря контента Значения в каждом уровне (выходы из сетей свертки) и, наконец, после умножения с “Постоянный” Значения, которые мы произвольно определили, мы можем начать процесс, определив эпоха ценность. «Постоянные» значения, которые вы видите в верхней части блока кода, являются весами выхода, Мы можем придать более высокую ценность для той функции, которую мы хотим быть на переднем плане Анкет

def train(model, content, style, generated, epochs = 10):
  optimizer = tf.keras.optimizers.SGD(learning_rate = 1e-4) 
  for epoch in range(epochs):
    with tf.GradientTape() as GT:
      loss = Train.calculate_step_loss(model, content, style, generated)

    print(f"EPOCH: {epoch + 1} \nLOSS: {loss}\n" + ("---" * 15))

    gradients = GT.gradient(loss, generated)
    optimizer.apply_gradients([(gradients, generated)])

  return generated

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

Давайте посмотрим на этого Бигбоя в действии! 🏃

from skimage import io
import tensorflow as tf

# train() function from src/train.py
from train import train

# feature extraction model from src/feature_extractor.py
from feature_extractor import FeatureExtractor

# all image paths
BASE = "./my/path/to/my/images"
CONTENT_IMAGE_PATH = os.path.join(BASE, "my_content_image.jpeg")
STYLE_IMAGE_PATH = os.path.join(BASE, "my_style_image.png")

# read your custom images 
CONTENT = io.imread(CONTENT_IMAGE_PATH)
STYLE = io.imread(STYLE_IMAGE_PATH)
COMBINED = tf.Variable(CONTENT) # tf.Tensor

# define feature extractor model
model = FeatureExtractor.vgg_extractor_model
# there are three options for models (check the src/feature_extractor.py)

# main training
STYLED_IMAGE = train(model = model,
                    content = CONTENT,
                    style = STYLE,
                    generated = COMBINED,
                    epochs = 50)

После создания и оптимизации для 50 эпох. Результаты здесь:

Заключение 💭

Ладно! Мы видели действительно основную реализацию и немного математического фона «переноса нервного стиля». Я пытался сделать это просто. Если у вас есть что -то в этой статье, вы можете связаться со мной в любое время.

Проверьте репозиторий: Перенос нервного стиля Egeabanci

Спросите меня о чем угодно в любое время дня: egeabanci@outlook.com.tr

Вы можете следовать за мной на GitHub, мы можем сотрудничать в проектах: https://github.com/Egesabanci

Оригинал: “https://dev.to/egesabanci/neural-style-transfer-in-a-most-simple-way-490k”