CVPR 2017|Deep Feature Flow for Video Recognition论文复现(pytorch版)

news2024/11/17 13:37:20

🏆引言:深度卷积神经网络在图像识别任务中取得了巨大的成功。然而,将最先进的图像识别网络转移到视频上并非易事,因为每帧评估速度太慢且负担不起。我们提出了一种快速准确的视频识别框架——深度特征流DFF。它只在稀疏关键帧上运行昂贵的卷积网络,并通过流场将其深度特征映射传播到其他帧。它实现了显著的加速,因为流计算相对较快。整个体系结构的端到端训练显著提高了识别精度。深度特征流是灵活和通用的。在目标检测和语义分割两个视频数据集上进行了验证。它极大地推进了视频识别任务的实践。

文章目录

模型架构

DFF的流程图

image-20221226165948305

feat网络相当于是pspnet的backbone,然后这个task网络就是pspnet用于预测的head

伪代码说明

image-20221226170248748

N f e a t N_{feat} Nfeat

<原文>:我们使用ResNet模型,具体来说,ResNet-50和ResNet-101模型在ImageNet预训练,最后的1000路分类层被丢弃。按照DeepLab进行语义分割,R-FCN进行目标检测的做法,将特征步幅从32缩小到16,以产生更密集的特征图。第一个block的conv5层,步距由2改为1,并且conv5中的所有3×3卷积核上应用空洞卷积,以保持视场(dilation=2)。对conv5追加一个随机初始化的3×3卷积,将特征信道维数降至1024,其中还应用了空洞卷积。生成的1024维特征映射是后续任务的中间特征矩阵 N f e a t N_{feat} Nfeat

feat网络实际上就是一个语义分割模型,作者采用了DeeplabV2,本人采用了pspnet-r101。并且语义分割模型pspnet101已在cityscape数据集上与训练好了。单独的pspnet-r101在cityscape验证集上mIOU=69

dff还有一个scale层,论文里面有说,不过我这里没有加进去,因为scale层容易干扰我后面的实验分析

输入:

gt = [batch_size,1,512,1024]
im_flow_list = [batch_size,3,2,512,1024]
im_seg_list = [batch_size,3,2,512,1024]

输出

pred.shape = [1,19,64,128]

N t a s k N_{task} Ntask

<原文>:在中间特征矩阵上应用随机初始化的1 × 1卷积层,得到(C+1)分图,其中C为类别数,1为背景类别。然后通过softmax层输出逐像素概率。因此,任务网络只有一个可学习的权重层。整体网络架构类似于DeepLab

task是一个分类器,作者采用了task=1*1conv+softmax,作者通过实验发现,有没有这个1*1conv效果差不多,使用0层基本上等同于使用1层,无论是精度还是速度。我们选择1层作为默认值,因为在特征传播之后会留下一些可调参数,这可能更通用。

image-20221226171055248

# net_task = 1*1 Conv + softmax
# 论文里面说有没有这个1x1conv没什么区别,多加一个conv可以为以后需要时调参数,或者说更常规
self.net_task = nn.Conv2d(num_classes, num_classes, kernel_size=1, stride=1, padding=0)

f l o w n e t flownet flownet

使用的是flownet,这里我直接搬用flownet的api。

实验

根据数据集中视频帧率的不同,评估时cityscape分割的关键帧时长l默认为5,ImageNet VID检测的关键帧时长l默认为10

视频语义分割的评价指标使用 mIoU,在计算 mIoU 时,设置了三个传播距 {1,5,9} 来 刻画传播精度, 其中 {1,5,9} 分别表示当前帧与关键帧距离为相邻帧、隔了 4 帧和隔 8 帧。

不过验证时我采用的传播距离固定是5

  • 训练时传播距离固定为5

  • 训练时传播距离在1-5之间随机采样

  • 在每个小批量中,随机抽取一对附近的视频帧 [ I k , I i ] , 0 ≤ i − k ≤ 9 [I_k, I_i] ,0≤i−k≤9 [Ik,Ii],0ik9

dis(传播距离)5random(1~5)random(0~9)
mIOU60.9860.9160.90

可以看到,三者实际上是差不多的。

代码

import torch
import torch.nn as nn
import torch.nn.functional as F

from mmseg.models import build_segmentor
from mmcv.utils import Config

from pspnet import pspnet_res101
from flownet import FlowNets
from warpnet import warp


