在手提式有线电话机端达成文书档案检查和测试

作者:冯牮

前言

  • 本文不是神经互联网或机器学习的入门教学,而是经过一个忠实的成品案例,体现了在手提式有线电话机客户端上运转一个神经互联网的重点技术点
  • 在卷积神经互连网适用的天地里,已经面世了有个别很经典的图像分类互联网,比如
    VGG16/VGG19,英斯ption v1-v4 Net,ResNet
    等,那几个分类网络平常又都足以当作任何算法中的基础网络布局,尤其是 VGG
    互联网,被许多别样的算法借鉴,本文也会利用 VGG16
    的底蕴互连网布局,不过不会对 VGG 网络做详细的入门教学
  • 虽说本文不是神经网络技术的入门教程,不过依然会交到一多元的连锁入门教程和技艺术文化书档案的链接,有助于进一步精晓本文的剧情
  • 实际使用到的神经互联网算法,只是本文的三个组成都部队分,除此之外,本文还介绍了怎么裁剪
    TensorFlow
    静态库以便于在二哥伦比亚大学端运营,如何准备锻练样本图片,以及练习神经网络时的各类技能等等

需借使怎么

lehu娱乐手机平台网站 1

急需很简单描述清楚,如上图,正是在一张图里,把矩形形状的文档的八个极点的坐标找出来。

历史观的技艺方案

谷歌 搜索 opencv scan
document,是可以找到好几篇有关的科目标,那一个学科里面的技术手段,也都大约,关键步骤就是调用
OpenCV 里面包车型客车三个函数,cv2.Canny() 和 cv2.findContours()。

lehu娱乐手机平台网站 2

看起来很不难就能达成出来,可是真实情况是,这一个学科,仅仅是个 demo
演示而已,用来演示的图片,都是最美丽的简易情状,真实的风貌图片会比这么些复杂的多,会有各个干扰因素,调用
canny 函数到手的边缘检查和测试结果,也会比 demo
中的景况凌乱的多,比如会检查和测试出不计其数种种长短的线段,也许是文书档案的边缘线被截断成了少数条短的线条,线段之间还留存距离不等的空当。别的,findContours
函数也不得不检测闭合的三头形的顶峰,可是并不可能确定保障那几个多边形正是三个合理的矩形。由此在大家的首先版技术方案中,对那些关键步骤,进行了汪洋的校勘和调优,归纳起来便是:

  • 改进 canny 算法的法力,扩充额外的手续,得到效果更好的边缘检查和测试图
  • 本着 canny
    步骤获得的边缘图,建立一套数学算法,从边缘图中寻觅出3个客观的矩形区域

历史观技艺方案的难度和局限性

  • canny
    算法的检查和测试效果,重视于几个阀值参数,那个阀值参数的挑三拣四,经常都以人工设置的阅历值,在改进的进度中,引入额外的步骤后,经常又会引入一些新的阀值参数,同样,也是信赖于调节和测试结果设置的阅历值。全体来看,那一个阀值参数的个数,不可能特别的多,因为只要太多了,就很难重视经验值进行安装,其它,固然有那个阀值参数,不过最后的参数只是一组或少数几组固定的重组,所以算法的鲁棒性又会压缩,很简单碰到边缘检查和测试效果不优异的景色
  • 在边缘图上树立的数学模型很复杂,代码达成难度大,而且也会遇见算法无能为力的风貌

下边那张图片,能够很好的验证地点列出的那三个难点:

lehu娱乐手机平台网站 3

那张图纸的率先列是输入的
image,最终的三列(先不用看那张图纸的第叁列),是用三组差别阀值参数调用
canny 函数和额外的函数后拿走的出口
image,可以看来,边缘检查和测试的效率,并不总是很精美的,有个别场景中,矩形的边,出现了很要紧的断裂,有个别边,甚至被完全擦除掉了,而另一部分现象中,又会检查和测试出累累惊动性质的长短边。可想而知,想用一个数学模型,适应那样不平整的边缘图,会是何等困难的一件业务。

想想什么立异

在率先版的技术方案中,负责的校友费用了多量的生气实行各样调优,终于赢得了还能够的功用,不过,就像是前边描述的那么,依旧会境遇检查和测试不出来的境况。在率先版技术方案中,遭逢那种情况的时候,选择的做法是本着这一个无法检查和测试的风貌,人工举行解析和调剂,调整已有个别一组阀值参数和算法,大概还亟需参与一些别的的算法流程(恐怕还会引入新的一对阀值参数),然后再组成到原有的代码逻辑中。经过若干轮这样的调动后,咱们发现,已经进来1个瓶颈,根据这种手段,很难进一步提高法测效果了。

既是守旧的算法手段已经到终极了,那不如试试机器学习/神经网络。

不算的神经网络算法

end-to-end 直接拟合

