Pseudo-3D Residual Networks算法的pytorch代码

这篇博客介绍了Pseudo-3D Residual Networks的pytorch实现,包括模型结构、数据处理和代码调试过程。文章以P3D199模型为例,详细解释了网络的构建,如P3D类、Bottleneck类的使用,以及如何利用预训练模型。并提供了代码地址供读者参考。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本篇博客是对第三方实现的Pseudo-3D Residual Networks算法的pytorch代码进行介绍,介绍顺序为代码调试顺序,建议先阅读论文或相关博客。
论文:Learning Spatio-Temporal Representation with Pseudo-3D Residual Networks。
代码地址:https://github.com/qijiezhao/pseudo-3d-pytorch

导入必须的模块

from __future__ import print_function
import torch
import torch.nn as nn
import numpy as np
import torch.nn.functional as F
from torch.autograd import Variable
import math
from functools import partial

__all__ = ['P3D', 'P3D63', 'P3D131','P3D199']

main函数中主要包括导入模型,准备数据,测试数据,打印结果这几个部分,其中导入模型和准备数据最重要。导入模型部分通过调用P3D199得到199层的P3D网络,另外参数pretrained=true表明导入的是预训练的模型,这样模型的参数就可以通过预训练模型的参数来初始化了,另一个参数num_classes=400是类别数。P3D199后面会详细介绍。
data=torch.autograd.Variable(torch.rand(10,3,16,160,160)).cuda()这一行是随机生成输入数据,第一个维度是10说明该输入数据包含10个clip,其中每个clip包含16帧图像,每帧图像是160*160的3通道图像。最后数据输入模型得到结果out。

if __name__ == '__main__':

    model = P3D199(pretrained=True,num_classes=400)
    model = model.cuda()

# if modality=='Flow', please change the 2nd dimension 3==>2
   data=torch.autograd.Variable(torch.rand(10,3,16,160,160)).cuda()
    out=model(data)
    print (out.size(),out)

调用P3D199函数得到199层的P3D网络。如果调用P3D63或P3D131则得到对应层数的P3D网络,不过由于P3D63和P3D131没有预训练模型,所以在实现中只有调用P3D类导入网络结构这一步。model = P3D(Bottleneck, [3, 8, 36, 3], modality=modality,**kwargs) 这一行通过调用P3D类获得网络结构,该函数的第二个参数[3, 8, 36, 3]表明其结构和ResNet-152对应,于是最后得到的就是199层的P3D网络。因为pretrained设置为True,所以pretrained_file就是准备好的预训练模型的压缩文件,通过weights=torch.load(pretrained_file)['state_dict']这一行读取预训练模型的参数,然后model.load_state_dict(weights)这一行将读取到的预训练模型的参数赋值给model这个网络结构,完成赋值。接下来介绍P3D这个类。

def P3D199(pretrained=False,modality='RGB',**kwargs):
    """construct a P3D199 model based on a ResNet-152-3D model.
    """
    model = P3D(Bottleneck, [3, 8, 36, 3], modality=modality,**kwargs)
    if pretrained==True:
        if modality=='RGB':
            pretrained_file='p3d_rgb_199.checkpoint.pth.tar'
        elif modality=='Flow':
            pretrained_file='p3d_flow_199.checkpoint.pth.tar'
        weights=torch.load(pretrained_file)['state_dict']
        model.load_state_dict(weights)
    return model

P3D这个类是构造网络结构的主体,之前介绍过在PyTorch中定义网络结构的时候都要继承基类torch.nn.Module,这里也是这样。先看看__init__,这是因为前面调用P3D类生成对象的时候会先调用__init__进行初始化。 self.input_channel = 3 if modality=='RGB' else 2这一行表示如果输入是视频帧(也就是图像),那么输入channel就是3,如果输入是optical flow,那么输入channel就是2。self.conv1_custom是网络的第一个卷积层,原来在ResNet中是2D的7*7大小的卷积核。self.maxpool是对最后3维都做了pooling,也就是对这3维都做了减半。self.maxpool_2是对倒数第3维度做了pooling,也就是对该维度做了减半。self.layer1到self.layer4是P3D网络的4个block,这个和ResNet网络中的conv2_x到conv5_x对应,以self.layer1 = self._make_layer(block, 64, layers[0], shortcut_type)为例,通过调用P3D类的make_layer方法来得到该block的层(后面会详细介绍_make_layer方法),一般函数名前面加上表示类内部函数,或者叫私有函数。几个输入的含义如下:block是Bottleneck,layers是一个列表(长度就是block的数量,这里就是4),其中的每个值表示对应的那个block包含多少个重复的residual结构,shortcut_type是residual采取的形式,默认是’B’,指明了ResNet中residual的具体类型。self.avgpool和ResNet网络中最后的7*7的均值池化一样,只不过这里采用的是5*5,主要是因为输入帧的大小是160*160,和ResNet中224*224大小的图像不同。self.layer1和其他3个layer不同的是输入中没有stride=2,这是因为在self.layer1之前已经进行过一次pool操作了,所以这里不需要stride,这和ResNet中每个block的feature map尺寸缩减策略是一致的。for m in self.modules():这个循环是用来对构造好的网络结构进行参数初始化,这里只对卷积层和BN层进行初始化。__init__的最后三行先是指定了网络输入数据的尺寸,这里16表示16帧图像,然后指定了均值和标准差用于数据归一化。接下来介绍P3D类的_make_layer方法。

