前面,材料已经准备得差不多了,现在可以开始。
首先是编码器,就是一个'预处理卷积'+VGG19的开头到 relu4-1 层。
'预处理卷积' 等同'@./helpers/preprocess.lua',
这个文件 <fast-neural-style-master>中有:
M.vgg = {}
local vgg_mean = {103.939, 116.779, 123.68}
--[[
在传递给VGG模型之前预处理图像。我们需要重新缩放
[0,1]到[0,255],从RGB转换为BGR,并减去平均值。
输入:
- img:形状张量(N,C,H,W)给出一批图像。图片
]]
function M.vgg.preprocess(img)
check_input(img)
local mean = img.new(vgg_mean):view(1, 3, 1, 1):expandAs(img)
local perm = torch.LongTensor{3, 2, 1}
return img:index(2, perm):mul(255):add(-1, mean)
end
从这里看出需要[0,1]的RGB数据。
编码器定义:
struct 编码器 //由 Vgg19 的 relu4-1 层输出
{
层数据 * PreprocessConv;//1 预处理卷积层
层数据 * Conv1;//2 //组
层数据 * Conv2;//2
层数据 * Conv3;//4
层数据 * Conv4;//1
//构造函数
编码器();
};
编码器::编码器()
{
int size;
层数据 * 层;
//用于一层(宏)
/*输入维度,输出维度,核宽*/
#define 初始化ONE层(IN,OUT,KW) \
\
层->输入维度=IN;\
层->输出维度=OUT;\
层->核宽=KW;\
层->权重长度=层->输出维度*层->输入维度*层->核宽*层->核宽;\
层->权重_数据=(float*)malloc(sizeof(float) * 层->权重长度);\
层->偏移长度=层->输出维度;\
层->偏移_数据=(float*)malloc(sizeof(float) * 层->偏移长度);\
\
层++;\
//用于一组(宏)
/*组名称,输入维度,输出维度,核宽,组中层数*/
#define 初始化层(ConvX,IN,OUT,KW,Num) \
size = sizeof(层数据)*Num;\
\
层=ConvX =(层数据 *)malloc(size);\
初始化ONE层(IN,OUT,KW)\
for (int i=0;i<Num-1 ;i++ )\
{\
初始化ONE层(OUT,OUT,KW)\
}\
//预处理层
/*名称,输入维度,输出维度,核宽,组中层数*/
初始化层(PreprocessConv,3,3,1,1)
//Conv1: 2层
初始化层(Conv1,3,64,3,2)
//Conv2: 2层
初始化层(Conv2,64,128,3,2)
//Conv3: 4层
初始化层(Conv3,128,256,3,4)
//Conv4: 4层
初始化层(Conv4,256,512,3,1)
}
解码器:
struct 解码器 //输入层 维度,大小 由 Vgg19 的 relu4-1 层输出 决定
{
//组
层数据 * Conv1;//1
层数据 * Conv2;//4
层数据 * Conv3;//2
层数据 * Conv4;//2
//构造函数
解码器();
};
解码器::解码器()
{
int size;
层数据 * 层;
#define 初始化解层(ConvX,IN,OUT,KW,Num) \
size = sizeof(层数据)*Num;\
\
层=ConvX =(层数据 *)malloc(size);\
for (int i=0;i<Num-1 ;i++ )\
{\
初始化ONE层(IN,IN,KW)\
}\
初始化ONE层(IN,OUT,KW)\
//Conv1: 1层
/*名称,输入维度,输出维度,核宽,组中层数*/
初始化解层(Conv1,512,256,3,1)
//Conv2: 4层
初始化解层(Conv2,256,128,3,4)
//Conv3: 2层
初始化解层(Conv3,128,64,3,2)
//Conv4: 2层
初始化解层(Conv4,64,3,3,2)
}
主流程:
1。内容图-->编码-->内容特征,
2。风格图-->编码-->风格特征,
3。内容特征,风格特征-->AdaIN-->目标特征,
4。目标特征 * 混合比 + (1 - 混合比) * 内容特征-->混合特征,(风格控制)
5。混合特征-->解码-->风格图。
C++主流程:
//载入图片
//缩放至 512x512 的图像 (VGG19 分类 224x224)
Resizeloadjpg(jpgname);//也可以原始大小,但不能太小,不然池化后...,太大费时.
编码器 encoder;
//从t7模型文件加载数据
loadt7Model(&encoder);
//取得特征层 (图像由全局变量jpg输入)
卷积层 * content=vgg(encoder);
卷积层 content_copy(content->width,content->height,content->depth);
content_copy.data=new float[content_copy.width*content_copy.height*content_copy.depth];
卷积层复制(content,&content_copy);
//载入风格图
Resizeloadjpg(Style_Name);
卷积层 * style=vgg(encoder);
AdaIN(*content,* style);
float alpha=0.5f;//混合比
风格控制(content_copy,*content,alpha);
解码器 decoder;
//loadModel(&decoder);//文本载入
//saveModel2进制(&decoder);//二进制保存
loadModel2进制(&decoder);//二进制载入
//生成风格图
Decoding("Adain-style", decoder,content);//保存输出风格名称,解码器参数,输入
//save_卷积层2jpg(style,);
效果图:
生成512x512,需要56秒。
这部分结束。