Le reti neurali convoluzionali sono la tipologia più potente di reti neurali per la classificazione e l’analisi delle immagini. Le loro applicazioni hanno superato molti limiti e si sono rivelate l’elemento cruciale di molte applicazioni di deep learning che vediamo oggi. A un livello molto alto, le CNN possono apprendere rappresentazioni interne a livello di feature delle immagini a loro fornite. È questo a renderle così potenti. Risulta che questa caratteristica saliente delle CNN non è utile solo per compiti come la classificazione delle immagini, ma anche per la costruzione di immagini. Applicazioni come Deep Dream e Neural Style Transfer compongono immagini in base alle attivazioni dei layer all’interno delle CNN e alle feature da esse estratte.
In questo tutorial studierai come funziona il Neural Style Transfer e come può essere implementato usando TensorFlow 2.0.
Nota: per seguire questo tutorial, è necessario sapere come funzionano le CNN. Se cerchi risorse per un rapido ripasso sulle CNN, prova le seguenti:
Per chi è alle prime armi nel campo della computer vision e del deep learning, il termine neural style transfer può risultare un po’ intimidatorio. Per comprendere ogni componente del termine, considera le due immagini seguenti:
Nel contesto del neural style transfer, l’immagine a sinistra è detta immagine di contenuto, mentre quella a destra è detta immagine di stile. L’obiettivo è stilizzare una delle immagini (in questo caso quella a sinistra) usando l’altra (quella a destra). Questo compone le ultime due parole del termine: style transfer. Per eseguire il processo, una rete neurale (CNN) viene addestrata a ottimizzare una funzione di loss personalizzata, da cui la prima parola: neural. Quando le due immagini sopra vengono fuse tramite neural style transfer, il risultato finale appare così (a destra) -
Potresti chiederti a cosa serva il neural style transfer. Immagina di avere l’immagine di un disegno originariamente realizzato da Vincent van Gogh. Vuoi vedere come quel disegno si tradurrebbe in uno dei tuoi. Questa è una delle applicazioni in cui il neural style transfer trova impiego. Un altro esempio sono diverse app di filtri fotografici come Prisma, che ti permettono di eseguire il neural style transfer con un’interfaccia fluida.
Separazione tra contenuto e stile
Finora, l’idea che potresti aver colto sul neural style transfer è che il processo consiste nel combinare il contenuto di un’immagine con lo stile di un’altra. In effetti, è esattamente così. In questa sezione, cerchiamo di capire cosa si intende per contenuto e stile nel contesto delle CNN.
Una CNN è spesso un insieme di diversi strati convoluzionali e di pooling. I layer convoluzionali sono responsabili dell’estrazione di feature altamente complesse da un’immagine, mentre i layer di pooling scartano informazioni spaziali dettagliate che non sono rilevanti per un problema di classificazione. L’effetto è che questo aiuta la CNN a imparare il contenuto di una data immagine piuttosto che elementi specifici come colore, texture e così via. Man mano che si va in profondità in una CNN, la complessità delle feature aumenta e i layer convoluzionali più profondi sono spesso indicati come rappresentazioni del contenuto.
Un esempio di stile è qualsiasi aspetto specifico delle proprietà dell’immagine come texture, colore e simili, ad esempio l’uso evidente di un determinato colore in un disegno. Ora la domanda è: come si estrae lo stile di un’immagine? Questo si fa calcolando le correlazioni tra i layer convoluzionali. Le correlazioni ci danno una misura di quanto siano simili/collegate due o più variabili. Per capirlo, considera un layer convoluzionale addestrato composto da diverse mappe di attivazione (feature map). Per ogni feature map puoi misurare quanto fortemente le feature da essa rilevate si relazionano con le altre feature map nello stesso layer. Questo ti fornisce una stima di aspetti come: un certo colore rilevato nella prima feature map è simile a un colore in un’altra mappa? Ci sono forme comuni tra le feature map? Questi tratti/somiglianze definiscono lo stile di un’immagine. Il processo di misurazione della somiglianza tra i contenuti di diverse feature map all’interno di un layer convoluzionale aiuta le reti a imparare una rappresentazione multi-scala dell’immagine che mette a fuoco caratteristiche spaziali come texture e colore.
Un punto fondamentale da tenere a mente è che, durante l’applicazione del neural style transfer, devi anche assicurarti che il contenuto di un’immagine venga preservato insieme allo stile desiderato dell’altra immagine. Vedrai come si fa in una sezione successiva. Nella prossima sezione imparerai come estrarre le feature da un’immagine (immagine di contenuto) e calcolare la content loss.
Quantificare l’immagine di contenuto e calcolare la Content Loss
Secondo il paper Image Style Transfer Using Convolutional Neural Networks, viene impiegata un’architettura CNN VGG-19 per estrarre sia le feature di contenuto sia quelle di stile rispettivamente dalle immagini di contenuto e di stile. Per ottenere le feature di contenuto, si usa il secondo layer convoluzionale del quarto blocco (di layer convoluzionali). Per comodità, gli autori lo hanno chiamato conv4_2. Una volta ottenute le feature di contenuto, dovrai confrontarle con un’immagine target per misurare la content loss. Cos’è un’immagine target? Perché qui è necessario calcolare la content loss? Facciamo un passo indietro e concentriamoci su queste due domande.
Per combinare le feature di contenuto e di stile in un’unica immagine, dovrai partire da un’immagine target, che può essere una semplice immagine vuota o una copia dell’immagine di contenuto. Ora, per apprendere efficacemente sia le feature di contenuto sia quelle di stile usando una CNN, ti serve una funzione di loss personalizzata, che ottimizzerai per ottenere un’immagine stilizzata fluida costruita a partire dalle immagini di contenuto e di stile. Questa funzione di loss personalizzata è essenzialmente un’unione di due loss differenti:
Content loss, che fa sì che la quantità complessiva di contenuto venga preservata.
Style loss, che regola la quantità di stile trasferita all’immagine target.
Ora che hai un’idea delle domande di cui sopra, torniamo alla content loss e definiamola. La content loss è definita come segue -
dove $T_c$ si riferisce all’immagine target e $C_c$ all’immagine di contenuto. Quindi, ciò che fa questa funzione di loss è darti una misura di quanto distano tra loro le feature delle immagini di contenuto e target. La rete punterà a minimizzare questa loss. Nella prossima sezione vedrai come determinare la style loss.
La Style Loss e la matrice di Gram
Per determinare la style loss, il paper indica di prendere le rappresentazioni (in sostanza numeri) dai seguenti layer e ottenere le matrici di Gram delle feature map all’interno di questi layer.
'conv1_1''conv2_1''conv3_1''conv4_1''conv5_1'Offerto da
Il vantaggio di utilizzare numerosi layer per definire la style loss è che consente di apprendere una rappresentazione multi-scala dello stile contenuto in un’immagine. Le matrici di Gram aiutano a determinare quanto siano simili le feature tra le feature map all’interno di un singolo layer convoluzionale. Questo riflette ulteriormente informazioni non localizzate sull’immagine, che ne plasmano lo stile. Una matrice di Gram in questo contesto si calcola nel modo seguente.
Considera che la dimensione di un’immagine convoluta sia 8x8x16, il che indica principalmente che ha 16 feature map. Ora ti interessa trovare le somiglianze tra le feature in queste feature map usando una matrice di Gram. Per farlo, appiattisci le prime due dimensioni dell’immagine convoluta e trasformale in un vettore 1D. Le dimensioni, se appiattite in questo caso, conterrebbero 64 elementi nel vettore 1D. Questo si ripete per tutte le feature map. Ottieni così una matrice finale di dimensione 16x64 (chiamiamola matrice A). Questa matrice viene poi trasposta (diventa 64x16) e moltiplicata per la matrice A. Una matrice di Gram, in questo caso, avrà dimensione 16x16. Un particolare valore nella matrice di Gram indica le somiglianze tra le feature map. Visivamente, questo processo assomiglia al seguente:
Per calcolare la style loss tra l’immagine target e quella di stile, si prendono le distanze quadratiche medie tra le loro matrici di Gram a ciascuno dei blocchi di layer convoluzionali. Formalmente, questo può essere definito come segue:
dove T(s,i) è la matrice di Gram dell’immagine target calcolata al blocco i e S(s,i) è la matrice di Gram dell’immagine di stile calcolata al blocco i. Con wi puoi assegnare pesi personalizzati ai diversi blocchi convoluzionali per ottenere una rappresentazione dettagliata dello stile. Infine, $a$ è una costante che tiene conto dei valori in ciascun layer all’interno dei blocchi. Mettiamo insieme le due loss per definire la loss totale che la rete ottimizza nel processo di neural style transfer.
Definire la Loss Totale
La loss totale ora è solo una questione di somma con pesi personalizzati -
dove $\alpha$ indica il peso del contenuto e $\beta$ indica il peso dello stile. Questo ti aiuta a mantenere un buon equilibrio tra il contenuto e la quantità di stile trasferita all’immagine target. L’effetto di diverse combinazioni di $\alpha$ e $\beta$ è mostrato nel paper ed è consigliabile darci un’occhiata. Ora hai tutti i pezzi per implementare il neural style transfer. Procediamo nella prossima sezione.
Neural Style Transfer in pratica
Per la parte di implementazione userai TensorFlow 2.0. Include molte aggiunte straordinarie ed è uno degli aggiornamenti più completi della libreria fino a oggi. Se ti interessa conoscerne alcune, puoi leggere questo articolo.
L’ultima versione di TensorFlow (al momento della stesura di questo tutorial) è 2.0.0-beta0. Se non l’hai ancora installata, procedi prima all’installazione seguendo le istruzioni riportate qui. Inizierai importando i pacchetti necessari e le immagini di contenuto e di stile.
# Packagesimport tensorflow as tf
from tensorflow.keras.applications.vgg19 import preprocess_input
from tensorflow.keras.models import Model
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(7)%matplotlib inline
print(tf.__version__)Offerto da
# Load the content and style images
content = plt.imread('Content.jpeg')
style = plt.imread('Style.jpg')# Display the images
fig,(ax1, ax2)= plt.subplots(1,2, figsize=(20,10))# Content and style images side-by-side
ax1.imshow(content)
ax1.set_title('Content Image')
ax2.imshow(style)
ax2.set_title('Style Image')
plt.show()Offerto da
Nel prossimo passaggio, scriverai una funzione di supporto che caricherà le due immagini in array di numeri (perché i computer capiscono solo numeri) e le ridimensionerà per renderle compatibili con il modello.
# Use load_image of content and style images
content = load_image('Content.jpeg')
style = load_image('Style.jpg')# Verify the shapes
content.shape, style.shape
Offerto da
(TensorShape([1,400,400,3]),TensorShape([1,400,400,3]))Offerto da
Le immagini sono state ridimensionate. Ora caricherai un modello VGG19 pre-addestrato per estrarre le feature. Poiché userai il modello per l’estrazione di feature, non avrai bisogno della parte di classificazione del modello.
vgg = tf.keras.applications.VGG19(include_top=False, weights='imagenet')
vgg.trainable =FalseOfferto da
Downloading data from https://github.com/fchollet/deep-learning-models/releases/download/v0.1/vgg19_weights_tf_dim_ordering_tf_kernels_notop.h5
80142336/80134624[==============================]- 5s 0us/step
Offerto da
Gli autori hanno specificato i nomi dei blocchi usati per estrarre le feature di contenuto e di stile. Il modello VGG19 che hai appena caricato adotta la stessa convenzione di denominazione. Per sfruttare questo, per prima cosa stamperai i nomi di tutti i layer presenti nella rete.
# Print the layer names for conveniencefor layer in vgg.layers:print(layer.name)Offerto da
Ora crea un modello VGG personalizzato composto dai layer specificati. Questo ti aiuterà a eseguire forward pass sulle immagini ed estrarre le feature necessarie lungo il percorso.
defmini_model(layer_names, model):
outputs =[model.get_layer(name).output for name in layer_names]
model = Model([vgg.input], outputs)return model
Offerto da
Definire una matrice di Gram è semplicissimo in TensorFlow e puoi farlo così:
# Gram matrixdefgram_matrix(tensor):
temp = tensor
temp = tf.squeeze(temp)
fun = tf.reshape(temp,[temp.shape[2], temp.shape[0]*temp.shape[1]])
result = tf.matmul(temp, temp, transpose_b=True)
gram = tf.expand_dims(result, axis=0)return gram
Offerto da
Ora definirai un modello personalizzato usando la funzione mini_model(). Servirà a restituire le feature di contenuto e di stile dalle rispettive immagini.
classCustom_Style_Model(tf.keras.models.Model):def__init__(self, style_layers, content_layers):super(Custom_Style_Model, self).__init__()
self.vgg = mini_model(style_layers + content_layers, vgg)
self.style_layers = style_layers
self.content_layers = content_layers
self.num_style_layers =len(style_layers)
self.vgg.trainable =Falsedefcall(self, inputs):# Scale back the pixel values
inputs = inputs*255.0# Preprocess them with respect to VGG19 stats
preprocessed_input = preprocess_input(inputs)# Pass through the mini network
outputs = self.vgg(preprocessed_input)# Segregate the style and content representations
style_outputs, content_outputs =(outputs[:self.num_style_layers],
outputs[self.num_style_layers:])# Calculate the gram matrix for each layer
style_outputs =[gram_matrix(style_output)for style_output in style_outputs]# Assign the content representation and gram matrix in# a layer by layer fashion in dicts
content_dict ={content_name:value
for content_name, value
inzip(self.content_layers, content_outputs)}
style_dict ={style_name:value
for style_name, value
inzip(self.style_layers, style_outputs)}return{'content':content_dict,'style':style_dict}Offerto da
Ora che hai definito il modello personalizzato, usiamolo sulle immagini per ottenere rispettivamente le feature di contenuto e di stile -
# Note that the content and style images are loaded in# content and style variables respectively
extractor = Custom_Style_Model(style_layers, content_layers)
style_targets = extractor(style)['style']
content_targets = extractor(content)['content']
In the paper, optimization was done using the L-BFGS algorithm, but you can use Adam also.Offerto da
opt = tf.optimizers.Adam(learning_rate=0.02)Offerto da
Definiamo ora i pesi complessivi di contenuto e stile e anche i pesi per ciascuna rappresentazione di stile come discusso in precedenza. Nota che si tratta di iperparametri su cui vale la pena sperimentare.
# Custom weights for style and content updates
style_weight=100
content_weight=10# Custom weights for different style layers
style_weights ={'block1_conv1':1.,'block2_conv1':0.8,'block3_conv1':0.5,'block4_conv1':0.3,'block5_conv1':0.1}Offerto da
Arriva ora la parte più cruciale, che rende il processo di neural style transfer molto più interessante: la funzione di loss.
# The loss function to optimizedeftotal_loss(outputs):
style_outputs = outputs['style']
content_outputs = outputs['content']
style_loss = tf.add_n([style_weights[name]*tf.reduce_mean((style_outputs[name]-style_targets[name])**2)for name in style_outputs.keys()])# Normalize
style_loss *= style_weight / num_style_layers
content_loss = tf.add_n([tf.reduce_mean((content_outputs[name]-content_targets[name])**2)for name in content_outputs.keys()])# Normalize
content_loss *= content_weight / num_content_layers
loss = style_loss + content_loss
return lossOfferto da
Ora scriverai un’altra funzione che:
Calcola i gradienti della funzione di loss appena definita.
Usa questi gradienti per aggiornare l’immagine target.
Con GradientTape puoi sfruttare l’autodifferenziazione, che consente di calcolare i gradienti di una funzione in base alla sua composizione. Userai anche il decorator tf.function per velocizzare le operazioni. Leggi di più qui.
@tf.function()deftrain_step(image):with tf.GradientTape()as tape:# Extract the features
outputs = extractor(image)# Calculate the loss
loss = total_loss(outputs)# Determine the gradients of the loss function w.r.t the image pixels
grad = tape.gradient(loss, image)# Update the pixels
opt.apply_gradients([(grad, image)])# Clip the pixel values that fall outside the range of [0,1]
image.assign(tf.clip_by_value(image, clip_value_min=0.0, clip_value_max=1.0))Offerto da
L’unico passo rimanente prima di addestrare la rete è definire l’immagine target. Per l’immagine target userai proprio l’immagine di contenuto.
Ora sei assolutamente pronto per addestrare la rete.
epochs =10
steps_per_epoch =100
step =0for n inrange(epochs):for m inrange(steps_per_epoch):
step +=1
train_step(target_image)
plt.imshow(np.squeeze(target_image.read_value(),0))
plt.title("Train step: {}".format(step))
plt.show()Offerto da
WARNING: Logging before flag parsing goes to stderr.
W0617 16:21:34.491543140709216896896 deprecation.py:323] From /usr/local/lib/python3.6/dist-packages/tensorflow/python/ops/math_grad.py:1205: add_dispatch_support.<locals>.wrapper (from tensorflow.python.ops.array_ops)is deprecated and will be removed in a future version.
Instructions for updating:
Use tf.where in2.0, which has the same broadcast rule as np.where Offerto da
Ti consigliamo di sperimentare con i pesi di contenuto e di stile per osservare i cambiamenti nell’immagine target.
Considerazioni finali
Il paper a cui abbiamo fatto riferimento qui nel tutorial non menziona un’ulteriore ottimizzazione della qualità dell’immagine costruita. Come probabilmente hai osservato nei risultati sopra, serve una certa morbidezza nella relazione spaziale tra contenuto complessivo e stile dell’immagine ottenuta. Per affrontare questo problema è stata introdotta la total_variantional_loss, analoga all’uso della regolarizzazione. Ad alto livello, la total_variational_loss penalizza gli artefatti ad alta frequenza introdotti dall’algoritmo originale di neural style transfer. Dai un’occhiata a questo tutorial se ti interessa implementarla. Di seguito alcune delle risorse a cui si è fatto riferimento per la stesura di questo tutorial:
Scopri i 15 migliori server MCP remoti che stanno trasformando lo sviluppo AI nel 2026. Scopri come migliorano automazione, ragionamento, sicurezza e velocità dei workflow.
Le reti neurali convoluzionali sono la tipologia più potente di reti neurali per la classificazione e l’analisi delle immagini. Le loro applicazioni hanno superato molti limiti e si sono rivelate l’elemento cruciale di molte applicazioni di deep learning che vediamo oggi. A un livello molto alto, le CNN possono apprendere rappresentazioni interne a livello di feature delle immagini a loro fornite. È questo a renderle così potenti. Risulta che questa caratteristica saliente delle CNN non è utile solo per compiti come la classificazione delle immagini, ma anche per la costruzione di immagini. Applicazioni come Deep Dream e Neural Style Transfer compongono immagini in base alle attivazioni dei layer all’interno delle CNN e alle feature da esse estratte.
In questo tutorial studierai come funziona il Neural Style Transfer e come può essere implementato usando
TensorFlow2.0.Nota: per seguire questo tutorial, è necessario sapere come funzionano le CNN. Se cerchi risorse per un rapido ripasso sulle CNN, prova le seguenti:
Che cos’è il Neural Style Transfer?
Per chi è alle prime armi nel campo della computer vision e del deep learning, il termine neural style transfer può risultare un po’ intimidatorio. Per comprendere ogni componente del termine, considera le due immagini seguenti:
Nel contesto del neural style transfer, l’immagine a sinistra è detta immagine di contenuto, mentre quella a destra è detta immagine di stile. L’obiettivo è stilizzare una delle immagini (in questo caso quella a sinistra) usando l’altra (quella a destra). Questo compone le ultime due parole del termine: style transfer. Per eseguire il processo, una rete neurale (CNN) viene addestrata a ottimizzare una funzione di loss personalizzata, da cui la prima parola: neural. Quando le due immagini sopra vengono fuse tramite neural style transfer, il risultato finale appare così (a destra) -
Potresti chiederti a cosa serva il neural style transfer. Immagina di avere l’immagine di un disegno originariamente realizzato da Vincent van Gogh. Vuoi vedere come quel disegno si tradurrebbe in uno dei tuoi. Questa è una delle applicazioni in cui il neural style transfer trova impiego. Un altro esempio sono diverse app di filtri fotografici come Prisma, che ti permettono di eseguire il neural style transfer con un’interfaccia fluida.
Separazione tra contenuto e stile
Finora, l’idea che potresti aver colto sul neural style transfer è che il processo consiste nel combinare il contenuto di un’immagine con lo stile di un’altra. In effetti, è esattamente così. In questa sezione, cerchiamo di capire cosa si intende per contenuto e stile nel contesto delle CNN.
Una CNN è spesso un insieme di diversi strati convoluzionali e di pooling. I layer convoluzionali sono responsabili dell’estrazione di feature altamente complesse da un’immagine, mentre i layer di pooling scartano informazioni spaziali dettagliate che non sono rilevanti per un problema di classificazione. L’effetto è che questo aiuta la CNN a imparare il contenuto di una data immagine piuttosto che elementi specifici come colore, texture e così via. Man mano che si va in profondità in una CNN, la complessità delle feature aumenta e i layer convoluzionali più profondi sono spesso indicati come rappresentazioni del contenuto.
Un esempio di stile è qualsiasi aspetto specifico delle proprietà dell’immagine come texture, colore e simili, ad esempio l’uso evidente di un determinato colore in un disegno. Ora la domanda è: come si estrae lo stile di un’immagine? Questo si fa calcolando le correlazioni tra i layer convoluzionali. Le correlazioni ci danno una misura di quanto siano simili/collegate due o più variabili. Per capirlo, considera un layer convoluzionale addestrato composto da diverse mappe di attivazione (feature map). Per ogni feature map puoi misurare quanto fortemente le feature da essa rilevate si relazionano con le altre feature map nello stesso layer. Questo ti fornisce una stima di aspetti come: un certo colore rilevato nella prima feature map è simile a un colore in un’altra mappa? Ci sono forme comuni tra le feature map? Questi tratti/somiglianze definiscono lo stile di un’immagine. Il processo di misurazione della somiglianza tra i contenuti di diverse feature map all’interno di un layer convoluzionale aiuta le reti a imparare una rappresentazione multi-scala dell’immagine che mette a fuoco caratteristiche spaziali come texture e colore.
Un punto fondamentale da tenere a mente è che, durante l’applicazione del neural style transfer, devi anche assicurarti che il contenuto di un’immagine venga preservato insieme allo stile desiderato dell’altra immagine. Vedrai come si fa in una sezione successiva. Nella prossima sezione imparerai come estrarre le feature da un’immagine (immagine di contenuto) e calcolare la content loss.
Quantificare l’immagine di contenuto e calcolare la Content Loss
L’algoritmo di neural style transfer è stato introdotto per la prima volta da Gatys et al. nel loro paper del 2015, A Neural Algorithm of Artistic Style. Questo tutorial fa però riferimento a Image Style Transfer Using Convolutional Neural Networks, che è una sorta di continuazione del paper precedente.
Secondo il paper Image Style Transfer Using Convolutional Neural Networks, viene impiegata un’architettura CNN VGG-19 per estrarre sia le feature di contenuto sia quelle di stile rispettivamente dalle immagini di contenuto e di stile. Per ottenere le feature di contenuto, si usa il secondo layer convoluzionale del quarto blocco (di layer convoluzionali). Per comodità, gli autori lo hanno chiamato
conv4_2. Una volta ottenute le feature di contenuto, dovrai confrontarle con un’immagine target per misurare la content loss. Cos’è un’immagine target? Perché qui è necessario calcolare la content loss? Facciamo un passo indietro e concentriamoci su queste due domande.Per combinare le feature di contenuto e di stile in un’unica immagine, dovrai partire da un’immagine target, che può essere una semplice immagine vuota o una copia dell’immagine di contenuto. Ora, per apprendere efficacemente sia le feature di contenuto sia quelle di stile usando una CNN, ti serve una funzione di loss personalizzata, che ottimizzerai per ottenere un’immagine stilizzata fluida costruita a partire dalle immagini di contenuto e di stile. Questa funzione di loss personalizzata è essenzialmente un’unione di due loss differenti:
Ora che hai un’idea delle domande di cui sopra, torniamo alla content loss e definiamola. La content loss è definita come segue -
dove $T_c$ si riferisce all’immagine target e $C_c$ all’immagine di contenuto. Quindi, ciò che fa questa funzione di loss è darti una misura di quanto distano tra loro le feature delle immagini di contenuto e target. La rete punterà a minimizzare questa loss. Nella prossima sezione vedrai come determinare la style loss.
La Style Loss e la matrice di Gram
Per determinare la style loss, il paper indica di prendere le rappresentazioni (in sostanza numeri) dai seguenti layer e ottenere le matrici di Gram delle feature map all’interno di questi layer.
Il vantaggio di utilizzare numerosi layer per definire la style loss è che consente di apprendere una rappresentazione multi-scala dello stile contenuto in un’immagine. Le matrici di Gram aiutano a determinare quanto siano simili le feature tra le feature map all’interno di un singolo layer convoluzionale. Questo riflette ulteriormente informazioni non localizzate sull’immagine, che ne plasmano lo stile. Una matrice di Gram in questo contesto si calcola nel modo seguente.
Considera che la dimensione di un’immagine convoluta sia 8x8x16, il che indica principalmente che ha 16 feature map. Ora ti interessa trovare le somiglianze tra le feature in queste feature map usando una matrice di Gram. Per farlo, appiattisci le prime due dimensioni dell’immagine convoluta e trasformale in un vettore 1D. Le dimensioni, se appiattite in questo caso, conterrebbero 64 elementi nel vettore 1D. Questo si ripete per tutte le feature map. Ottieni così una matrice finale di dimensione 16x64 (chiamiamola matrice A). Questa matrice viene poi trasposta (diventa 64x16) e moltiplicata per la matrice A. Una matrice di Gram, in questo caso, avrà dimensione 16x16. Un particolare valore nella matrice di Gram indica le somiglianze tra le feature map. Visivamente, questo processo assomiglia al seguente:
Per calcolare la style loss tra l’immagine target e quella di stile, si prendono le distanze quadratiche medie tra le loro matrici di Gram a ciascuno dei blocchi di layer convoluzionali. Formalmente, questo può essere definito come segue:
dove T(s,i) è la matrice di Gram dell’immagine target calcolata al blocco i e S(s,i) è la matrice di Gram dell’immagine di stile calcolata al blocco i. Con wi puoi assegnare pesi personalizzati ai diversi blocchi convoluzionali per ottenere una rappresentazione dettagliata dello stile. Infine, $a$ è una costante che tiene conto dei valori in ciascun layer all’interno dei blocchi. Mettiamo insieme le due loss per definire la loss totale che la rete ottimizza nel processo di neural style transfer.
Definire la Loss Totale
La loss totale ora è solo una questione di somma con pesi personalizzati -
dove $\alpha$ indica il peso del contenuto e $\beta$ indica il peso dello stile. Questo ti aiuta a mantenere un buon equilibrio tra il contenuto e la quantità di stile trasferita all’immagine target. L’effetto di diverse combinazioni di $\alpha$ e $\beta$ è mostrato nel paper ed è consigliabile darci un’occhiata. Ora hai tutti i pezzi per implementare il neural style transfer. Procediamo nella prossima sezione.
Neural Style Transfer in pratica
Per la parte di implementazione userai
TensorFlow 2.0. Include molte aggiunte straordinarie ed è uno degli aggiornamenti più completi della libreria fino a oggi. Se ti interessa conoscerne alcune, puoi leggere questo articolo.L’ultima versione di
TensorFlow(al momento della stesura di questo tutorial) è2.0.0-beta0. Se non l’hai ancora installata, procedi prima all’installazione seguendo le istruzioni riportate qui. Inizierai importando i pacchetti necessari e le immagini di contenuto e di stile.Nel prossimo passaggio, scriverai una funzione di supporto che caricherà le due immagini in array di numeri (perché i computer capiscono solo numeri) e le ridimensionerà per renderle compatibili con il modello.
Le immagini sono state ridimensionate. Ora caricherai un modello VGG19 pre-addestrato per estrarre le feature. Poiché userai il modello per l’estrazione di feature, non avrai bisogno della parte di classificazione del modello.
Gli autori hanno specificato i nomi dei blocchi usati per estrarre le feature di contenuto e di stile. Il modello VGG19 che hai appena caricato adotta la stessa convenzione di denominazione. Per sfruttare questo, per prima cosa stamperai i nomi di tutti i layer presenti nella rete.
Ti interessano però i seguenti per ottenere le feature di stile:
Per le feature di contenuto, ti servirà
conv4_2. Le salverai in variabili di conseguenza.Ora crea un modello VGG personalizzato composto dai layer specificati. Questo ti aiuterà a eseguire forward pass sulle immagini ed estrarre le feature necessarie lungo il percorso.
Definire una matrice di Gram è semplicissimo in TensorFlow e puoi farlo così:
Ora definirai un modello personalizzato usando la funzione
mini_model(). Servirà a restituire le feature di contenuto e di stile dalle rispettive immagini.Ora che hai definito il modello personalizzato, usiamolo sulle immagini per ottenere rispettivamente le feature di contenuto e di stile -
Definiamo ora i pesi complessivi di contenuto e stile e anche i pesi per ciascuna rappresentazione di stile come discusso in precedenza. Nota che si tratta di iperparametri su cui vale la pena sperimentare.
Arriva ora la parte più cruciale, che rende il processo di neural style transfer molto più interessante: la funzione di loss.
Ora scriverai un’altra funzione che:
Con
GradientTapepuoi sfruttare l’autodifferenziazione, che consente di calcolare i gradienti di una funzione in base alla sua composizione. Userai anche il decoratortf.functionper velocizzare le operazioni. Leggi di più qui.L’unico passo rimanente prima di addestrare la rete è definire l’immagine target. Per l’immagine target userai proprio l’immagine di contenuto.
Ora sei assolutamente pronto per addestrare la rete.
Ti consigliamo di sperimentare con i pesi di contenuto e di stile per osservare i cambiamenti nell’immagine target.
Considerazioni finali
Il paper a cui abbiamo fatto riferimento qui nel tutorial non menziona un’ulteriore ottimizzazione della qualità dell’immagine costruita. Come probabilmente hai osservato nei risultati sopra, serve una certa morbidezza nella relazione spaziale tra contenuto complessivo e stile dell’immagine ottenuta. Per affrontare questo problema è stata introdotta la total_variantional_loss, analoga all’uso della regolarizzazione. Ad alto livello, la total_variational_loss penalizza gli artefatti ad alta frequenza introdotti dall’algoritmo originale di neural style transfer. Dai un’occhiata a questo tutorial se ti interessa implementarla. Di seguito alcune delle risorse a cui si è fatto riferimento per la stesura di questo tutorial:
Se vuoi affinare le tue competenze di deep learning, potresti consultare i seguenti corsi e tutorial di DataCamp: