田小默的博客

  • Home

  • Tags

  • Archives

  • About

DEEP COMPLEX NETWORKS(复数网络)

Posted on 2018-12-16 | Edited on 2018-12-25
  • 论文地址
  • 代码地址

各个基础组件

Complex Convolution (复数卷积)

Activation (激活)

BatchNormalization (批量标准化)

  1. 实数的批量标准化

$
x = \frac{x - E(x)}{x.std()}
$

  1. 复数Batch Normalization

如果分别对实部和虚部进行标准化会导致分布为一个圆形,可能是一个椭圆,但是将此看作一个白化2d矢量,每一部分将按方差平方根进行缩放。通过x-E(x),然后乘一个2 X 2的协方差矩阵完成。

$
x = \frac{x - E(x)}{\sqrt{V} }
$

  • E(x):x的均值
  • V = 协方差矩阵

$\boldsymbol { V } = \left( \begin{array} { c c } { V _ { r r } } & { V _ { r i } } \\ { V _ { i r } } & { V _ { i i } } \end{array} \right) = \left( \begin{array} { c c } { \operatorname { Cov } ( \Re { x } , \Re { x } ) } & { \operatorname { Cov } ( \Re { x } , \Im { x } ) } \\ { \operatorname { Cov } ( \Im { x } , \Re { x } ) } & { \operatorname { Cov } ( \Im { x } , \Im { x } ) } \end{array} \right)
$

  • Cov:协方差

根号V分之一的计算方法:

对于2*2矩阵A

$A = \left[ \begin{array} { l l } { a } & { b } \\ { c } & { d } \end{array} \right]$

1/A公式:

$\begin{aligned} \frac{1}{A} & = \frac { 1 } { | A | } \left[ \begin{array} { c c } { d } & { - b } \\ { - c } & { a } \end{array} \right] \\ & = \frac { 1 } { a d - b c } \left[ \begin{array} { c c } { d } & { - b } \\ { - c } & { a } \end{array} \right] \end{aligned}$

sqrt(A)公式:

$\sqrt{A} = \pm \frac { 1 } { \sqrt { \tau + 2 \delta } } \left( A + \delta I _ { 2 } \right) = \pm \frac { 1 } { \sqrt { \tau + 2 \delta } } \left[ \begin{array} { c c } { a + \delta } & { b } \\ { c } & { d + \delta } \end{array} \right]$

$\tau = \operatorname { trace } A = a + d$

$\delta = \pm \sqrt { \operatorname { det } A } = \pm \sqrt { a d - b c }$

所以,

$$\frac{1}{\sqrt(A)} = \frac{1}{\delta * \sqrt{\tau} - 2\delta}
\left[
\begin{array} { c c }
{ d + \delta } & { -b } \\
{ -c } & { a + \delta }
\end{array}
\right]$$

$$x=\frac{x-E(x)}
{\sqrt{V}} = \frac{1}
{ \delta * \sqrt { \tau } - 2 \delta }
\left[ \begin {array} { c c }
{ V _ { i i } + \delta } & { -V _ { ri } } \\
{ -V_{ ir } }&{ V_ { rr } + \delta }
\end{array}
\right]
(x-E(x))
$$

$$=\frac{1}
{\delta * \sqrt{\tau}-2\delta}
\left[\begin{array}{cc}
{V_{ii}+\delta}&{-V_{ri}}\\
{-V_{ir}}&{V_{rr}+\delta}
\end{array}\right] \left[\begin{array}{l}{x_{real}}\\{x_{image}}\end{array}\right]$$

参考:

Square root of a 2 by 2 matrix

Matrix Inverse

线代启示录

Initialization (初始化)

'SR超分辨率'

Posted on 2018-11-19 | Edited on 2018-12-24

超分辨率技术(Super Resolution,SR)是从观测到的低分辨率图像重建出相应的高分辨率图像。应用可以从两个方面看待,一是提升设备的测量精度,力求恢复真实可靠的细节部分,如医学图像上超分辨率重建,卫星图像重建和监控设备人脸重建等;二是追求整体的视觉效果,细节要求不高,如低分辨率视频恢复,模糊相片恢复等.

DL之前的SR

从信号处理角度看,低分辨率(Low Resolution)图像是无法恢复成高分辨率(High Resolution)图像,由香农采样定理可知,主要因为丢失了图像的高频信息。

1
香农采样定理,又称奈奎斯特采样定理,是信息论,特别是通讯与信号处理学科中的一个重要基本结论。1924年奈奎斯特(Nyquist)就推导出在理想低通信道的最高大码元传输速率的公式:理想低通信道的最高大码元传输速率=2W*log2N 。(其中W是理想低通信道的带宽,N是电平强度)

最简单的方法是梯度锐化和拉普拉斯锐化,但效果聊胜于无。

image

这里说两种典型的SR算法,左图,找到图片中相似的大尺寸区域,然后利用进行SR,下面这个动图就是这样,这种方法缺点很明显。

image

右图,对各种边缘信息建立数据库,然后匹配,这个方法也很明显,鲁棒性不够。

DL时代的SR

随着硬件计算性能的提升,人工智能进入了DL时代,SR也相应出现了新的使用DL的方法。

标准介绍

  • PSNR(Peak Signal to Noise Ratio,峰值信噪比)

$MSE=\frac{1}{H * W}\sum_{i=1}^h\sum_{j=1}^w(X(i,j)-Y(i,j))^2$

$PSNR=10log_{10}(\frac{(2^n-1)^2}{MSE})$

MSE表示当前图像X和参考图像Y的均方误差(Mean Square Error),H、W分别为图像的高度和宽度;n为每像素的比特数,一般取8,即像素灰阶数为256. PSNR的单位是dB,数值越大表示失真越小。虽然PSNR和人眼的视觉特性并不完全一致,但是一般认为PSNR在38以上的时候,人眼就无法区分两幅图片了。

SSIM(structural similarity, 结构相似性),也是一种全参考的图像质量评价指标,它分别从亮度、对比度、结构三方面度量图像相似性。

image

SRCNN

  • 论文,Learning a Deep Convolutional Network for Image Super-Resolution, ECCV2014
  • 代码

image

先使用双三次(bicubic)插值放大到目标大小,然后三层卷积做非线性映射,输出结果。三层卷积核大小分别为9*9,1*1,5*5,输出channel分别是64,32,3.

SC is outperforms the sparse-coding-based method,是[Image Super-Resolution via Sparse Representation](http://101.96.10.64/www.columbia.edu/~jw2966/papers/YWHM10-TIP.pdf)这篇论文是黄煦涛和马毅小组的Jianchao Yang的作品。这篇论文提出的算法,在形式上和后文这些DL算法已经非常类似了,也是基于HR和LR配对的有监督训练。区别只在于这篇论文使用矩阵的稀疏表示来拟合SR函数,而DL算法使用神经网络拟合SR函数。前者是线性变换,而后者是非线性变换。

FSRCNN

  • 论文 Accelerating the Super-Resolution Convolutional Neural Network,ECCV2016
  • 代码

image

SRCNN加速版本,主要改进有三点:

  1. 最后一层使用反卷积放大图片,不用bicubic
  2. 改变特征维数,使用更小的卷积核更多的卷积层
  3. 共享卷积层,放大不同的倍数只需改变反卷积层fine-tuning最后的反卷积层

FSPCN

  • 论文Real-Time Single Image and Video Super-Resolution Using an Efficient Sub-Pixel Convolutional Neural Network
  • 代码
  1. tensorflow版本
  2. pytorch版本
  3. caffe版本

image

也是基于SRCNN,和FSRCNN不同的是在最后层不是反卷积来放大,而是使用多个通道融合,R^2个channel,每个feature map和原图大小一样,然后在R^2个channel相同位置合并成一个R*R的子区域,这样放大为 H*R X H*R

image
image

VDSR

  • 论文Accurate Image Super-Resolution Using Very Deep Convolutional Networks
  • 代码
  1. code
  2. caffe
  3. tensorflow
  4. pytorch

作者认为输入的低分辨率图像和输出的高分辨率图像在很大程度上是相似的,也就是指低分辨率图像携带的低频信息与高分辨率图像的低频信息相近,训练时带上这部分会多花费大量的时间,实际上我们只需要学习高分辨率图像和低分辨率图像之间的高频部分残差即可。残差网络结构的思想特别适合用来解决超分辨率问题,可以说影响了之后的深度学习超分辨率方法。

image

改进个人认为有两点点:

  1. 使用了ResNet的残差结构,使得网络可以比较深(20层)
  2. 将不同倍数的图像放到一起训练,使得鲁棒性能比较好

文中使用了自适应梯度裁剪,使得训练收敛加快

image

image

看起来提升还是比较明显的,收敛速度提升也很明显

DRCN

  • 论文Deeply-Recursive Convolutional Network for Image Super-Resolution, CVPR2016
  • 代码
    1. code
    2. tensorflow

image

主要想法是RNN和Skip connection,原始图像插值输出后进入Embedding network,相当于提取特征,然后进入RNN,每一层都输出,最后合并输出。

image
可以看出Skip connection类似残差

RED

  • 论文Image Restoration Using Convolutional Auto-encoders with Symmetric Skip Connections, NIPS2016

image

分为encoder和decoder,感觉像Unet

DRRN

  • 论文Image Super-Resolution via Deep Recursive Residual Network, CVPR2017
  • 代码
    1. caffe
    2. pytorch

image
这个是结合了之前的结构,感觉好像 Unet…

LapSRN

  • 论文Deep Laplacian Pyramid Networks for Fast and Accurate Super-Resolution, CVPR2017
  • 代码
    1. matconvnet
    2. pytorch
    3. tensorflow

iamge

本文的主要思想是一点一点的放大,不要一口吃成个胖子,可能撑死,细嚼慢咽。细数前面的集中方法,无论先放大,还是最后放大,都存在一个问题,就是一步到位。具体作者提出存在的三个问题:

  1. 先上采样的存在计算开销浪费,反卷积和亚像素存在性能较差的问题
  2. 使用 l2 loss,导致预测模糊
  3. 一步到位的放大,对不同的放大倍数不能很好的适应

image

LapSRN通过逐步上采样,一级一级预测残差的方式,在做高倍上采样时,也能得到中间低倍上采样结果的输出。由于尺寸是逐步放大,不是所有的操作都在大尺寸特征上进行,因此速度比较快。LapSRN设计了损失函数来训练网络,对每一级的结果都进行监督,因此取得了不错的结果。

iamge
image

SRDenseNet

  • 论文Image Super-Resolution Using Dense Skip Connections, ICCV2017
  • 代码
    1. pytorch_1
    2. pytorch_2
    3. tensorflow

image

这个听名字看上图的模型可以看出来,这就是DenseNet版本的SR啊。作者在三种情况下做了对比,结果猜都可以猜出来

image

不同模型对比,不知道放大多少倍…

image

SRGAN

  • 论文[Photo-Realistic Single Image Super-Resolution Using a Generative Adversarial Network], CVPR2017
  • 代码
    1. tensorflow_1
    2. tensorflow_2
    3. tensorflow_3
    4. torch
    5. caffe
    6. keras
    7. pytorch

image

利用GAN做SR,一个生成网络,一个测试网络。只是这里的Loss有点不一样,作者说使用普通的均方差loss虽然峰值信噪比不错,但是感官上并不好,作者了其它的loss,感官效果提升,但是细节有些会丢失。

image

EDSR

  • 论文Enhanced Deep Residual Networks for Single Image Super-Resolution, CVPRW2017
  • 代码
    1. torch
    2. tensorflow
    3. pytorch

EDSR是NTIRE2017超分辨率挑战赛上获得冠军的方案。

image

作者认为在SR任务中使用Resnet结构的话,不需要使用BN层。作者文章中说,原始的ResNet最一开始是被提出来解决高层的计算机视觉问题,比如分类和检测,直接把ResNet的结构应用到像超分辨率这样的低层计算机视觉问题,显然不是最优的。去掉BN后,节省了内存资源。

  • EDSR

image

  • MDSR

image

image

DBSR

  • 论文Deep Back-Projection Networks For Super-Resolution,CVPR2018
  • 代码
    1. pytorch
    2. caffe

image

Winner (1st) of NTIRE2018 Competition (Track: x8 Bicubic Downsampling).从上图可以看出来是怎么搞得,不断的上采样,再卷积下采样,然后这样重复来回搞。想想参数应该不少。

作者把深度学习在超分辨率中分四种类型:

1)Predefined upsampling:这种方法通常是先在网络之外将原始的LR(Low Resolution)的图像通过插值法扩大到MR级别的图像,再将MR图像输入网络。这种方法是深度学习方法在超分辨率领域的开山之作SRCNN所采用的,SRCNN先将图像插值扩大,在通过三个简单的卷积层将其映射到HR图像上。之后使用同样方法的网络通常是通过残差结构(VDSR、DRCN)或者递归结构(DRCN)来获得更好的非线性映射的。然而,这种方法有一个问题,就是有可能在插值过程中向图像中加入新的噪声。

