Quantization of SR Methods Work Log

Time:2023.10.09-2023.11.10

Paper Reading

  1. VRT: A Video Restoration Transformer (arXiv 2022)-> VRT
    • feature: parallel computation + long-range dependency modelling + mutual attention for frame alignment
  2. BasicVSR++: Improving Video Super-Resolution with Enhanced Propagation and Alignment (CVPR 2022) -> BasicVSR++
  3. Learning Trajectory-Aware Transformer for Video Super-Resolution (CVPR 2022) -> TTVSR
  4. An Implicit Alignment for Video Super-Resolution (CVPR2023) -> IA-RT/IA-CNN
  5. Rethinking Alignment in Video Super-Resolution Transformers (NIPS2022) -> PSRT
  6. ResQ: Residual Quantization for Video Perception (ICCV 2023) -> ResQ
    • motivation: residuals exhibit a significantly lower variance than the frame activations, and can be quantized with lower error.
    • verified tasks: Human Pose Estimation/Semantic Segmentation
    • limitations:
      • requires the propagation of representations to future timesteps, leading to a memory overhead potentially impacting latency -> 对VSR任务影响小,例如BasicVSR++ 本身就是基于帧间传播的,且目前VSR对latency要求不高
      • implementing location-specific quantized operations is not trivial and requires specialized hardware or gather-scatter implementations of convolutions -> 实际部署困难问题 特定区域的量化选择 涉及稀疏处理的调度问题
      • ResQ is able to reduce the amortized cost of video processing, yet the peak BOPs is not reduced

Idea

  1. BasicVSR++ + Paddleslim 量化看结果 -> false

  2. openmmlab 的 mmagic project 内置的 BasicVSR++ + mmrazor project 进行量化 -> false

  3. BasicVSR++ + Dipoorlet PTQ -> false: ValueError: cannot reshape array of size 3628800 into shape (0,0,3,180,320) dipoorlet可能不支持动态输入

  4. BasicVSR++ + MQBench PTQ -> pending

    1. 使用mmedit构建的BasicVSR++symbolic traces时会出现报错TypeError: 'BasicVSR' object is not subscriptable, 故尝试直接通过模型的archetecturecheckpoint构建模型 -> suspend (必要性不强,工作量不小~)
    2. torch fx if symbolic trace fause: torch.fx.proxy.TraceError: symbolically traced variables cannot be used as inputs to control flow
  5. BasicVSR++ + PPL Quantization Tool(PPQ) PTQ -> inprogress