率先想到的,正是效仿人脸对齐(face
alignment)的思路,营造五个端到端(end-to-end)的互联网,直接回归拟合,相当于让那个神经网络直接出口
4个极点的坐标,可是,经过尝试后发觉,根本拟合不出来。后来仔细研商了一下,觉得无法平素拟合也是对的,因为:

  • 除开分类(classification)难点之外,全部的要求看上去都像是叁个回归(regression)难点,假诺回归是全能的,学术界为何还要去搞其余各样各种的网络模型
  • face alignment 之所以得以用回归互联网获取很好的拟合效果,是因为在输入
    image 上先做了 bounding box 检查和测试,收缩了人脸图像范围后,才做的
    regression
  • 人脸上的重庆大学特征点,具有尤其强烈的总计学特征,所以 regression
    能够发挥效率
  • 在要求更高检测精度的场地中,其实也是用到了更扑朔迷离的网络模型来化解face alignment 难题的

YOLO && FCN

新生还尝试过用 YOLO 互联网做 Object Detection,用 FCN 网络做像素级的
Semantic Segmentation,不过结果都很不可以,比如:

  • 达不到文书档案检查和测试成效想要的精确度
  • 网络结构复杂,运算量大,在堂哥大上无法成功实时检查和测试

实惠的神经互连网算法

前边尝试的三种神经网络算法,都不可能取得想要的效果,后来换了一种思路,既然守旧的技术手段里含有了三个第二的手续,那能否用神经互连网来分别改革那七个步骤呢,经过分析发现,能够品味用神经互连网来替换
canny
算法,也等于用神经网络来对图像中的矩形区域展开边缘检查和测试,只要那一个边缘检查和测试可以去除越来越多的滋扰因素,那第3个步骤里面包车型客车算法也就足以变得更简单了。

神经互联网的输入和出口

lehu娱乐手机平台网站 4

根据那种思路,对于神经互连网部分,将来的需求变成了上海教室所示的指南。

HED(Holistically-Nested Edge Detection) 网络

边缘检测那种必要,在图像处理领域里面,平日号称 艾德ge Detection 或 Contour
Detection,依据那么些思路,找到了 Holistically-Nested 艾德ge Detection
网络模型。

HED 互连网模型是在 VGG16 网络布局的底子上统一筹划出来的,所以有需要先看看
VGG16。

lehu娱乐手机平台网站 5

上图是 VGG16 的法则图,为了有利于从 VGG16 过渡到 HED,我们先把 VGG16
变成上面那种示意图:

lehu娱乐手机平台网站 6

在地方那个示意图里,用分化的颜料区分了 VGG16 的两样组成都部队分。

lehu娱乐手机平台网站 7

从示意图上得以见见,黄绿代表的卷积层和革命表示的池化层,能够很鲜明的分开出五组,上航海用教室用群青线条框出来的就是内部的第2组。

lehu娱乐手机平台网站 8

HED 互联网要使用的正是 VGG16 互联网之中的那五组,前面部分的 fully connected
层和 softmax 层,都是不必要的,别的,第⑤组的池化层(金棕)也是不要求的。

lehu娱乐手机平台网站 9

去掉不需求的一部分后,就获得上图那样的网络布局,因为有池化层的功力,从第2组起来,每一组的输入
image 的长度宽度值,皆从前一组的输入 image 的长度宽度值的二分一。

lehu娱乐手机平台网站 10

HED 网络是一种多规格多融合(multi-scale and multi-level feature
learning)的网络布局,所谓的多规格,正是如上海教室所示,把 VGG16
的每一组的末段2个卷积层(黄褐部分)的输出取出来,因为每一组得到的 image
的长度宽度尺寸是不雷同的,所以那里还供给用转置卷积(transposed
convolution)/反卷积(deconv)对每一组得到的 image
再做1遍运算,从效益上看,也就是把第一至五组获得的 image
的长度宽度尺寸分别扩充 2 至 16 倍,那样在各种尺度(VGG16
的每一组就是1个尺度)上取得的 image,都以相同的尺寸了。

lehu娱乐手机平台网站 11

把每3个尺码上获得的平等大小的
image,再融合到共同,那样就获得了最终的出口
image,也正是兼备边缘检查和测试效果的 image。

依据 TensorFlow 编写的 HED 网络布局代码如下:

def hed_net(inputs, batch_size):
    # ref https://github.com/s9xie/hed/blob/master/examples/hed/train_val.prototxt
    with tf.variable_scope('hed', 'hed', [inputs]):
        with slim.arg_scope([slim.conv2d, slim.fully_connected],
                        activation_fn=tf.nn.relu,
                        weights_initializer=tf.truncated_normal_initializer(0.0, 0.01),
                        weights_regularizer=slim.l2_regularizer(0.0005)):
            # vgg16 conv && max_pool layers
            net = slim.repeat(inputs, 2, slim.conv2d, 12, [3, 3], scope='conv1')
            dsn1 = net
            net = slim.max_pool2d(net, [2, 2], scope='pool1')

            net = slim.repeat(net, 2, slim.conv2d, 24, [3, 3], scope='conv2')
            dsn2 = net
            net = slim.max_pool2d(net, [2, 2], scope='pool2')

            net = slim.repeat(net, 3, slim.conv2d, 48, [3, 3], scope='conv3')
            dsn3 = net
            net = slim.max_pool2d(net, [2, 2], scope='pool3')

            net = slim.repeat(net, 3, slim.conv2d, 96, [3, 3], scope='conv4')
            dsn4 = net
            net = slim.max_pool2d(net, [2, 2], scope='pool4')

            net = slim.repeat(net, 3, slim.conv2d, 192, [3, 3], scope='conv5')
            dsn5 = net
            # net = slim.max_pool2d(net, [2, 2], scope='pool5') # no need this pool layer

            # dsn layers
            dsn1 = slim.conv2d(dsn1, 1, [1, 1], scope='dsn1')
            # no need deconv for dsn1

            dsn2 = slim.conv2d(dsn2, 1, [1, 1], scope='dsn2')
            deconv_shape = tf.pack([batch_size, const.image_height, const.image_width, 1])
            dsn2 = deconv_mobile_version(dsn2, 2, deconv_shape) # deconv_mobile_version can work on mobile

            dsn3 = slim.conv2d(dsn3, 1, [1, 1], scope='dsn3')
            deconv_shape = tf.pack([batch_size, const.image_height, const.image_width, 1])
            dsn3 = deconv_mobile_version(dsn3, 4, deconv_shape)

            dsn4 = slim.conv2d(dsn4, 1, [1, 1], scope='dsn4')
            deconv_shape = tf.pack([batch_size, const.image_height, const.image_width, 1])
            dsn4 = deconv_mobile_version(dsn4, 8, deconv_shape)

            dsn5 = slim.conv2d(dsn5, 1, [1, 1], scope='dsn5')
            deconv_shape = tf.pack([batch_size, const.image_height, const.image_width, 1])
            dsn5 = deconv_mobile_version(dsn5, 16, deconv_shape)

            # dsn fuse
            dsn_fuse = tf.concat(3, [dsn1, dsn2, dsn3, dsn4, dsn5])
            dsn_fuse = tf.reshape(dsn_fuse, [batch_size, const.image_height, const.image_width, 5]) #without this, will get error: ValueError: Number of in_channels must be known.

            dsn_fuse = slim.conv2d(dsn_fuse, 1, [1, 1], scope='dsn_fuse')

    return dsn_fuse, dsn1, dsn2, dsn3, dsn4, dsn5

陶冶网络

cost 函数

舆论给出的 HED
互联网是二个通用的边缘检查和测试网络,遵照诗歌的叙述,每贰个规格上赢得的
image,都亟需加入 cost 的盘算,那有的的代码如下:

input_queue_for_train = tf.train.string_input_producer([FLAGS.csv_path])
image_tensor, annotation_tensor = input_image_pipeline(dataset_root_dir_string, input_queue_for_train, FLAGS.batch_size)

dsn_fuse, dsn1, dsn2, dsn3, dsn4, dsn5 = hed_net(image_tensor, FLAGS.batch_size)

cost = class_balanced_sigmoid_cross_entropy(dsn_fuse, annotation_tensor) + \
       class_balanced_sigmoid_cross_entropy(dsn1, annotation_tensor) + \
       class_balanced_sigmoid_cross_entropy(dsn2, annotation_tensor) + \
       class_balanced_sigmoid_cross_entropy(dsn3, annotation_tensor) + \
       class_balanced_sigmoid_cross_entropy(dsn4, annotation_tensor) + \
       class_balanced_sigmoid_cross_entropy(dsn5, annotation_tensor)

安分守己那种方式磨炼出来的互连网,检查和测试到的边缘线是有一点粗的,为了取得更细的边缘线,通过反复测验找到了一种优化方案,代码如下:

input_queue_for_train = tf.train.string_input_producer([FLAGS.csv_path])
image_tensor, annotation_tensor = input_image_pipeline(dataset_root_dir_string, input_queue_for_train, FLAGS.batch_size)

dsn_fuse, _, _, _, _, _ = hed_net(image_tensor, FLAGS.batch_size)

cost = class_balanced_sigmoid_cross_entropy(dsn_fuse, annotation_tensor)

也正是不再让种种尺度上获取的 image 都参预 cost
的测算,只行使融合后拿走的尾声 image 来展开计算。

三种 cost 函数的功力相比较如下图所示,左边是优化过后的效劳:

lehu娱乐手机平台网站 12

