目录

  • demo(cfg)
    • run_demo(cfg, frame_provider)
      • class VideoManager
      • model.put(task)
        • Predictor.__init__(self, cfg, gpu_id=None)
          • build_model(cfg, gpu_id=None)
          • Registry用法小结(在不确定选择哪个类时使用)
          • cu.load_test_checkpoint(cfg, self.model)
        • Predictor.__call__(self, task)
      • model.get(task)
  • demo(cfg):

demo(cfg)

       if cfg.DEMO.THREAD_ENABLE:frame_provider = ThreadVideoManager(cfg)else:frame_provider = VideoManager(cfg)for task in tqdm.tqdm(run_demo(cfg, frame_provider)):   # tqdm在长循环中添加一个进度提示信息 参数为一个迭代器frame_provider.display(task)

cfg.DETECTION.ENABLE==False and cfg.DEMO.PREDS_BOXES == “” 进入else
cfg.DEMO.THREAD_ENABLE=False 创建一个VideoManager对象(frame_provider),其初始化中根据输入视频地址获取了视频参数并设置了输出结果视频的相关参数。其中宽、高、FPS采用输入视频的值(cfg中未给出),裁剪大小等使用cfg设置值。

run_demo(cfg, frame_provider)

run_demo为一个迭代器,yield task
首先设置种子、日志,打印日志

video_vis = VideoVisualizer(参数省略)
async_vis = AsyncVis(video_vis, n_workers=cfg.DEMO.NUM_VIS_INSTANCES)
if cfg.NUM_GPUS <= 1:model = ActionPredictor(cfg=cfg, async_vis=async_vis)
else:model = AsyncDemo(cfg=cfg, async_vis=async_vis)seq_len = cfg.DATA.NUM_FRAMES * cfg.DATA.SAMPLING_RATE  # 序列长度seq_len=帧数16*采样率5=80
  • 创建VideoVisualizer对象(video_vis),根据cfg初始化属性值
  • 创建AsyncVis对象(async_vis),其成员主要包括两个mp.Queue()和包含cpu个数个_VisWorker对象(工作进程)的列表procs
  • 若单GPU,创建ActionPredictor(model),其成员包括一个Predictor对象(predictor)和AsyncVis对象(async_vis);
  • 若多GPU,创建AsyncDemo(model),其成员包括一个AsycnActionPredictor对象和AsyncVis对象(async_vis)
    • AsycnActionPredictor对象的成员主要包括两个mp.Queue()和包含gpu个数个_Predictor对象的列表procs。(类似AsyncVis)
    • _Predictor对象的run方法中创建Predictor对象

回到run_demo函数体中:
设置序列长度seq_len=帧数16*采样率5=80
然后从frame_provider中获取task,依次跳入VideoManager的__iter__(self)方法和__next__(self)方法

for able_to_read, task in frame_provider:

class VideoManager

class VideoManager:def __iter__(self):return selfdef __next__(self):self.id += 1    # 每次迭代id+1task = TaskInfo()task.img_height = self.display_height......frames = []if len(self.buffer) != 0:frames = self.bufferwas_read = Truewhile was_read and len(frames) < self.seq_length:   #读入self.seq_length长度的帧到frames列表中,每帧为(720,1280,3)(读入测试视频大小)的ndarraywas_read, frame = self.cap.read()   # self.cap为cv2.VideoCapture对象。frames.append(frame)if was_read and self.buffer_size != 0:self.buffer = frames[-self.buffer_size :]task.add_frames(self.id, frames)task.num_buffer_frames = 0 if self.id == 0 else self.buffer_sizereturn was_read, task #若读取的帧不足seq_length,则was_read为False
  • task为封装了一些数据成员的TaskInfo类,表示每次处理的一个视频剪辑。成员包括frames,id,bboxes,action_preds,num_buffer_frames,img_height,img_width,crop_size,clip_vis_size。
  • 使用自身的一些成员值为task成员赋值
  • 每次读取self.seq_length长度的帧到frames列表,用作输入,更新task.frames和task.num_buffer_frames
  • 返回was_read,task 。若读取的帧不足seq_length,则was_read为False

再回到run_demo函数体中

    for able_to_read, task in frame_provider:if not able_to_read:breakif task is None:time.sleep(0.02)continuenum_task += 1model.put(task)try:task = model.get()num_task -= 1yield taskexcept IndexError:continue# 若在前面的每次循环中有没成功yield的,则再循环get,再yieldwhile num_task != 0:    ......

循环中每次得到的task首先put进model,再从model中get,最后yield。若有没成功yield的,则再循环get,再yield。主要函数为model.put(task)和model.get()

model.put(task)

当model为单GPU时的ActionPredictor对象

