百度飞桨顶会论文复现(5):视频分类论文之《Representation Flow for Action Recognition》篇

这次老师在课上总共领读了4篇分类论文,我这里分享其中的一篇论文,是关于使用神经网络对光流进行学习。
课程地址是:https://aistudio.baidu.com/aistudio/education/group/info/1340。
论文地址是:https://arxiv.org/abs/1810.01455。
Github地址是:https://github.com/piergiaj/representation-flow-cvpr19。
论文中文翻译地址:https://blog.csdn.net/qq_42037746/article/details/107411080。

文章目录

    • 1.相关介绍
    • 2.本文方法
      • 2.1 光流法介绍
      • 2.2 光流层细节
    • 3.结果展示

1.相关介绍

这里我将按照老师上课领读的顺序来进行介绍。
过去在对视频进行分类时,一般需要设计两个网络,一个网路输入静态图像得到图像特征另一个网络输入两张图像之间的光流,学习运动特征;然后对两个特征进行融合,进行最终的视频分类。这里最主要的问题是光流的计算成本比较高,通常需要上百次的迭代优化;另一个是需要训练两个网络,这使得模型在推理时资源消耗较大,限制了其应用。因此本文作者设计了一种CNN层:表示光流层,对光流进行学习,并且表示光流层可以对任意一层特征图进行学习。
在这里插入图片描述


2.本文方法

2.1 光流法介绍

在介绍本文方法之前首先回顾下什么是光流?光流是用来描述像素随时间在图像之间运动的方法
在光流法中一个基本假设是:同一个空间点的像素灰度值,在各个图像中是固定不变的,可以用I(x,y,t)I(x,y,t)I(x,y,t)来表示像素灰度。
下图中,ttt时刻图像中像素位置为(x,y)(x,y)(x,y),在t+dtt+dtt+dt时刻运动到(x+dx,y+dy)(x+dx,y+dy)(x+dx,y+dy),由于灰度不变可得:
I(x,y,t)=I(x+dx,y+dy,t+dt)I(x,y,t)=I(x+dx,y+dy,t+dt)I(x,y,t)=I(x+dx,y+dy,t+dt)
泰勒一阶展开,像素运动(u1,u2)(u_1,u_2)(u1,u2)即为光流矢量。
在这里插入图片描述


2.2 光流层细节

论文的整体网络结构如下,可以看到输入只有图片,与以往的分类网络不同的是多了一个Flow Layer,这也是整个网络的核心部分。
在这里插入图片描述
下图为光流层迭代计算过程,这里F1,F2F_1,F_2F1F2为两张图片的特征图。
在这里插入图片描述

  1. 初始时u=0,p=0,pc=F2−F1u=0,p=0,p_c=F_2-F_1u=0,p=0,pc=F2F1;然后进行nnn次迭代计算;

  2. 计算特征图F2F_2F2的梯度,这里的梯度是通过卷积操作计算的,下面的矩阵表示为卷积核 。∇F2x=[10−120−210−1]∗F2,∇F2y=[121000−1−2−1]∗F2\nabla{F_{2x}}=\begin{bmatrix}1&0&-1\\2&0&-2\\1&0&-1\end{bmatrix}*F_2,\nabla{F_{2y}}=\begin{bmatrix}1&2&1\\0&0&0\\-1&-2&-1\end{bmatrix}*F_2F2x=121000121F2F2y=101202101F2

  3. 然后是更新vvv的值;

  4. 计算ppp的散度:divergence(p)=px∗wx+py∗wydivergence(p)=p_x*w_x+p_y*w_ydivergence(p)=pxwx+pywy

  5. 然后是计算速度梯度,操作和求F2F_2F2梯度类似: ∇ux=[10−120−210−1]∗ux,∇uy=[121000−1−2−1]∗uy\nabla{u_{x}}=\begin{bmatrix}1&0&-1\\2&0&-2\\1&0&-1\end{bmatrix}*u_x,\nabla{u_{y}}=\begin{bmatrix}1&2&1\\0&0&0\\-1&-2&-1\end{bmatrix}*u_yux=121000121ux,uy=101202101uy

  6. 跟新p的值;