2)Single upsampling:FSRCNN和ESPCN都属于这个类型,输入他们的都是原始的LR图像,通过非线性映射之后,在网络的最后再重组成为HR图像(FSRCNN是反卷积,ESPCN是亚像素卷积层)。这种方法在实践中非常的快,但是因为网络容量有限,这两个网络都不能学习到太过复杂的映射。NTIRE2017的冠军EDSR也是这样的方法,但是因为其参数过多,需要过长的训练时间,所以为后续实现更少参数的网络留下了空间。

3)Progressive upsampling:代表就是LapSRN,这种方法在一个前向传播的网络中逐步的放大图像的分辨率,我们可以将其简化成为是几个stack在一起的升采样网络,因为这种方法仅仅依赖于有限的低分辨率信息,所以很轻易的就被深度较浅的DBPN打败了。

4)Iterative up and downsampling:也就是这篇文章所提出的方法,作者关注在不同的深度提高SR的采样率,并且将重建的损失分布到各个阶段去,这种方法通过学习多个升降采样算子来使得网络能在生成更深的特征的时候保留更多的HR信息。

作者称以前的方法没有充分的学习到图片中的信息,这样来回上采样下采样可以充分学习。

image

image

当让网络也用到了DenseNet的结构

image

image

看来参数量还好

image

image

image

看起来很厉害的样子

参考:

  1. 深度学习(二十一)——图像超分辨率, SRCNN, DRCN
  2. 从SRCNN到EDSR,总结深度学习端到端超分辨率方法发展历程
  3. NTIRE 2018 超分辨率 CVPR Workshop
  4. 如何评价CVPR2018论文Deep Back-Projection Networks For SR?
  5. 深度反向投影网络(DBPN)–通过Back-Projection来超分辨率的新方法

General_Language_Understanding_Evaluation_benchmark

Posted on 2018-11-14

parpe:glue

一个用于通用语言理解评估的基准,用来训练,预测和分析自然语言理解系统的资源整合

包括:

  • 基于现有数据集构建九个句子或句对语言理解任务的基准,并使用各种大小,不同难度,不同文本类型的数据集,

  • 一种诊断数据集,旨在评估和分析自然语言中发现的各种语言现象的模型性能

  • 用于跟踪基准测试性能的公共排行榜和用于可视化诊断集上模型性能

GLUE基准与模型无关,因此任何能够处理句子和句子对并产生相应预测的系统都有资格参与。选择基准测试任务以便使用参数共享或其他传输学习技术来支持跨任务共享信息的模型。GLUE的最终目标是推动研究开发通用和强大的自然语言理解系统。

11个任务

可以看到包括情感分析,语义分析,相似度评价,问答,文本识别等常见NLP任务

Leaderboard

看看排行榜,是不是好多熟悉身影,Bert稳居第一

Bert

Posted on 2018-11-14 | Edited on 2018-11-15

BERT is designed to pre-train deep bidirectional representations by jointly conditioning on both left and right context in all layers. As a result, the pre-trained BERT representations can be fine-tuned with just one additional output layer to create state-of-theart models for a wide range of tasks。

论文
代码

它在11项自然语言处理任务中获得了最新的最新成果,包括将GLUE基准推至80.4%(绝对改进率7.6%),MultiNLI精度达到86.7%(绝对改进5.6%)和SQuAD v1.1问题回答测试F1到93.2(1.5绝对改进),超过人类表现2.0。

GLUE(通用语言理解评价标准):80.4%

MultiNLI :86.7%

SQuAD:93.3%

原来将语言表示应用于下游任务有两种策略

  1. feature-base

    如 ELMO,用于下游任务时,使用特定的结构,加上与训练好的representation作为补充的特征

  2. fine-tuning

    如 GPT,用于下游任务通过fine_tuning模型

但是他们都是单向的…

作者认为这种单向的结构限制了模型的表示能力,虽然OpenAI GPT使用了left-to-right的结构,但只能在self-attention层之前的token.这种方法对于sentencelevel 的任务还好,对于token-level任务可能就不那么好了。

BERT,1.使用双向编码器,2.使用了 masked languge model(MLM),3.还有句子预测任务(next sentence prediction)

BERT\ELMO\GPT

一张图看出区别,可以看出只有BERT依赖于左右上下文

模型架构使用了tensor2tensor,有大小两种模型。

这里输入比较有想法,token embedding + segment embedding + position embedding,这样可以用在不同任务

与训练任务

  1. 完形填空(Masked)
  2. 下一句话预测

实验结果看[论文]

Hello World

Posted on 2018-11-11 | Edited on 2019-01-24

Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.

Quick Start

Create a new post

1
$ hexo new "My New Post"

More info: Writing

Run server

1
$ hexo server

More info: Server

Generate static files

1
$ hexo generate

More info: Generating

Deploy to remote sites

1
$ hexo deploy

More info: Deployment

linux查看系统信息

Posted on 2018-09-11 | Edited on 2018-11-11

linux系统常用查看系统信息命令

常用命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# uname -a # 查看内核/操作系统/CPU信息

# head -n 1 /etc/issue # 查看操作系统版本

# cat /proc/cpuinfo # 查看CPU信息

# hostname # 查看计算机名

# lspci -tv # 列出所有PCI设备

# lsusb -tv # 列出所有USB设备

# lsmod # 列出加载的内核模块

# env # 查看环境变量资源

# free -m # 查看内存使用量和交换区使用量

# df -h # 查看各分区使用情况

# du -sh <目录名> # 查看指定目录的大小

# grep MemTotal /proc/meminfo # 查看内存总量

# grep MemFree /proc/meminfo # 查看空闲内存量

# uptime # 查看系统运行时间、用户数、负载

# cat /proc/loadavg # 查看系统负载磁盘和分区

# mount | column -t # 查看挂接的分区状态

# fdisk -l # 查看所有分区

# swapon -s # 查看所有交换分区

# hdparm -i /dev/hda # 查看磁盘参数(仅适用于IDE设备)

# dmesg | grep IDE # 查看启动时IDE设备检测状况网络

# ifconfig # 查看所有网络接口的属性

# iptables -L # 查看防火墙设置

# route -n # 查看路由表

# netstat -lntp # 查看所有监听端口

# netstat -antp # 查看所有已经建立的连接

# netstat -s # 查看网络统计信息进程

# ps -ef # 查看所有进程

# top # 实时显示进程状态用户