class ActionPredictor:def put(self, task):"""Make prediction and put the results in `async_vis` task queue."""task = self.predictor(task) # 处理输入数据(每个task的帧序列),输入到模型,得到X类的得分值self.async_vis.get_indices_ls.append(task.id)self.async_vis.put(task)    # 加入到async_vis的task_queue(多进程队列)中

首先调用predictor.py中的Predictor对象的__call__方法, 处理输入数据(每个task的帧序列),输入到模型得到X类的得分值。另外将task.id和task分别加入到self.async_vis中。
下面细看predictor对象(Predictor类对象)

Predictor.init(self, cfg, gpu_id=None)
class Predictor:def __init__(self, cfg, gpu_id=None):if cfg.NUM_GPUS:self.gpu_id = (torch.cuda.current_device() if gpu_id is None else gpu_id)# Build the video model and print model statistics.self.model = build_model(cfg, gpu_id=gpu_id)self.model.eval()self.cfg = cfgif cfg.DETECTION.ENABLE:self.object_detector = Detectron2Predictor(cfg, gpu_id=self.gpu_id)logger.info("Start loading model weights.")cu.load_test_checkpoint(cfg, self.model)logger.info("Finish loading model weights")

其中主要有build_model和load_test_checkpoint两个重要函数
build_model函数在slowfast/models/build.py/build_model

build_model(cfg, gpu_id=None)
def build_model(cfg, gpu_id=None):......# Construct the modelname = cfg.MODEL.MODEL_NAMEmodel = MODEL_REGISTRY.get(name)(cfg)......return model

前后省略部分为关于gpu的判断和设置
model = MODEL_REGISTRY.get(name)(cfg) 根据cfg.MODEL.MODEL_NAME构建相应模型类的对象 类定义在slowfast/models/video_model_builder.py中 类名只有SlowFast、ResNet、X3D。 在构建过程中会根据cfg.MODEL.ARCH(包含c2d、c2d_nopool、i3d、i3d_nopool、slow、slowfast、x3d) 设定核的尺寸。