此外还有一些,遵照 HED 散文里的须要,总结 cost
的时候,无法利用大规模的方差 cost,而应该利用 cost-sensitive loss
function,代码如下:

def class_balanced_sigmoid_cross_entropy(logits, label, name='cross_entropy_loss'):
    """
    The class-balanced cross entropy loss,
    as in `Holistically-Nested Edge Detection
    <http://arxiv.org/abs/1504.06375>`_.
    This is more numerically stable than class_balanced_cross_entropy

    :param logits: size: the logits.
    :param label: size: the ground truth in {0,1}, of the same shape as logits.
    :returns: a scalar. class-balanced cross entropy loss
    """
    y = tf.cast(label, tf.float32)

    count_neg = tf.reduce_sum(1. - y) # the number of 0 in y
    count_pos = tf.reduce_sum(y) # the number of 1 in y (less than count_neg)
    beta = count_neg / (count_neg + count_pos)

    pos_weight = beta / (1 - beta)
    cost = tf.nn.weighted_cross_entropy_with_logits(logits, y, pos_weight)
    cost = tf.reduce_mean(cost * (1 - beta), name=name)

    return cost

转置卷积层的双线性开始化

在尝试 FCN 网络的时候,就被这么些题材卡住过非常长一段时间,遵照 FCN
的供给,在选取转置卷积(transposed
convolution)/反卷积(deconv)的时候,要把卷积核的值起始化成双线性放大矩阵(bilinear
upsampling
kernel),而不是常用的正态分布随机起始化,同时还要接纳相当小的学习率,那样才更易于让模型没有。

HED
的杂文中,并没有明了的渴求也要运用那种方法发轫化转置卷积层,可是,在磨炼进程中窥见,选取那种办法展开起初化,模型才更易于消失。

这一部分的代码如下:

def get_kernel_size(factor):
    """
    Find the kernel size given the desired factor of upsampling.
    """
    return 2 * factor - factor % 2


def upsample_filt(size):
    """
    Make a 2D bilinear kernel suitable for upsampling of the given (h, w) size.
    """
    factor = (size + 1) // 2
    if size % 2 == 1:
        center = factor - 1
    else:
        center = factor - 0.5
    og = np.ogrid[:size, :size]
    return (1 - abs(og[0] - center) / factor) * (1 - abs(og[1] - center) / factor)


def bilinear_upsample_weights(factor, number_of_classes):
    """
    Create weights matrix for transposed convolution with bilinear filter
    initialization.
    """
    filter_size = get_kernel_size(factor)

    weights = np.zeros((filter_size,
                        filter_size,
                        number_of_classes,
                        number_of_classes), dtype=np.float32)

    upsample_kernel = upsample_filt(filter_size)

    for i in xrange(number_of_classes):
        weights[:, :, i, i] = upsample_kernel

    return weights

教练进度冷运行

HED 互连网不像 VGG
互连网那样很简单就进入没有状态,也不太不难进入期望的完美图景,主若是两地点的原委:

  • 前边提到的转置卷积层的双线性初步化,正是3个生死攸关成分,因为在 陆个条件上,都急需反卷积,假诺反卷积层不可能没有,那全数 HED
    都不会跻身期望的好好状态
  • 其余多少个缘故,是由 HED
    的多规格引起的,既然是多规格了,那每种尺度上赢得的 image
    都应该对模型的末尾输出 image 发生贡献,在教练的进度中窥见,如若输入
    image 的尺码是 224*224,仍旧很简单就磨炼成功的,但是当把输入 image
    的尺寸调整为 256*256 后,很容易并发一种现象,就是 5 个尺码上获取的
    image,会有 1 ~ 2 个 image 是无用的(全体是金红)

为了化解那里遭遇的题材,采纳的方法就是先使用少量样本图片(比如 3000张)演练网络,在非常的短的陶冶时间(比如迭代 一千 次)内,假诺 HED
网络不可能彰显出收敛的来头,也许无法达到 5 个规格的 image
全体有效的情形,那就直接遗弃那轮的磨练结果,重新打开下一轮练习,直到知足截至,然后才使用完整的磨练样本集合继续陶冶网络。

教练数据集(多量合成数据 + 少量实打实数据)

HED
杂文里使用的教练数据集,是对准通用的边缘检查和测试目标的,什么形态的边缘都有,比如上边这种:

lehu娱乐手机平台网站 13

用那份数据训练出来的模型,在做文书档案扫描的时候,检查和测试出来的边缘效果并不优良,而且这份演习数据集的范本数量也相当的小,惟有一百多张图片(因为那种图片的人为标注费用太高了),那也会潜移默化模型的身分。

未来的急需里,要检测的是有所自然透视和旋转变换效果的矩形区域,所以可以大胆的猜想,尽管准备一批针对性更强的陶冶样本,应该是足以拿走更好的边缘检查和测试效果的。

