Quantization of SR Methods Work Log
Time:2023.10.09-2023.11.10
Paper Reading
- VRT: A Video Restoration Transformer (arXiv 2022)->
VRT- feature: parallel computation + long-range dependency modelling + mutual attention for frame alignment
- BasicVSR++: Improving Video Super-Resolution with Enhanced Propagation and Alignment (CVPR 2022) ->
BasicVSR++ - Learning Trajectory-Aware Transformer for Video Super-Resolution (CVPR 2022) ->
TTVSR - An Implicit Alignment for Video Super-Resolution (CVPR2023) ->
IA-RT/IA-CNN - Rethinking Alignment in Video Super-Resolution Transformers (NIPS2022) ->
PSRT - 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
BasicVSR+++Paddleslim量化看结果 -> falseopenmmlab 的
mmagicproject 内置的BasicVSR+++mmrazorproject 进行量化 -> falseBasicVSR+++DipoorletPTQ -> false: ValueError: cannot reshape array of size 3628800 into shape (0,0,3,180,320) dipoorlet可能不支持动态输入BasicVSR+++MQBenchPTQ -> pending- 使用
mmedit构建的BasicVSR++在symbolic traces时会出现报错TypeError: 'BasicVSR' object is not subscriptable, 故尝试直接通过模型的archetecture和checkpoint构建模型 -> suspend (必要性不强,工作量不小~) - torch fx
ifsymbolic trace fause:torch.fx.proxy.TraceError: symbolically traced variables cannot be used as inputs to control flow
- 使用
BasicVSR+++PPL Quantization Tool(PPQ)PTQ -> inprogress
Issue Log
command:
whereisvswhich- 用途:
whereis用于查找可执行文件、源代码文件和帮助文档等。
输出:它返回指定命令的可执行文件路径、man页面(帮助文档)路径以及源代码路径(如果可用)。
限制:通常,whereis 不搜索PATH环境变量中指定的所有目录,而是搜索标准的系统目录。因此,它可能无法找到用户自定义安装的命令。 - 用途:
which用于查找可执行命令的位置,通常用于查找命令是否在系统PATH中,并返回找到的第一个匹配的命令。
输出:它会搜索PATH环境变量中指定的目录以查找命令。
注意:which 仅返回第一个匹配的命令的路径,因此如果有多个同名命令,它只会返回一个。
- 用途:
environment setup
- NvidiaDriver/CUDA/CUDNN installation
- note: 传统上,安装 NVIDIA Driver 和 CUDA Toolkit 的步骤是分开的,但实际上现在可以直接安装 CUDA Toolkit,系统将自动安装与其版本匹配的 NVIDIA Driver。
- Pull docker image: torch 1.13.1
- command:
docker pull cnstark/pytorch:1.13.1-py3.9.16-cuda11.7.1-ubuntu20.04
- command:
- Dipoorlet dependency:
- CUDA Toolkit == 11.8
- CUDNN == 8.7.0
- onnxruntime-gpu == 1.16.0
- python == 3.8.10
- torch == 2.0.0
- Ubuntu kenerl unroll (回滚)
sudo dpkg --get-selections | grep linux-image查看系统已经安装的kernelsudo apt-get remove linux-image-x.x.x-xx-generic卸载目前的kernelsudo update-grub更新开机引导程序 ps: GRUB(GRand Unified Bootloader)是一个用于管理计算机开机引导过程的引导加载程序,支持引导多操作系统 windows/linux发行版/BSDsudo reboot重启系统uname -r查看当前kernel是否已经完成回滚sudo apt-mark hold/unhold linux-image-5.4.0-xx-generic设置 hold 参数保持当前kernel不更新, 设置 unhold 解除更新限制
- NvidiaDriver/CUDA/CUDNN installation
command:
pip install -U package命令中的-U参数表示升级(update)已安装的 Python package到最新版本。confusion: PTQ static vs dynamic
- PTQ static
- 使用校准数据集离线计算缩放因子(Scale)和零点(Zero Point)
- 所有激活(Activation)都使用相同的缩放因子和零点
- PTQ dynamic
- 缩放因子(Scale)和零点(Zero Point)是在推理时计算的,并且特定用于每次的激活(Activation)
- 因此它们更准确,但引入了额外的计算开销
- PTQ static
confusion: BI degradation vs BD degradation
- BI -> bicubic-down,降质过程仅包含双三次下采样
- BD -> blur-down,通过高斯模糊下采样
confusion: argparse library
- basic:
parser = argparse.ArgumetParser(description, epilog)-> 创建 ArgumentParser 对象,其中 description 是一个简要的程序描述,epilog 是一个在帮助信息的结尾显示的额外文本 - 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,故用-代替
- 整数类型参数:
- basic:
parse_args(): 解析命令行参数,并返回一个包含所有参数值的命名空间对象 - extension:
add_subparsers()-> 添加子命令解析器,允许你为你的程序创建子命令(类似于 git 命令的子命令,如 git clone、git commit 等) - extension:
set_defaults()-> 为参数设置默认值 - extension:
add_argument_group()-> 将参数分组到一个组中,用于更好地组织帮助信息 - extension:
format_help()-> 生成帮助信息 - extension:
error(msg)-> 在参数解析过程中发生错误时触发错误消息
- basic:
confusion:
{:08d}.png字符串格式化模板{}: 这是一个占位符,用于表示将要插入的值。在这个模板中,{} 用来表示一个整数:08d: 这是格式说明符,指定了如何格式化这个整数。其中:0表示要用零来填充空白位置8表示总共要占用 8 个字符的宽度,包括填充的零和数字本身d表示要格式化的值是一个十进制整数
confusion: function
os.path.splitext()- input: 文件路径(或文件名)
- return: 一个包含两个部分的元组tuple i.e. (文件名, 文件扩展名)
confusion: print(model) 实现
- 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: 属性是对象的数据成员,而方法是对象上的函数成员,用于定义对象的行为。实际上,方法是对象上的可调用属性
- print(model) # 当你使用 print 函数来打印一个对象时,它会尝试调用该对象的
confusion:
glob.glob(os.path.join(img_dir, '*'))import os后os.path.join(img_dir, '*')返回值'img_dir/*'类型为str->type(os.path.join(img_dir, '*')) == <class 'str'>import glob后glob.glob(os.path.join(img_dir, '*'))返回值为指定路径下的文件列表 ->type(glob.glob(os.path.join(img_dir, '*'))) == <class 'list'>
confusion:
img_dir_split = re.split(r'[\\/]', img_dir)这行代码使用正则表达式来分割文件路径- 具体来讲首先
import re # re(regular expression) 是 python 中的正则表达式模块, r’[\/]’ 表示一个正则表达式的字符集, 它匹配一个正斜杠 / 或反斜杠 \ 中的任何一个字符, ‘\‘ 用于转义字符。这在处理文件路径时很有用,因为不同的操作系统使用不同的路径分隔符,有些使用正斜杠 /,而有些使用反斜杠 \。使用 [\/] 可以在跨平台的情况下匹配路径中的分隔符,而不必担心操作系统差异 img_dir_split = re.split(r'[\\/]', img_dir)它会将指定的文件路径 img_dir 按照正斜杠 / 或反斜杠 \ 进行分割,并将分割的部分存储在一个列表中。返回值为由文件路径名各部分(str)组成的list -> 例如 img_dir_split == [‘data’, ‘demo_000’]
- 具体来讲首先
confusion:
img_dir_split[:-1]- img_dir_split[:-1] 是 Python 中的列表切片(slicing)操作,它用于获取列表 img_dir_split 中的一部分元素
- 具体来说,[:-1] 表示切片从列表的开头到倒数第二个元素(不包括倒数第一个元素)。这个操作会返回一个新的列表,包含了 img_dir_split 中从第一个元素到倒数第二个元素(不包括倒数第一个元素)的所有元素
confusion:
lq_folder = reduce(os.path.join, img_dir_split[:-1])from functools import reduce导入包reduce,它用于将一个二元函数应用于可迭代的元素,从左到右依次累积结果- 上述代码的目的是将 img_dir_split 列表切片后的元素 i.e.
img_dir_split[:-1]通过操作系统路径连接起来,然后返回连接后的结果。
confusion:
assert isinstance(transforms, Sequence)from collections.abc import SequenceSequence是在Python中的抽象基类,用于定义一组通用的接口和方法,而不是具体的实现。Sequence它表示序列类型,如列表、元组、字符串等。assert isinstance(transforms, Sequence)这种检查可以用于确保transforms具有序列类型的行为,以便在代码中安全地使用类似列表或元组的操作。
confusion:
@PIPELINES.register_module()from ..registry import PIPELINES: 从相对于当前模块的上一级目录中的 registry 模块中导入名为 PIPELINES 的对象@PIPELINES.register_module()的作用是将被装饰的函数或类注册到名为 PIPELINES 的模块或类的注册表中。这通常在Python中用于实现插件或扩展性架构,以便在运行时动态添加和管理功能。
confusion:
dict类实例化后的对象object如何访问- 在Python中,字典的键和值是通过方括号
[]来访问的(如data["meta"], data为dict类的实例,meta是其中一个key),而不是通过点.来访问 - 在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)对象的一个方法
- 类的成员(类变量和类方法):
- 在Python中,字典的键和值是通过方括号
confusion: python func
range()生成有序的整数序列range(stop): start(可选):序列的起始值,默认为 0range(start, stop): stop(必需):序列的结束值,但不包括该值。range() 会生成从 start 到 stop-1 的整数序列range(start, stop, step): step(可选):可选参数,控制序列中的值之间的步长,默认为 1, e.g.list(range(0, 21, 5)) == [0, 5, 10, 15, 20]
confusion: python slicing operation
- 假设data为一维list或str,
data[start:end]选取范围 start -> end-1, step == 1; 若start未指定,则默认为0; 若end未指定,则默认选取到最后一个元素(包含最后一个元素) - 假设data为多维NumPy array,
data[:, start:end:step]选取 dim==0 所有元素, 选取 dim==1 的 start -> end-1, step==step的元素 - 假设data为一维list或str,
data[-5:]选取从倒数第5个元素直至末尾最后一个元素,最后一个元素index为-1
- 假设data为一维list或str,
command:
find . -name "*.tar" | while read NAME ; do mkdir -p "${NAME%.tar}"; tar -xvf "${NAME}" -C "${NAME%.tar}"; rm -f "${NAME}"; donerecursively unzip filesfind . -name "*.tar": 这部分使用find命令来在当前目录及其子目录中查找文件名匹配*.tar的文件|: 这是管道符号,它将find命令的输出(即找到的所有.tar文件的路径列表)传递给管道符号右侧的命令while read NAME: 这部分创建一个while循环,它将逐行读取管道传入的文件路径,并将每行内容赋值给NAME变量do: 这标志着while循环的开始mkdir -p "${NAME%.tar}": 这是在循环中的第一个命令。它使用mkdir命令创建目录,并且-pno error if existing, make parent directories as needed.${NAME%.tar}是一种变量扩展,它会从NAME变量的值中删除.tar扩展名,然后创建一个对应的目录tar -xvf "${NAME}" -C "${NAME%.tar}": 这是在循环中的第二个命令。它使用tar命令来解压缩NAME变量中指定的.tar文件,并将解压后的文件放入对应的目录${NAME%.tar}, note: 参数说明-C, --directory=DIR change to directory DIR用于指定解压缩操作的目标目录rm -f "${NAME}": 这是在循环中的第三个命令。它使用rm命令删除原始的.tar文件。-f选项表示不会询问确认done: 这标志着while循环的结束
command:
python -c "Python code to execute"-c参数是Python解释器的一个命令行选项,它允许你在命令行中执行一段Python代码,而不必编写一个独立的Python脚本文件。
confusion:
dict(xx=yy) 和 dict = {'xx': yy}异同dict(xx=yy)和dict = {'xx': yy}构造出来的字典在本质上是相同的dict(xx=yy)的语法是一种关键字参数的方式,其中xx是键,yy是值。这种方式适用于在函数调用中将多个键值对传递给函数,而不需要明确创建字典对象dict = {'xx': yy}是显式创建一个字典的方式,其中'xx'是键,yy是值。这种方式更适用于创建独立的字典对象,以便在程序中进行操作和访问
confusion:
from easydict import EasyDict作用: 可以像访问属性一样访问字典的值value, 而不必使用my_dict['key']confusion:
apt和dpkg- dpkg 和 apt 是在 Debian 及其衍生发行版(如 Ubuntu)中用于软件包管理的两个重要工具,它们之间存在密切的关系,但有不同的职责。
- dpkg(Debian Package): dpkg 是底层的软件包管理工具,用于安装、卸载和管理 Debian 系统上的软件包。它直接处理软件包的安装和卸载,以及配置文件的处理。dpkg 可以从本地 .deb 文件安装软件包,也可以从软件源下载并安装软件包。
- apt(Advanced Package Tool): apt 是一个高级的软件包管理工具,建立在 dpkg 之上,提供更高级的功能。apt 可以自动解决软件包之间的依赖关系,并处理升级、安装、卸载等操作。它使用软件源(repositories)来获取软件包信息,并允许用户方便地搜索、安装和更新软件。
- 简而言之,dpkg 是更基础的工具,直接负责软件包的安装和卸载,而 apt 提供了更高级、用户友好的接口,使软件包管理更加方便,它处理了更多的任务,包括依赖解决、更新软件源、搜索软件包等。
- dpkg 和 apt 是在 Debian 及其衍生发行版(如 Ubuntu)中用于软件包管理的两个重要工具,它们之间存在密切的关系,但有不同的职责。
confusion:
SIMDMIMDSIMTSIMD: SIMD 是指单指令流多数据流(Single Instruction, Multiple Data)的计算模式。在计算机体系结构中,SIMD 是一种并行计算的方式,它允许同时对多个数据执行相同的操作,以提高并行计算的效率。SIMT: 类似于 SIMD,SIMT 是 NVIDIA GPU 中一种并行计算模式,它允许执行单一指令在多个线程上。MIMD: MIMD(Multiple Instruction, Multiple Data): 在 MIMD 模式中,多个处理单元同时执行不同的指令,处理不同的数据。每个处理单元都有自己的指令流和数据流,可以独立运行。MIMD 适用于处理多个独立的任务,每个任务可能需要不同的指令序列。
confusion:
GCC编译器MakeCMakeMakefileCMakeLists.txt区别- GCC 编译器:
- 作用: 将高级语言源代码编译成机器码或可执行文件。
- 使用场景: 用于直接编译源代码,生成可执行文件。
- Make:
- 作用: 构建工具,根据 Makefile 中定义的规则和依赖关系来管理和调度项目(调用GCC编译器)的构建过程。
- 使用场景: 用于自动化构建过程,确保只有发生更改的文件被重新编译。
- Makefile:
- 作用: 文本文件,包含项目的构建规则、依赖关系和编译动作。
- 使用场景: Make 工具根据 Makefile 中的规则来判断哪些文件需要重新构建,然后调用适当的编译器。
- CMake:
- 作用: 生成用于不同构建系统的构建配置文件,如 Makefile。
- 使用场景: 提供跨平台的构建配置,允许开发者在不同的构建系统上使用相同的配置。
- makefile在一些简单的工程完全可以人工手下,但是当工程非常大的时候,手写makefile也是非常麻烦的,如果换了个平台makefile又要重新修改。这时候就出现了Cmake这个工具,cmake就可以更加简单的生成makefile文件给上面那个make用。当然cmake还有其他功能,就是可以跨平台生成对应平台能用的makefile,你不用再自己去修改了
- CMakeLists.txt:
- 作用: 文本文件,包含 CMake 的配置和项目信息。
- 使用场景: CMake 使用 CMakeLists.txt 来生成项目的构建配置文件,其中定义了项目的结构、依赖关系和编译选项。
- cmake根据什么生成makefile呢?它又要根据一个叫CMakeLists.txt文件(学名:组态档)去生成makefile。 CMakeLists.txt文件谁写啊?亲,是你自己手写的。
- 总结:
GCC 编译器是用于将源代码编译为机器码的工具。
Make 是一个构建工具,使用 Makefile 来自动管理项目的构建过程。
CMake 是一个用于生成跨平台构建配置的工具,可以生成 Makefile 或其他构建系统的配置文件。
Makefile 包含构建项目所需的规则和命令,由 Make 工具读取执行。
CMakeLists.txt 包含项目的配置信息和结构,由 CMake 解析生成构建配置。
- GCC 编译器:
confusion: ssh 添加 public_key 至目标远程主机实现无需密码登录
- 本地host
ssh-keygen -t rsa -b 4096 -C "your_email@example.com- -t rsa: 指定密钥类型为 RSA。
- -b 4096: 指定密钥的位数,4096 位是一种常见的安全选择。
- -C “your_email@example.com“: 在生成的密钥中添加注释,通常使用你的电子邮件地址。
- 将生成的ssh public key (id_rsa.pub) 复制到远程target 的
~/.ssh/authorized_keys(如果没有则自建此文件)中即可
- 本地host
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
- 示例:
confusion: ubuntu 除用
ifconfig查看本机ip之外,还可以用ip addr(较新的ubuntu默认安装了ip命令), 一般前者失效时后者有效,不用再安装net-tools包confusion:
register_buffer()register_buffer是 PyTorch 中 nn.Module 类提供的一个方法,用于注册一个缓冲张量。这个缓冲张量不会被视为模型的参数,但会被包含在模型的状态中,并在模型的state_dict中保存。这通常用于存储不需要优化的固定参数,比如在模型中使用的常数或预先计算好的张量。
confusion: Slurm(Simple Linux Utility for Resource Management)作业调度系统
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
4git status # 查看本地仓库哪些文件被修改了
git add . # 把修改的文件放入staging area,准备commit
git commit -m "commit remark message" # 本地仓库正式commit更改
git push origin main # 将本地修改同步到github repo
confusion: 更改ubuntu root密码
sudo passwd或者sudo passwd rootconfusion: python 切片 slicing 语法
[start:stop:step]1
2
3start:起始位置的索引。
stop:终止位置的索引(不包含在切片内)。
step:步长,表示每次移动的距离。如果不指定这些值,默认值为:
1
2
3start 默认为第一个元素(索引 0)。
stop 默认为最后一个元素的下一个位置(即列表的长度)。
step 默认为 1。当你使用 [::-1] 时,两个冒号 : 表示没有指定 start 和 stop,因此默认取整个序列。而 -1 作为步长表示从最后一个元素开始,以步长为 1 的方向逐步向前取值,实现反向取值。
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)
- Peak Signal to Noise Ratio (PSNR)
- 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
- BSConvU as shallow feature extraction
PaperReference
- Rethinking Alignment in Video Super-Resolution Transformers(NIPS 2022) -> VIT 视频超分(VSR)中帧/特征对齐不是必要操作