Registry用法小结(在不确定选择哪个类时使用)
from fvcore.common.registry import Registry
XXX_REGISTRY = Registry("XXX")
XXX_REGISTRY.__doc__ = """
#然后在类定义的上一行添加“@XXX_REGISTRY.register()”
@XXX_REGISTRY.register()
class X3D(nn.Module):pass
@XXX_REGISTRY.register()
class ResNet(nn.Module)pass
# 通过XXX_REGISTRY.get(name)方法,返回相应的类(的构造函数)
model=XXX_REGISTRY.get('X3D')('''类构造函数参数''')
cu.load_test_checkpoint(cfg, self.model)

加载模型参数:
首先检查cfg.TEST.CHECKPOINT_FILE_PATH,若为"",即没给出测试用checkpoint的地址, 则检查cfg.OUTPUT_DIR路径下的checkpoints文件夹中有无checkpoint(即自己训练产生的)。 若仍无,则检查cfg.TRAIN.CHECKPOINT_FILE_PATH

Predictor.call(self, task)
class Predictor:def __call__(self, task):......frames, bboxes = task.frames, task.bboxes......# 以TEST_CROP_SIZE:356作为短边长度,将每帧数据缩放# frames从(720,1280,3)的数组列表变为(356,632,3)的数组列表frames = [cv2_transform.scale(self.cfg.DATA.TEST_CROP_SIZE, frame)    # TEST_CROP_SIZE:356for frame in frames]# 数据预处理:归一化、标准化、调整维度、选择cfg.DATA.NUM_FRAMES帧、放入列表、增加维度inputs = process_cv2_inputs(frames, self.cfg)   # [(1,3,16,356,632)]......preds = self.model(inputs, bboxes)  # 得到该片段 属于各类别的得分值.....task.add_action_preds(preds)    # 将预测得分作为task的一项属性值.....return task

先提取出task中的数据做了预处理,包括从中采样出cfg.DATA.NUM_FRAMES个帧
因为task中总帧数为cfg.DATA.NUM_FRAMES * cfg.DATA.SAMPLING_RATE,所以采样cfg.DATA.NUM_FRAMES个帧,采样率即为cfg.DATA.SAMPLING_RATE。
经过模型得到该片段属于各类别的得分值,并将得分添加为task的一项属性值。

当model为多GPU时的AsyncDemo对象,最终同样是调用Predictor对象的__call__方法

model.get(task)

pass

demo(cfg):

        for task in tqdm.tqdm(run_demo(cfg, frame_provider)):   # tqdm在长循环中添加一个进度提示信息 参数为一个迭代器frame_provider.display(task)

回到demo,将run_demo()返回(yield)的一个task作为参数, 调用frame_provider.display(task),将task的frame写到指定文件(cfg.DEMO.OUTPUT_FILE)

为每一帧添加得分框的过程在Asyncis的_VisWorker的run中 调用draw_predictions -> video_vis.draw_clip_range -> self.draw_clip -> self.draw_one_frame :根据cfg.DEMO.VIS_MODE(“top-k"或"thres”)选择类别。 由于defaults.py中默认DEMO.VIS_MODE = “thres”, 而得分低于阈值,所以没有选出类别
在yaml中的DEMO下添加VIS_MODE: top-k

X3D代码理解之demo(cfg)相关推荐

  1. X3D代码理解之test(cfg)

    目录 test(cfg) construct_loader(cfg, split, is_precise_bn=False) Kinetics.__init__(self, cfg, mode, nu ...

  2. 【HSI】高光谱的数据集分类深度学习实战及代码理解

    [HSI]高光谱的数据集分类深度学习实战及代码理解 文章目录 [HSI]高光谱的数据集分类深度学习实战及代码理解 一.配置文件编写 二.高光谱图像的处理 2.1图像数据变换 2.2 数据整合 2.3 ...

  3. Reverse Attention的代码理解

    目录 前言 1. REA模块的代码实现 2. REA模块在CFF模块中的调用 3. CFF模块在OSFormer中的调用 4.疑问分析 4. 下一步计划 参考 前言 通过溯源Reverse Atten ...

  4. fishnet:论文阅读与代码理解

    fishnet:论文阅读与代码理解 一.论文概述 二.整体框架 三.代码理解 四.总结 fishnet论文地址:http://papers.nips.cc/paper/7356-fishnet-a-v ...

  5. 【软件分析】Tai-e实验代码理解与踩坑记录

    软件分析实验Tai-e代码理解与踩坑记录 A1 A2 A3 A4 实现类层次结构分析(CHA) 实现过程间常量传播 实现过程间 Worklist 求解器 A5 A6 A7 实例字段 load stor ...

  6. 【camera】自动泊车-基于深度学习的视觉车位检测项目(课程设计--训练代码、测试代码、部署demo)(2)

    **基于深度学习的点定位回归和角度预测的车位检测 基于深度学习的点定位回归和角度预测 基于深度学习的角点检测和角度回归 ** 项目下载地址:训练代码.测试代码.部署demo 数据集百度网盘下载:数据集 ...

  7. 通过汇编一个简单的C程序,分析汇编代码理解计算机是如何工作的

    实验目的: 通过反汇编一个简单的C程序,分析汇编代码理解计算机是如何工作的 实验过程: 通过vi程序进行编程: int g(int x) { return x + 3; } int f(int x) ...

  8. Self-Tuning Spectral Clustering论文阅读和代码理解

    一.代码问题 运行test_segimage.m时,存在如下错误: Building affinity matrix took 0.092672 second Error using dist2aff ...

  9. Deep Learning论文笔记之(五)CNN卷积神经网络代码理解

    Deep Learning论文笔记之(五)CNN卷积神经网络代码理解 zouxy09@qq.com http://blog.csdn.net/zouxy09          自己平时看了一些论文,但 ...

最新文章

  1. linux内核引入模块机制,Linux内核设备驱动之Linux内核模块加载机制笔记整理
  2. jQuery样式操作
  3. lua学习笔记之模式查找
  4. 51nod 1414 冰雕 思路:暴力模拟题
  5. find_first_of和find函数的区别
  6. GitHub下载文件时缓慢的问题
  7. centos7升级gcc到5.3.0
  8. linux system V IPC 信号灯和共享内存实例
  9. 用WPF实现在ListView中的鼠标悬停Tooltip显示
  10. Linux进程间通信——消息队列
  11. webview 禁用横竖屏切换_X5内核WebView横屏切换崩溃
  12. 【Linux_Fedora_应用系列】_1_如何安装音乐播放器和mp3解码
  13. uniapp实现签名板效果
  14. 多加速器驱动AGX的目标检测与车道分割
  15. docker以外的构建、运行、管理和分发容器候选项
  16. 视频音频提取器推荐:快速提取视频中的音频!
  17. 微信小程序第三方登录
  18. 计算机应用基础小结,计算机应用基础教学小结
  19. 【python】plt.cm.Spectral,颜色分配
  20. ensp配置基本语句

热门文章

  1. Vue:使用elementUI upload组件上传excel文件
  2. 远程网络监视(rmon)与简单网络管理协议(snmp)之间是什么关系
  3. [模板]线性递推+BM
  4. 基于JAVA中小学教师培训管理系统计算机毕业设计源码+系统+数据库+lw文档+部署
  5. xxxiNetxxxxx2
  6. 一键绕过App签名验证
  7. pyaudio usb playback_「APPSO」苹果还会为 iPhone 换上 USB-C 吗?
  8. 数据清理、转换、合并、重塑
  9. win10+1060+tensorflow-gpu安装过程
  10. 【数据结构】单链表的实现