58
правок
Изменения
Добавлено описание первого прохода гармонизации, немного исправлены определения лоссов.
{{Определение
|definition =
$\mathcal{L}^{\alpha}_{content}(I, O, l) = \displaystyle\sum_l \frac{\alpha_l}{2 N_l M_l}\displaystyle\sum_{i, j} (F^l_{ij}\left[I\right] - F^l_{ij}\left[O\right])^2$ {{---}} функция потерь содержания на слое , где $\alpha_l$ {{---}} вклад $l$-го слоя в функцию потерь<ref name="NotOriginalDef">Здесь используется определение функции потерь, которое отличается от статьи Гатиса, но используется в таком виде в статье про гармонизацию.</ref>.}}
{{Определение
|definition =
$\mathcal{L}^{\beta}_{style}(I, O) = \displaystyle\sum_l \frac{w_l\beta_l}{4N_l^2M_l2N_l^2} \displaystyle\sum_{i, j} (G^l_{ij}\left[I\right] - G^l_{ij}\left[O\right])^2$ {{---}} функция потерь стиля, где $w_l\beta_l$ {{---}} вклад $l$-го слоя в функцию потерь<ref name="NotOriginalDef"/>.}}
Итоговой функцией потерь будет $\mathcal{L}_{Gatys} = \alpha\mathcal{L}_{content}(I, O, L) + \betaw_{style}\mathcal{L}_{style}(I, O)$<ref name="NotOriginalDef"/>. Веса Вес $w_{style}$, векторы $\alpha $ и $\beta, последовательность $w_l$ и слой $L$ являются, в некотором смысле, гиперпараметрами алгоритма, которые нужно подбирать<ref name="GEB16"/>.
*'''TODO''': GEB16 Figure 3 (влияние $w_l$)
{{Определение
|definition =
Пусть $R = histmatch(S, O, S)$ {{---}} отображение пикселей такое, что гистограмма $S$ совпадает с гистограммой $R(O)$.}}
{{Определение
|definition =
$\mathcal{L}^{\gamma}_{histogramhist}(O, S) = \displaystyle\sum_l \gamma_l \displaystyle\sum_{i, j} (F^l_{ij}\left[O\right] - R(F^l_{ij}\left[O\right]))^2$ {{---}} функция потерь гистограмм, где
$\gamma_l$ {{---}} вклад $l$-го слоя в функцию потерь}}
==Глубокая гармонизация картин==
Для того чтобы вставить изображение в картину или рисунок нужно не только сделать бесшовный переход и изменить цвета, но ещё и изменить текстуру вставляемого изображения, например сымитировать мазки кистью. Используем для этого комбинацию подходов из других статей<ref name="GEB16"/><ref name="JAFF16"/><ref name="WRB17"/>.
Алгоритм будет состоять из двух проходов. Первый проход будет делать грубую гармонизацию, а второй {{---}} более тщательную. Отличаться они будут '''стилевым маппингом todo: придумать норм название''' и функциями потерь.
{{Определение
|definition =
'''Стилевым маппингом''' мы будем называть отображение $P : \mathcal{R}^{N_l \times M_l} \rightarrow \mathcal{R}^{N_l \times M_l}$, которое некоторым образом переставляет столбцы матрицы (не обязательно обратимо, то есть столбцы могут теряться и копироваться). Более формально, пусть $p(j)$ {{---}} новая позиция столбца $j$, тогда $P(Q)_{i, p(j)} = Q_{ij}$.}}
Один проход будет состоять из 3 частей:
# Входное $I$ и стилевое $S$ изображения подаются на вход нейронной сети VGG-19, так мы получаем $F^l_{ij}\left[I\right]$ и $F^l_{ij}\left[S\right]$.
# Для каждого слоя $l$ некоторым алгоритмом cтроится стилевой маппинг $P_l$, который сопоставляет столбцам из $F_l[I]$ столбцы из $F_l[S]$.
# Изображение $O$ восстанавливается градиентным спуском по пространству изображений, используя некоторую функцию потерь.
'''fun''' SinglePassHarmonization(
I, <font color="green"> // Входное изображение </font>
Mask, <font color="green"> // Маска </font>
S, <font color="green"> // Стилевое изображение </font>
$\pi$, <font color="green"> // Алгоритм построения стилевого маппинга </font>
$\mathcal{L}$ <font color="green"> // Функция потерь </font>
):
F_I := ComputeNeuralActivations(I)
F_S := ComputeNeuralActivations(S)
P := $\pi$(F_I, Mask, F_S)
O := Reconstruct(I, Mask, S, P, $\mathcal{L}$)
'''return''' O
===Первый проход===
'''TODO:''' нормально объяснить что такое патч (возможно проще картинкой)
{{Определение
|definition =
'''Вектор активации''' (англ. ''activation vector'') {{---}} это вектор значений функции активации для каждого фильтра свёрточного слоя. Заметим, что столбцы $F_l$ являются векторами активации.}}
{{Определение
|definition =
'''Патчем''' (англ. ''patch'') для столбца $j$ будем называть тензор $3 \times 3 \times N_l$, который состоит из соседних векторов активации в тензоре свёрточного слоя, с центром в столбце $j$}}
Первый проход делает грубую гармонизацию, но при этом он хорошо работает с любыми стилями. Здесь используется алгоритм <code>IndependentMapping</code> для построения стилевого маппинга. Этот алгоритм для каждого столбца $j$ в $F_l[I]$ ищет столбец $p(j)$ в $F_l[S]$, такой что евклидово расстояние между патчем $F_l[I]$ с центром $j$ и патчем $F_l[S]$ с центром $p(j)$ минимально (метод ближайшего соседа).
'''fun''' IndependentMapping(
F_I, <font color="green"> // Выходы слоёв после входного изображения </font>
Mask, <font color="green"> // Маска </font>
F_S <font color="green"> // Выходы слоёв после стилевого изображения </font>
):
'''for''' l '''in''' range(1, L): <font color="green"> // L = количество слоёв сети </font>
'''for''' j '''in''' range(1, M[l]): <font color="green"> // M[l] = количество признаков на выходе l-го слоя сети </font>
'''if''' j '''in''' Resize(Mask, l): <font color="green"> // рассматриваем патчи только внутри маски, которую нужно масштабираовать в соответсвии с размером слоя l </font>
p(j) := NearestNeighborIndex(F_I, j, F_S)
P := MakeStyleMapping(p) <font color="green"> // Делаем стилевой маппинг с помощью функции p(j) </font>
'''return''' P
В первом проходе используется модифицированная функция потерь $\mathcal{L}_{Gatys}$, с тем лишь отличием, что к $F_l[S]$ применяется стилевой маппинг $P_l$.
{{Определение
|definition =
$\mathcal{L}_1(I, S, O, P) = \mathcal{L}^{\alpha}_{content}(I, O) + w_{style}\mathcal{L}^{\beta}_{style}(S, O, P)$, где $w_{style}$ {{---}} вес стилевой функции потерь}}
* '''TODO''' Figure 2b (результаты после первого прохода)
===Второй проход===
Второй проход делает более качественную гармонизацию после первого прохода. Здесь мы будем использовать более сложный алгоритм <code>ConsistentMapping</code> построения стилевого маппинга и более сложную функцию потерь. Суть этого алгоритма в том, чтобы найти стилевой мапинг на некотором слое $l_{ref}$ и перенести этот маппинг на остальные слои.
{{Определение
|definition =
$\mathcal{L}_2(I, S, O, P) = \mathcal{L}^{\alpha}_{content}(I, O) + w_{style}\mathcal{L}^{\beta}_{s1}(S, O, P) + w_{hist}\mathcal{L}^{\gamma}_{hist}(S, O) + w_{tv}\mathcal{L}_{tv}(O)$, где $w_{style}$, $w_{hist}$, $w_{tv}$ {{---}} веса соответсвующих функций потерь}}
===Итоговый алгоритм===
'''fun''' Harmonization(
I, <font color="green"> // Входное изображение </font>
S <font color="green"> // Стилевое изображение </font>
):
<font color="green"> // Тут будет комментарий Грубый проход алгоритма. Каждый слой рассматривается отдельно при построении стилевого маппинга. </font> I' := SinglePassHarmonization(I, MMask, S, IndependentMapping, $\mathcal{L}_1$) <font color="green"> // Тут тоже Улучшение результата. Стилевой маппинг строится консистентно для всех слоёв. </font> O := SinglePassHarmonization(I', MMask, S, ConsistentMapping, $\mathcal{L}_2$)
'''return''' O
* '''TODO''' как подбирать гиперпараметры $w_{style}$, $w_{hist}$, $w_{tv}$, $\alpha$, $\beta$, $\gamma$
* '''TODO''' красивые картинки
Возможно лучше так, но это не точно:
'''fun''' Harmonization(
$I$, <font color="green"> // Входное изображение </font>
$M$, <font color="green"> // Маска </font>
$S$ <font color="green"> // Стилевое изображение </font>
):
<font color="green"> // Грубый проход алгоритма. Каждый слой рассматривается отдельно при построении стилевого маппинга. </font>
$I'$ := SinglePassHarmonization($I$, $M$, $S$, IndependentMapping, $\mathcal{L}_1$)
<font color="green"> // Улучшение результата. Стилевой маппинг строится консистентно для всех слоёв. </font>
$O$ := SinglePassHarmonization($I'$, $M$, $S$, ConsistentMapping, $\mathcal{L}_2$)
'''return''' $O$
'''fun''' SinglePassHarmonization(
$I$, <font color="green"> // Входное изображение </font> $M$, <font color="green"> // Маска </font> $S$, <font color="green"> // Стилевое изображение </font> $\pi$, <font color="green"> // Алгоритм построения стилевого маппинга </font> $\mathcal{L}$ <font color="green"> // Neural mapping function todo: translate this shit Функция потерь </font>
):
'''return''' $O$
==Глубокий блендинг==