Wolfram Computation Meets Knowledge

AdaIN-Style Trained on MS-COCO and Painter by Numbers Data

Transfer the style of one image to another image

Released in 2017, this is the first real-time feedforward image stylization model to accept arbitrary styles. Building on the interpretation of neural style transfer as a statistical domain adaptation task, the model leverages a novel technique called Adaptive Instance Normalization (AdaIN). The AdaIN layer inside the net performs the style transfer by aligning the mean and variance of the content and style feature maps.

Number of layers: 109 | Parameter count: 10,516,675 | Trained size: 42 MB

Training Set Information

Examples

Resource retrieval

Retrieve the resource object:

In[1]:=
ResourceObject["AdaIN-Style Trained on MS-COCO and Painter by Numbers \
Data"]
Out[1]=

Get the pre-trained net:

In[2]:=
NetModel["AdaIN-Style Trained on MS-COCO and Painter by Numbers Data"]
Out[2]=

Basic usage

Restyle an image:

In[3]:=
CloudGet["https://www.wolframcloud.com/objects/3c61017a-3c27-46f5-8b60-144b6ddc4bfa"] (* Evaluate this cell to copy the example input from a cloud object *)
Out[3]=

Control the stylization weighting

More flexibility can be obtained by manipulating the different subnetworks separately. Separate the NetGraph into its components:

In[4]:=
net = NetModel[
  "AdaIN-Style Trained on MS-COCO and Painter by Numbers Data"]
Out[4]=
In[5]:=
netEncoder = NetExtract[net, "Content"]
Out[5]=
In[6]:=
encoderChain = NetExtract[net, "encoder_content"]
Out[6]=
In[7]:=
adaIN = NetExtract[net, "adaIN"]
Out[7]=
In[8]:=
decoderChain = NetExtract[net, "decoder"]
Out[8]=
In[9]:=
netDecoder = NetExtract[net, "Output"]
Out[9]=

Obtain the encoded content and style features:

In[10]:=
CloudGet["https://www.wolframcloud.com/objects/7830bf4a-64a8-47fb-b615-4cc507a06038"] (* Evaluate this cell to copy the example input from a cloud object *)
In[11]:=
CloudGet["https://www.wolframcloud.com/objects/2438e2e3-e319-4671-aee1-84c8022715e4"] (* Evaluate this cell to copy the example input from a cloud object *)

Run the net on the features:

In[12]:=
adaptedFeatures = 
  adaIN[<|"c_in" -> contentFeatures, "s_in" -> styleFeatures|>];

To control the stylization weight, blend the adapted features with the content features:

In[13]:=
blendedFeatures[w_] := w*adaptedFeatures + (1 - w)*contentFeatures

Stylize the content with different style weights:

In[14]:=
netDecoder@decoderChain[blendedFeatures[0.3]]
Out[14]=
In[15]:=
netDecoder@decoderChain[blendedFeatures[0.9]]
Out[15]=

Adapt to any size

Automatic image resizing can be avoided by replacing the net encoders. First get the net:

In[16]:=
net = NetModel[
  "AdaIN-Style Trained on MS-COCO and Painter by Numbers Data"]
Out[16]=

Extract the original mean channel values:

In[17]:=
meanRGB = NetExtract[net, "Content"][["MeanImage"]]
Out[17]=

Obtain the content and style features:

In[18]:=
CloudGet["https://www.wolframcloud.com/objects/8659a65a-13fa-46a9-abaf-b3f441ed93ff"] (* Evaluate this cell to copy the example input from a cloud object *)
In[19]:=
CloudGet["https://www.wolframcloud.com/objects/f50a65f5-0593-48e8-a5b2-ab79523e25be"] (* Evaluate this cell to copy the example input from a cloud object *)

Create the new net encoders with the desired dimensions:

In[20]:=
netEncC = 
  NetEncoder[{"Image", ImageDimensions[content], 
    "MeanImage" -> meanRGB}];
In[21]:=
netEncS = 
  NetEncoder[{"Image", ImageDimensions[style], 
    "MeanImage" -> meanRGB}];

Attach the new net encoders and run the network:

In[22]:=
resizedNet = 
 NetReplacePart[
  net, {"Content" -> netEncC, "Style" -> netEncS, 
   "Output" -> NetDecoder["Image"]}]
Out[22]=

Restyle an image using the new resized network:

In[23]:=
resizedNet@<|"Content" -> content, "Style" -> style|>
Out[23]=

Net information

Inspect the number of parameters of all arrays in the net:

In[24]:=
NetInformation[
 NetModel["AdaIN-Style Trained on MS-COCO and Painter by Numbers \
Data"], "ArraysElementCounts"]
Out[24]=

Obtain the total number of parameters:

In[25]:=
NetInformation[
 NetModel["AdaIN-Style Trained on MS-COCO and Painter by Numbers \
Data"], "ArraysTotalElementCount"]
Out[25]=

Obtain the layer type counts:

In[26]:=
NetInformation[
 NetModel["AdaIN-Style Trained on MS-COCO and Painter by Numbers \
Data"], "LayerTypeCounts"]
Out[26]=

Display the summary graphic:

In[27]:=
NetInformation[
 NetModel["AdaIN-Style Trained on MS-COCO and Painter by Numbers \
Data"], "SummaryGraphic"]
Out[27]=

Export to MXNet

Export the net into a format that can be opened in MXNet:

In[28]:=
jsonPath = 
 Export[FileNameJoin[{$TemporaryDirectory, "net.json"}], 
  NetModel["AdaIN-Style Trained on MS-COCO and Painter by Numbers \
Data"], "MXNet"]
Out[28]=

Export also creates a net.params file containing parameters:

In[29]:=
paramPath = FileNameJoin[{DirectoryName[jsonPath], "net.params"}]
Out[29]=

Get the size of the parameter file:

In[30]:=
FileByteCount[paramPath]
Out[30]=

The size is similar to the byte count of the resource object:

In[31]:=
ResourceObject[
  "AdaIN-Style Trained on MS-COCO and Painter by Numbers \
Data"]["ByteCount"]
Out[31]=

Represent the MXNet net as a graph:

In[32]:=
Import[jsonPath, {"MXNet", "NodeGraphPlot"}]
Out[32]=

Requirements

Wolfram Language 11.2 (September 2017) or above

Reference