class P3D(nn.Module):

    def __init__(self, block, layers, modality='RGB',
        shortcut_type='B', num_classes=400,dropout=0.5,ST_struc=('A','B','C')):
        self.inplanes = 64
        super(P3D, self).__init__()
        # self.conv1 = nn.Conv3d(3, 64, kernel_size=7, stride=(1, 2, 
### 伪3D残差网络用于时空特征表示学习 伪3D残差网络(Pseudo-3D Residual Networks, P3D)是一种通过分解3D卷积操作来高效学习视频数据中时空特征的方法。这种方法的核心在于将复杂的3D卷积运算分为时间维度上的1D卷积和空间维度上的2D卷积,从而显著降低计算复杂度和内存需求。 #### 核心原理 传统的3D卷积可以直接捕捉视频中的时空信息,但由于其高计算成本和内存占用,难以扩展到深层网络结构。P3D网络通过引入三种不同的模块化设计——即 **Type A**, **Type B**, 和 **Type C** ——实现了对3D卷积的有效近似[^1]。这些模块分别对应于不同的时空建模策略: 1. **Type A**: 首先应用一个单独的时间卷积 (1×3×3),随后是一个标准的空间卷积 (3×1×1)。 2. **Type B**: 将时间卷积与空间卷积融合为单一的操作单元,其中时间卷积嵌入在两个空间卷积之间。 3. **Type C**: 反转顺序,首先执行空间卷积 (3×3×1),再接续时间卷积 (1×1×3)。 这种模块化的设计允许灵活调整模型的复杂性和性能表现,同时保持较低的资源开销。 #### 实现细节 为了进一步理解如何构建P3D网络,以下是其实现的关键部分: 1. **基础架构继承自ResNet** P3D网络的基础框架来源于经典的二维残差网络(ResNet)。它通过对原始ResNet层进行修改,加入额外的时间维度处理能力,形成适合视频分析的新组件。 2. **多尺度特征提取** 利用堆叠的不同类型的P3D块,可以在多个尺度上捕获丰富的动态特性。例如,在高层级上关注长期依赖关系;而在低层级则更注重局部运动模式。 3. **优化目标函数** 训练过程中通常采用交叉熵损失作为分类任务的主要指标,并可能结合其他正则项以提升泛化能力和防止过拟合。 下面展示了一段简单的PyTorch代码示例,演示如何定义基本的P3D Type B Block: ```python import torch.nn as nn class P3DBlockB(nn.Module): def __init__(self, in_channels, out_channels, kernel_size=3, stride=1, padding=1): super(P3DBlockB, self).__init__() # Spatial Convolution self.spatial_conv = nn.Conv3d(in_channels, out_channels, kernel_size=(1, kernel_size, kernel_size), stride=stride, padding=(0, padding, padding)) # Temporal Convolution self.temporal_conv = nn.Conv3d(out_channels, out_channels, kernel_size=(kernel_size, 1, 1), stride=1, padding=(padding, 0, 0)) def forward(self, x): identity = x # Apply spatial convolution first out = self.spatial_conv(x) # Followed by temporal convolution out = self.temporal_conv(out) return out + identity ``` 此代码片段展示了如何创建一个基于Type B配置的小型P3D块实例。 #### 特征可视化 文章还探讨了通过DeepDraw工具对学到的行为类别进行可视化的过程[^3]。尽管生成的结果质量有限,但它揭示了网络确实能够识别特定动作的相关视觉线索。例如,“摩托车竞赛”的案例显示出了清晰的比赛场景特征。 --- ### 总结 综上所述,伪3D残差网络提供了一种高效的解决方案,能够在减少硬件负担的同时保留强大的时空表达能力。这对于实时视频处理以及大规模数据集的应用尤为重要。
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值