使用部分
一、编程环境
编程环境使用Windows11上的Anaconda环境,Python版本为3.6. 关于Conda环境的建立和管理,可以参考我的博客:【Anaconda】【Windows编程技术】【Python】Anaconda的常用命令及实操
二、项目结构(代码非本人原创)
根目录MXNet-Gluon-Style-Transfer下包含dataset(数据集)文件夹、images(图像)文件夹、models(模型)文件夹。venv1—venv4为之前创建的4个虚拟环境(不使用)。其他重要文件包括:
run.py:运行入口
images文件夹结构
content:待转换的内容图片;
output:转换结果输出位置;
styles:风格图片。
三、run.py内容
import os
os.system("python main.py eval --content-image images/content/lyq.jpg --style-image images/styles/shipwreck.jpg --output-image images/output/1.jpg --model models/21styles.params --cuda=0")
代码解释:
python main.py eval # 运行main.py,选项为eval(evaluate,测试模型)
--content-image images/content/lyq.jpg # 内容图片
--style-image images/styles/shipwreck.jpg # 风格图片
--output-image images/output/1.jpg # 输出图片
--model models/21styles.params # 模型选择
--cuda=0 # 是否使用cuda加速(笔者电脑没有N家显卡,选择0)
四、运行测试
原图片:
风格图片:
结果图片:
原理部分
Python的第三方库mxnet(通过以下语句导入:)
import mxnet as mx
from mxnet import autograd, gluon
from mxnet.gluon import nn, Block, HybridBlock, Parameter, ParameterDict
import mxnet.ndarray as F
一、模型训练
训练模型时,用到VGG16模型。模型位于torchvision.models中:
from torchvision import models
vgg = models.vgg16(pretrained=True)
print(vgg)
vgg16模型结构如下。(执行上述代码,会首先从pytorch官网下载预训练网络的权重,并输出网络的每一层说明。)它先进行特征提取,然后进行分类。特征提取和分类部分都用简单的序列模型(Sequential)构建。特征提取部分由5个类似的子结构组成,每个子结构包括卷积层(Conv2d)、非线性激活函数(ReLU)层,以及最大池化(MaxPool2d)层:
VGG(
# 特征提取部分
(features): Sequential(
# 子结构 1
(0): Conv2d(3, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(1): ReLU(inplace=True)
(2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(3): ReLU(inplace=True)
(4): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
# 子结构 2
(5): Conv2d(64, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(6): ReLU(inplace=True)
(7): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(8): ReLU(inplace=True)
(9): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
# 子结构 3
(10): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(11): ReLU(inplace=True)
(12): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(13): ReLU(inplace=True)
(14): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(15): ReLU(inplace=True)
(16): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
# 子结构 4
(17): Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(18): ReLU(inplace=True)
(19): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(20): ReLU(inplace=True)
(21): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(22): ReLU(inplace=True)
(23): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
# 子结构 5
(24): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(25): ReLU(inplace=True)
(26): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(27): ReLU(inplace=True)
(28): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(29): ReLU(inplace=True)
(30): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
)
# 平均池化部分
(avgpool): AdaptiveAvgPool2d(output_size=(7, 7))
# 分类部分
(classifier): Sequential(
(0): Linear(in_features=25088, out_features=4096, bias=True)
(1): ReLU(inplace=True)
(2): Dropout(p=0.5, inplace=False)
(3): Linear(in_features=4096, out_features=4096, bias=True)
(4): ReLU(inplace=True)
(5): Dropout(p=0.5, inplace=False)
(6): Linear(in_features=4096, out_features=1000, bias=True)
)
)