<filename>Neural_Style/transformer_net.py
# coding:utf8
"""
code refer to https://github.com/abhiskk/fast-neural-style/blob/master/neural_style/transformer_net.py
"""
import torch as t
from torch import nn
import numpy as np

def deprocessImg(x):
    return (x + 1.0) * 127.5

class TransformerNet(nn.Module):
    def __init__(self, alpha):
        super(TransformerNet, self).__init__()

        # 下卷积层
        self.initial_layers = nn.Sequential(
            ConvLayer(3, int(alpha * 32), 9, 1),
            ConvLayer(int(alpha * 32), int(alpha * 64), 3, 2),
            ConvLayer(int(alpha * 64), int(alpha * 128), 3, 2)
        )

        # Residual layers(残差层)
        self.res_layers = nn.Sequential(
            ResidualBlock(int(alpha * 128)),
            ResidualBlock(int(alpha * 128)),
            ResidualBlock(int(alpha * 128)),
            ResidualBlock(int(alpha * 128)),
            ResidualBlock(int(alpha * 128))

        )
        # Upsampling Layers(上卷积层)
        self.upsample_layers = nn.Sequential(   
            UpsampleConvLayer(int(alpha * 128), int(alpha * 64), 3, 1, 2),
            UpsampleConvLayer(int(alpha * 64), int(alpha * 32), 3, 1, 2),
            ConvLayer(int(alpha * 32), 3, 9, 1, relu=False),
            nn.Tanh()
        )

    def forward(self, x):
        x = self.initial_layers(x)
        x = self.res_layers(x)
        x = self.upsample_layers(x)
        x = deprocessImg(x)
        return x


class ConvLayer(nn.Module):
    """
    add ReflectionPad for Conv
    默认的卷积的padding操作是补0，这里使用边界反射填充
    输入和输出size相同
    """

    def __init__(self, in_channels, out_channels, kernel_size, stride, relu=True):
        super(ConvLayer, self).__init__()
        self.relu = relu
        reflection_padding = int(np.floor(kernel_size / 2))
        self.reflection_pad = nn.ReflectionPad2d(reflection_padding)
        self.conv2d = nn.Conv2d(in_channels, out_channels, kernel_size, stride)
        self.ins = nn.InstanceNorm2d(out_channels, affine=True)

    def forward(self, x):
        out = self.reflection_pad(x)
        out = self.conv2d(out)
        out = self.ins(out)
        if self.relu:
            out = nn.ReLU()(out)
        return out


class UpsampleConvLayer(nn.Module):
    """UpsampleConvLayer
    默认的卷积的padding操作是补0，这里使用边界反射填充
    先上采样，然后做一个卷积(Conv2d)，而不是采用ConvTranspose2d，这种效果更好，参见
    ref: http://distill.pub/2016/deconv-checkerboard/
    """

    def __init__(self, in_channels, out_channels, kernel_size, stride, upsample=None):
        super(UpsampleConvLayer, self).__init__()
        self.upsample = upsample
        self.conv2d = ConvLayer(in_channels, out_channels, kernel_size, stride)

    def forward(self, x):
        x_in = x
        if self.upsample:
            x_in = t.nn.functional.interpolate(x_in, scale_factor=self.upsample)
        out = self.conv2d(x_in)
        return out


class ResidualBlock(nn.Module):
    """ResidualBlock
    introduced in: https://arxiv.org/abs/1512.03385
    recommended architecture: http://torch.ch/blog/2016/02/04/resnets.html
    """

    def __init__(self, channels):
        super(ResidualBlock, self).__init__()
        self.conv1 = ConvLayer(channels, channels, kernel_size=3, stride=1)
        self.conv2 = ConvLayer(channels, channels, kernel_size=3, stride=1, relu=False)

    def forward(self, x):
        residual = x
        out = self.conv1(x)
        out = self.conv2(out)
        out = out + residual
        return out

<filename>Neural_Style/transformer_net.py
# coding:utf8
"""
code refer to https://github.com/abhiskk/fast-neural-style/blob/master/neural_style/transformer_net.py
"""
import torch as t
from torch import nn
import numpy as np

def deprocessImg(x):
    return (x + 1.0) * 127.5