# w # 查看活动用户

# id <用户名> # 查看指定用户信息

# last # 查看用户登录日志

# cut -d: -f1 /etc/passwd # 查看系统所有用户

# cut -d: -f1 /etc/group # 查看系统所有组

# crontab -l # 查看当前用户的计划任务服务

# chkconfig –list # 列出所有系统服务

# chkconfig –list | grep on # 列出所有启动的系统服务程序

# rpm -qa # 查看所有安装的软件包

系统

1
2
3
4
5
6
7
8
# uname -a # 查看内核/操作系统/CPU信息
# head -n 1 /etc/issue # 查看操作系统版本
# cat /proc/cpuinfo # 查看CPU信息
# hostname # 查看计算机名
# lspci -tv # 列出所有PCI设备
# lsusb -tv # 列出所有USB设备
# lsmod # 列出加载的内核模块
# env # 查看环境变量

资源

1
2
3
4
5
6
7
# free -m # 查看内存使用量和交换区使用量
# df -h # 查看各分区使用情况
# du -sh <目录名> # 查看指定目录的大小
# grep MemTotal /proc/meminfo # 查看内存总量
# grep MemFree /proc/meminfo # 查看空闲内存量
# uptime # 查看系统运行时间、用户数、负载
# cat /proc/loadavg # 查看系统负载

磁盘和分区

1
2
3
4
5
# mount | column -t # 查看挂接的分区状态
# fdisk -l # 查看所有分区
# swapon -s # 查看所有交换分区
# hdparm -i /dev/hda # 查看磁盘参数(仅适用于IDE设备)
# dmesg | grep IDE # 查看启动时IDE设备检测状况

网络

1
2
3
4
5
6
# ifconfig # 查看所有网络接口的属性
# iptables -L # 查看防火墙设置
# route -n # 查看路由表
# netstat -lntp # 查看所有监听端口
# netstat -antp # 查看所有已经建立的连接
# netstat -s # 查看网络统计信息

进程

1
2
# ps -ef # 查看所有进程
# top # 实时显示进程状态

用户

1
2
3
4
5
6
# w # 查看活动用户
# id <用户名> # 查看指定用户信息
# last # 查看用户登录日志
# cut -d: -f1 /etc/passwd # 查看系统所有用户
# cut -d: -f1 /etc/group # 查看系统所有组
# crontab -l # 查看当前用户的计划任务

服务

1
2
# chkconfig --list # 列出所有系统服务
# chkconfig --list | grep on # 列出所有启动的系统服务

程序

1
# rpm -qa # 查看所有安装的软件包

查看Linux内核版本命令(两种方法):

1
2
3
4
5
6
7
8
9
1、cat /proc/version
[root@localhost ~]# cat /proc/version
Linux version 2.6.18-194.8.1.el5.centos.plus
(mockbuild@builder17.centos.org) (gcc version 4.1.220080704
(Red Hat 4.1.2-48)) #1 SMP Wed Jul 7 11:50:45 EDT 2010
2、uname -a
[root@localhost ~]# uname -a
Linux localhost.localdomain 2.6.18-194.8.1.el5.centos.plus
#1 SMP Wed Jul 7 11:50:45 EDT 2010 i686 i686 i386 GNU/Linux

查看Linux系统版本的命令(3种方法):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1、lsb_release -a,即可列出所有版本信息:
[root@localhost ~]# lsb_release -a
LSB Version: :core-3.1-ia32:core-3.1-noarch:graphics-3.1-ia32:graphics-3.1-noarch
Distributor ID: CentOS
Description: CentOS release 6.5 (Final)
Release: 6.5
Codename: Final
这个命令适用于所有的Linux发行版,包括Redhat、SuSE、Debian…等发行版。
2、cat /etc/redhat-release,这种方法只适合Redhat系的Linux:
[root@localhost ~]# cat /etc/redhat-release
CentOS release 6.7 (Final)
3、cat /etc/issue,此命令也适用于所有的Linux发行版。
[root@localhost ~]# cat /etc/issue
CentOS release 6.7 (Final)
Kernel \r on an \m

CMake

Posted on 2018-09-04 | Edited on 2018-10-16

[TOC]

什么是 CMake

All problems in computer science can be solved by another level of indirection.

David Wheeler

你或许听过好几种 Make 工具,例如 GNU Make ,QT 的 qmake ,微软的 MS nmake,BSD Make(pmake),Makepp,等等。这些 Make 工具遵循着不同的规范和标准,所执行的 Makefile 格式也千差万别。这样就带来了一个严峻的问题:如果软件想跨平台,必须要保证能够在不同平台编译。而如果使用上面的 Make 工具,就得为每一种标准写一次 Makefile ,这将是一件让人抓狂的工作。

CMake就是针对上面问题所设计的工具:它首先允许开发者编写一种平台无关的==CMakeList.txt==文件来定制整个编译流程,然后再根据目标用户的平台进一步生成所需的本地化 Makefile 和工程文件,如 Unix 的 Makefile或Windows的Visual_Studio 工程。从而做到“Write once, run everywhere”。显然,CMake 是一个比上述几种 make 更高级的编译配置工具。一些使用 CMake 作为项目架构系统的知名开源项目有 VTK、ITK、KDE、OpenCV、OSG 等 [1]。

在 linux 平台下使用 CMake 生成 Makefile 并编译的流程如下:

  • 编写 CMake 配置文件 CMakeLists.txt 。
  • 执行命令 cmake PATH 或者 ccmake PATH 生成 Makefile 11ccmake 和 cmake 的区别在于前者提供了一个交互式的界面。 。其中, PATH 是 CMakeLists.txt 所在的目录。
  • 使用 make 命令进行编译

入门案例:单个源文件

对于简单的项目,只需要写几行代码就可以了。例如,假设现在我们的项目中只有一个源文件 main.cc ,该程序的用途是计算一个数的指数幂。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <stdio.h>
#include <stdlib.h>
/**
* power - Calculate the power of number.
* @param base: Base value.
* @param exponent: Exponent value.
*
* @return base raised to the power exponent.
*/
double power(double base, int exponent)
{
int result = base;
int i;

if (exponent == 0) {
return 1;
}

for(i = 1; i < exponent; ++i){
result = result * base;
}
return result;
}
int main(int argc, char *argv[])
{
if (argc < 3){
printf("Usage: %s base exponent \n", argv[0]);
return 1;
}
double base = atof(argv[1]);
int exponent = atoi(argv[2]);
double result = power(base, exponent);
printf("%g ^ %d is %g\n", base, exponent, result);
return 0;
}

编写 CMakeLists.txt

首先编写 CMakeLists.txt 文件,并保存在与 main.cc 源文件同个目录下:

1
2
3
4
5
6
# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)
# 项目信息
project (Demo1)
# 指定生成目标
add_executable(Demo main.cc)

CMakeLists.txt 的语法比较简单,由命令、注释和空格组成,其中命令是不区分大小写的。符号 # 后面的内容被认为是注释。命令由命令名称、小括号和参数组成,参数之间使用空格进行间隔。

对于上面的 CMakeLists.txt 文件,依次出现了几个命令:
cmake_minimum_required:指定运行此配置文件所需的 CMake 的最低版本;
project:参数值是 Demo1,该命令表示项目的名称是 Demo1 。
add_executable: 将名为 main.cc 的源文件编译成一个名称为 Demo 的可执行文件。
编译项目

之后,在当前目录执行 cmake . ,得到 Makefile 后再使用 make 命令编译得到 Demo1 可执行文件。

多个源文件

同一目录,多个源文件

上面的例子只有单个源文件。现在假如把 power 函数单独写进一个名为 MathFunctions.c 的源文件里,使得这个工程变成如下的形式:

1
2
3
4
5
6
7
./Demo2
|
+--- main.cc
|
+--- MathFunctions.cc
|
+--- MathFunctions.h

CMakeLists.txt

1
2
3
4
5
6
# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)
# 项目信息
project (Demo2)
# 指定生成目标
add_executable(Demo main.cc MathFunctions.cc)

更省事的方法是使用 aux_source_directory命令,该命令会查找指定目录下的所有源文件,然后将结果存进指定变量名。其语法如下:

1
aux_source_directory(<dir> <variable>)

可以修改 CMakeLists.txt 如下:

1
2
3
4
5
6
7
8
9
# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)
# 项目信息
project (Demo2)
# 查找当前目录下的所有源文件
# 并将名称保存到 DIR_SRCS 变量
aux_source_directory(. DIR_SRCS)
# 指定生成目标
add_executable(Demo ${DIR_SRCS})

这样,CMake 会将当前目录所有源文件的文件名赋值给变量 DIR_SRCS ,再指示变量 DIR_SRCS 中的源文件需要编译成一个名称为 Demo 的可执行文件。

多个目录,多个源文件

现在进一步将 MathFunctions.h 和 MathFunctions.cc 文件移动到 math 目录下。

1
2
3
4
5
6
7
8
9
./Demo3
|
+--- main.cc
|
+--- math/
|
+--- MathFunctions.cc
|
+--- MathFunctions.h

对于这种情况,需要分别在项目根目录 Demo3 和 math 目录里各编写一个 CMakeLists.txt 文件。为了方便,我们可以先将 math 目录里的文件编译成静态库再由 main 函数调用。

根目录中的 CMakeLists.txt :

1
2
3
4
5
6
7
8
9
10
11
12
13
# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)
# 项目信息
project (Demo3)
# 查找当前目录下的所有源文件
# 并将名称保存到 DIR_SRCS 变量
aux_source_directory(. DIR_SRCS)
# 添加 math 子目录
add_subdirectory(math)
# 指定生成目标
add_executable(Demo main.cc)
# 添加链接库
target_link_libraries(Demo MathFunctions)