Issue Log

  1. command: whereis vs which

    1. 用途:whereis 用于查找可执行文件、源代码文件和帮助文档等。
      输出:它返回指定命令的可执行文件路径、man页面(帮助文档)路径以及源代码路径(如果可用)。
      限制:通常,whereis 不搜索PATH环境变量中指定的所有目录,而是搜索标准的系统目录。因此,它可能无法找到用户自定义安装的命令。
    2. 用途:which用于查找可执行命令的位置,通常用于查找命令是否在系统PATH中,并返回找到的第一个匹配的命令。
      输出:它会搜索PATH环境变量中指定的目录以查找命令。
      注意:which 仅返回第一个匹配的命令的路径,因此如果有多个同名命令,它只会返回一个。
  2. environment setup

    1. NvidiaDriver/CUDA/CUDNN installation
      • note: 传统上,安装 NVIDIA Driver 和 CUDA Toolkit 的步骤是分开的,但实际上现在可以直接安装 CUDA Toolkit,系统将自动安装与其版本匹配的 NVIDIA Driver。
    2. Pull docker image: torch 1.13.1
      • command: docker pull cnstark/pytorch:1.13.1-py3.9.16-cuda11.7.1-ubuntu20.04
    3. Dipoorlet dependency:
      • CUDA Toolkit == 11.8
      • CUDNN == 8.7.0
      • onnxruntime-gpu == 1.16.0
      • python == 3.8.10
      • torch == 2.0.0
    4. Ubuntu kenerl unroll (回滚)
      • sudo dpkg --get-selections | grep linux-image 查看系统已经安装的kernel
      • sudo apt-get remove linux-image-x.x.x-xx-generic 卸载目前的kernel
      • sudo update-grub 更新开机引导程序 ps: GRUB(GRand Unified Bootloader)是一个用于管理计算机开机引导过程的引导加载程序,支持引导多操作系统 windows/linux发行版/BSD
      • sudo reboot 重启系统
      • uname -r 查看当前kernel是否已经完成回滚
      • sudo apt-mark hold/unhold linux-image-5.4.0-xx-generic 设置 hold 参数保持当前kernel不更新, 设置 unhold 解除更新限制
  3. command: pip install -U package 命令中的 -U 参数表示升级(update)已安装的 Python package到最新版本。

  4. confusion: PTQ static vs dynamic

    1. PTQ static
      • 使用校准数据集离线计算缩放因子(Scale)和零点(Zero Point)
      • 所有激活(Activation)都使用相同的缩放因子和零点
    2. PTQ dynamic
      • 缩放因子(Scale)和零点(Zero Point)是在推理时计算的,并且特定用于每次的激活(Activation)
      • 因此它们更准确,但引入了额外的计算开销
  5. confusion: BI degradation vs BD degradation

    1. BI -> bicubic-down,降质过程仅包含双三次下采样
    2. BD -> blur-down,通过高斯模糊下采样
  6. confusion: argparse library

    1. basic: parser = argparse.ArgumetParser(description, epilog) -> 创建 ArgumentParser 对象,其中 description 是一个简要的程序描述,epilog 是一个在帮助信息的结尾显示的额外文本
    2. basic: add_argument(name or flags, ...) -> 添加命令行参数(xxx: positional argument or --xxx: option that takes a value)。name or flags 参数可以是单个选项(例如 ‘-f’),也可以是多个选项(例如 ‘-f’, ‘–file’)。你可以使用许多其他关键字参数来配置参数的行为,如 type、default、help 等,示例如下
      • 整数类型参数: parser.add_argument('--count', type=int, help='An integer value')
      • 浮点类型参数: parser.add_argument('--rate', type=float, help='A floating-point value')
      • 字符串类型参数: parser.add_argument('--name', type=str, help='A string value')
      • 布尔类型参数: parser.add_argument('--verbose', action='store_true', help='Enable verbose mode')
      • 文件路径参数: parser.add_argument('--file', type=argparse.FileType('r'), help='A file path')
      • 目录路径参数: parser.add_argument('--directory', type=str, help='A directory path')
      • note: 很奇怪的点在于关键字参数--xx_x中使用_传入参数时会出现error: unrecognized arguments: --xx_x,故用-代替
    3. basic: parse_args(): 解析命令行参数,并返回一个包含所有参数值的命名空间对象
    4. extension: add_subparsers() -> 添加子命令解析器,允许你为你的程序创建子命令(类似于 git 命令的子命令,如 git clone、git commit 等)
    5. extension: set_defaults() -> 为参数设置默认值
    6. extension: add_argument_group() -> 将参数分组到一个组中,用于更好地组织帮助信息
    7. extension: format_help() -> 生成帮助信息
    8. extension: error(msg) -> 在参数解析过程中发生错误时触发错误消息
  7. confusion: {:08d}.png 字符串格式化模板

    1. {}: 这是一个占位符,用于表示将要插入的值。在这个模板中,{} 用来表示一个整数
    2. :08d: 这是格式说明符,指定了如何格式化这个整数。其中:
      • 0 表示要用零来填充空白位置
      • 8 表示总共要占用 8 个字符的宽度,包括填充的零和数字本身
      • d 表示要格式化的值是一个十进制整数
  8. confusion: function os.path.splitext()

    1. input: 文件路径(或文件名)
    2. return: 一个包含两个部分的元组tuple i.e. (文件名, 文件扩展名)
  9. confusion: print(model) 实现

    1. print(model) # 当你使用 print 函数来打印一个对象时,它会尝试调用该对象的 __str__()__repr__() 方法来获取一个可打印的字符串表示
      • model.__repr__ 输出model的属性__repr__ i.e. 方法的名称 -> <bound method Module.__repr__ of xxx>
      • model.__repr__() 输出model的method__repr__() i.e. 方法的调用 的结果 -> xxx
      • note: 属性是对象的数据成员,而方法是对象上的函数成员,用于定义对象的行为。实际上,方法是对象上的可调用属性
  10. confusion: glob.glob(os.path.join(img_dir, '*'))

    1. import osos.path.join(img_dir, '*') 返回值 'img_dir/*'类型为 str -> type(os.path.join(img_dir, '*')) == <class 'str'>
    2. import globglob.glob(os.path.join(img_dir, '*')) 返回值为指定路径下的文件列表 -> type(glob.glob(os.path.join(img_dir, '*'))) == <class 'list'>
  11. confusion: img_dir_split = re.split(r'[\\/]', img_dir) 这行代码使用正则表达式来分割文件路径

    1. 具体来讲首先import re # re(regular expression) 是 python 中的正则表达式模块 , r’[\/]’ 表示一个正则表达式的字符集, 它匹配一个正斜杠 / 或反斜杠 \ 中的任何一个字符, ‘\‘ 用于转义字符。这在处理文件路径时很有用,因为不同的操作系统使用不同的路径分隔符,有些使用正斜杠 /,而有些使用反斜杠 \。使用 [\/] 可以在跨平台的情况下匹配路径中的分隔符,而不必担心操作系统差异
    2. img_dir_split = re.split(r'[\\/]', img_dir) 它会将指定的文件路径 img_dir 按照正斜杠 / 或反斜杠 \ 进行分割,并将分割的部分存储在一个列表中。返回值为由文件路径名各部分(str)组成的list -> 例如 img_dir_split == [‘data’, ‘demo_000’]
  12. confusion: img_dir_split[:-1]

    1. img_dir_split[:-1] 是 Python 中的列表切片(slicing)操作,它用于获取列表 img_dir_split 中的一部分元素
    2. 具体来说,[:-1] 表示切片从列表的开头到倒数第二个元素(不包括倒数第一个元素)。这个操作会返回一个新的列表,包含了 img_dir_split 中从第一个元素到倒数第二个元素(不包括倒数第一个元素)的所有元素
  13. confusion: lq_folder = reduce(os.path.join, img_dir_split[:-1])

    1. from functools import reduce 导入包reduce,它用于将一个二元函数应用于可迭代的元素,从左到右依次累积结果
    2. 上述代码的目的是将 img_dir_split 列表切片后的元素 i.e. img_dir_split[:-1]通过操作系统路径连接起来,然后返回连接后的结果。
  14. confusion: assert isinstance(transforms, Sequence)

    1. from collections.abc import Sequence Sequence是在Python中的抽象基类,用于定义一组通用的接口和方法,而不是具体的实现。Sequence它表示序列类型,如列表、元组、字符串等。
    2. assert isinstance(transforms, Sequence)这种检查可以用于确保transforms具有序列类型的行为,以便在代码中安全地使用类似列表或元组的操作。
  15. confusion: @PIPELINES.register_module()

    1. from ..registry import PIPELINES: 从相对于当前模块的上一级目录中的 registry 模块中导入名为 PIPELINES 的对象
    2. @PIPELINES.register_module()的作用是将被装饰的函数或类注册到名为 PIPELINES 的模块或类的注册表中。这通常在Python中用于实现插件或扩展性架构,以便在运行时动态添加和管理功能。
  16. confusion: dict类实例化后的对象object如何访问

    1. 在Python中,字典的键和值是通过方括号[]来访问的(如data["meta"], data为dict类的实例, meta 是其中一个key),而不是通过点.来访问
    2. 在Python中,可以使用点号 .来访问以下类型的成员或属性
      • 类的成员(类变量和类方法): MyClass.my_class_variable 或 MyClass.my_class_method()
      • 实例对象的属性和方法: my_object.my_instance_variable 或 my_object.my_instance_method()
      • 模块的函数和变量:math.sqrt()
      • 实例化后的内置类:my_string.upper(),其中 upper() 是字符串(str)对象的一个方法
  17. confusion: python func range() 生成有序的整数序列

    1. range(stop): start(可选):序列的起始值,默认为 0
    2. range(start, stop): stop(必需):序列的结束值,但不包括该值。range() 会生成从 start 到 stop-1 的整数序列
    3. range(start, stop, step): step(可选):可选参数,控制序列中的值之间的步长,默认为 1, e.g. list(range(0, 21, 5)) == [0, 5, 10, 15, 20]
  18. confusion: python slicing operation

    1. 假设data为一维list或str, data[start:end] 选取范围 start -> end-1, step == 1; 若start未指定,则默认为0; 若end未指定,则默认选取到最后一个元素(包含最后一个元素)
    2. 假设data为多维NumPy array, data[:, start:end:step] 选取 dim==0 所有元素, 选取 dim==1 的 start -> end-1, step==step的元素
    3. 假设data为一维list或str, data[-5:] 选取从倒数第5个元素直至末尾最后一个元素,最后一个元素index为-1
  19. command: find . -name "*.tar" | while read NAME ; do mkdir -p "${NAME%.tar}"; tar -xvf "${NAME}" -C "${NAME%.tar}"; rm -f "${NAME}"; done recursively unzip files

    1. find . -name "*.tar": 这部分使用 find 命令来在当前目录及其子目录中查找文件名匹配 *.tar 的文件
    2. |: 这是管道符号,它将 find 命令的输出(即找到的所有 .tar文件的路径列表)传递给管道符号右侧的命令
    3. while read NAME: 这部分创建一个 while 循环,它将逐行读取管道传入的文件路径,并将每行内容赋值给 NAME 变量
    4. do: 这标志着 while 循环的开始
    5. mkdir -p "${NAME%.tar}": 这是在循环中的第一个命令。它使用 mkdir 命令创建目录,并且 -p no error if existing, make parent directories as needed. ${NAME%.tar} 是一种变量扩展,它会从 NAME 变量的值中删除 .tar扩展名,然后创建一个对应的目录
    6. tar -xvf "${NAME}" -C "${NAME%.tar}": 这是在循环中的第二个命令。它使用 tar 命令来解压缩 NAME变量中指定的 .tar文件,并将解压后的文件放入对应的目录 ${NAME%.tar}, note: 参数说明 -C, --directory=DIR change to directory DIR 用于指定解压缩操作的目标目录
    7. rm -f "${NAME}": 这是在循环中的第三个命令。它使用 rm 命令删除原始的 .tar 文件。-f 选项表示不会询问确认
    8. done: 这标志着 while 循环的结束
  20. command: python -c "Python code to execute"

    1. -c 参数是 Python 解释器的一个命令行选项,它允许你在命令行中执行一段 Python 代码,而不必编写一个独立的 Python 脚本文件。
  21. confusion: dict(xx=yy) 和 dict = {'xx': yy}异同

    1. dict(xx=yy)dict = {'xx': yy} 构造出来的字典在本质上是相同的
    2. dict(xx=yy) 的语法是一种关键字参数的方式,其中 xx 是键,yy 是值。这种方式适用于在函数调用中将多个键值对传递给函数,而不需要明确创建字典对象
    3. dict = {'xx': yy} 是显式创建一个字典的方式,其中 'xx' 是键,yy 是值。这种方式更适用于创建独立的字典对象,以便在程序中进行操作和访问
  22. confusion: from easydict import EasyDict 作用: 可以像访问属性一样访问字典的值value, 而不必使用my_dict['key']

  23. confusion: aptdpkg

    1. dpkg 和 apt 是在 Debian 及其衍生发行版(如 Ubuntu)中用于软件包管理的两个重要工具,它们之间存在密切的关系,但有不同的职责。
      • dpkg(Debian Package): dpkg 是底层的软件包管理工具,用于安装、卸载和管理 Debian 系统上的软件包。它直接处理软件包的安装和卸载,以及配置文件的处理。dpkg 可以从本地 .deb 文件安装软件包,也可以从软件源下载并安装软件包。
      • apt(Advanced Package Tool): apt 是一个高级的软件包管理工具,建立在 dpkg 之上,提供更高级的功能。apt 可以自动解决软件包之间的依赖关系,并处理升级、安装、卸载等操作。它使用软件源(repositories)来获取软件包信息,并允许用户方便地搜索、安装和更新软件。
      • 简而言之,dpkg 是更基础的工具,直接负责软件包的安装和卸载,而 apt 提供了更高级、用户友好的接口,使软件包管理更加方便,它处理了更多的任务,包括依赖解决、更新软件源、搜索软件包等。
  24. confusion: SIMD MIMD SIMT

    1. SIMD: SIMD 是指单指令流多数据流(Single Instruction, Multiple Data)的计算模式。在计算机体系结构中,SIMD 是一种并行计算的方式,它允许同时对多个数据执行相同的操作,以提高并行计算的效率。
    2. SIMT: 类似于 SIMD,SIMT 是 NVIDIA GPU 中一种并行计算模式,它允许执行单一指令在多个线程上。
    3. MIMD: MIMD(Multiple Instruction, Multiple Data): 在 MIMD 模式中,多个处理单元同时执行不同的指令,处理不同的数据。每个处理单元都有自己的指令流和数据流,可以独立运行。MIMD 适用于处理多个独立的任务,每个任务可能需要不同的指令序列。
  25. confusion: GCC编译器 Make CMake Makefile CMakeLists.txt 区别

    • GCC 编译器:
      1. 作用: 将高级语言源代码编译成机器码或可执行文件。
      2. 使用场景: 用于直接编译源代码,生成可执行文件。
    • Make:
      1. 作用: 构建工具,根据 Makefile 中定义的规则和依赖关系来管理和调度项目(调用GCC编译器)的构建过程。
      2. 使用场景: 用于自动化构建过程,确保只有发生更改的文件被重新编译。
    • Makefile:
      1. 作用: 文本文件,包含项目的构建规则、依赖关系和编译动作。
      2. 使用场景: Make 工具根据 Makefile 中的规则来判断哪些文件需要重新构建,然后调用适当的编译器。
    • CMake:
      1. 作用: 生成用于不同构建系统的构建配置文件,如 Makefile。
      2. 使用场景: 提供跨平台的构建配置,允许开发者在不同的构建系统上使用相同的配置。
      3. makefile在一些简单的工程完全可以人工手下,但是当工程非常大的时候,手写makefile也是非常麻烦的,如果换了个平台makefile又要重新修改。这时候就出现了Cmake这个工具,cmake就可以更加简单的生成makefile文件给上面那个make用。当然cmake还有其他功能,就是可以跨平台生成对应平台能用的makefile,你不用再自己去修改了
    • CMakeLists.txt:
      1. 作用: 文本文件,包含 CMake 的配置和项目信息。
      2. 使用场景: CMake 使用 CMakeLists.txt 来生成项目的构建配置文件,其中定义了项目的结构、依赖关系和编译选项。
      3. cmake根据什么生成makefile呢?它又要根据一个叫CMakeLists.txt文件(学名:组态档)去生成makefile。 CMakeLists.txt文件谁写啊?亲,是你自己手写的。
    • 总结:
      GCC 编译器是用于将源代码编译为机器码的工具。
      Make 是一个构建工具,使用 Makefile 来自动管理项目的构建过程。
      CMake 是一个用于生成跨平台构建配置的工具,可以生成 Makefile 或其他构建系统的配置文件。
      Makefile 包含构建项目所需的规则和命令,由 Make 工具读取执行。
      CMakeLists.txt 包含项目的配置信息和结构,由 CMake 解析生成构建配置。
  26. confusion: ssh 添加 public_key 至目标远程主机实现无需密码登录

    • 本地host ssh-keygen -t rsa -b 4096 -C "your_email@example.com
      1. -t rsa: 指定密钥类型为 RSA。
      2. -b 4096: 指定密钥的位数,4096 位是一种常见的安全选择。
      3. -C “your_email@example.com“: 在生成的密钥中添加注释,通常使用你的电子邮件地址。
    • 将生成的ssh public key (id_rsa.pub) 复制到远程target 的 ~/.ssh/authorized_keys (如果没有则自建此文件)中即可
  27. confusion: chmod mode file 中的 mode 含义 -> 用每个分组读写操作权限用3bit表示, 从左到右依次是 rwx

    • 示例: drwxr--r-- : d 代表 directory 目录, 所有者(user)拥有权限 read write 没有 execute,用数字表示为 6 = 4 + 2 + 0 ,群组(group)和其他(others)只有权限 read, 数字表示为 4 = 4 + 0 + 0, 综上此文件的 mode 为 644
  28. confusion: ubuntu 除用 ifconfig 查看本机ip之外,还可以用 ip addr (较新的ubuntu默认安装了 ip 命令), 一般前者失效时后者有效,不用再安装 net-tools

  29. confusion: register_buffer()

    • register_buffer 是 PyTorch 中 nn.Module 类提供的一个方法,用于注册一个缓冲张量。这个缓冲张量不会被视为模型的参数,但会被包含在模型的状态中,并在模型的 state_dict 中保存。这通常用于存储不需要优化的固定参数,比如在模型中使用的常数或预先计算好的张量。
  30. confusion: Slurm(Simple Linux Utility for Resource Management)作业调度系统

  31. confusion: github 克隆别人的仓库,修改更新后如何推送到自己的 github 账户下

    • 新建 github 上我的空repo, 可以不需要 readme.md 和 license, 因为克隆别人仓库一般都有

    • clone github 上他人仓库,重命名仓库文件夹名称使之与github上我的repo同名

    • git remote 设定远端repo是我的github新建的repo git remote set-url origin https://github.com/kyrie2to11/gptq_test.git

    • 修改本地仓库文件后,推送到远端github repo

      1
      2
      3
      4
      git status # 查看本地仓库哪些文件被修改了
      git add . # 把修改的文件放入staging area,准备commit
      git commit -m "commit remark message" # 本地仓库正式commit更改
      git push origin main # 将本地修改同步到github repo
  32. confusion: 更改ubuntu root密码 sudo passwd 或者 sudo passwd root

  33. confusion: python 切片 slicing 语法 [start:stop:step]

    1
    2
    3
    start:起始位置的索引。
    stop:终止位置的索引(不包含在切片内)。
    step:步长,表示每次移动的距离。

    如果不指定这些值,默认值为:

    1
    2
    3
    start 默认为第一个元素(索引 0)。
    stop 默认为最后一个元素的下一个位置(即列表的长度)。
    step 默认为 1。

    当你使用 [::-1] 时,两个冒号 : 表示没有指定 start 和 stop,因此默认取整个序列。而 -1 作为步长表示从最后一个元素开始,以步长为 1 的方向逐步向前取值,实现反向取值。

  34. results_list = self.get_bboxes(*outs, img_metas=img_metas, rescale=rescale)*outs的作用

    • 在这个上下文中,*outs 是一种使用在函数调用中的语法,它表示将一个可迭代对象(比如列表或元组)中的元素分别传递给函数作为独立的参数。这个语法称为“拆包”(unpacking)。
    • 具体到你的代码中,outs 可能是一个包含多个元素的可迭代对象(比如元组),而 self.get_bboxes 函数的参数需要这些元素作为独立的参数传递进去。使用 *outs 就能够方便地将 outs 中的元素拆包传递给函数。
    • 这种方式在函数参数数量不确定,或者希望通过一个可迭代对象传递参数时非常有用。在这里,*outs 将 outs 中的内容展开,作为 self.get_bboxes 函数的独立参数传递给函数。

