levelDB 学习笔记

大三的时候看过一点levelDB的源码,不过没有怎么用过。

最近有个需求是存人脸的feature到硬盘,似乎使用levelDB比较合适,因此来学习一下使用。

levelDB简介

Leveldb是google开源的一个高效率的K/V数据库.有如下特点:

  1. 首先,LevelDb是一个持久化存储的KV系统,和Redis这种内存型的KV系统不同,LevelDb不会像Redis一样狂吃内存,而是将大部分数据存储到磁盘上。
  2. 其次,LevleDb在存储数据时,是根据记录的key值有序存储的,就是说相邻的key值在存储文件中是依次顺序存储的,而应用可以自定义key大小比较函数,LevleDb会按照用户定义的比较函数依序存储这些记录。
  3. 再次,像大多数KV系统一样,LevelDb的操作接口很简单,基本操作包括写记录,读记录以及删除记录。也支持针对多条操作的原子批量操作。
  4. 另外,LevelDb支持数据快照(snapshot)功能,使得读取操作不受写操作影响,可以在读操作过程中始终看到一致的数据。
  5. 除此外,LevelDb还支持数据压缩等操作,这对于减小存储空间以及增快IO效率都有直接的帮助。
  6. LevelDb性能非常突出,官方网站报道其随机写性能达到40万条记录每秒,而随机读性能达到6万条记录每秒。总体来说,LevelDb的写操作要大大快于读操作,而顺序读写操作则大大快于随机读写操作。

LevelDB的安装

以ubuntu14.04为例,但实际上除了路径可能不同,其他部分是系统无关的。

leveldb_github地址

然后记得切换到指定tag

可以使用git tag命令得到,然后用git checkout命令切换,我这里使用的是1.20版本

之后直接执行make

之后将头文件拷贝到系统路径下:

编译之后分别会得到out-shared和out-static两个文件夹,分别是动态库和静态库

我们进入out-shared文件夹,讲libleveldb.so*的三个文件(有两个是链接)拷贝到/usr/lib下

然后用sudo ldconfig 命令将动态库加到缓存中。

我们用如下代码测试一下:

编译选项为:

g++ mytest.cc -o mytest -lpthread -lleveldb

如果运行得到jason,表示安装成功。

 

LevelDB的使用

一些基本操作可以参考github文档

不过发现levelDB的接口似乎只支持key和value都是string类型。。

然而对于人脸提取feature,实际上需要的是string映射到float**

偶然发现caffe中使用了levelDB

该代码 如下:

发现它的做法是使用google的protobuf,将数据序列化成string,再存入数据库。

 

 

 

caffe2 添加自定义op

记录一些一个没有之前没有接触过caffe/caffe2的人为了添加自定义的op 到caffe2需要做的工作.

首先参考caffe2 tutorial,随便跑个op来试试,不妨以比较简单的  Accumulate_op 为例子.

这个op的作用就是计算Y=X+gamma*Y, 其中X为输入,Y为输出,gamma是参数.

跑起来这个运算所需要的代码如下:

c之后我们仿照caffe2/operators/accumultate_op.h和affe2/operators/accumultate_op.cc,仿写一个我们自己的运算atest_op.h和atest_op.cc

实现的功能为Y=5*X+gamma*Y

之后我们编译整个caffe2,编译方式是运行pytorch/scripts/build_local.sh

编译成功后,需要将pytorch目录添加到PYTHONPATH中

然后运行

看是否成功

编译的时候可能出现mpi_test.cc.o: undefined reference to symbol ‘_ZN3MPI8Datatype4FreeEv  的报错。。解决办法是把CMakeList中的MPI关掉就好了。。。

以及。。。operators中的文件都不要删。。。本想删一些不相关的op来减少编译时间。。。想法是对的。。。但是似乎只删op是行不通的。。。。不如不删。。。不然会编译出现奇怪的错误!

不然会编译出现奇怪的错误!

不然会编译出现奇怪的错误!

以及。。。从github download的速度太慢了。。。干脆开了个40$/m的vps来搞。。。

编译成功后修改测试的python代码,来测试一下我们定义的op

发现确实是得到了Y=5*X+gamma*Y 的结果。。