该文件添加了下面的内容: 第3行,使用命令 add_subdirectory 指明本项目包含一个子目录 math,这样 math 目录下的 CMakeLists.txt 文件和源代码也会被处理 。第6行,使用命令 target_link_libraries 指明可执行文件 main 需要连接一个名为 MathFunctions 的链接库 。

子目录中的 CMakeLists.txt:

1
2
3
4
5
# 查找当前目录下的所有源文件
# 并将名称保存到 DIR_LIB_SRCS 变量
aux_source_directory(. DIR_LIB_SRCS)
# 生成链接库
add_library (MathFunctions ${DIR_LIB_SRCS})

在该文件中使用命令 add_library 将 src 目录中的源文件编译为静态链接库。

自定义编译选项

CMake 允许为项目增加编译选项,从而可以根据用户的环境和需求选择最合适的编译方案。

例如,可以将 MathFunctions 库设为一个可选的库,如果该选项为 ON ,就使用该库定义的数学函数来进行运算。否则就调用标准库中的数学函数库。

CMakeLists 文件

我们要做的第一步是在顶层的 CMakeLists.txt 文件中添加该选项:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)
# 项目信息
project (Demo4)
# 加入一个配置头文件,用于处理 CMake 对源码的设置
configure_file (
"${PROJECT_SOURCE_DIR}/config.h.in"
"${PROJECT_BINARY_DIR}/config.h"
)
# 是否使用自己的 MathFunctions 库
option (USE_MYMATH
"Use provided math implementation" ON)
# 是否加入 MathFunctions 库
if (USE_MYMATH)
include_directories ("${PROJECT_SOURCE_DIR}/math")
add_subdirectory (math)
set (EXTRA_LIBS ${EXTRA_LIBS} MathFunctions)
endif (USE_MYMATH)
# 查找当前目录下的所有源文件
# 并将名称保存到 DIR_SRCS 变量
aux_source_directory(. DIR_SRCS)
# 指定生成目标
add_executable(Demo ${DIR_SRCS})
target_link_libraries (Demo ${EXTRA_LIBS})

其中:
第7行的 configure_file 命令用于加入一个配置头文件 config.h ,这个文件由 CMake 从 config.h.in 生成,通过这样的机制,将可以通过预定义一些参数和变量来控制代码的生成。
第13行的 option 命令添加了一个 USE_MYMATH 选项,并且默认值为 ON 。
第17行根据 USE_MYMATH 变量的值来决定是否使用我们自己编写的 MathFunctions 库。
修改 main.cc 文件

之后修改 main.cc 文件,让其根据 USE_MYMATH 的预定义值来决定是否调用标准库还是 MathFunctions 库:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include 
#include
#include "config.h"
#ifdef USE_MYMATH
#include "math/MathFunctions.h"
#else
#include
#endif
int main(int argc, char *argv[])
{
if (argc < 3){
printf("Usage: %s base exponent \n", argv[0]);
return 1;
}
double base = atof(argv[1]);
int exponent = atoi(argv[2]);

#ifdef USE_MYMATH
printf("Now we use our own Math library. \n");
double result = power(base, exponent);
#else
printf("Now we use the standard library. \n");
double result = pow(base, exponent);
#endif
printf("%g ^ %d is %g\n", base, exponent, result);
return 0;
}

编写 config.h.in 文件

上面的程序值得注意的是第2行,这里引用了一个 config.h 文件,这个文件预定义了 USE_MYMATH 的值。但我们并不直接编写这个文件,为了方便从 CMakeLists.txt 中导入配置,我们编写一个 config.h.in 文件,内容如下:

1
#cmakedefine USE_MYMATH

这样 CMake 会自动根据 CMakeLists 配置文件中的设置自动生成 config.h 文件。

编译项目

现在编译一下这个项目,为了便于交互式的选择该变量的值,可以使用 ccmake 命令 22也可以使用 cmake -i 命令,该命令会提供一个会话式的交互式配置界面。 :

从中可以找到刚刚定义的 USE_MYMATH 选项,按键盘的方向键可以在不同的选项窗口间跳转,按下 enter 键可以修改该选项。修改完成后可以按下 c 选项完成配置,之后再按 g 键确认生成 Makefile 。ccmake 的其他操作可以参考窗口下方给出的指令提示。

我们可以试试分别将 USE_MYMATH 设为 ON 和 OFF 得到的结果:

USE_MYMATH 为 ON

运行结果:
12345 [ehome@xman Demo4]$ ./DemoNow we use our own MathFunctions library. 7 ^ 3 = 343.000000 10 ^ 5 = 100000.000000 2 ^ 10 = 1024.000000
此时 config.h 的内容为:
1 #define USE_MYMATH
USE_MYMATH 为 OFF

运行结果:
12345 [ehome@xman Demo4]$ ./DemoNow we use the standard library. 7 ^ 3 = 343.000000 10 ^ 5 = 100000.000000 2 ^ 10 = 1024.000000
此时 config.h 的内容为:
1 / #undef USE_MYMATH /

安装和测试

CMake 也可以指定安装规则,以及添加测试。这两个功能分别可以通过在产生 Makefile 后使用 make install 和 make test 来执行。在以前的 GNU Makefile 里,你可能需要为此编写 install 和 test 两个伪目标和相应的规则,但在 CMake 里,这样的工作同样只需要简单的调用几条命令。

定制安装规则

首先先在 math/CMakeLists.txt 文件里添加下面两行:

1
2
3
# 指定 MathFunctions 库的安装路径
install (TARGETS MathFunctions DESTINATION bin)
install (FILES MathFunctions.h DESTINATION include)

指明 MathFunctions 库的安装路径。之后同样修改根目录的 CMakeLists 文件,在末尾添加下面几行:

1
2
# 指定安装路径install (TARGETS Demo DESTINATION bin)
install (FILES "${PROJECT_BINARY_DIR}/config.h" DESTINATION include)

通过上面的定制,生成的 Demo 文件和 MathFunctions 函数库 libMathFunctions.o 文件将会被复制到 /usr/local/bin 中,而 MathFunctions.h 和生成的 config.h 文件则会被复制到 /usr/local/include 中。我们可以验证一下33顺带一提的是,这里的 /usr/local/ 是默认安装到的根目录,可以通过修改 CMAKE_INSTALL_PREFIX 变量的值来指定这些文件应该拷贝到哪个根目录。:

1
2
3
4
5
6
7
8
9
10
11
12
13
[ehome@xman Demo5]$ sudo make install
[ 50%] Built target MathFunctions
[100%] Built target Demo
Install the project...
-- Install configuration: ""
-- Installing: /usr/local/bin/Demo
-- Installing: /usr/local/include/config.h
-- Installing: /usr/local/bin/libMathFunctions.a
-- Up-to-date: /usr/local/include/MathFunctions.h
[ehome@xman Demo5]$ ls /usr/local/bin
Demo libMathFunctions.a
[ehome@xman Demo5]$ ls /usr/local/include
config.h MathFunctions.h

为工程添加测试

添加测试同样很简单。CMake 提供了一个称为 CTest 的测试工具。我们要做的只是在项目根目录的 CMakeLists 文件中调用一系列的 add_test 命令。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 启用测试
enable_testing()
# 测试程序是否成功运行
add_test (test_run Demo 5 2)
# 测试帮助信息是否可以正常提示
add_test (test_usage Demo)
set_tests_properties (test_usage
PROPERTIES PASS_REGULAR_EXPRESSION "Usage: .* base exponent")
# 测试 5 的平方
add_test (test_5_2 Demo 5 2)
set_tests_properties (test_5_2
PROPERTIES PASS_REGULAR_EXPRESSION "is 25")
# 测试 10 的 5 次方
add_test (test_10_5 Demo 10 5)
set_tests_properties (test_10_5
PROPERTIES PASS_REGULAR_EXPRESSION "is 100000")
# 测试 2 的 10 次方
add_test (test_2_10 Demo 2 10)
set_tests_properties (test_2_10
PROPERTIES PASS_REGULAR_EXPRESSION "is 1024")

用来测试输出是否包含后面跟着的字符串。

让我们看看测试的结果:
123456789101112131415 [ehome@xman Demo5]$ make testRunning tests…Test project /home/ehome/Documents/programming/C/power/Demo5 Start 1: test_run1/4 Test #1: test_run ……………………. Passed 0.00 sec Start 2: test_5_22/4 Test #2: test_5_2 ……………………. Passed 0.00 sec Start 3: test_10_53/4 Test #3: test_10_5 …………………… Passed 0.00 sec Start 4: test_2_104/4 Test #4: test_2_10 …………………… Passed 0.00 sec100% tests passed, 0 tests failed out of 4Total Test time (real) = 0.01 sec
如果要测试更多的输入数据,像上面那样一个个写测试用例未免太繁琐。这时可以通过编写宏来实现:
1234567891011 # 定义一个宏,用来简化测试工作macro (do_test arg1 arg2 result)add_test (test_${arg1}_${arg2} Demo ${arg1}${arg2})set_tests_properties (test_${arg1}_${arg2} PROPERTIES PASS_REGULAR_EXPRESSION ${result})endmacro (do_test)# 使用该宏进行一系列的数据测试do_test (52”is 25”)do_test (105”is 100000”)do_test (210”is 1024”)
关于 CTest 的更详细的用法可以通过 man 1 ctest 参考 CTest 的文档。

支持 gdb

让 CMake 支持 gdb 的设置也很容易,只需要指定 Debug 模式下开启 -g 选项:
123 set(CMAKE_BUILD_TYPE “Debug”)set(CMAKE_CXX_FLAGS_DEBUG “$ENV{CXXFLAGS} -O0 -Wall -g -ggdb”)set(CMAKE_CXX_FLAGS_RELEASE “$ENV{CXXFLAGS} -O3 -Wall”)
之后可以直接对生成的程序使用 gdb 来调试。