依赖第②版技术方案征集回去的实际处境图片,大家付出了一套简单的标号工具,人工标注了
1200 张图片(标注那 1200 张图片的小运开支也很高),不过这 1200
多张图片如故有广大难点,比如对于神经网络来说,1200
个演习样本其实还是不够的,其它,这几个图片覆盖的气象其实也正如少,有个别图片的相似度相比较高,那样的数码放到神经互连网里练习,泛化的成效并不好。

于是,还使用技术手段,合成了80000多张陶冶样本图片。

lehu娱乐手机平台网站 14

如上海体育场合所示,一张背景图和一张前景图,能够合成出一对磨练样本数据。在合成图片的经过中,用到了上面那几个技能和技能:

  • 在前景图上添加旋转、平移、透视变换
  • 对背景图实行了随机的剪裁
  • 经过试验比较,生成合适宽度的边缘线
  • OpenCV
    不帮忙透明图层之间的团团转和透视变换操作,只可以选择最低精度的插值算法,为了改正这点,后续改成了选用iOS 模拟器,通过 CALayer 上的操作来合成图片
  • 在不断创新陶冶样本的长河中,还遵照真人真事样本图片的总计意况和种种途径的申报音信,刻意模仿了有的更扑朔迷离的范本场景,比如凌乱的背景环境、直线边缘困扰等等

由此持续的调整和优化,最后才练习出三个如意的模型,能够再次经过下边这张图纸中的第①列看一下神经互联网模型的边缘检查和测试效果:

lehu娱乐手机平台网站 15

在表哥大配备上运行 TensorFlow

lehu娱乐手机平台网站,在手机上行使 TensorFlow 库

TensorFlow 官方是永葆 iOS 和 Android
的,而且有明晰的文书档案,照着做就行。不过因为 TensorFlow 是借助于 protobuf
3
的,所以有恐怕会赶上一些任何的题材,比如上面那三种,就是大家在五个不等的
iOS APP 中碰到的难题和解决办法,能够用作三个参考:

  • A 产品应用的是 protobuf
    2,同时鉴于各样历史原因,使用并且停留在了很旧的某部版本的 Base
    库上,而 protobuf 3 的内部也使用了 Base 库,当 A 产品升级到 protobuf
    3 后,protobuf 3 的 Base 库和 A 源码中的 Base
    库发生了一部分出人意料的争辩,最终的化解办法是手动修改了 A 源码中的 Base
    库,防止编写翻译时的争执
  • B 产品也是使用的 protobuf 2,而且 B
    产品采取到的三个第贰方模块(没有源码,唯有二进制文件)也是依靠于
    protobuf 2,直接升级 B 产品应用的 protobuf
    库就没用了,最后动用的方式是修改 TensorFlow 和 TensorFlow 中选取的
    protobuf 3 的源代码,把 protobuf 3
    换了一个命名空间,那样八个不等版本的 protobuf 库就足以存活了

Android 上因为作者是足以接纳动态库的,所以固然 app 必须利用 protobuf 2
也绝非关联,分歧的模块使用 dlopen
的格局加载各自必要的一定版本的库就能够了。

在二弟大上行使练习取得的模型文件

模型常常都以在 PC 端演习的,对于多数使用者,都以用 Python
编写的代码,得到 ckpt
格式的模子文件。在行使模型文件的时候,一种做法正是用代码重新创设出全体的神经网络,然后加载这一个ckpt 格式的模型文件,固然是在 PC
上利用模型文件,用那么些法子其实也是可以接受的,复制粘贴一下 Python
代码就足以另行构建整个神经网络。可是,在手提式有线电话机上只好采取 TensorFlow 提供的
C++ 接口,假使照旧用同样的笔触,就须要用 C++ API
重新构建2回神经网络,那个工作量就有点大了,而且 C++ API 使用起来比
Python API 复杂的多,所以,在 PC 上磨练完互联网后,还必要把 ckpt
格式的模型文件转换到 pb 格式的模型文件,那么些 pb 格式的模子文件,是用
protobuf
系列化得到的二进制文件,里面包含了神经互联网的具体组织以及各类矩阵的数值,使用这个pb
文件的时候,不供给再用代码营造完全的神经网络结构,只必要反类别化一下就能够了,那样的话,用
C++ API 编写的代码就会简单很多,其实那也是 TensorFlow 推荐的施用格局,在
PC 上使用模型的时候,也应有利用这种 pb 文件(练习进程中动用 ckpt 文件)。

HED 网络在四弟大上赶上的奇怪 crash

在大哥伦比亚大学上加载 pb 模型文件同时运营的时候,碰着过2个诡异的失实,内容如下:

Invalid argument: No OpKernel was registered to support Op 'Mul' with these attrs.  Registered devices: [CPU], Registered kernels:
  device='CPU'; T in [DT_FLOAT]

     [[Node: hed/mul_1 = Mul[T=DT_INT32](hed/strided_slice_2, hed/mul_1/y)]]