撒花!(然而这只是最近要做的任务中最容易的一条线orz…

需要注意的是,运行bash build_local.sh脚本之后会在pytorch目录下生成build文件夹,下次编译的时候直接在build目录下执行make -j20,这样才是增量编译

编译的时候直接在build目录下执行make -j20,这样才是增量编译

编译的时候直接在build目录下执行make -j20,这样才是增量编译

不然每次执行build_local.sh…不知caffe2用了什么机制…每次要把所有文件编译一遍…简直没有人性啊…16个cpu一起编也要5分钟Orz

以及...要在自己定义的函数最后返回true…这样在运行的时候才不会报错.否则会报net error 的错误Orz….我好傻啊?

 

 

Eigen: C++开源矩阵学习笔记

接触Eigen的原因是最近在看caffe/caffe2源码,caffe2中使用了Eigen库. Eigen 是一个基于C++模板的线性代数库,直接将库下载后放在项目目录下,然后包含头文件就能使用,非常方便。对于Linux用户,只需要把头文件放到/usr/include 下即可此外,Eigen的接口清晰,稳定高效。

之后会更新一些,Eigen中我使用过的函数.

ubuntu14.04LTS 下使用方式:

然后尝试运行如下代码,直接编译即可.如果可以正常运行,表明安装完毕.

map的使用办法:

double arr[9]={1,2,3,4,5,6,7,8,9};
Map<MatrixXd> A(arr,3,3);
得到
1 4 7
2 5 8
3 6 9

以看出默认是按列优先的…
如果需要按行优先,可以修改矩阵的定义方式:
typedef Matrix<double, Dynamic, Dynamic,RowMajor>rMatrixXd;//定义矩阵行优先
double arr[9]={1,2,3,4,5,6,7,8,9};
Map A(arr,3,3);

map使用的时候,只需要指定map<>中,缺少(dynamic)的维度.
比如

得到结果

1
2
3
4

平均值

对于矩阵:

1 4 7
2 5 8
3 6 9

按行求平均值A.rowwise().mean()

得到:

4
5
6

按列求平均值 A.colwise().mean
得到
2 5 8

unaryExpr()

参数为一元函数算子,表示对每一项应用该一元算子.具体看例子

返回的结果为:
1 16 49
4 25 64
9 36 81

 

replicate

将一个对象重复多干次.

语法为A.replicate(x,y)表示将A横向扩展x次(包含本身),纵向扩展y次(包含本身),共得到x*y个

 

linux/win双系统 更新win后 grub 出现 Error: unknown filesystem 的解决办法

windows自己更新把grub更新挂了….

更新的时候要重启几次,重启一次挂一次…

讲真,windows(或者说win10?) 是我见过的最辣鸡的OS了…  自己把自己弄挂这事不是一两次了.

下面说修复办法:

先ls,得到一堆诸如(hd0,gpt7) 这种

然后选设X=第一个(x,y)形式的输出

之后

[/crayon]

然后记得要进入linux分区…..
执行:
sudo update-grub
sudo grub-install /dev/sda

总结:珍爱生命,远离辣鸡windows!!!!!

珍爱生命,远离辣鸡windows!!!!!

珍爱生命,远离辣鸡windows!!!!!

cmake 学习笔记

前置技能点:

gnu make

linux下.so,.a,.o文件

cmake是一个工具,也可以看成一门语言。

学习cmake最大的障碍在于看不懂全是大写的英文

学习cmake主要参考了《cmake practice》

不过感觉作者有些啰嗦…不重要的东西讲了半天,重要的东西却一带而过。。。表述得也不是特别流畅。。。但是还是感谢作者的分享吧orz…

继续阅读“cmake 学习笔记”

linux 下 .o 文件, .a文件,.so文件

发现我对工程一无所知QAQ

参考资料:

LibraryArchives-StaticAndDynamic

简单得说就是:A  .a file is a static library, while a .so file is a shared object (dynamic) library similar to a DLL on Windows.

至于.o文件,其实就相当于win下的obj文件。至于win下的obj文件,其实就是因为编译没办法一次编译所有文件得到.exe文件,所以生成了中间的文件,就是.obj文件。

生成静态库还是动态库是开发者可以选择的,不过需要遵循一些原则。

静态库的好处是,把程序给用户之后,不需要再给额外的库就可以直接运行了。

但是程序会比较臃肿。

 

非极大值抑制(Non-Maximum Suppression,NMS)

 

NMS是为了在诸多CV任务如边缘检测,目标检测等,找到局部最大值

其主要思想是先设定一个阈值,然后计算检测框的IOU(所谓IOU,也就是intersection-over-union,指的是相交面积除以相并面积,是来衡量overlap程度的指数)。如果IOU大于阈值,说明overlap过大,我们要通过某种算法来将其剔除。

比如下图,在经典的人脸识别任务中,出现了多个检测框,每个检测框有一个置信度confidence,我们通过某个算法,保留一个最好的。

 

 

顺便说一下算法的实现步骤把,其实不太重要。就是贪心。

其基本操作流程如下:

  • 首先,计算每一个 bounding box 的面积:
    • (x1, y1) ⇒ 左上点的坐标,(x2, y2) ⇒ 右下点的坐标;
    • (x2-x1+1)x(y2-y1+1)
  • 根据 scores 进行排序(一般从小到大),将 score 最大的bounding box置于队列,接下来计算其余 bounding box 与当前 score 最大的 bounding box 的 IoU,抑制(忽略也即去除)IoU大于设定阈值的 bounding box;
  • 重复以上过程,直至候选 bounding boxes 为空;

 

最后上一段python代码吧…也很简单,直接转载了别人的…

 

参考链接

目标窗口检测算法-NMS非极大值抑制

mysql 出现 innoDB: Cannot allocate memory for the buffer pool 的解决办法

emmm,博客的数据库又挂了。

看了下log,发现innoDB: Cannot allocate memory for the buffer pool 的error

查了下,貌似是内存不够了? orz

用free 命令看了下,阿里云ecs貌似是默认没有swap分区的。

于是参考云服务器 ECS Linux SWAP 配置概要说明 

设置了swap分区。看下还会不会挂orz

reid 相关任务记录

被师兄(同事?)普及了一番实验规范orz…

我还是太年轻了

所谓的一个fc的版本是右边的.一个放着不动,另一个在sequence_len(10)的维度上做ave,然后再expand成原来的维度.如下图.

 

 

任务命名规则:

如D1V2_a_1,D1表示使用第一个数据集,V2表示是第二个大版本,a表示在V2大版本上的微调,最后的数字表示这是第几次运行该任务(跑三次以减少波动的影响)

logdir的地址为:/mnt/lustre/renkuanze/Data_t1/reid/log/{$jobname}

 

  • D1:使用ilivids 数据集
    • D1V1表示最初始的 baseline model
    • D1V2表示改为使用一个fc
      • D1V2_a是一个在一个FC上,不添加光流的修改版本
      • D1V2_b是在一个FC上的baseline版本(也就是有光流)
      • D1V2_c是在一个FC上,有光流,batchsize从32改为64,gpu数目从4改为8的版本
    • D1V3表示将softmax改为sigmod
      • D1V3_b表示将softmax改为sigmod的baseline版本
  • D2:使用prid2011数据集
    • D2V1表示初始的baseline model
    • D2V2表示改为使用一个fc
      • D2V2_b是在一个FC上的baseline版本

 

 

分类评价指标之Cumulative Match Characteristi (CMC)曲线

CMC曲线全称是Cumulative Match Characteristic (CMC) curve,也就是累积匹配曲线,同ROC曲线Receiver Operating Characteristic (ROC) curve一样,是模式识别系统,如人脸,指纹,虹膜等的重要评价指标,尤其是在生物特征识别系统中,一般同ROC曲线( 多标签图像分类任务的评价方法-mean average precision(mAP) 以及top x的评价方法)一起给出,能够综合评价出算法的好坏。

转一篇通俗易懂的解释:

Shortly speaking, imagine that you have 5 classes. For simplicity, imagine you have one test per class. Each test produces a score when compared to each class. Let’s start from test1 which belongs to class1:
As your similarity measure, here, is Euclidian distance, the more distance a test has compared to a class, the less similarity is obtained. Without loss of generality, let’s suppose that the distance measures are calibrated and normalized in terms of similarity scores.
If the score between test1 and class1 is larger than the other 4 classes (or the Euclidian distance between test1 and class1 is less than the other 4 classes), class 1 is recognized in the first rank. As an example, let’s suppose the following similarity scores (not Euclidian distances):
Test1 VS class 1= .95
Test1 VS class 2= .7
Test1 VS class 3= .9
Test1 VS class 4= .72
Test1 VS class 5= .3
What do these scores say? These similarity scores say that test 1 is more similar to class 1 than the other classes. So, test 1 is correctly recognized in the first rank.
Let’s suppose that test2, test 3, test 4 and test 5 are also recognized in the first rank.
So, we can conclude that we have a perfect CMC curve (y-x). because all of the 5 test are correctly recognized. A perfect CMC curve is as following:
Rank 1: 100%
Rank2: 100%
Rank 5:100%
Now, let’s suppose the following situation:
Test1 VS class 1= .9
Test1 VS class 2= .95
Test1 VS class 3= .4
Test1 VS class 4= .72
Test1 VS class 5= .3
What do these scores say? They say that test 1 is more similar to class 2 than class 1 (This is a mismatch and it is not correct!). So, the correct match (.9) is not the top match here (the top match is .95 which is a mismatch). In other words, test 1 is not recognized as the top match, but it is recognized among top “two matches” (the top two matches are .95 and .9). This is what rank 2 recognition means!
Now, if test 1 is recognized among top two matches but the other tests (i.e., test 2, test 3,… test 5) are recognized in the first rank (Rank 1), the first rank recognition rate is 80% (test 1 is not among the top matches, i,e, 1 out of 5 is incorrect in first rank recognition which yields 80%) but the second rank recognition rate is 100%, because all of the tests are correctly recognized among the top “two matches”. Some of them are recognized in the first rank (test 2, test 3, test 4, and test 5) while some of them are recognized in the second rank (test 1). So, the second rank recognition rate is 100%.
So, the CMC curve will be as following:
Rank1  80% (tests 2,3,4,5 are among the N=1 top matches )
Rank2 100% (tests 1,2,3,4,5 are among the N=2 top matches )
Rank3 100%  (tests 1,2,3,4,5 are among the N=3 top matches )
Rank 5 100%  (tests 1,2,3,4,5 are among the N=5 top matches )
Now, consider that test1, test 2, test 3 are recognized in the first rank, test 4 is recognized in the second rank and test 5 is recognized in the fourth rank. what is the CMC curve>? Here is the answer:
Rank 1:  60% (tests 1,2,3 are among the N=1 top matches )
Rank 2: 80% (test 1,2 ,3 ,4 are among N=2 top matches)
Rank 3: 80% (test 1,2 ,3 ,4 are among N=3 top matches)
Rank 4: 100% (test 1,2 ,3 ,4 and 5 are among N=4 top matches)
Rank 5: 100% (test 1,2 ,3 ,4 and 5 are among N=5 top matches)
Reference:
Grother, Patrick, Ross J. Micheals, and P. Jonathon Phillips. “Face recognition vendor test 2002 performance metrics.” Audio-and Video-Based Biometric Person Authentication. Springer Berlin Heidelberg, 2003.

 

 

pytorch 函数笔记

记录一些常用的…总去查文档也是有点麻烦

  • tensor.view 的作用是reshape 比如 a = torch.range(1, 16) 得到一个tensor  that has 16 elements from 1 to 16. 在a=a.view(4,4)就得到了一个4*4的tensor。 需要注意reshape之后元素的个数不能改变(16==4*4)  参数-1的作用是,我懒得算这一维度应该是多少,(由于元素个数不能改变)所以希望自动被计算。需要注意的是,只有一个维度可以写-1。 不过view和reshape有些区别:reshape always copies memory. view never copies memory

  • torch.squeeze  将输入张量形状中的 1 去除并返回。 如果输入是形如(A×1×B×1×C×1×D),那么输出形状就为: (A×B×C×D)当给定 dim时,那么挤压操作只在给定维度上。例如,输入形状为: (A×1×B)squeeze(input, 0) 将会保持张量不变,只有用  squeeze(input, 1),形状会变成 (A×B)。注意: 返回张量与输入张量共享内存,所以改变其中一个的内容会改变另一个。

  • torch.unsqueeze  返回一个新的张量,对输入的制定位置插入维度 1 注意: 返回张量与输入张量共享内存,所以改变其中一个的内容会改变另一个。如果 dim为负,则将会被转化dim+input.dim()+1

     

  • tensor.expand(*size)   扩展tensor.可以保持维度数目不变,每一维度的size增加(比如A*B变到C*D,其中C>=A,D>=B).-1参数表示某一个维度的size不发生改变  . 有可以扩展tensor到更多的维度,新增加的维度会默认放在最前面,并且不能以-1作为参数。

  • tensor.contiguous  将一个tensor变成连续的。(一些ops如expand/expand_as会让tensor 不连续)

光流法初探

算是CV领域的传统算法了

只写两句话就够了。

它是空间运动物体在观察成像平面上的像素运动的瞬时速度,是利用图像序列中像素在时间域上的变化以及相邻帧之间的相关性来找到上一帧跟当前帧之间存在的对应关系,从而计算出相邻帧之间物体的运动信息的一种方法。

研究光流场的目的就是为了从图片序列中近似得到不能直接得到的运动场。运动场,其实就是物体在三维真实世界中的运动;光流场,是运动场在二维图像平面上(人的眼睛或者摄像头)的投影。

 

参考资料:

光流Optical Flow介绍与OpenCV实现

 

Reid iLIDS-VID 数据集 切分

ilids-vid数据集

150个人做trainning,150个人做
在training set里面,每个人有来自两个不同camera的两段video,之后再怎么切分去train是自己的事

在bash脚本里面有两个参数,(一段比如100个frame的video里切割出很多sequence),一个参数是seq_len,是一个sequence的长度,还有一个是seq_std,是切割间隔,所以如果第一个参数是10,第二个参数是5,就会切割出来20个sequence

end-to-end 神经网络

所谓end-to-end 神经网络,更多是一种思想。

这种思想的核心是,比如对于图像处理,输入原始图像数据,输出的是直接有用的结果(有用取决于具体的任务,比如自动驾驶)

也就是尽可能少得减少人为干预,使训练是end (原始数据)  to end (对应用问题直接有用的结果)

端到端指的是输入是原始数据,输出是最后的结果,原来输入端不是直接的原始数据,而是在原始数据中提取的特征,这一点在图像问题上尤为突出,因为图像像素数太多,数据维度高,会产生维度灾难,所以原来一个思路是手工提取图像的一些关键特征,这实际就是就一个降维的过程。
那么问题来了,特征怎么提?
特征提取的好坏异常关键,甚至比学习算法还重要,举个例子,对一系列人的数据分类,分类结果是性别,如果你提取的特征是头发的颜色,无论分类算法如何,分类效果都不会好,如果你提取的特征是头发的长短,这个特征就会好很多,但是还是会有错误,如果你提取了一个超强特征,比如染色体的数据,那你的分类基本就不会错了。
这就意味着,特征需要足够的经验去设计,这在数据量越来越大的情况下也越来越困难。
于是就出现了端到端网络,特征可以自己去学习,所以特征提取这一步也就融入到算法当中,不需要人来干预了。
简单得说,符合end-to-end 的神经网络,特征应该是网络自己学习,而不是人为提取。
参考资料:

Pose-driven Deep Convolutional Model for Person Re-identification 阅读笔记

1709.08325

Reid问题指的是判断一个probe person 是否在被不同的camera捕获的gallery person 中出现。

通常是如下情景:给出一个特定camera下某个特定人的probe image 或者 video sequence,从其他camera处询问这个人的图像,地点,时间戳。

 

ReID问题至今没有很好得解决,主要原因是,不同camera下,人的姿势(pose),观察的视角(viewpoint) 变化太大了。

传统方法主要在两个大方向上努力:

  1. 用一些在图像上抽取的不变量来作为人的特征feture
  2. 去学习一个不同的距离度量方式,以至于同一个人在不同camera之间的距离尽可能小。

但是由于在实际中,行人的pose和 摄像机的viewpoint不可控,因此与之相关的feture可能不够健壮。

学习新的不同的距离度量方式需要每对camera分别计算距离,然而这是O(n^2)的时间复杂度,凉凉。

 

近些年Deep learning发展迅猛,并且在很多CV任务上表现良好。所以自然有人想把Deep learning 方法应用到Reid任务上。

目前Deep learning的做法一般分为两部分:

  • 使用softmax loss 结合person ID labels得到一个global representation
  • 首先用预定义好的body 刚体模型去得到local representation,然后将global 和local representation 融合。

目前用deep learning的方法效果已经不错了,比传统方法要好。但是目前的deep learning方法没有考虑到人的姿势(pose)的变化。

虽然目前也有些deep learning的办法在处理Reid问题时使用pose estimation algorithms 来预测行人的pose,

但是这种办法是手动完成而不是一个end-to-end(什么是end-to-end 神经网络) 的过程

所以考虑pose的潜力还没有被完全发掘。

这篇paper主要做了以下工作:

  • 提出了一种新的深层结构,将身体部分转化成相应的特征表示,以此来克服pose变化带来的问题
  • 提出了一个用来自动学习各部分权值的sub-network

这两部分工作都是end-to-end的