最终,经过nnn次迭代即可得到最终的像素运动速度uuu
下面是原作者光流层实现代码,首先网络的定义:

class FlowLayer(nn.Module):def __init__(self, channels=1, bottleneck=32, params=[1,1,1,1,1], n_iter=10):super(FlowLayer, self).__init__()self.bottleneck = nn.Conv3d(channels, bottleneck, stride=1, padding=0, bias=False, kernel_size=1)self.unbottleneck = nn.Conv3d(bottleneck*2, channels, stride=1, padding=0, bias=False, kernel_size=1)self.bn = nn.BatchNorm3d(channels)channels = bottleneckself.n_iter = n_iterif params[0]:self.img_grad = nn.Parameter(torch.FloatTensor([[[[-0.5,0,0.5]]]]).repeat(channels,channels,1,1))self.img_grad2 = nn.Parameter(torch.FloatTensor([[[[-0.5,0,0.5]]]]).transpose(3,2).repeat(channels,channels,1,1))else:self.img_grad = nn.Parameter(torch.FloatTensor([[[[-0.5,0,0.5]]]]).repeat(channels,channels,1,1), requires_grad=False)self.img_grad2 = nn.Parameter(torch.FloatTensor([[[[-0.5,0,0.5]]]]).transpose(3,2).repeat(channels,channels,1,1), requires_grad=False)            if params[1]:self.f_grad = nn.Parameter(torch.FloatTensor([[[[-1],[1]]]]).repeat(channels,channels,1,1))self.f_grad2 = nn.Parameter(torch.FloatTensor([[[[-1],[1]]]]).repeat(channels,channels,1,1))self.div = nn.Parameter(torch.FloatTensor([[[[-1],[1]]]]).repeat(channels,channels,1,1))self.div2 = nn.Parameter(torch.FloatTensor([[[[-1],[1]]]]).repeat(channels,channels,1,1))            else:self.f_grad = nn.Parameter(torch.FloatTensor([[[[-1],[1]]]]).repeat(channels,channels,1,1), requires_grad=False)self.f_grad2 = nn.Parameter(torch.FloatTensor([[[[-1],[1]]]]).repeat(channels,channels,1,1), requires_grad=False)self.div = nn.Parameter(torch.FloatTensor([[[[-1],[1]]]]).repeat(channels,channels,1,1), requires_grad=False)self.div2 = nn.Parameter(torch.FloatTensor([[[[-1],[1]]]]).repeat(channels,channels,1,1), requires_grad=False)self.channels = channelsself.t = 0.3  self.l = 0.15self.a = 0.25        if params[2]:self.t = nn.Parameter(torch.FloatTensor([self.t]))if params[3]:self.l = nn.Parameter(torch.FloatTensor([self.l]))if params[4]:self.a = nn.Parameter(torch.FloatTensor([self.a]))

前向传播:

