基于tensorflow框架训练超像素subpixel模型

       Subpixel算法自身是一种插值算法,与常规的双线性或cubic插值算法相比,提升了图像的分辨率和插值质量(SNR),但达不到人脸解析的效果。为了达成该效果,可选取人脸数据集(如celebA),训练阶段配合DCGAN(深度卷积生成对抗网络)算法,对生成器部分做了二次优化,训练完成后取GAN中的生成网络部分做部署。

1. 网络框架

 在部署和推理阶段的网络结构如下,网络命名为ESPCN(efficient subpixel convolutional network)。

                                                               ESPCN 网络结构

                                                               ESPCN 参数部署(batch_size=64为例)

Subpixel部署阶段的网络架构主要由3层反卷积、lrelu激活以及自定义的像素移位层(PS)构成的。

值得注意的是PS输入feature maps是48通道32*32大小的,48=3*4^2,其中r=4,代表放大倍数(upscaling factor),PS层进行像素重组,输出图像大小扩增为4倍,为(48*r)*(48*r)=128*128,输出通道数为48/r^2=48/16=3

2. 计算复杂度

(1)空间复杂度

网络参数规模如下(batch_size=64为例,部署阶段cnn空间复杂度与batch_size无关):

layer name

滤波器超参数

滤波器参数规格
(kernel_size_h*kernel_size_w*output_channel*input_channel)

输入feature map规格
(batch_size*h*w*channel)

输出feature map规格
(batch_size*h*w*channel)

g_h0_deconv

kernel_size:1
stride:1

padding:0

1*1*64*3

64*32*32*3

64*32*32*64

g_h0_lrelu

slope:0.2

——

64*32*32*64

64*32*32*64

g_h1_deconv

kernel_size:5
stride:1

padding:2

5*5*64*64

64*32*32*64

64*32*32*64

g_h1_lrelu

slope:0.2

——

64*32*32*64

64*32*32*64

g_h1_deconv

kernel_size:5
stride:1

padding:2

5*5*48*64

64*32*32*64

64*32*32*48

PS

——

——

64*32*32*48

64*128*128*3

tanh

——

——

64*128*128*3

64*128*128*3

Total参数数量(空间复杂度)=1*1*64*3+5*5*64*64+5*5*48*64=179392

(2)时间复杂度

计算batch_size=1时的时间复杂度如下:

layer

运算说明

计算公式(input_channel_output_channel_kernel_h*kernel_w*input_featuremap_h*input_featuremap_w)

total MAC计算量

g_h0_deconv

MAC运算次数

3*64*1*1*32*32

196608

g_h0_lrelu

激活次数(in place)

1*32*32*64

65536

g_h1_deconv

MAC运算次数

64*64*5*5*32*32

104857600

g_h1_lrelu

激活次数(in place)

1*32*32*64

65536

g_h1_deconv

MAC运算次数

64*48*5*5*32*32

78643200

PS

——

——

——

tanh

激活次数(in place)

1*128*128*3

49152

总计

183877632

Batch_size=1 infer的MAC计算次数=183877632,约1亿8千多万次浮点计算。

3. 特殊层考虑

1.deconv layer

严格来讲反卷积的叫法并不科学,矩阵只有是方阵时才有求逆运算。Deconv是转置卷积,是feature map升采样的过程。

对于常规卷积运算来说,有如下公式成立:

O是输出feature map大小,i是输入feature map大小,p为padding,k为conv的kernel size。半中括号表示向下取整。

对该公式做下变形,O和i交换符号位置后,就可得到反卷积的运算公式如下:

Deconv有两种操作实现方法:

  1. 转化为matrix乘法运算:将input feature map展开为1D向量,deconv kernel为2*2,假设为[1 2;3 4],那么按(a)图做weight矩阵做矩阵乘法,可得到输出的1D feature map向量,再还原为2D output feature map;
  2. Input feature map插0后做常规卷积运算:deconv中stride为放大倍数,假设stride=2,那么可以在input feature map上做隔1点插0后,再做常规卷积运算。

    两种运算结果做deconv是等价的。

2. lrelu layer

以slope=0.2为例:

    

    计算公式:

3. PS layer

PS层的作用是将H*W*(C*r^2)的blob,变换为(r*H)*(r*W)*C,也就是说有r^2*C个input channel,feature map大小为H*W,经过PS重新编排后,通道数缩减为1/r^2倍,变成C个channel,但feature map变大了,变为(r*H)*(r*W),这样可以达到上采样和提升分辨率效果。

PS层的操作算子设计公式如下:

其中中括号为向下取整(floor),mod为求余运算。

直观的示例如下:

输入blob为8*8*12  pixel的排列如下:

经过PS后的输出blob为16*16*3  pixel排列如下:

    采用了r*r邻居机制进行排列

    放大因子r=2  所以输出的channel为12/2^2=3,输出的feature map视野为输入的2倍,对于1个2*2的cell,将输入blob的pixel按照黄色、绿色、蓝色的图中示例顺序进行填充,最终可得到3通道16*16的超像素图像。

4. Tanh layer

    利用tanh激活函数将feature map的value映射到(-1,1)区间。

计算公式如下:

4. 验证

1.参考了subpixel工程(https://github.com/tetrachrome/subpixel),通过training代码用dcgan训练了subpixel实现model;

2.Model准备:tensorflow框架下利用celebA人脸检测数据集训练25个epoch得到subpixel模型用于测试;

3.人脸ROI区域截取:根据网络参数配置,调整为32*32大小;

4.将32*32图像送进subpixel网络做超像素解析;

5.得到解析结果,大小为128*128。

5. 建议及结论

  • 1)ESPCN网络可达到人脸超像素解析效果;
  • 2)ESPCN由3层deconv、2层lrelu、1层PS和1层tanh组成,估算参数容量(空间复杂度)179392,MAC运算(时间复杂度)约1亿8千多万次,参数容量和运算次数不大;
  • 3)从算法优化角度来讲,通过精心设计人脸训练集(如特定地区的受关注人脸库)和训练参数调优后,有望获得更好的超像素解析效果;
  • 4)deconv、lrelu、PS和tanh层目前芯片不支持,需要做针对性开发及验证。
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是基于Zernike矩的亚像素边缘检测的Python代码示例: ```python import cv2 import numpy as np from scipy.special import comb from scipy.special import factorial def zernike_moments(img, degree): # 计算Zernike矩 moments = [] rows, cols = img.shape x, y = np.meshgrid(np.arange(cols), np.arange(rows)) radius = np.sqrt((2 * x - cols + 1) ** 2 + (2 * y - rows + 1) ** 2) / rows theta = np.arctan2(2 * y - rows + 1, 2 * x - cols + 1) for n in range(degree + 1): for m in range(n + 1): if (n - m) % 2 == 0: R_nm = np.zeros_like(radius) R_nm[radius <= 1] = zernike_radial(n, m, radius[radius <= 1]) moments.append(np.sum(img * R_nm * np.exp(-1j * m * theta)) / np.sum(R_nm ** 2)) return moments def zernike_radial(n, m, r): # 计算Zernike径向函数 if (n - m) % 2 != 0 or abs(m) > n: return np.zeros_like(r) if n == 0: return np.ones_like(r) elif n == 1: if m == 1: return 2 * r elif m == 0: return np.sqrt(2) * (2 * r - 1) else: return np.sqrt(2) * (2 * r - 1) else: k = (n - m) // 2 s = 0 for i in range(k + 1): s += ((-1) ** i * comb(n - i, k - i) * comb(n - 2 * k + i, k - i) * r ** (n - 2 * i)) return s * np.sqrt(factorial(n - m) / (factorial(n + m) * np.pi)) def subpixel_edge_detection(img, degree, threshold): # 亚像素边缘检测 moments = zernike_moments(img, degree) rows, cols = img.shape x, y = np.meshgrid(np.arange(cols), np.arange(rows)) radius = np.sqrt((2 * x - cols + 1) ** 2 + (2 * y - rows + 1) ** 2) / rows theta = np.arctan2(2 * y - rows + 1, 2 * x - cols + 1) edges = np.zeros_like(img) for n in range(degree + 1): for m in range(n + 1): if (n - m) % 2 == 0: if abs(moments[n * (n + 1) // 2 + m]) > threshold: R_nm = np.zeros_like(radius) R_nm[radius <= 1] = zernike_radial(n, m, radius[radius <= 1]) edges += np.real(moments[n * (n + 1) // 2 + m] * R_nm * np.exp(1j * m * theta)) return edges / np.max(edges) # 示例用法 img = cv2.imread('image.jpg', 0) edges = subpixel_edge_detection(img, degree=10, threshold=0.1) cv2.imshow('Edges', edges) cv2.waitKey(0) cv2.destroyAllWindows() ``` 在代码中,`zernike_moments`函数用于计算Zernike矩,`zernike_radial`函数用于计算Zernike径向函数,`subpixel_edge_detection`函数用于进行亚像素边缘检测。在示例用法中,读取一张灰度图像,然后调用`subpixel_edge_detection`函数进行亚像素边缘检测。`degree`参数指定Zernike矩的阶数,`threshold`参数指定阈值,用于筛选Zernike矩。最后显示边缘检测结果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值