故而离奇,是因为从字面上看,这么些荒唐的意思是贫乏乘法操作(Mul),然则小编用别样的神经网络模型做过相比,乘法操作模块是可以健康办事的。

谷歌 搜索后发觉众三人赶上过类似的情事,可是错误新闻又并差别,后来在
TensorFlow 的 github issues 里到底找到了头脑,综合起来解释,是因为
TensorFlow
是根据操作(Operation)来模块化设计和编码的,每2个数学计算模块正是3个Operation,由于各类原因,比如内部存款和储蓄器占用大小、GPU 独占操作等等,mobile 版的
TensorFlow,并没有包括全数的 Operation,mobile 版的 TensorFlow 协理的
Operation 只是 PC 完整版 TensorFlow
的四个子集,作者遇见的那个错误,正是因为使用到的某部 Operation 并不扶助mobile 版。

安分守纪这么些线索,在 Python
代码中每一个排查,后来稳定到了出标题标代码,修改前后的代码如下:

def deconv(inputs, upsample_factor):
    input_shape = tf.shape(inputs)

    # Calculate the ouput size of the upsampled tensor
    upsampled_shape = tf.pack([input_shape[0],
                               input_shape[1] * upsample_factor,
                               input_shape[2] * upsample_factor,
                               1])

    upsample_filter_np = bilinear_upsample_weights(upsample_factor, 1)
    upsample_filter_tensor = tf.constant(upsample_filter_np)

    # Perform the upsampling
    upsampled_inputs = tf.nn.conv2d_transpose(inputs, upsample_filter_tensor,
                                              output_shape=upsampled_shape,
                                              strides=[1, upsample_factor, upsample_factor, 1])

    return upsampled_inputs

def deconv_mobile_version(inputs, upsample_factor, upsampled_shape):
    upsample_filter_np = bilinear_upsample_weights(upsample_factor, 1)
    upsample_filter_tensor = tf.constant(upsample_filter_np)

    # Perform the upsampling
    upsampled_inputs = tf.nn.conv2d_transpose(inputs, upsample_filter_tensor,
                                              output_shape=upsampled_shape,
                                              strides=[1, upsample_factor, upsample_factor, 1])

    return upsampled_inputs

标题正是由 deconv 函数中的 tf.shape 和 tf.pack 那多少个操作引起的,在 PC
版代码中,为了简洁,是依照那三个操作,自动计算出
upsampled_shape,修改过后,则是必要调用者用 hard coding
的法子设置相应的 upsampled_shape。

裁剪 TensorFlow

TensorFlow
是二个很庞大的框架,对于手提式无线电话机来说,它占用的体积是相比较大的,所以需求尽或然的削减
TensorFlow 库占用的体积。

实质上在解决日前境遇的卓越 crash
问题的时候,已经指明了一种裁剪的笔触,既然 mobile 版的 TensorFlow
本来正是 PC
版的几个子集,那就表示能够依据现实的须要,让这几个子集变得更小,这也就高达了裁剪的目标。具体来说,便是修改
TensorFlow 源码中的
tensorflow/tensorflow/contrib/makefile/tf_op_files.txt
文件,只保留使用到了的模块。针对 HED 网络,原有的 200 多少个模块裁剪到只剩
46 个,裁剪过后的 tf_op_files.txt 文件如下:

tensorflow/core/kernels/xent_op.cc
tensorflow/core/kernels/where_op.cc
tensorflow/core/kernels/unpack_op.cc
tensorflow/core/kernels/transpose_op.cc
tensorflow/core/kernels/transpose_functor_cpu.cc
tensorflow/core/kernels/tensor_array_ops.cc
tensorflow/core/kernels/tensor_array.cc
tensorflow/core/kernels/split_op.cc
tensorflow/core/kernels/split_v_op.cc
tensorflow/core/kernels/split_lib_cpu.cc
tensorflow/core/kernels/shape_ops.cc
tensorflow/core/kernels/session_ops.cc
tensorflow/core/kernels/sendrecv_ops.cc
tensorflow/core/kernels/reverse_op.cc
tensorflow/core/kernels/reshape_op.cc
tensorflow/core/kernels/relu_op.cc
tensorflow/core/kernels/pooling_ops_common.cc
tensorflow/core/kernels/pack_op.cc
tensorflow/core/kernels/ops_util.cc
tensorflow/core/kernels/no_op.cc
tensorflow/core/kernels/maxpooling_op.cc
tensorflow/core/kernels/matmul_op.cc
tensorflow/core/kernels/immutable_constant_op.cc
tensorflow/core/kernels/identity_op.cc
tensorflow/core/kernels/gather_op.cc
tensorflow/core/kernels/gather_functor.cc
tensorflow/core/kernels/fill_functor.cc
tensorflow/core/kernels/dense_update_ops.cc
tensorflow/core/kernels/deep_conv2d.cc
tensorflow/core/kernels/xsmm_conv2d.cc
tensorflow/core/kernels/conv_ops_using_gemm.cc
tensorflow/core/kernels/conv_ops_fused.cc
tensorflow/core/kernels/conv_ops.cc
tensorflow/core/kernels/conv_grad_filter_ops.cc
tensorflow/core/kernels/conv_grad_input_ops.cc
tensorflow/core/kernels/conv_grad_ops.cc
tensorflow/core/kernels/constant_op.cc
tensorflow/core/kernels/concat_op.cc
tensorflow/core/kernels/concat_lib_cpu.cc
tensorflow/core/kernels/bias_op.cc
tensorflow/core/ops/sendrecv_ops.cc
tensorflow/core/ops/no_op.cc
tensorflow/core/ops/nn_ops.cc
tensorflow/core/ops/nn_grad.cc
tensorflow/core/ops/array_ops.cc
tensorflow/core/ops/array_grad.cc