class DFF(nn.Module):
    def __init__(self, num_classes=19, weight_res101=None, weight_flownet=None):
        super(DFF, self).__init__()

        # reference branch选用pspnet_res50
        # TODO(12.26):预训练pspnet-r50模型
        self.net_feat = pspnet_res101()

        # net_task = 1*1 Conv + softmax
        # 论文里面说有没有这个1x1conv没什么区别,多加一个conv可以为以后需要时调参数,或者说更常规
        self.net_task = nn.Conv2d(num_classes, num_classes, kernel_size=1, stride=1, padding=0)

        # 光流场‘O()’选择FlowNets,预测的光流图
        self.flownet = FlowNets()

        # 用于传播关键帧到当前帧的可学习函数‘W()’,即将预测的光流图和关键帧的语义分割图进行融合
        self.warp = warp()

        # 权重初始化
        # TODO:将res101 -> res50
        self.weight_init(weight_res101, weight_flownet)

        # 交叉熵损失函数
        # FIXME:ignore_index=255?
        self.criterion_semantic = nn.CrossEntropyLoss(ignore_index=255)

    def weight_init(self, weight_res101, weight_flownet):
        if weight_res101 is not None:

            # 加载预训练权重
            weight = torch.load(weight_res101, map_location='cpu')
            weight = weight['state_dict']

            # 加载预训练权重
            self.net_feat.model.load_state_dict(weight, False)

            # 冻结backdone的参数,仅调整decode_head的参数
            self.net_feat.fix_backbone()

        if weight_flownet is not None:
            weight = torch.load(weight_flownet, map_location='cpu')
            self.flownet.load_state_dict(weight, True)

        # 为了使得网络中信息更好的流动,每一层输出的方差应该尽量相等
        nn.init.xavier_normal_(self.net_task.weight)
        self.net_task.bias.data.fill_(0)
        print('pretrained weight loaded')

    # ---------------------------------Input-----------------------------------------------
    # gt = [batch_size,1,512,1024]
    # im_flow_list = [batch_size,3,2,512,1024]
    # im_seg_list = [batch_size,3,2,512,1024]
    # -------------------------------------------------------------------------------------
    def forward(self, im_seg_list, im_flow_list, gt=None):

        # 输入的视频数据参数值,依次为 bastchsize, 通道, 关键帧间隔时间, 帧高度, 帧宽度
        n, c, t, h, w = im_seg_list.shape

        # 推理关键帧的语义结果
        pred = self.net_feat(im_seg_list[:, :, 0, :, :])
        # pred.shape = [1,19,64,128]

        # 双线性插值等比放大2倍
        pred = F.interpolate(pred, scale_factor=2, mode='bilinear', align_corners=False)
        # pred.shape = [1,19.128.256]

        # 计算关键帧的光流传播:首先将关键帧和当前帧的tensor在通道处堆叠,然后传入flownet,从而根据关键帧和当前帧计算光流,
        flow = self.flownet(torch.cat([im_flow_list[:, :, -1, :, :], im_flow_list[:, :, 0, :, :]], dim=1))

        # 将关键帧的pred传入warp(),然后和当前帧的flow继续一个W()函数,输出pred
        pred_result = self.warp(pred, flow)

        # 将经过warp输出的pred放到task网络里面
        pred_result = self.net_task(pred_result)
        # 双线性插值放大4倍
        pred_result = F.interpolate(pred_result, scale_factor=4, mode='bilinear', align_corners=False)
        # pred_result.shape = [1,19,512,1024]

        if gt is not None:
            loss = self.criterion_semantic(pred_result, gt)

            # .unsqueeze(0) 表示,在第一个位置增加维度
            loss = loss.unsqueeze(0)
            return loss
        else:
            return pred_result

    def evaluate(self, im_seg_list, im_flow_list):
        out_list = []
        t = im_seg_list.shape[2]
        pred = self.net_feat(im_seg_list[:, :, 0, :, :])
        # pred.shape = [1,19,64,128]

        pred = F.interpolate(pred, scale_factor=2, mode='bilinear', align_corners=False)
        # pred.shape = [1,19,128,256]

        # 将经过net_feat的关键帧,再经过net_task处理
        out = self.net_task(pred)

        # 长宽均放大4倍
        out = F.interpolate(out, scale_factor=4, mode='bilinear', align_corners=False)
        # out.shape = [1,19,512,1024]

        # 输入:out.shape = torch.Size([1, 19, 512, 1024])
        out = torch.argmax(out, dim=1)
        # 输出:out.shape = torch.Size([1, 512, 1024])

        out_list.append(out)

        # FIXME:eval时也不需要for循环吗?

        # 当前帧和关键帧做一个光流估计
        flow = self.flownet(torch.cat([im_flow_list[:, :, -1, :, :], im_flow_list[:, :, 0, :, :]], dim=1))

        # 扔进‘W()’函数里
        pred_result = self.warp(pred, flow)

        # 对堆叠结果进行卷积
        pred_result = self.net_task(pred_result)
        pred_result = F.interpolate(pred_result, scale_factor=4, mode='bilinear', align_corners=False)

        # 取最大的可能性结果
        out = torch.argmax(pred_result, dim=1)
        out_list.append(out)

        return out_list

    def set_train(self):
        self.net_feat.eval()
        self.net_feat.model.decode_head.conv_seg.train()
        self.net_task.train()
        self.flownet.train()