Metrics(Full-Reference)

  1. Peak Signal to Noise Ratio (PSNR)
  2. Structural SIMilarity (SSIM)

Milestone

Model Description Dataset Val PSNR Val SSIM Params Runtime on oneplus7T [ms] FLOPs [G]
VapSR_4_1 Functional VapSR_4 with pixel norm realized by layer normalization, VAB activation: RELU, Attention using Partial conv REDS 27.790268 0.77721727 59,468 654.0 (INT8_CPU) 7.462
SWAT_0 Sliding Window, VAB Attention, Partial Conv, Channel Shuffle(mix_ratio=4) REDS 27.842232 0.77754354 50,624 271.0 (FP16_CPU) 5.803

AI benchmark setting for Runtime test:

  • Input Values range(min,max): 0,255
  • Inference Mode: INT8/FP16
  • Acceleration: CPU/TFLite GPU Delegate

Benchmark

Rank Model Source Dataset Test PSNR Test SSIM Params Runtime on oneplus7T [ms]
1 Diggers Real-Time Video Super-Resolution based on Bidirectional RNNs(2021 SOTA) REDS(train_videos: 240, test_videos: 30) 27.98 - 39,640 -
2 VSR_12 Ours REDS(train_videos: 240, test_videos: 30) 27.981062 0.7824855 57,696 62.8

PaperWriting

No.1

  1. BSConvU as shallow feature extraction

PaperReference

  1. Rethinking Alignment in Video Super-Resolution Transformers(NIPS 2022) -> VIT 视频超分(VSR)中帧/特征对齐不是必要操作