急需强调的一些是,这种操作思路,是针对性分化的神经互联网结构有两样的剪裁格局,原则正是用到如何模块就保存什么模块。当然,因为有点模块之间还留存隐含的注重关系,所以裁剪的时候也是要再三品味数次才能不负众望的。

除却,还有上面这几个通用手段也足以兑现裁剪的指标:

  • 编写翻译器级别的 strip
    操作,在链接的时候会自动的把没有调用到的函数去除掉(集成开发条件里常见已经自行将那一个参数设置成了一级结合)
  • 凭借一些高等技术和工具,对二进制文件进行瘦身

借助全部那一个裁剪手段,末了大家的 ipa 安装包的大大小小只扩充了
3M。假如不做手动裁剪这一步,那 ipa 的增量,则是 30M 左右。

裁剪 HED 网络

依照 HED 散文给出的参阅音讯,获得的模型文件的大大小小是
56M,对于手提式有线电话机来说也是相比大的,而且模型越大也表示总计量越大,所以须要考虑能还是不能够把
HED 网络也裁剪一下。

HED 互连网是用 VGG16 作为基础互连网布局,而 VGG
又是3个获得大面积验证的根底互连网布局,由此修改 HED
的完好布局自然不是3个睿智的精选,至少不是首要选择的方案。

设想到今天的供给,只是检查和测试矩形区域的边缘,而并不是检查和测试通用场景下的广义的边缘,能够认为前者的复杂度比继任者更低,所以一种有效的思路,正是保留
HED 的完全布局,修改 VGG 每一组卷积层里面包车型大巴卷积核的数码,让 HED
网络变的更『瘦』。

依据那种思路,经过再三调整和品尝,最后获得了一组合适的卷积核的数额参数,对应的模子文件唯有4.2M,在 One plus 7P 上,处理每帧图片的年月开销是 0.1
秒左右,满足实时性的渴求。

神经网络的剪裁,近期在科学界也是三个很紧俏的园地,有某个种差别的辩驳来促成不一样指标的剪裁,不过,也并不是说各种互连网布局都有裁剪的空间,平常来说,应该结合真实意况,使用合适的技术手段,选用贰个正好大小的模子文件。

TensorFlow API 的选择

TensorFlow 的 API
是很灵活的,也比较底层,在求学进度中发觉,各种人写出来的代码,风格差距十分的大,而且许多工程师又选择了各式种种的技能来简化代码,可是那实在反而在无意又追加了代码的翻阅难度,也不便利代码的复用。

其三方社区和 TensorFlow
官方,都意识到了那个题材,所以更好的做法是,使用封装度更高但又保持灵活性的
API 来举行付出。本文中的代码,正是采纳 TensorFlow-Slim 编写的。

OpenCV 算法

虽说用神经网络技术,已经获得了八个比 canny
算法更好的边缘检查和测试效果,但是,神经互连网也并不是智勇兼资的,烦扰是照旧存在的,所以,第二个步骤中的数学模型算法,照旧是索要的,只可是因为第多个步骤中的边缘检查和测试有了小幅面立异,所以第一个步骤中的算法,获得了稳当的简化,而且算法全部的适应性也更强了。

那有的的算法如下图所示:

lehu娱乐手机平台网站 16