if __name__ == '__main__':
    model = DFF(weight_res101=None, weight_flownet=None)
    model.cuda().eval()

    im_seg_list = torch.rand([1, 3, 5, 512, 1024]).cuda()
    im_flow_list = torch.rand([1, 3, 5, 512, 1024]).cuda()
    with torch.no_grad():
        out_list = model.evaluate(im_seg_list, im_flow_list)
        print(len(out_list), out_list[0].shape)

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

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

相关文章

数据结构与算法_五大算法之--回溯算法

1 回溯算法 回溯算法具有通用性&#xff0c;但是算法的效率不高&#xff0c;通常可以通过剪枝等操作提高算法的效率。 算法思想&#xff1a; 在包含问题的所有解空间树中&#xff0c;按照深度优先搜索的策略&#xff0c;从根节点出发&#xff0c;深度搜索解空间树。当搜索到某…

APSIM作物生长模型学习

由于研究需要&#xff0c;将对APSIM模型使用进行一定学习&#xff0c;特做此笔记&#xff0c;也供该模型的初学者共同进步。 首先是版本选择&#xff0c;这个模型发展较长&#xff0c;有经典的classic版本和次世代版本&#xff0c;而经过实际验证&#xff0c;次世代版本和经典版…

RHCSA 第六天笔记

网络配置 1&#xff0c;ip 命令 ip a 2,修改配置文件&#xff08;不推荐&#xff09; 3&#xff0c;nmcli命令 4&#xff0c;nmtui命令 5&#xff0c;cockpit 网络接口是指网络中的计算机或网络设备与其他设备实现通讯的进出口。这里&#xff0c;主要是指计算机的网络接口即网…

学习笔记之Vue组件化编程(二)

Vue组件化编程&#xff08;二&#xff09;Vue组件化编程一、模块与组件&#xff0c;模块化与组件化1.1 对组件的理解1.2 模块1.3 组件1.4 模块化1.5 组件化&#xff08;二&#xff09;Vue组件化编程 一、模块与组件&#xff0c;模块化与组件化 1.1 对组件的理解 在传统式编写…

Centos7下mysql8.0读写分离的配置

1.前言 1.关于读写分离的原理&#xff0c;这里不做太多赘述。主要从服务器去读取主服务的binlog日志&#xff0c;完成数据同步的过程。 这里我在mac开启了2个虚拟机&#xff0c;ip分别为192.168.31.109 ,192.168.31.208系统为centos 2.配置主从分离之前&#xff0c;需要安装…

第二十五讲:OSPF路由协议邻居认证配置

在相同OSPF区域的路由器上启用身份验证的功能&#xff0c;只有经过身份验证的同一区域的路由器才能互相通告路由信息。这样做不但可以增加网络安全性&#xff0c;对OSPF重新配置时&#xff0c;不同口令可以配置在新口令和旧口令的路由器上&#xff0c;防止它们在一个共享的公共…

android血量条的制作

最近&#xff0c;项目中需要用到血量条&#xff0c;想到血量条这东西&#xff0c;在游戏中经常见到。那么&#xff0c;再android开发中如何制作血量条呢&#xff1f;这里本人想到了两种方法&#xff0c;在网上找到一种最优方案。 方法一&#xff1a;用多张相同的图片拼凑而成的…

Docker安装nginx以及nginx-gui控制面板

一、安装nginx 1、搜索镜像 docker search nginx2、拉取镜像 docker pull nginx3、创建Nginx挂载配置文件 # 创建挂载目录 mkdir -p /install/nginx/conf mkdir -p /install/nginx/log mkdir -p /install/nginx/html# 生成容器 # 将容器nginx.conf文件复制到宿主机 # 将容器…

公网远程连接本地socket服务【内网穿透】

文章目录1. 配置本地socket服务2. 本地socket服务暴露至公网2.1 创建隧道映射9999端口2.2 获取公网地址3. 公网连接本地socket服务端1. 配置本地socket服务 Java 服务端demo环境 jdk1.8框架:springbootmaven开发工具:IDEA 在pom文件引入第三包封装的netty框架maven坐标 <…