def forward(self, x):residual = x[:,:,:-1]x = self.bottleneck(x)inp = self.norm_img(x)x = inp[:,:,:-1]y = inp[:,:,1:]b,c,t,h,w = x.size()x = x.permute(0,2,1,3,4).contiguous().view(b*t,c,h,w)y = y.permute(0,2,1,3,4).contiguous().view(b*t,c,h,w)u1 = torch.zeros_like(x)u2 = torch.zeros_like(x)l_t = self.l * self.ttaut = self.a/self.tgrad2_x = F.conv2d(F.pad(y,(1,1,0,0)), self.img_grad, padding=0, stride=1)#, groups=self.channels)grad2_x[:,:,:,0] = 0.5 * (x[:,:,:,1] - x[:,:,:,0])grad2_x[:,:,:,-1] = 0.5 * (x[:,:,:,-1] - x[:,:,:,-2])grad2_y = F.conv2d(F.pad(y, (0,0,1,1)), self.img_grad2, padding=0, stride=1)#, groups=self.channels)grad2_y[:,:,0,:] = 0.5 * (x[:,:,1,:] - x[:,:,0,:])grad2_y[:,:,-1,:] = 0.5 * (x[:,:,-1,:] - x[:,:,-2,:])p11 = torch.zeros_like(x.data)p12 = torch.zeros_like(x.data)p21 = torch.zeros_like(x.data)p22 = torch.zeros_like(x.data)gsqx = grad2_x**2gsqy = grad2_y**2grad = gsqx + gsqy + 1e-12rho_c = y - grad2_x * u1 - grad2_y * u2 - xfor i in range(self.n_iter):rho = rho_c + grad2_x * u1 + grad2_y * u2 + 1e-12v1 = torch.zeros_like(x.data)v2 = torch.zeros_like(x.data)mask1 = (rho < -l_t*grad).detach()v1[mask1] = (l_t * grad2_x)[mask1]v2[mask1] = (l_t * grad2_y)[mask1]mask2 = (rho > l_t*grad).detach()v1[mask2] = (-l_t * grad2_x)[mask2]v2[mask2] = (-l_t * grad2_y)[mask2]mask3 = ((mask1^1) & (mask2^1) & (grad > 1e-12)).detach()v1[mask3] = ((-rho/grad) * grad2_x)[mask3]v2[mask3] = ((-rho/grad) * grad2_y)[mask3]del rhodel mask1del mask2del mask3v1 += u1v2 += u2u1 = v1 + self.t * self.divergence(p11, p12)u2 = v2 + self.t * self.divergence(p21, p22)del v1del v2u1 = u1u2 = u2u1x, u1y = self.forward_grad(u1)u2x, u2y = self.forward_grad(u2)p11 = (p11 + taut * u1x) / (1. + taut * torch.sqrt(u1x**2 + u1y**2 + 1e-12))p12 = (p12 + taut * u1y) / (1. + taut * torch.sqrt(u1x**2 + u1y**2 + 1e-12))p21 = (p21 + taut * u2x) / (1. + taut * torch.sqrt(u2x**2 + u2y**2 + 1e-12))p22 = (p22 + taut * u2y) / (1. + taut * torch.sqrt(u2x**2 + u2y**2 + 1e-12))del u1xdel u1ydel u2xdel u2yflow = torch.cat([u1,u2], dim=1)flow = flow.view(b,t,c*2,h,w).contiguous().permute(0,2,1,3,4)flow = self.unbottleneck(flow)flow = self.bn(flow)return F.relu(residual+flow)

3.结果展示

首先作者分析了对不同特征层使用光流层的分类结果:可以看出在第三个残差块后面使用光流层效果最好在这里插入图片描述
然后作者讨论了不同结构光流层的分类结果,可看到Flow-Conv-Flow的分类效果是最好的。
在这里插入图片描述
最后作者与现有的SOTA模型进行了对比,可以看到,FCF+(2+1)D的效果是最好的。在这里插入图片描述
这里简单对《Representation Flow for Action Recognition》论文进行了介绍,更多理解还需要反复阅读论文和阅读源码。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/439684.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

智能算法(GA、DBO等)求解零等待流水车间调度问题(NWFSP)

先做一个声明&#xff1a;文章是由我的个人公众号中的推送直接复制粘贴而来&#xff0c;因此对智能优化算法感兴趣的朋友&#xff0c;可关注我的个人公众号&#xff1a;启发式算法讨论。我会不定期在公众号里分享不同的智能优化算法&#xff0c;经典的&#xff0c;或者是近几年…

一步步编写操作系统 50 加载内核3