添加环境检查

本节对应的源代码所在目录:Demo6。

有时候可能要对系统环境做点检查,例如要使用一个平台相关的特性的时候。在这个例子中,我们检查系统是否自带 pow 函数。如果带有 pow 函数,就使用它;否则使用我们定义的 power 函数。

添加 CheckFunctionExists 宏

首先在顶层 CMakeLists 文件中添加 CheckFunctionExists.cmake 宏,并调用 check_function_exists 命令测试链接器是否能够在链接阶段找到 pow 函数。
123 # 检查系统是否支持 pow 函数include (${CMAKE_ROOT}/Modules/CheckFunctionExists.cmake)check_function_exists (pow HAVE_POW)
将上面这段代码放在 configure_file 命令前。

预定义相关宏变量

接下来修改 config.h.in 文件,预定义相关的宏变量。
12 // does the platform provide pow function?#cmakedefine HAVE_POW
在代码中使用宏和函数

最后一步是修改 main.cc ,在代码中使用宏和函数:
1234567 #ifdef HAVE_POW printf(“Now we use the standard library. \n”); double result = pow(base, exponent);#else printf(“Now we use our own Math library. \n”); double result = power(base, exponent);#endif

添加版本号

给项目添加和维护版本号是一个好习惯,这样有利于用户了解每个版本的维护情况,并及时了解当前所用的版本是否过时,或是否可能出现不兼容的情况。

首先修改顶层 CMakeLists 文件,在 project 命令之后加入如下两行:
12 set (Demo_VERSION_MAJOR 1)set (Demo_VERSION_MINOR 0)
分别指定当前的项目的主版本号和副版本号。

之后,为了在代码中获取版本信息,我们可以修改 config.h.in 文件,添加两个预定义变量:
123 // the configured options and settings for Tutorial#define Demo_VERSION_MAJOR @Demo_VERSION_MAJOR@#define Demo_VERSION_MINOR @Demo_VERSION_MINOR@
这样就可以直接在代码中打印版本信息了:
12345678910111213141516171819202122232425262728293031 #include #include #include #include “config.h”#include “math/MathFunctions.h”int main(int argc, char *argv[]){if (argc < 3){// print version infoprintf(“%s Version %d.%d\n”, argv[0], Demo_VERSION_MAJOR, Demo_VERSION_MINOR);printf(“Usage: %s base exponent \n”, argv[0]);return1; }double base = atof(argv[1]);int exponent = atoi(argv[2]);#if defined (HAVE_POW)printf(“Now we use the standard library. \n”);double result = pow(base, exponent);#elseprintf(“Now we use our own Math library. \n”);double result = power(base, exponent);#endifprintf(“%g ^ %d is %g\n”, base, exponent, result);return0;}

生成安装包

本节将学习如何配置生成各种平台上的安装包,包括二进制安装包和源码安装包。为了完成这个任务,我们需要用到 CPack ,它同样也是由 CMake 提供的一个工具,专门用于打包。

首先在顶层的 CMakeLists.txt 文件尾部添加下面几行:
1234567 # 构建一个 CPack 安装包include (InstallRequiredSystemLibraries)set (CPACK_RESOURCE_FILE_LICENSE “${CMAKE_CURRENT_SOURCE_DIR}/License.txt”)set (CPACK_PACKAGE_VERSION_MAJOR “${Demo_VERSION_MAJOR}”)set (CPACK_PACKAGE_VERSION_MINOR “${Demo_VERSION_MINOR}”)include (CPack)
上面的代码做了以下几个工作:
导入 InstallRequiredSystemLibraries 模块,以便之后导入 CPack 模块;
设置一些 CPack 相关变量,包括版权信息和版本信息,其中版本信息用了上一节定义的版本号;
导入 CPack 模块。
接下来的工作是像往常一样构建工程,并执行 cpack 命令。
生成二进制安装包:
1 cpack -C CPackConfig.cmake
生成源码安装包
1 cpack -C CPackSourceConfig.cmake
我们可以试一下。在生成项目后,执行 cpack -C CPackConfig.cmake 命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[ehome@xman Demo8]$ cpack -C CPackSourceConfig.cmake
CPack: Create package using STGZ
CPack: Install projects
CPack: - Run preinstall target for: Demo8
CPack: - Install project: Demo8
CPack: Create package
CPack: - package: /home/ehome/Documents/programming/C/power/Demo8/Demo8-1.0.1-Linux.sh generated.
CPack: Create package using TGZ
CPack: Install projects
CPack: - Run preinstall target for: Demo8
CPack: - Install project: Demo8
CPack: Create package
CPack: - package: /home/ehome/Documents/programming/C/power/Demo8/Demo8-1.0.1-Linux.tar.gz generated.
CPack: Create package using TZ
CPack: Install projects
CPack: - Run preinstall target for: Demo8
CPack: - Install project: Demo8
CPack: Create package
CPack: - package: /home/ehome/Documents/programming/C/power/Demo8/Demo8-1.0.1-Linux.tar.Z generated.

此时会在该目录下创建 3 个不同格式的二进制包文件:
12 [ehome@xman Demo8]$ ls Demo8-*Demo8-1.0.1-Linux.sh Demo8-1.0.1-Linux.tar.gz Demo8-1.0.1-Linux.tar.Z
这 3 个二进制包文件所包含的内容是完全相同的。我们可以执行其中一个。此时会出现一个由 CPack 自动生成的交互式安装界面:

完成后提示安装到了 Demo8-1.0.1-Linux 子目录中,我们可以进去执行该程序:
123 [ehome@xman Demo8]$ ./Demo8-1.0.1-Linux/bin/Demo 52Now we use our own Math library. 5 ^ 2 is 25
关于 CPack 的更详细的用法可以通过 man 1 cpack 参考 CPack 的文档。

将其他平台的项目迁移到 CMake

CMake 可以很轻松地构建出在适合各个平台执行的工程环境。而如果当前的工程环境不是 CMake ,而是基于某个特定的平台,是否可以迁移到 CMake 呢?答案是可能的。下面针对几个常用的平台,列出了它们对应的迁移方案。

autotools
am2cmake 可以将 autotools 系的项目转换到 CMake,这个工具的一个成功案例是 KDE 。
Alternative Automake2CMake 可以转换使用 automake 的 KDevelop 工程项目。
Converting autoconf tests
qmake
qmake converter 可以转换使用 QT 的 qmake 的工程。
Visual Studio
vcproj2cmake.rb 可以根据 Visual Studio 的工程文件(后缀名是 .vcproj 或 .vcxproj)生成 CMakeLists.txt 文件。
vcproj2cmake.ps1 vcproj2cmake 的 PowerShell 版本。
folders4cmake 根据 Visual Studio 项目文件生成相应的 “source_group” 信息,这些信息可以很方便的在 CMake 脚本中使用。支持 Visual Studio 9/10 工程文件。
CMakeLists.txt 自动推导
gencmake 根据现有文件推导 CMakeLists.txt 文件。
CMakeListGenerator 应用一套文件和目录分析创建出完整的 CMakeLists.txt 文件。仅支持 Win32 平台。

加入第三方库

CMake构建工程的时候很多程序可以使用写好的库,这就会涉及到库的编译链接过程。这里使用的提到的 Ubuntu下libxml2的安装和使用xml库作为讲解示例,如何安转运行请点击链接。

CMakeLists.txt文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
PROJECT(seglink)

# compiler flags
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 ${OpenMP_CXX_FLAGS} -Wall -fPIC -D_GLIBCXX_USE_CXX11_ABI=0")

# TensorFlow dependencies
EXECUTE_PROCESS(COMMAND python3 -c "import os; os.environ['TF_CPP_MIN_LOG_LEVEL']='3'; import tensorflow as tf; print(tf.sysconfig.get_include())"
OUTPUT_VARIABLE TF_INC)
MESSAGE(STATUS "Found TF_INC: " ${TF_INC})

#MESSAGE( STATUS "this var key = ${USER_KEY}.")
# boost

# target
INCLUDE_DIRECTORIES(${TF_INC})
ADD_LIBRARY(seglink SHARED
utilities.h
sample_crop_bbox_op.cc
encode_groundtruth_op.cc
decode_segments_links_op.cc
combine_segments_op.cc
detection_mask_op.cc
clip_rboxes_op.cc
polygons_to_rboxes_op.cc
project_polygons_op.cc)

