有没有想过,利用机器学习来画画,今天,我将手把手带大家进入深度学习模型neural style的代码实战当中。
neural-style模型是一个风格迁移的模型,是GitHub上一个超棒的项目,那么什么是风格迁移,我们来举一个简单的例子:
这里,我选择了将梵高的画风和我们的东北大学的工学馆相结合,让工学馆融入了 梵高的星空效果图,在经过100次的迭代后得到了带有星空效果的图片。
另外我们可以尝试与其他风格结合:
那么接下来就带大家一起进入这个项目的实战之中,如果大家想了解更多过于neural network相关的理论请自己查阅资料,我在这里就不具体介绍了。
论文地址:https://arxiv.org/abs/1508.06576
项目地址:https://github.com/cysmith/neural-style-tf
该项目可以干什么,除了上面单方面的图片效果外,我们也可以使用多种风格的样式混为一起,或者把视频导入后输出带有其他风格的视频。或者使用语义分割,实现不同的区域有不同的风格。本博客将持续更新,将最新的一些玩法更新到博客上来,同时也可能有算法的优化,这些都是后话了。
我们可以用这个项目为我们自己的学校做明信片,即使你不会画画,也可以制作一些自己风格的图片等等。
那么现在我们开始吧。
在我们下载好项目代码后,我们还需要一个权重文件,这里直接提供网盘分享:
https://pan.baidu.com/s/106YVMURhXDC0aZj6sQmasA
尝试其他文件的效果,可以访问这个网站下载:http://www.vlfeat.org/matconvnet/pretrained/
下载好了后直接放在项目的文件夹中,放在和neural_style.py一个目录下。
该项目基于tensorflow框架,这里我强烈推荐GPU版本,这里的深度学习模型不像其他的模型,有训练出来的文件,而是直接梯度下降进行转化,CPU的转化比较慢,因此这里推荐GPU的tensorflow,依赖CUDA和cudnn,CUDA依赖7.5版本以上,cudnn选择对应CUDA版本。然后打开命令行,输入以下命令:
pip install tensorflow-gpu
如果你安装过CPU版本的tensorflow,那么也不用担心,你只需要在anaconda里面新搭建一个环境,这里不做详细的解释,如果大家有疑问可以直接在网络上搜索具体的安装方法,如果有问题也可以联系我。
当然不一定非得是GPU版本,CPU版本也可以,只是转换的速度问题。
接着如果你想参与视频的转化,还需要opencv-python的包,我们输入以下命令:
pip install opencv-python
好了,那么环境的搭建基本结束,我们开始实战吧。
在我们的项目代码中,我们发现neural_style.py这个文件,即专门用于转化图片风格。
下面我们列出相关的参数:
--content_img
:内容图像的文件名。示例:lion.jpg
--content_img_dir
:内容映像的相对或绝对目录路径。默认值:./image_input
--style_imgs
:样式图像的文件名。要使用多个样式图像,请传递以空格分隔的列表。 示例:--style_imgs starry-night.jpg
--style_imgs_weights
:每个样式图像的混合权重。 默认值 :(1.0
仅假设1个样式图像)--style_imgs_dir
:样式图像的相对或绝对目录路径。默认值:./styles
--init_img_type
:用于初始化网络的映像。选择:content
,random
,style
。默认值:content
--max_size
:输入图像的最大宽度或高度。默认值:512
--content_weight
:内容丢失功能的权重。默认值:5e0
--style_weight
:风格损失功能的重量。默认值:1e4
--tv_weight
:总变分损失函数的权重。默认值:1e-3
--temporal_weight
:时间损失函数的权重。默认值:2e2
--content_layers
:用于内容图像的以空格分隔的 VGG-19图层名称。默认值:conv4_2
--style_layers
:用于样式图像的以空格分隔的 VGG-19图层名称。默认值:relu1_1 relu2_1 relu3_1 relu4_1 relu5_1
--content_layer_weights
:每个内容层的空间分隔权重与内容丢失。默认值:1.0
--style_layer_weights
:每个样式图层的空间分隔权重丢失。默认值:0.2 0.2 0.2 0.2 0.2
--original_colors
:布尔标志,指示样式是否已传输但不是颜色。--color_convert_type
:用于亮度匹配转换为原始颜色的颜色空间(YUV,YCrCb,CIE L * u * v *,CIE L * a * b *)。选择:yuv
,ycrcb
,luv
,lab
。默认值:yuv
--style_mask
:布尔标志,指示样式是否转移到蒙版区域。--style_mask_imgs
:样式掩码图像的文件名(例如:)face_mask.png
。要使用多个样式蒙版图像,请传递以空格分隔的列表。 示例:--style_mask_imgs face_mask.png face_mask_inv.png
--noise_ratio
:如果网络初始化,内容图像和噪声图像之间的插值random
。默认值:1.0
--seed
:随机数生成器的种子。默认值:0
--model_weights
:VGG-19网络的权重和偏差。默认值:imagenet-vgg-verydeep-19.mat
--pooling_type
:卷积神经网络中的池化类型。选择:avg
,max
。默认值:avg
--device
:GPU或CPU设备。强烈建议使用GPU模式但需要NVIDIA CUDA。选择:/gpu:0
/cpu:0
。默认值:/gpu:0
--img_output_dir
:将输出写入的目录。 默认值:./image_output
--img_name
:输出图像的文件名。默认值:result
--verbose
:布尔标志,指示是否应将语句打印到控制台。
看着应该很让人眼花缭乱吧,那么我们进入实战来了解吧,项目里面有一些图片和风格图,而默认的图片输入路径是image_input,默认的输出路径是image_output,默认的风格图片保存地址是styles,大家如果把图片放在相应的位置即可直接运行,如果想放在其他位置则需要更改内容映像的相对或绝对目录路径:--content_img_dir。
那么我们先来实战一波,这里我在image_input里放上来了一张自己的图片,我起名school.jpg,在styles里有一张星空的图片,大家自行选择,如果图片放在固定文件夹那就不需要更改映像路径,也就是content_img_dir这个参数。
定位到项目文件夹,打开cmd,输入以下命令:
gpu版本:
python neural_style.py --content_img school.jpg --style_imgs starry-night.jpg --max_size 620 --max_iterations 100 --original_colors --verbose
cpu版本:
python neural_style.py --content_img school.jpg --style_imgs starry-night.jpg --max_size 620 --max_iterations 100 --original_colors --device /cpu:0 --verbose
大家注意到了这两行代码的区别就在于多了一个--device参数,就是确认使用CPU还是GPU,默认是GPU,如果使用GPU可以不填这个参数,如果是CPU需要填写。
下面解释一下常用的参数:--content_img是选择需要转换风格的图片,把图片放在image_input这个文件夹里,content_img的参数就是这个文件夹里图片的名字,记得加上文件的后缀。--style_imgs的参数选择是放在styles文件夹里面的图片文件名。--max_size是你选择需要转化的图片最大像素长度,我不建议使用过大的图片,大家转化图片时可以尽可能缩小图片大小,Windows自带的照片编辑器可以更改,大家查看图片像素大小也很简单,右键图片->属性->详细信息即可看到图片的长宽各多少像素,建议长尽量不要超过1000,不然性能一般的电脑可能会卡住。--max_iterations这个参数是图片迭代次数,次数过小可能有欠拟合,没有风格图片的风格;但是过大有过拟合现象,即原有的图片失去自己的特征,建议100-1000,根据自己图片来定。因为图片好坏在于个人审美,因此大家可以多导出几张选择自己觉得最适合的图片。最后的--verbose参数是在命令行是否反馈数据,如果没有就是命令行没有任何显示,建议还是加上。我这里直接迭代100次,下面是导出的图片。
我们发现,这张图片虽然有了梵高的画作星空的油画特征,可是颜色却是自己本来的颜色,那么如何导出和风格图片差不多的颜色呢,这里就要简单说明一下上述命令中的--original_colors,这个命令加上后就会让输入图片色彩保留自己的特征,如果大家想要风格图片的色彩特征的话可以直接删除这个--original_colors,然后再次转换得出以下图片:
这是一样的迭代次数,只是色彩参照不一样,大家根据自己喜好选取。
那么更多的参数调整请看上述的表,我介绍的参数是最基本的,大家可以入手的参数。
这里需要介绍另一个参数:--style_imgs_weights,就是权重。比如,我想要有两种风格的图片,两种风格更侧重哪个风格,这就是权重。比如我要给一张图片蒙娜丽莎和中国水墨画的风格,假设蒙娜丽莎的图片是mnls.jpg,中国水墨画的图片叫china.jpg。那么我们可以这样使用:
CPU:
python neural_style.py --content_img school.jpg --style_imgs mnls.jpg china.jpg --max_size 620 --max_iterations 200 --device /cpu:0 --verbose --style_imgs_weights 0.5 0.5
GPU:
python neural_style.py --content_img school.jpg --style_imgs mnls.jpg china.jpg --max_size 620 --max_iterations 200 --verbose --style_imgs_weights 0.5 0.5
我对--style_imgs这个参数选择两张图片,名字用空格隔开即可,在--style_imgs_weights这个参数,假如说我希望两种风格影响一样,即五五分,那么我的这个参数在--style_imgs_weights后面直接输入0.5 0.5,要注意的是权重的参数总和需要为1。
大家可以把很多风格,不一定是两个,也可以是三个或四个,按一定的权重设置,然后输出多风格的图片。
下面一张是蒙娜丽莎风格的图片:
这张是中国水墨画风格的图片:
如下是两种风格1:1的组合:
效果可能并不是很明显,不过的确是有差异的,大家可以自己动手尝试去做好看的图片。
1.注意迭代的次数,放止过拟合与欠拟合的现象。
2.好看的图片一定要选对风格,否则就算拟合的再好,风格不适合图片也不好看的。
3.选择的图片和风格图片物体大小也会影响输出图片。
4.多风格图片注意风格之间的权重关系。
终归这是别人的一个成果,我们只是调用了别人的成果,有兴趣的建议理解该算法并且尝试研究超越该算法。