接上节&#xff0c;在这里&#xff0c;我们把参数放到了栈中保存&#xff0c;大家注意到了&#xff0c;参数入栈的顺序是先从最右边的开始&#xff0c;最后压入的参数最左边的&#xff0c;其实这是某种约定&#xff0c;要不&#xff0c;为什么不先把中间的参数src入栈呢。既然主…

动手学无人驾驶(5):多传感器数据融合

本系列的前4篇文章主要介绍了深度学习技术在无人驾驶环境感知中的应用&#xff0c;包括交通标志识别&#xff0c;图像与点云3D目标检测。关于环境感知部分的介绍本系列暂且告一段落&#xff0c;后续如有需要再进行补充。 现在我们开启新的篇章&#xff0c;在本文中将会介绍无人…

详解两阶段3D目标检测网络PVRCNN:Point-Voxel Feature Set Abstraction for 3D Object Detection

在《动手学无人驾驶&#xff08;4&#xff09;&#xff1a;基于激光雷达点云数据3D目标检测》一文中介绍了3D目标检测网络PointRCNN。今天介绍该作者新提出的3D检测模型&#xff1a;PVRCNN&#xff0c;论文已收录于CVPR2020。 作者个人主页为&#xff1a;https://sshaoshuai.gi…

一步步编写操作系统 53 任务状态段TSS介绍

操作系统是利用PCB来维护所有任务的&#xff0c;包括进程和线程&#xff0c;但cpu提供的是TSS&#xff0c;linux系统可没用它&#xff0c;因为效率太低。但是还是要了解下TSS才清楚操作系统中某些操作的原因。 本节中所讲的特权级与它有着密不可分的联系&#xff0c;TSS作用不…

动手学无人驾驶(6):基于IMU和GPS数据融合的自车定位

在上一篇博文《动手学无人驾驶&#xff08;5&#xff09;&#xff1a;多传感器数据融合》介绍了如何使用Radar和LiDAR数据对自行车进行追踪&#xff0c;这是对汽车外界运动物体进行定位。 对于自动驾驶的汽车来说&#xff0c;有时也需要对自身进行更精确的定位&#xff0c;今天…

【Codeforces - 798C】 Mike and gcd problem(思维,贪心)

题干&#xff1a; Mike has a sequence A  [a1, a2, ..., an] of length n. He considers the sequence B  [b1, b2, ..., bn] beautiful if the gcd of all its elements is bigger than 1, i.e. . Mike wants to change his sequence in order to make it beauti…

一步步编写操作系统 48 加载内核1

其实&#xff0c;我们等了这一刻好久好久&#xff0c;即使我不说&#xff0c;大家也有这样的认识&#xff0c;linux内核是用c 语言写的&#xff0c;咱们肯定也要用c语言。其实...说点伤感情的话&#xff0c;今后的工作只是大部分&#xff08;99%&#xff09;都要用c语言来写&am…

Coursera自动驾驶课程第1讲:Welcome to the self-driving cars specialization

本专栏为Coursera自动驾驶课程笔记&#xff0c;B站上也有配套课程视频&#xff0c;对自动驾驶技术感兴趣的朋友可以看看。 本讲对应视频&#xff1a; https://www.bilibili.com/video/BV1WE411D74g?p1https://www.bilibili.com/video/BV1WE411D74g?p2https://www.bilibili.…

Coursera自动驾驶课程第2讲:The Requirements for Autonomy

上一讲《Coursera自动驾驶课程第1讲&#xff1a;Welcome to the self-driving cars specialization》对本课程进行了整体概述&#xff0c;同时回顾了自动驾驶汽车的发展历史。 从本讲我们开始进入正式的学习&#xff0c;我们将首先了解到如何划分自动驾驶汽车等级、以及自动驾…

一步步编写操作系统 51 加载内核4

