Chainer笔记 -- SRCNN
首先来说一说为什么会来写chainer, 尽管最近已经不打算再继续用chainer了, 但是对于刚接触深度学习的人来说, 极简单的安装和极简单的gpu加速使得chainer仍是一个简单快速上手的深度学习库

什么是SRCNN 论文地址: https://ieeexplore.ieee.org/document/7115171
SRCNN全称为Super Resolution Convolutional Network, 这是第一个使用深度学习的超分辨率算法 (超分辨率算法: 从低分辨率图像得到高分辨率图像的算法). SRCNN具有极其简单的结构, 甚至比许多分类器简单很多, 十分适合用来做演示.
SRCNN是在YUV通道的V上进行图像复原 (YUV图像: 使用V(亮度), 和UV(CbCr色度)) , 这比起使用RGB的CNN可以减少很多权重以加快计算速度并且不会损失细节
SRCNN一共有3层, 分别为: 提取图像特征, 非线性映射, 重构图像

ps: 卷积核尺寸为9,1,5的SRCNN也称SRCNN(9-1-5), 更改卷积核尺寸可以得到SRCNN(9-3-5), SRCNN(9-5-5), 尽管卷积核尺寸越大会提升得到图像的真实性, 但是这也会大大减慢计算速度, 所以这里使用915作栗子



如何训练SRCNN
SRCNN里的结构:
提取图像特征: 卷积核尺寸9, 输入通道1, 输出通道64, 步长1, padding -, 有bias [ReLU]
非线性映射: 卷积核尺寸1, 输入通道64, 输出通道32, 步长1, padding 0, 有bias [ReLU]
重构图像: 卷积核尺寸5, 输入通道32, 输出通道1, 步长1, padding -, 有bias
训练 train: 以下称 提取图像特征为conv1, 非线性映射为conv2, 重构图像为conv3
为了加快计算速度, 我们输入使用33x33处理过的小图片块, 并且让conv1和conv3的padding为0, 那么输出图像为21x21, 对应的label为图像块中央区域, 并且loss使用均方误差函数
图像处理: 裁出需要的大小为33x33的图像A, 经过双三次插值缩小后放大得到33x33的图像B, 图像B为训练输入, 而A的从坐标(6,6)到(26,26)则为label
实际使用 test:
为了保证输出输入大小一致, 我们需要把conv1和conv3的padding设置为4和2
以下为我使用了450张不知道从哪里扒来的p站图片作为训练集, 训练了150epoches的结果, 一般来说应该训练几千甚至几万epoches的, 但是我真的没这个算力


以下是Chainer时间
如何使用Chainer
Chainer内置了大量深度学习使用的函数和连接层, 而且也拥有和其他深度学习库一样的傻瓜式一键反向传播和一键更新权重 官方手册: https://docs.chainer.org/en/stable/reference/index.html
chainer的特点是可以设置连接层的输入为None, 它会在第一次调用连接层时根据输入调整内部结构, 并且chainer使用的基本数据类Variable的运算是建立在传入的数据类上的(使用Variable.data可以重新访问传入的数据), 这意味着可以完全使用cupy代替numpy达到GPU加速的效果 AMD No!
Chainer的安装: 无脑pip, 请 **ps: chainer安装时会顺便带上cuda, cupy和内置的caffe, 但是在安装时会阻止这些库的错误, 这使得chainer是唯一一个可以在termux(安卓版linux命令行模拟器)安装成功的深度学习库, 手机端开发ok
基本使用:

注意1: 有研究指出深度学习对精度没有太高的要求, 所以chainer为了提高计算速度默认是使用float32, 请注意传入的数据需要手动从默认的float64改为float32 (当然也可以把chainer默认数据改为float64, 但是何乐而不为呢)
注意2: chainer里的连接层的输入, 第一个维度必须是batchsize, 比如说一个vgg16, 默认输入是(3,224,224), 而在chainer里面则是 (n, 3,224,224), 这是为了一次计算可以计算多个输入从而提升速度
实例1: 通过反向传播更新输入 x→[0.75, -1.5, 0]
首先随机生成一个x, 然后指定target_x=[0.75, -1.5, 0], target_x经过一个连接层和sigmoid后得到label,
x经过连接层和sigmoid后得到y, y与label作均方误差, 并使用反向传播更新x, 使得x→target_x


可以看到随着x的更新会越来越接近target_x

关于图片操作
图片处理的库我使用的是opencv, 当然用pillow也可以实现, 所以我这里就不贴代码了, 只说明我做了哪些图片处理的函数
load_img(img_path) 以RGB形式加载图片, 返回一个范围在[0,255], 形状为(h,w,3)的numpy数组
save_img(img_path, img) 以RGB形式把img数组保存至img_path里
RGB_2_YUV(img) 把RGB数组转换成YUV数组, 返回 (h,w,3) 的数组
YUV_2_RGB(img) 把YUV数组转换成RGB数组, 返回 (h,w,3) 的数组
normaliz_img(img) 把数组从[0,255]归一化为[0,1], 并返回
denormaliz_img(img) 把数组从[0,1]变为[0,255], clamp掉<0和>255的数据, 并返回

实现SRCNN
首先定义全局变量, 注意训练集最好是风格统一的, 否则可能导致学习效果不太好 waifu2x在风景图效果不好也是同理

然后定义SRCNN的结构

训练部分:
def train(model, imgs_path, epoches, lr, batchsize=10, scale=3, test_img=None, test_n_train=100)
首先在训练部分里定义两个必要的函数

然后训练函数的主体:

最后使用两行函数开始训练模型


源码下载 盘.白度.com/s/1ENKRnx7nylkAV3zFSKh5ZQ, 提取码8bry
(内置彩蛋)
chainer里虽然自带数据集格式, 也知道迭代器和训练器, 但是深度学习的乐趣不就是自己魔改训练器吗