编译错误信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
(dl) amax@amax36:~/HGH/seglink$ python ./manage.py build_op
[ 11%] Building CXX object CMakeFiles/seglink.dir/sample_crop_bbox_op.cc.o
[ 22%] Building CXX object CMakeFiles/seglink.dir/detection_mask_op.cc.o
[ 33%] Building CXX object CMakeFiles/seglink.dir/decode_segments_links_op.cc.o
[ 44%] Building CXX object CMakeFiles/seglink.dir/encode_groundtruth_op.cc.o
[ 55%] Building CXX object CMakeFiles/seglink.dir/combine_segments_op.cc.o
[ 66%] Building CXX object CMakeFiles/seglink.dir/project_polygons_op.cc.o
[ 77%] Building CXX object CMakeFiles/seglink.dir/clip_rboxes_op.cc.o
[ 88%] Building CXX object CMakeFiles/seglink.dir/polygons_to_rboxes_op.cc.o
In file included from /home/amax/anaconda3/envs/dl/lib/python3.6/site-packages/tensorflow/include/tensorflow/core/platform/mutex.h:31:0,
from /home/amax/anaconda3/envs/dl/lib/python3.6/site-packages/tensorflow/include/tensorflow/core/framework/variant.h:31,
from /home/amax/anaconda3/envs/dl/lib/python3.6/site-packages/tensorflow/include/tensorflow/core/framework/allocator.h:26,
from /home/amax/anaconda3/envs/dl/lib/python3.6/site-packages/tensorflow/include/tensorflow/core/framework/op_kernel.h:23,
from /home/amax/HGH/seglink/seglink/cpp/combine_segments_op.cc:10:
/home/amax/anaconda3/envs/dl/lib/python3.6/site-packages/tensorflow/include/tensorflow/core/platform/default/mutex.h:25:22: fatal error: nsync_cv.h: 没有那个文件或目录
compilation terminated.
CMakeFiles/seglink.dir/build.make:62: recipe for target 'CMakeFiles/seglink.dir/sample_crop_bbox_op.cc.o' failed
make[2]: *** [CMakeFiles/seglink.dir/sample_crop_bbox_op.cc.o] Error 1
CMakeFiles/Makefile2:67: recipe for target 'CMakeFiles/seglink.dir/all' failed
make[1]: *** [CMakeFiles/seglink.dir/all] Error 2
Makefile:83: recipe for target 'all' failed
make: *** [all] Error 2
cp: 无法获取'libseglink.so' 的文件状态(stat): 没有那个文件或目录
Building complete

找不到头文件,因此需要修改CMakeLists.txt让让编译系统找到头文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
PROJECT(seglink)

# compiler flags
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 ${OpenMP_CXX_FLAGS} -Wall -fPIC -D_GLIBCXX_USE_CXX11_ABI=0")

# TensorFlow dependencies
EXECUTE_PROCESS(COMMAND python3 -c "import os; os.environ['TF_CPP_MIN_LOG_LEVEL']='3'; import tensorflow as tf; print(tf.sysconfig.get_include())"
OUTPUT_VARIABLE TF_INC)
MESSAGE(STATUS "Found TF_INC: " ${TF_INC})

#MESSAGE( STATUS "this var key = ${USER_KEY}.")
# boost

include_directories(/home/amax/anaconda3/envs/dl/lib/python3.6/site-packages/tensorflow/include/external/nsync/public)

# target
INCLUDE_DIRECTORIES(${TF_INC})
ADD_LIBRARY(seglink SHARED
utilities.h
sample_crop_bbox_op.cc
encode_groundtruth_op.cc
decode_segments_links_op.cc
combine_segments_op.cc
detection_mask_op.cc
clip_rboxes_op.cc
polygons_to_rboxes_op.cc
project_polygons_op.cc)

修改称上面的样子再进行编译,成功。

cython-setup.py修改

Posted on 2018-09-04 | Edited on 2018-10-16

源码为linux系统的,在windows运行出现问题,找不到相关文件 bbox,查看

发现是由cython编写的,生成的文件为.so格式,在windows下自然用不了。

修改setup文件,生成windows文件.pyd。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#原文件
from Cython.Build import cythonize
import os
from os.path import join as pjoin
import numpy as np
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext

def find_in_path(name, path):
for dir in path.split(os.pathsep):
binpath = pjoin(dir, name)
if os.path.exists(binpath):
return os.path.abspath(binpath)
return None

def locate_cuda():
# first check if the CUDAHOME env variable is in use
if 'CUDAHOME' in os.environ:
home = os.environ['CUDAHOME']
nvcc = pjoin(home, 'bin', 'nvcc')
else:
# otherwise, search the PATH for NVCC
default_path = pjoin(os.sep, 'usr', 'local', 'cuda', 'bin')
nvcc = find_in_path('nvcc', os.environ['PATH'] + os.pathsep + default_path)
if nvcc is None:
raise EnvironmentError('The nvcc binary could not be '
'located in your $PATH. Either add it to your path, or set $CUDAHOME')
home = os.path.dirname(os.path.dirname(nvcc))

cudaconfig = {'home':home, 'nvcc':nvcc,
'include': pjoin(home, 'include'),
'lib64': pjoin(home, 'lib64')}
for k, v in cudaconfig.items():
#for k, v in cudaconfig.iteritems():
if not os.path.exists(v):
raise EnvironmentError('The CUDA %s path could not be located in %s' % (k, v))
return cudaconfig

CUDA = locate_cuda()


try:
numpy_include = np.get_include()
except AttributeError:
numpy_include = np.get_numpy_include()

def customize_compiler_for_nvcc(self):
self.src_extensions.append('.cu')
default_compiler_so = self.compiler_so
super = self._compile
def _compile(obj, src, ext, cc_args, extra_postargs, pp_opts):
print(extra_postargs)
if os.path.splitext(src)[1] == '.cu':
# use the cuda for .cu files
self.set_executable('compiler_so', CUDA['nvcc'])
# use only a subset of the extra_postargs, which are 1-1 translated
# from the extra_compile_args in the Extension class
postargs = extra_postargs['nvcc']
else:
postargs = extra_postargs['gcc']

super(obj, src, ext, cc_args, postargs, pp_opts)
# reset the default compiler_so, which we might have changed for cuda
self.compiler_so = default_compiler_so
# inject our redefined _compile method into the class
self._compile = _compile


# run the customize_compiler
class custom_build_ext(build_ext):
def build_extensions(self):
customize_compiler_for_nvcc(self.compiler)
build_ext.build_extensions(self)

ext_modules = [
Extension(
"utils.bbox",
["bbox.pyx"],
extra_compile_args={'gcc': ["-Wno-cpp", "-Wno-unused-function"]},
include_dirs = [numpy_include]
),
Extension(
"utils.cython_nms",
["cython_nms.pyx"],
extra_compile_args={'gcc': ["-Wno-cpp", "-Wno-unused-function"]},
include_dirs = [numpy_include]
),
]

setup(
ext_modules=ext_modules,
cmdclass={'build_ext': custom_build_ext},
)

直接运行

1
python .\setup_cpu.py build_ext --inplace

出现错误

1
2
3
File "setup_cpu.py", line 50, in customize_compiler_for_nvcc
default_compiler_so = self.compiler_so
AttributeError: 'MSVCCompiler' object has no attribute 'compiler_so'

这里自定义的编译器为linux的gcc,需要修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
from Cython.Build import cythonize
import os
from os.path import join as pjoin
import numpy as np
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext

def find_in_path(name, path):
for dir in path.split(os.pathsep):
binpath = pjoin(dir, name)
if os.path.exists(binpath):
return os.path.abspath(binpath)
return None


try:
numpy_include = np.get_include()
except AttributeError:
numpy_include = np.get_numpy_include()

# run the customize_compiler
class custom_build_ext(build_ext):
def build_extensions(self):
self.compiler.src_extensions.append('.cu')
self.compiler.set_executable('compiler_so', 'nvcc')
self.compiler.set_executable('linker_so', 'nvcc --shared')
if hasattr(self.compiler, '_c_extensions'):
self.compiler._c_extensions.append('.cu') # needed for Windows
self.compiler.spawn = self.spawn
build_ext.build_extensions(self)

ext_modules = [
Extension(
"utils.bbox",
["bbox.pyx"],
extra_compile_args=['-Wno-cpp', '-Wno-unused-function', '-std=c99'],
include_dirs = [numpy_include]
),
Extension(
"utils.cython_nms",
["cython_nms.pyx"],
extra_compile_args=['-Wno-cpp', '-Wno-unused-function', '-std=c99'],
include_dirs = [numpy_include]
),]

setup(
ext_modules=ext_modules,
cmdclass={'build_ext': custom_build_ext},
)

运行生成build和utile文件夹,将utile中的.pyd文件拷贝出来,删除两个文件夹

参考博客

cython源文件和编译

cython官方文档

文本检测识别算法

Posted on 2018-09-01 | Edited on 2019-01-13

[TOC]

CTPN(Connectionist Text Proposal Network)

  • 论文
  • 代码

idea

  • 文本检测和一般目标检测的不同——文本线是一个sequence(字符、字符的一部分、多字符组成的一个sequence),而不是一般目标检测中只有一个独立的目标。这既是优势,也是难点。优势体现在同一文本线上不同字符可以互相利用上下文,可以用sequence的方法比如RNN来表示。难点体现在要检测出一个完整的文本线,同一文本线上不同字符可能差异大,距离远,要作为一个整体检测出来难度比单个目标更大——因此,作者认为预测文本的竖直位置(文本bounding box的上下边界)比水平位置(文本bounding box的左右边界)更容易。

  • Top-down(先检测文本区域,再找出文本线)的文本检测方法比传统的bottom-up的检测方法(先检测字符,再串成文本线)更好。自底向上的方法的缺点在于(这点在作者的另一篇文章中说的更清楚),总结起来就是没有考虑上下文,不够鲁棒,系统需要太多子模块,太复杂且误差逐步积累,性能受限。

  • RNN和CNN的无缝结合可以提高检测精度。CNN用来提取深度特征,RNN用来序列的特征识别(2类),二者无缝结合,用在检测上性能更好。

pipeline

image

  1. VGG16的前5个conv stage(conv5_3)作为base net得到 feature map(W H C)
  2. 在Conv5的feature map的每个位置上取3 3 C的窗口的特征,这些特征将用于预测该位置k个anchor(anchor的定义和Faster RCNN类似)对应的类别信息,位置信息。这个特征向量将用来预测和10个anchor之间的偏移距离,也就是说每一个窗口中心都会预测出10个text propsoal。
  3. 将每一行的所有窗口对应的33C的特征(W33C)输入到RNN(BLSTM)中,得到W256的输出
  4. 将RNN的W*256输入到512维的fc层
  5. fc层特征输入到三个分类或者回归层中。第二个2k scores 表示的是k个anchor的类别信息(是字符或不是字符)。第一个2k vertical coordinate和第三个k side-refinement是用来回归k个anchor的位置信息。2k vertical coordinate表示的是bounding box的高度和中心的y轴坐标(可以决定上下边界),k个side-refinement表示的bounding box的水平平移量。这边注意,只用了3个参数表示回归的bounding box,因为这里默认了每个anchor的width是16,且不再变化(VGG16的conv5的stride是16)。回归出来的box如Fig.1中那些红色的细长矩形,它们的宽度是一定的。
  6. 用简单的文本线构造算法,把分类得到的文字的proposal(图Fig.1(b)中的细长的矩形)合并成文本线