class TransformerNet(nn.Module):
    def __init__(self, alpha):
        super(TransformerNet, self).__init__()

        # 下卷积层
        self.initial_layers = nn.Sequential(
            ConvLayer(3, int(alpha * 32), 9, 1),
            ConvLayer(int(alpha * 32), int(alpha * 64), 3, 2),
            ConvLayer(int(alpha * 64), int(alpha * 128), 3, 2)
        )

        # Residual layers(残差层)
        self.res_layers = nn.Sequential(
            ResidualBlock(int(alpha * 128)),
            ResidualBlock(int(alpha * 128)),
            ResidualBlock(int(alpha * 128)),
            ResidualBlock(int(alpha * 128)),
            ResidualBlock(int(alpha * 128))

        )
        # Upsampling Layers(上卷积层)
        self.upsample_layers = nn.Sequential(   
            UpsampleConvLayer(int(alpha * 128), int(alpha * 64), 3, 1, 2),
            UpsampleConvLayer(int(alpha * 64), int(alpha * 32), 3, 1, 2),
            ConvLayer(int(alpha * 32), 3, 9, 1, relu=False),
            nn.Tanh()
        )

    def forward(self, x):
        x = self.initial_layers(x)
        x = self.res_layers(x)
        x = self.upsample_layers(x)
        x = deprocessImg(x)
        return x


class ConvLayer(nn.Module):
    """
    add ReflectionPad for Conv
    默认的卷积的padding操作是补0，这里使用边界反射填充
    输入和输出size相同
    """

    def __init__(self, in_channels, out_channels, kernel_size, stride, relu=True):
        super(ConvLayer, self).__init__()
        self.relu = relu
        reflection_padding = int(np.floor(kernel_size / 2))
        self.reflection_pad = nn.ReflectionPad2d(reflection_padding)
        self.conv2d = nn.Conv2d(in_channels, out_channels, kernel_size, stride)
        self.ins = nn.InstanceNorm2d(out_channels, affine=True)

    def forward(self, x):
        out = self.reflection_pad(x)
        out = self.conv2d(out)
        out = self.ins(out)
        if self.relu:
            out = nn.ReLU()(out)
        return out


class UpsampleConvLayer(nn.Module):
    """UpsampleConvLayer
    默认的卷积的padding操作是补0，这里使用边界反射填充
    先上采样，然后做一个卷积(Conv2d)，而不是采用ConvTranspose2d，这种效果更好，参见
    ref: http://distill.pub/2016/deconv-checkerboard/
    """

    def __init__(self, in_channels, out_channels, kernel_size, stride, upsample=None):
        super(UpsampleConvLayer, self).__init__()
        self.upsample = upsample
        self.conv2d = ConvLayer(in_channels, out_channels, kernel_size, stride)

    def forward(self, x):
        x_in = x
        if self.upsample:
            x_in = t.nn.functional.interpolate(x_in, scale_factor=self.upsample)
        out = self.conv2d(x_in)
        return out


class ResidualBlock(nn.Module):
    """ResidualBlock
    introduced in: https://arxiv.org/abs/1512.03385
    recommended architecture: http://torch.ch/blog/2016/02/04/resnets.html
    """

    def __init__(self, channels):
        super(ResidualBlock, self).__init__()
        self.conv1 = ConvLayer(channels, channels, kernel_size=3, stride=1)
        self.conv2 = ConvLayer(channels, channels, kernel_size=3, stride=1, relu=False)

    def forward(self, x):
        residual = x
        out = self.conv1(x)
        out = self.conv2(out)
        out = out + residual
        return out

# coding:utf8 code refer to https://github.com/abhiskk/fast-neural-style/blob/master/neural_style/transformer_net.py # 下卷积层 # Residual layers(残差层) # Upsampling Layers(上卷积层) add ReflectionPad for Conv     默认的卷积的padding操作是补0，这里使用边界反射填充     输入和输出size相同 UpsampleConvLayer     默认的卷积的padding操作是补0，这里使用边界反射填充     先上采样，然后做一个卷积(Conv2d)，而不是采用ConvTranspose2d，这种效果更好，参见     ref: http://distill.pub/2016/deconv-checkerboard/ ResidualBlock     introduced in: https://arxiv.org/abs/1512.03385     recommended architecture: http://torch.ch/blog/2016/02/04/resnets.html