【MyBatis】安装 + 框架搭建 + 优化 + 增删改查(全程一条龙服务讲解~)

目录 前言 一、准备工作 1.1、下载MyBatis 1.2、数据库设计 二、搭建框架 2.1、创建Maven项目 2.2、jar包、引入依赖 2.3、创建MyBatis核心配置文件 2.4、映射文件 2.5、通过junit测试功能 2.6、框架优化 三、增删改查优化 四、小结——注意事项 前言 本篇全程从0…

软件测试工程师的发展道路

最近看到一些测试朋友&#xff0c;对测试未来比较迷茫&#xff0c;不知该如何前行&#xff0c;无方向感。目前来看&#xff0c;业界目前存在一个普遍的矛盾&#xff0c;一方面很多人会觉得测试没有发展前途&#xff0c;另一方面&#xff0c;又有非常多的企业急需专业的测试人员…

React学习05-React Router 5

React Router 5 相关理解 SPA 单页Web应用&#xff08;single page web application&#xff0c;SPA&#xff09;。整个应用只有一个完整的页面。点击页面中的链接不会刷新页面&#xff0c;只会做页面的局部更新。数据都需要通过ajax请求获取, 并在前端异步展现。 路由 什么…

全球十大数据安全事件

2021年&#xff0c;数据隐私泄露事件频发&#xff0c;涉及面广&#xff0c;影响力大&#xff0c;企业因此陷入数据保护合规与社会舆情压力的双重危机。近日&#xff0c;有国外媒体梳理了2021年十大数据泄密事件&#xff0c;并对事件进行了点评分析&#xff0c;可供读者参考。据…

第二十九讲:神州路由器DHCP协议的配置

实验拓扑图如下所示 操作步骤&#xff1a; 步骤1&#xff1a;按照图1&#xff0c;正确连接拓扑结构图。 步骤2&#xff1a;为路由器设置主机名称和配置接口IP地址。 Router>enable &#xff01;进入特权模式 Router #config &a…

MySQL高级【SQL性能分析】

目录 1&#xff1a;SQL性能分析 1.1&#xff1a;SQL执行频率 1.2&#xff1a;慢查询日志 1.3&#xff1a;profile详情 1.4&#xff1a;explain 1&#xff1a;SQL性能分析 1.1&#xff1a;SQL执行频率 MySQL 客户端连接成功后&#xff0c;通过 show [session|global] sta…

2022年的5G行业:“5G+”很火,5G网络迟迟未能普及

作者 | 曾响铃 文 | 响铃说 2022年&#xff0c;5G行业依旧是如火如荼地发展&#xff0c;5G技术继续深刻地改变着我们的生活与生产&#xff0c;影响社会经济发展的方方面面。 回顾过去的一年&#xff0c;5G行业有看点&#xff0c;也有疑虑。 5G网络已基本覆盖全国。截至 202…

PaddleNLP开源基于UIE的情感分析,解决小样本难题,助力客户意见洞察与舆情分析!

情感分析&#xff08;Sentiment Analysis&#xff09;是近年来国内外研究的热点&#xff0c;旨在对带有情感色彩的主观性文本进行分析、处理、归纳和推理。情感分析具有广泛的应用场景&#xff0c;可被应用于消费决策、舆情分析、个性化推荐等领域。 如上图所示&#xff0c;情…

移位操作符、位操作符,原码、反码、补码

整数的二进制的表达形式有3种。原码反码补码下面我们举一个例子吧十进制的2原码&#xff1a;00000000000000000000000000000010&#xff08;常见的形式&#xff09;反码&#xff1a;00000000000000000000000000000010补码&#xff1a;00000000000000000000000000000010小结 正整…

k8s集群部署02

k8s集群部署02k8s集群部署02仍然报错若镜像拉取过慢原因k8s集群部署02 一、pod基本操作Pod是可以创建和管理Kubernetes计算的最小可部署单元&#xff0c;一个Pod代表着集群中运行的一个进程&#xff0c;每个pod都有一个唯一的ip。一个pod类似一个豌豆荚&#xff0c;包含一个或…

Hack the Box CTF 比赛 简单难度 XOR 密码学题目 Crypto 流程| Multikey Walkthrough

这是近期参加HTB夺旗战时遇到的一道难度为简单的密码学Crypto题目。但是我觉得挺有意思&#xff0c;就做下记录。 1. 题目&#xff1a; 题干没有太多的内容&#xff0c;就是一段python程序&#xff0c;和一个output的加密结果&#xff0c;如下。 Python&#xff1a; import …