依据号码顺序,多少个关键步骤做了下边那个工作:

  1. 用 HED 互联网检查和测试边缘,能够观望,那里获得的边缘线仍旧存在有的惊动的
  2. 在前一步获得的图像上,使用 HoughLinesP 函数检查和测试线段(大青线段)
  3. 把前一步获得的线条延长成直线(棕黄直线)
  4. 在其次步中检查和测试到的线条,有部分是很相近的,大概有些短线段是可以一连成一条更长的线条的,所以能够选拔局地方针把它们统一到共同,那些时候,就要借助第一步中获取的直线。定义一种政策判断两条直线是或不是等于,当碰到相等的两条直线时,把那两条直线各自对应的线条再统一或三番五次成一条线条。这一步成功后,前面包车型大巴步调就只必要水晶色的线条而不供给中蓝的直线了
  5. 依据第⑤步获得的线条,总结它们中间的交叉点,临近的交叉点也得以统一,同时,把每个交叉点和产生那几个交叉点的线条也要提到在联合署名(每3个青白的点,都有一组淡金红的线条和它关系)
  6. 对此第六步获得的具备交叉点,每一回取出个中的 4 个,判断那 五个点构成的四边形是不是是3个合理的矩形(有透视变换效果的矩形),除了正规的判定政策,比如角度、边长的比值之外,还有3个论断标准正是每条边是不是能够和第伍步中获取的相应的点的关联线段重合,假诺不能够重合,则那些四边形就不太大概是我们期待检查和测试出来的矩形
  7. 经过第⑥步的过滤后,假使得到了多少个四边形,能够再选择三个粗略的过滤策略,比如排序找出周长或面积最大的矩形

对此地点这一个事例,第贰版技术方案中检查和测试出来的边缘线如下图所示:

lehu娱乐手机平台网站 17

有趣味的读者也能够考虑一下,在那种边缘图中,如何筹划算法才能找出我们目的在于的不得了矩形。

总结

算法角度

  • 神经网络的参数/超参数的调优,平时只可以依据经验来设置,有 magic trick
    的成分
  • 神经网络/机器学习是一门考试科学
  • 对此监督学习,数据的标号费用很高,这一步很简单现身瓶颈
  • 舆论、参考代码和自个儿的代码,这三者之间不完全一致也是例行情形
  • 对于一些要求,能够在模型的准确度、大小和平运动行速度之间找三个平衡点

工程角度

  • end-to-end 网络无效的时候,能够用 pipeline
    的思路设想难点、拆分业务,针对性的使用神经互连网技术
  • 起码要熟识精晓一种神经网络的支出框架,而且要追求代码的工程品质
  • 要控制神经互连网技术中的一些中坚套路,举一反三
  • 要在教育界和工产业界中间找平衡点,尽或者多的上学一些不等难点领域的神经网络模型,作为技术储备

参考文献

Hacker’s guide to Neural
Networks

神经互联网浅讲:从神经元到深度学习
分类与回归不一样是哪些?
神经互联网架构演进史:全面回看从LeNet5到ENet十余种架构

数据的娱乐:冰与火
为何“高大上”的算法工程师变成了多少民工?
推特(TWTR.US)人工智能理事Yann
LeCun谈深度学习的局限性

The best explanation of Convolutional Neural Networks on the
Internet!

从入门到了解:卷积神经互联网初学者指南
Transposed Convolution, Fractionally Strided Convolution or
Deconvolution

A technical report on convolution arithmetic in the context of deep
learning

Visualizing what ConvNets
learn

Visualizing Features from a Convolutional Neural
Network

Neural networks: which cost function to
use?

difference between tensorflow tf.nn.softmax and
tf.nn.softmax_cross_entropy_with_logits

Why You Should Use Cross-Entropy Error Instead Of Classification Error
Or Mean Squared Error For Neural Network Classifier
Training

Tensorflow 3
Ways

TensorFlow-Slim
TensorFlow-Slim image classification
library

Holistically-Nested Edge Detection
深度卷积神经互联网在指标检查和测试中的进展
全卷积网络:从图像级精通到像素级掌握
图像语义分割之FCN和CLANDF

Image Classification and Segmentation with Tensorflow and
TF-Slim

Upsampling and Image Segmentation with Tensorflow and
TF-Slim

Image Segmentation with Tensorflow using CNNs and Conditional Random
Fields

How to Build a Kick-Ass Mobile Document Scanner in Just 5
Minutes

MAKE DOCUMENT SCANNER USING PYTHON AND
OPENCV

Fast and Accurate Document Detection for
Scanning


越来越多美丽内容欢迎关心腾讯 Bugly的微信公众账号:

lehu娱乐手机平台网站 18

腾讯
Bugly
是一款专为移动开发者塑造的身分监督工具,帮助开发者火速,便捷的定位线上使用崩溃的意况以及解决方案。智能合并功能接济开发同学把每一日上报的数千条
Crash
依据根因合并分类,每一天早报会列出影响用户数最多的垮台,精准定位作用帮忙开发同学定位到出难题的代码行,实时举报能够在公告后快速的摸底应用的材料情形,适配最新的
iOS, Android 官方操作系统,鹅厂的工程师都在应用,快来参预大家吧!

You can leave a response, or trackback from your own site.

Leave a Reply

网站地图xml地图