今天初步入门了一下Vrep,为了防止忘记踩过的坑和一些细节,记录一下。

为了快速使用Vrep,我拿出了几个月没有用过的鼠标。在开始之前,先介绍三个基本的鼠标操作:

  1. 按住鼠标左键拖动,可以移动视图。
  2. 滚动鼠标滚轴,可以放大缩小视图。
  3. 按住中键拖动,可以改变视角。(这大概是我第一次用到这个鼠标操作……)

打开Vrep,新建一个视图,可以看到这样一个界面:


打开Vrep

场景里有一个水平面,右下角还有一个小小的直角坐标系。按住中键拖动时,这个直角坐标系也会随之旋转。

实现旋转功能非常简单,只需要转动轴和物体即可。

首先创建一个球体(或正方体等whatever)。点击Add->Primitive Shape->Sphere,在弹出的对话框中可以设置球的半径等参数。确认之后场景中出现一个球体,貌似在默认情况下球下边沿就是和水平面对齐了的。

创建球体对话框
创建球体

接下来创建一个旋转关节,点击Add->Joint->Revolute。


创建关节

通过菜单栏中的object/item shift和object/item rotate将旋转关节和球体的中轴重合(即x和y坐标设为一致的,z坐标只需将关节下边沿和水平面对齐即可)。


对齐关节和球体

一个方便的对齐方法如下。同时选中关节和球体,将一个的位置应用到另一个。


另一个对齐的方法

接下来设置两个物体的层级关系,在Scene hierarchy中将Sphere拖入Revolute_joint。


设置层级关系

之后,为了能够使用lua脚本给旋转关节设置速度,建立一个随便什么物体,使旋转关节和球体层级关系上属于这个物体。右键Scene hierarchy中这个物体,Add->Associated Child Script->Non threaded。之后这个物体名字右侧会出现一个小的文件图标,双击这个图标就可以查看并修改lua脚本。


设置lua脚本

在lua脚本中,sysCall_init函数添加以下两句。

1
2
v0=1
handle=sim.getObjectHandle('Revolute_joint')

在sysCall_actuation函数中添加以下一句给关节设置速度。

1
sim.setJointTargetVelocity(handle,v0)

双击Scene hierarchy中旋转关节的图标,在属性中点击最下的Show dynamic properties dialog,然后在新弹出的对话框中,选中Motor enabled。理论上现在就可以转动了。


打开关节转动

最后一步,把豌豆射手的网格模型贴上去。网格模型是我从网上下载的STL模型,通过File->Import->Mesh导入即可。为了美观,让这个网格模型叶子的中心和关节的x、y轴对齐。效果差不多是这个样子。


插入网格模型

然后将网格模型从属于球体。运行之后,这个豌豆射手就可以旋转了。最后我们将除网格之外的所有东西隐藏掉(可以看到Scene Hierarchy中名字变暗了),就可以实现一个旋转的豌豆射手了。隐藏物体时,把对勾全部消掉。


隐藏物体

最后效果如下:

这周效率不高,周二回学校才开始读paper,结果读到今天又读不进去了。如果顺利的话,在开学前把网络结构这几篇再过一遍。最近读的几篇paper都没有什么惊喜感,不过多读还是有点好处的。我发现读paper的速度提高了一丢丢,这是个好事。实验又出现了一些奇怪的问题,明天去找老师讨论一番。

晚上去听了音乐会,北京交响乐团的,演奏柴一和贝七,最后加演了一首友谊地久天长。感觉柴一一般,贝七还行,大概因为听贝七比较少。

惊闻下周就要开始小学期了,而我的密码学第三次作业还是没写。室友们今天都回来了,不过估计马上他们都要走了。

这周比较伤心的事情是……德国队出局了。其实刚刚知道这个消息心中有点悲愤但也只是有点,结果早上很早很早的时候突然醒了,怎么也接受不了这个事实。现在我倒是接受了,奶一口法国队夺冠。

总之本周比较平淡,由于对刚搭好的博客新鲜感还没有过去,所以随便记了点流水账。周末还有一些工作要做,需要恢复到正常的作息时间了。

Link:arXiv:1805.04855

这又是一篇尝试将二阶统计量用于神经网络的paper,应用场景是表情识别。在文中,作者给出了如何使用covariance pooling做图像的表情识别和视频的表情识别。

表情识别更依赖于面部关键点的扭曲程度而不是是否存在某个关键点,因此作者认为二阶统计量相比于一阶统计量更容易捕捉到面部特征的扭曲程度,更适用于表情的识别。除此之外,covariance pooling还可以捕捉特征在各个帧之间的变化,因此可以被用在视频的表情识别中。

相较于之前使用协方差矩阵的工作,这篇文章在协方差矩阵的基础上又使用了降维层和non-linear rectification层。这一部分使用了后面提到的manifold network,它主要有两个作用:(1)由于协方差矩阵flatten后直接接全连接层过大,这部分可以起到降维的作用;(2)可以保留原矩阵中的几何信息。我猜测covariance pooling中的pooling是指降维这一部分。但是有一点有待进一步思考:Pooling最主要的作用是不变形还是降维,covariance pooling中是否有能体现不变形的部分?

模型

对于图像的表情识别,分成以下几步:

图像的表情识别

  • 由于图像中存在很多不相关信息,首先进行脸部识别,然后根据关键点将人脸摆好。
  • 接下来将人脸通过CNN输出特征。
  • 使用CNN得到的特征做covariance pooling,并且把covariance matrix输入到后面接的manifold network中学习深度二阶统计量。

视频中的表情识别和图像的表情识别类似:

视频的表情识别

  • 在视频中抽取出一些帧,进行脸部识别。
  • 将各帧中的人脸串接起来输入到3D卷积中。
  • 将3D CNN得到的特征做covariance pooling,并把covariance matrix输入到manifold network中。注意这一步和图像不同,这里的协方差矩阵求的是各帧的特征之间的协方差,也即时间轴上的协方差矩阵。

因此可以看到,核心就是covariance pooling和manifold network部分。

Covariance Pooling

文中对于covariance pooling的描述如下:

给定一组特征 \(f_1, f_2, …, f_n\in \mathbb{R}^d\)是一组特征,他们的covariance matrix为
$$\mathbf{C}=\frac{1}{n-1}\sum_{i=1}^n(\mathbf{f_i}-\mathbf{\bar f})(\mathbf{f_i}-\mathbf{\bar f})^T$$
其中,\(\mathbf{\bar f}=\frac{1}{n}\sum_{i=1}^n\mathbf{f_i}\)。

对于图像中的表情识别,我们这样定义\(f_1, f_2, …, f_n\):令\(\mathbf(X)\in \mathbb{R}^{w\times h \times d}\),其中\(w,h,d\)分别是卷积层输出的width,height和channel数。将\(\mathbf{X}\) flatten成一个\(n\times d\)的矩阵命名为\(\mathbf{X’}\),那么\(f_1, f_2, …, f_n\)就是\(\mathbf{X’}\)的各列。

其实简单来看,就是将卷积层的输出中每个channel flatten成一个向量,对d个向量求协方差矩阵。

对于视频中的表情识别,用来做协方差矩阵的不再是各个channel的向量,而是从不同帧中提取出来的特征向量。细节还没有仔细研究。

SPD Manifold Network (SPDNet) Layers

这部分内容来自《A Riemannian Network for SPD Matrix Learning》(arXiv:1608.04233)。SPDNet将对称正定矩阵作为输入学习出新的特征。

考虑上一部分定义的协方差矩阵\(\mathbf{C}\)可能是一个对称半正定矩阵,为了符合SPDNet的输入要求,将其变成以下对称正定矩阵
$$\mathbf{C^+}=\mathbf{C}+\lambda trace(\mathbf{C})\mathbf{I}$$
其中,\(\lambda\)是正则化参数,\(\mathbf{I}\)是单位矩阵。

SPDNet中主要有三层:

  • Bilinear Mapping Layer (BiMap):考虑到协方差矩阵flatten后直接接全连接层的话,全连接层输入过多,因此可以用这一层来进行降维。另一方面,这一层可以保留原矩阵的几何信息。设\(\mathbf{X_{k-1}}\)是该层的输入,\(\mathbf{W_k}\in \mathbb{R}_*^{d_k \times d_{k-1}}\)是权重矩阵,那么输出\(\mathbf{X_{k}}\in \mathbb{R}^{d_k \times d_k}\)定义为
    $$\mathbf{X_k}=f_b^k(\mathbf{X_{k-1};\mathbf{W_k}})=\mathbf{W_k}\mathbf{X_{k-1}}\mathbf{W_k}^T$$

  • Eigenvalue Rectification (ReEig):这一层有点类似于ReLU,可以引入非线性。设输入为\(\mathbf{X_{k-1}}\),对输入做特征值分解得到\(\mathbf{X_{k-1}}=\mathbf{U_{k-1}}\Sigma_{k-1}\mathbf{U_{k-1}}^T\),那么输出\(\mathbf{X_{k}}\)定义为
    $$\mathbf{X_k}=f_r^k(\mathbf{X_{k-1}})=\mathbf{U_{k-1}}max(\epsilon \mathbf{I}, \sigma_{k-1})\mathbf{U_{k-1}}^T$$
    其中,max操作是逐元素取max。

  • Log Eigenvalue Layer (LogEig):按照文中的说法,这一部分的作用是“给黎曼流形中的元素赋予李群结构,使得矩阵被flatten后可以使用标准的欧式运算”。这个原理超出了我的知识范围,因此目前还没有理解。好在理论难但是做法简单。设输入为\(\mathbf{X_{k-1}}\),对输入做特征值分解得到\(\mathbf{X_{k-1}}=\mathbf{U_{k-1}}\Sigma_{k-1}\mathbf{U_{k-1}}^T\),那么输出\(\mathbf{X_{k}}\)定义为
    $$\mathbf{X_k}=f_l^k(\mathbf{X_{k-1}})=\mathbf{U_{k-1}}log(\Sigma_{k-1})\mathbf{U_{k-1}}^T$$

把BiMap和ReEig两层用BiRe表示,那么SPDNet结构如下:

SPDNet

实验

文章中主要用了Static Facial Expressions in the Wild (SFEW) 2.0 dataset和Real-world Affective Faces (RAF) dataset连个数据集,前者用于图像表情识别,后者用于视频表情识别。

实验中比较了使用不同的baseline训练或finetune的结果和使用covariance pooling得到的结果,使用covariance pooling可以提升三四个点。实验中还比较了covariance pooling+SPDNet中一些参数的影响,比如SPDNet后使用多少个全连接层以及SPDNet中BiRe层的个数等等,实验结果详见paper。

总结

看了几篇关于如何在网络中使用二阶统计量后发现,貌似大多数paper到求covariance matrix那里都是一致的,重点在于得到covariance matrix后要怎么处理。针对这篇文章来说,就是使用SPDNet来处理covariance matrix。

对于这篇paper,还有一些细节没有搞清楚:

  • Covariance pooling的pooling是怎么体现的。按照模型部分的描述,covariance pooling貌似只求了一个covariance matrix。
  • SPDNet的理论,这个超出了我的数学知识,不太能读懂。
  • 关于视频中的表情识别文中描述的比较简略,细节不清楚。
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×