细节

  • conv5的featuremap作为输入入,宽度恰好被固定为16个像素。只用来预测纵轴y即可。

image

c anchor中心,h anchor高度,a 是预测,*是实际,h是提议的高度

  • score阈值设置:0.7 (+NMS)
  • Recurrent Connectionist Text Proposals
    • RNN类型:BLSTM(双向LSTM),每个LSTM有128个隐含层
    • RNN输入:每个滑动窗口的33C的特征(可以拉成一列),同一行的窗口的特征形成一个序列
    • RNN输出:每个窗口对应256维特征
    • 使用RNN和不适用RNN的效果对比,CTPN是本文的方法(Connectionist Text Proposal Network)

总结

这篇文章的方法最大亮点在于把RNN引入检测问题(以前一般做识别)。文本检测,先用CNN得到深度特征,然后用固定宽度的anchor来检测text proposal(文本线的一部分),并把同一行anchor对应的特征串成序列,输入到RNN中,最后用全连接层来分类或回归,并将正确的text proposal进行合并成文本线。这种把RNN和CNN无缝结合的方法提高了检测精度。

翻译原文

参考——1

参考——2

EAST: An Efficient and Accurate Scene Text Detector

旷世科技 CVPR2017

  • 论文

image

1.分析目前存在的文本检测方法总结

  1. a– Reading Text in the Wild with Convolutional Neural Networks (15年vgg实验室提出,只能检测、识别水平文字)

    整个方法分为两部分,1.检测,使用Region Proposal mechanism检测数文字区域,然后使用Proposal Filtering(使用的是random forest方法)过滤文字候选框,最后进行一些合并调整得到Word boxes,这部分由于Bounding Box Regression不能完全覆盖文字,导致识别错误,所以又搞了个CNN网络来调整regression framework。2.识别,使用CNN一次识别出整个单词,与以往的单词分割识别再组合不同,这部分数据是人工生成的[方法1]

    参考文章
    论文

  2. b– Multi-Oriented Text Detection with Fully Convolutional Networks (2016CVPR 白翔大佬,检测多方向文字)

    具体方法是,将输入图片经过几层卷积得到salient map,然后使用MSER提取候选文字区域,接着候选字符提取出来,确定整个候选字符的方向,最后生成候选框

    参考文章
    论文

  3. c – Scene Text Detection via Holistic, Multi-Channel Prediction (arXiv2016 白翔大佬在Face++的)

    这个主要方法是从原图中获取三个mask,分别是文本行mask,字符mask和方向mask,然后使用这三个mask获取文本框。文本行mask数据集有,那字符和方向的mask是怎么得到的呢,通过swt得到字符mask,然后获取方向的mask.

    有三个mask怎么得到文本框的呢,可以是文本行mask得到一个文本框,使用字符框得到多个框再使用德劳内三角化,最后得到文本框。

    参考文章-1
    参考文章-2
    论文

  4. d – Detecting Text in Natural Image with Connectionist Text Proposal Network (Weilin Huang——ECCV2016)

    这个就是大名鼎鼎的CTPN啦

2.Pipeline 网络结构

image

分为三部分:feature extractor\feature-merging\output layer

  1. Feature extractor 特征提取

    使用PVNet提取图片特征,分别抽出1/4、1/8、1/16、1/32大小的feature map

  2. Feature merging 特征合并

    将上面提取的特征上采样合并,最后得到32channel的featuare

  3. Output layer 输出层

    分为两部分:score map和 RBOX or QUAD

    score map 是使用1*1的卷积核获取的。RBOX是带角度的Box,这个分为4个geomatry map和1个rotation angle。QUAD是四个坐标点,xy两轴,所以是8个。

3.Label generation

image

当输出4个Geomatry map和一个rototion map时,label怎么生成的呢。看上图,(a)中黄色虚线框是人工标注,绿色实现框是缩小0.3后的Label,文章说这样可以避免人工标注错误带来的误差;(b)就是score map label,白色表示文本区域,黑色表示背景;(c) 生成RBOX几何映射;(d)每个像素到矩形边界的距离有4个通道;(e)旋转角度.

4. Loss Function

$L = L _ { \mathrm { s } } + \lambda _ { \mathrm { g } } L _ { \mathrm { g } }$

Ls和Lg分别代表scoreh额geomatry的loss,λg代表权重,文章设为1

$L _ { \mathrm {s}}= - \beta \mathbf { Y } ^{}\log \hat { \mathbf { Y } } - ( 1 - \beta ) \left( 1 - \mathbf { Y } ^ { } \right) \log ( 1 - \hat { \mathbf { Y } } )$

Ls使用的是交叉熵

在Geomatry生成使用RBox和Quad时用不同的Loss function

RBox 的loss分为AABB和R两部分,Box AABB的loss是iou

$L _ { \mathrm { AABB } } = - \log \operatorname { IoU } \left( \hat { \mathbf { R } } , \mathbf { R } ^ { } \right) = - \log \frac { \left| \hat { \mathbf { R } } \cap \mathbf { R } ^ { } \right| } { \left| \hat { \mathbf { R } } \cup \mathbf { R } ^ { * } \right| }$

但是这里的iou是加了权重的,是加到各个边的距离的权重,角度loss使用cos 计算

$L _ { \theta } \left( \hat { \theta } , \theta ^ { } \right) = 1 - \cos \left( \hat { \theta } - \theta ^ { } \right)$

下面是RBox loss的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
def loss(y_true_cls, y_pred_cls,
y_true_geo, y_pred_geo,
training_mask):
'''
define the loss used for training, contraning two part,
the first part we use dice loss instead of weighted logloss,
the second part is the iou loss defined in the paper
:param y_true_cls: ground truth of text
:param y_pred_cls: prediction os text
:param y_true_geo: ground truth of geometry
:param y_pred_geo: prediction of geometry
:param training_mask: mask used in training, to ignore some text annotated by ###
:return:
'''
classification_loss = dice_coefficient(y_true_cls, y_pred_cls, training_mask)
# scale classification loss to match the iou loss part
classification_loss *= 0.01

# d1 -> top, d2->right, d3->bottom, d4->left
d1_gt, d2_gt, d3_gt, d4_gt, theta_gt = tf.split(value=y_true_geo, num_or_size_splits=5, axis=3)
d1_pred, d2_pred, d3_pred, d4_pred, theta_pred = tf.split(value=y_pred_geo, num_or_size_splits=5, axis=3)
area_gt = (d1_gt + d3_gt) * (d2_gt + d4_gt)
area_pred = (d1_pred + d3_pred) * (d2_pred + d4_pred)
w_union = tf.minimum(d2_gt, d2_pred) + tf.minimum(d4_gt, d4_pred)
h_union = tf.minimum(d1_gt, d1_pred) + tf.minimum(d3_gt, d3_pred)
area_intersect = w_union * h_union
area_union = area_gt + area_pred - area_intersect
L_AABB = -tf.log((area_intersect + 1.0)/(area_union + 1.0))
L_theta = 1 - tf.cos(theta_pred - theta_gt)
tf.summary.scalar('geometry_AABB', tf.reduce_mean(L_AABB * y_true_cls * training_mask))
tf.summary.scalar('geometry_theta', tf.reduce_mean(L_theta * y_true_cls * training_mask))
L_g = L_AABB + 20 * L_theta

return tf.reduce_mean(L_g * y_true_cls * training_mask) + classification_loss

Quad loss, ⚆_⚆ 没看懂怎么做的,也没有代码,这里仅贴个公式吧。

$L _ { \mathrm { g } } = L _ { \mathrm { QUAD } } \left( \hat { \mathbf { Q } } , \mathbf { Q } ^ { } \right) = \min _ { \mathbf { Q } \in P _ { Q ^ { } } } \sum _ { c _ { i } \in \mathbb { C } _ { \mathbf { Q } } } \frac { \operatorname { smoothed } _ { L 1 } \left( c _ { i } - \tilde { c } _ { i } \right) } { 8 \times N _ { \mathbf { Q } ^ { * } } }$

5. Locality-Aware NMS

locality_aware_nms在标准nms的基础上加了weighted_merge,所谓weighted_merge就是将2个IOU高于某个threshold的输出框,进行基于得分的合并。合并后的输出框的坐标数值介于2个合并的输入框之间,感觉这样操作可以将所有回归出的框的坐标信息都利用起来,有助于减少位置误差,而不是像传统的nms一样,直接取分数最高的那个。

参考文章_1

参考文章_2

参考文章_3

参考文章_4