咱们的内容都是连栽的&#xff0c;如果您没看过我之前的文章&#xff0c;本节您是看不懂的。 接上节。 介绍完内核初始化的函数kernel_init后&#xff0c;本节代码部分还差一点点没说啦&#xff0c;下面看代码&#xff1a; …略 179 ;在开启分页后&#xff0c;用gdt新的地址…

Coursera自动驾驶课程第3讲:Self-Driving Hardware and Software Architectures

在上一讲《Coursera自动驾驶课程第2讲&#xff1a;The Requirements for Autonomy》中我们了解到了如何划分自动驾驶汽车等级、以及自动驾驶三大模块&#xff1a;感知、决策和执行。 本讲我们将学习新的模块&#xff1a;自动驾驶汽车的硬件和软件架构。 B站视频链接&#xff…

一步步编写操作系统 54 CPL和DPL入门1

我们在工作中&#xff0c;公司都给员工配有员工卡&#xff0c;此员工卡就是员工身份的“标签”&#xff0c;用它来出入公司、食堂就餐等。给公司创造价值的是员工的生产力&#xff0c;不是员工卡&#xff0c;员工卡只是公司人事部门管理员工的一种手段而已。 现在说计算机&…

Coursera自动驾驶课程第4讲:Safety Assurance for Autonomous Vehicles

在上一讲《Coursera自动驾驶课程第3讲&#xff1a;Self-Driving Hardware and Software Architectures》中我们了解了自动驾驶汽车常用的传感器和硬件组件、软件系统。 本讲我们将学习新的模块&#xff0c;也是自动驾驶汽车最重要的模块之一&#xff1a;安全模块。 B站视频链…

【Codeforces - 1000C】Covered Points Count(思维,离散化,差分)

题干&#xff1a; You are given nn segments on a coordinate line; each endpoint of every segment has integer coordinates. Some segments can degenerate to points. Segments can intersect with each other, be nested in each other or even coincide. Your task i…

Coursera自动驾驶课程第5讲:Vehicle Dynamic Modeling

在上一讲《Coursera自动驾驶课程第4讲&#xff1a;Safety Assurance for Autonomous Vehicles》中我们了解了自动驾驶汽车中一个非常重要的模块&#xff1a;安全模块。 本讲我们将学习新的模块&#xff1a;汽车运动学和动力学模块。&#xff08;这部分可能需要一定的理论力学和…

Java同步锁——lock与synchronized 的区别【转】

在网上看来很多关于同步锁的博文&#xff0c;记录下来方便以后阅读 一、Lock和synchronized有以下几点不同&#xff1a; 1&#xff09;Lock是一个接口&#xff0c;而synchronized是Java中的关键字&#xff0c;synchronized是内置的语言实现&#xff0c;synchronized是在JVM层面…

Coursera自动驾驶课程第6讲:Vehicle Longitudinal Control

在上一讲《Coursera自动驾驶课程第5讲&#xff1a;Vehicle Dynamic Modeling》中我们了解了汽车运动学和动力学模块。 本讲我们继续学习新的模块&#xff1a;汽车纵向控制。具体地&#xff0c;我们将学习PID控制算法&#xff0c;看看该算法是如何在自动驾驶汽车中应用的。 B站…

Java并发:线程共享变量可见性原理

0、线程安全性&#xff1a;线程安全性包括两个方面&#xff0c;①可见性。②原子性。 0.1、线程之间的通信&#xff1a;线程的通信是指线程之间以何种机制来交换信息。在命令式编程中&#xff0c;线程之间的通信机制有两种共享内存和消息传递。 &#xff08;1&#xff09;在共…

Coursera自动驾驶课程第7讲:Vehicle Lateral Control

在上一讲《Coursera自动驾驶课程第6讲&#xff1a;Vehicle Longitudinal Control》中我们了解了如何使用PID算法进行汽车纵向控制。 本讲我们继续学习新的模块&#xff1a;汽车横向控制。具体地&#xff0c;我们将学习三种控制算法&#xff1a;Pure pursuit&#xff0c;Stanle…