AdvancedEAST

  • [代码](https://github.com/huoyijie/AdvancedEAST)

Seglink (Detecting Oriented Text in Natural Images by Linking Segments)

论文

代码

1. idea

  • 提出了文本行检测的两个基本组成元素:==segment==和==link==
  • 提出了基于SSD的改进版网络结构(全卷积网络结果)同时预测不同尺度的segments和link
  • 提出了两种link类型: 层内连接(within-layer link)和跨层连接(cross-layer link)
  • 可以处理多方向和任意长度的文本
  • Pipeline
  • 整个实现过程包括两部分:首先检测segments,links,然后使用融合算法得到最终文本行.具体步骤如下:

2. Pipeline

主干网络是沿用了SSD网络结构,并修改修改了最后的Pooling层,将其改为卷积层.

  • 首先用VGG16作为base net,并将VGG16的最后两个全连接层改成卷积层.
  • 接着增加一些额外的卷积层,用于提取更深的特征,最后的修改SSD的Pooling层,将其改为卷积层提取不同层的feature map,文中提取了conv4_3, conv7, conv8_2, conv9_2, conv10_2, conv11.这里其实操作还是和SSD网络一样,对不同层的featuremap使用3*3的卷积层产生最终的输出(包括segment和link),不同特征层输出的维度是不一样的,因为除了conv4_3层外,其它层存在跨层的link.这里segment是text的带方向bbox信息(它可能是个单词,也可能是几个字符,总之是文本行的部分),link是不同bbox的连接信息(文章将其也增加到网络中自动学习).
  • 然后通过融合规则,将segment的box信息和link信息进行融合,得到最终的文本行.

PixelLink

  • 论文
  • 代码

1. Abstract

基于语义分割的文本检测会有文本彼此接近导致它们很难分离.这篇文章使用将同一实例像素连接在一起进行分割。

以前的方法都至少包含两中分类:

  1. 文本\非文本分类(SegLink\EAST\TextBoxes)
  2. 位置回归 (SegLink\CTPN\EAST)

PixelLink受Seglink启发,分别预测文本、非文本和相邻8个像素的连接.

2. Network Architecture

image

PixelLink的架构。训练CNN模型以执行两种基于像素的预测:文本/非文本预测和链接预测。经过阈值处理后,通过正向链接将正像素连接在一起,实现实例分割。然后应用minAreaRect直接从分割结果中提取边界框。使用后置滤波可以有效地消除噪音预测。为了更好地说明输入样本。虚线框中的八个热图代表八个方向上的链接预测。虽然有些词在文本/非文本预测中难以分离,但它们可以通过链接预测分离。

2.1 PixelLink + VGG16 2s

image

PixelLink + VGG16 2s(2s表示预测图是原始图的一半)的结构。 fc6和fc7被提换成卷积层。上采样操作直接通过双线性插值完成。来自不同阶段的特征地图通过上采样和增加操作的级联进行融合。除pool5外的所有池层都采用2步幅,而pool5则采用1。因此,fc7的大小与conv5_3相同,因此合并时不需要上采样。conv 1x1,2(16) 代表具有2或16个内核的卷积层,分别用于文本/非文本预测或链接预测。

2.2 Linking Pixels Together

像素连接过程使用两个像素查看是否同时连接,这样才将它们看成一个连接组建。

2.3 Extraction of Bounding Box

使用miniAreaRect提取连接组建的最小外接矩形。这一步可以看出PixelLink和基于回归的方法之间的本质区别,即边界框直接从实例分割中获得,而不是位置回归。

2.4 Filter

使用边界框的几何特征进行过滤

3. Loss

$L = \lambda L _ { p i x e l } + L _ { l i n k }$

Lpixel 是像素分类Loss,Llink 是连接Loss。由于分任务更重要,λ设为2.

  • Pixel loss

    图片中文字的大小可能差异很大,这样对于那些小文字就不太友好。因此使用了一种新的损失函数,Balance Cross-Entropy(平衡交叉熵),就是为了让每个实例的权重相同。

    设第i个实例的面积为$S_i$ , 其上每个像素的权重为$w _ { i } = \frac { B _ { i } } { S _ { i } }$ ,$B_i$ 是实例平均像素数
    $B _ { i } = \frac { S } { N } , S = \sum _ { i } S _ { i } , \forall i \in { 1 , \ldots , N }$

    对于正负样本不平衡问题采用OHEM解决。最后的pixel loss,S实例总面积,r取3.
    $L _ { p i x e l } = \frac { 1 } { ( 1 + r ) S } W L _ { p i x e l _ { - } C E }$

  • Link loss

    正连接和负连接分别计算。
    $L_{link_{-} CE}$是链路预测的交叉熵损失矩阵。$W_{pos-link}$ 和 $W_{nge-link}$分别是正面和负面链接的权重。具体计算方法,对于像素 (i,j) 的第k个邻居:

    $\begin{aligned} L _ { l i n k _ { - } p o s } & = W _ { p o s - l i n k } L _ { l i n k _ { - } C E } \ L _ { l i n k _ { - } n e g } & = W _ { n e g _ { - } l i n k } L _ { l i n k _ { - } C E } \end{aligned}$

    $\begin{aligned} W _ { p o s - l i n k } ( i , j , k ) & = W ( i , j ) \left( Y _ { l i n k } ( i , j , k ) = = 1 \right) \ W _ { n e g _ { - } l i n k } ( i , j , k ) & = W ( i , j ) \left( Y _ { l i n k } ( i , j , k ) = = 0 \right) \end{aligned}$

4. Summary

  • 与CTPN,EAST,SegLink相比,PixelLink放弃了边框回归方法来检测文本行的bbox,而是采用实例分割方法,直接从分割的文本行区域得到文本行的bbox.PixelLink可以以更少额数据和更快地速度进行训练.
  • 假设提取特征的主干网络结构采用VGG16(当然你也可以采用其它主干网络结构),PixelLink不需要在imagenet预训练的模型上进行fine-tuned(即直接从头开始训练),而CTPN,EAST,SegLink都需要在imagenet预训练的模型上进行fine-tuned
  • 与CTPN,EAST,SegLink相比,PixelLink对感受野的要求更少,因为每个神经元值只负责预测自己及其邻域内的状态.
    与SegLink一样,不能检测很大的文本,这是因为link主要是用于连接相邻的segments,而不能用于检测相距较远的文本行

参考文章_1

参考文章_2

参考文章_3

Pixel-Anchor: A Fast Oriented Scene Text Detector with Combined Networks

论文

TextBoxes

  • 论文
  • 代码

1. Abstract

TextBoxes的灵感来源于SSD,SSD旨在检测图像中的一般物体,但无法识别具有极高宽高比的字。在TextBoxes中提出了文本框图层来解决这个问题.

2. Architecture

image

TextBoxes架构TextBoxes是一个28层完全卷积网络。其中13个是从VGG-16继承的。在VGG-16层之后增加了9个额外的卷积层。文本框图层连接到6个卷积图层。在每个Map上,文本框图层预测72个向量,它们是12个默认框的分数(2-d)和偏移量(4-d)。对所有文本框图层的聚合输出应用非最大抑制。

  • 文本框层

    假设图像和特征图大小分别是Xim\Yim)和Xmap\Ymap)。在feature map位置(i,j)一个默认框$\mathbf { b } _ { 0 } = \left( x _ { 0 } , y _ { 0 } , w _ { 0 } , h _ { 0 } \right)$,文本框输出层预测输出$( \Delta x , \Delta y , \Delta w , \Delta h , c )$,对应在原图上$\mathbf { b } = ( x , y , w , h )$

    $\begin{aligned} x & = x _ { 0 } + w _ { 0 } \Delta x \ y & = y _ { 0 } + h _ { 0 } \Delta y \ w & = w _ { 0 } \exp ( \Delta w ) \ h & = h _ { 0 } \exp ( \Delta h ) \end{aligned}$

与一般物体不同,单词文本倾向于具有较大的宽高比。因此,使用包含具有较大宽高比的“长”默认框。具体而言,我们为默认box定义6种纵横比,包括1,2,3,5,7和10。但是,这会使默认框在水平方向密集而垂直稀疏,这会导致较差的匹配框。为了解决这个问题,每个默认框都设置了垂直偏移。

image

而且,在文本框图层中,采用不规则的1 5卷积滤波器而不是标准的3 3卷积滤波器。这种初始式滤波器可以产生矩形的接收区域,它可以更好地融合具有较大纵横比的字,还可以避免方形接收区带来的噪声信号。

3.Loss

$L ( x , c , l , g ) = \frac { 1 } { N } \left( L _ { \mathrm { conf } } ( x , c ) + \alpha L _ { \mathrm { loc } } ( x , l , g ) \right)$

分为位置loss和置信度loss的加权和

参考文章_1

参考文章_2

参考文章_3

TextBoxes++

  • 论文
  • 代码

TextSpotter

SPCNet

FOST

  • 论文
  • 代码没放出来,github上别人实现的都没有识别分支(*  ̄ー ̄),这给EAST有什么区别,你们实现了什么啊

image

看到没就是快

image

https://zhuanlan.zhihu.com/p/38655369
https://www.cnblogs.com/skyfsm/p/9776611.html
https://zhuanlan.zhihu.com/p/39796620

命名空间

Posted on 2018-08-28 | Edited on 2018-10-16

为什么存在命名空间

随着项目的增大,名称相互冲突的可能性也再增加,不同成员、不同厂商的命名可能出现冲突,不兼容等问题。为了解决这种冲突,命名空间出现了。

默认存在命名空间

声明区域(declaration region)

可以在其中声明的区域

  • 全局声明:在函数外部声明
  • 局部声明:在函数内部声明

    潜在作用区域

    从声明点开始 –> 声明区域末尾


自定义的命名空间

自定义命名空间,提供一个声明名称的区域,一个命名空间中的名称不会与另一个命名空间中的名称冲突,同时其他部分可以使用命名空间中的东西。关键字:namespace

using 声明 v.s using 编译指令

先留个坑,慢慢填

1234
田小默

田小默

33 posts
21 tags
GitHub Weibo Zhihu
© 2019 田小默
Powered by Hexo v3.8.0
|
Theme – NexT.Pisces v6.6.0
总访问量次 | 总访客人 |