Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FX 支持使用 FP16 #1049

Open
wants to merge 31 commits into
base: dev
Choose a base branch
from
Open

FX 支持使用 FP16 #1049

wants to merge 31 commits into from

Conversation

Blinue
Copy link
Owner

@Blinue Blinue commented Jan 2, 2025

效果可以使用 //!USE FP16 声明对半精度浮点数的支持,条件满足时会有以下变化:

  1. MP_FP16 被定义。
  2. MF 系列宏被定义为 min16float 族,如 MF4 为 min16float4,MF3x3为 min16float3x3 等。不使用 FP16 时这些宏被定义为对应的 float 类型。
  3. 符合条件的纹理被声明为 min16float 类型,例如 R16G16B16A16_FLOAT 格式的输入定义变为 Texture2D<min16float4>,输出定义变为 RWTexture2D<min16float4>;R16G16_UNORM 格式的输入定义变为 Texture2D<min16float2>,输出定义变为 RWTexture2D<unorm min16float2>。包含 32 位浮点数的格式仍使用 float 类型。

即使效果声明支持 FP16,也不意味着一定使用,有两种例外情况:GPU 不支持 FP16 或通过开发者选项禁用了 FP16。

添加了新的内置函数 MulAdd,等效于矩阵乘然后加上向量,让我们可以在 dp4 或 mad 之间灵活切换。目前大部分基于机器学习的效果大量使用 dp4,根据我的测试,切换为 mad 后性能提升相当可观。如果使用 FP16,mad 的性能可以进一步提升,而 dp4 的性能不升反降。

所有合适的效果都会适配 FP16 和 MulAdd,性能对比如下:

效果 当前 此 PR 使用 FP16 性能提升
Jinc 0.205ms 0.201ms +2%
Anime4K_3D_[AA_]Upscale_US 0.132ms 0.131ms +0.1%
Anime4K_Restore_L 0.559ms 0.433ms +22.5%
Anime4K_Restore_M 0.351ms 0.344ms +2%
Anime4K_Restore_S 0.161ms 0.154ms +4.3%
Anime4K_Restore_Soft_L 0.559ms 0.433ms +22.5%
Anime4K_Restore_Soft_M 0.352ms 0.345ms +2%
Anime4K_Restore_Soft_S 0.161ms 0.154ms +4.3%
Anime4K_Restore_Soft_UL 2.85ms 1.86ms +34.7%
Anime4K_Upscale_L 0.55ms 0.432ms +21.5%
ACNet 0.617ms 0.524ms +15.1%
CuNNy-16x16C-NVL 15.7ms 6.4ms +59.2%

其他更改:

  1. 添加开发者选项性能测试模式,开启后将持续渲染不做等待,用于测试效果的性能。
  2. 不再使用 wil::CreateDirectoryDeepNoThrow,因为它不支持相对路径,应改为使用 Win32Helper::CreateDir。
  3. 内联常量改为使用全局只读变量实现以避免宏定义引起的名字冲突,如 Fix effect shader compile error #678
  4. 引入 rapidhash,删除现有 wyhash 实现,这会使现有缓存失效,但也是清理技术债务的好机会。
  5. 优化效果缓存逻辑,避免出现哈希碰撞时读取错误的缓存,修改了缓存文件名。
  6. 效果可以在 //!MAGPIE EFFECT 块包含 StubDefs.hlsli 以减少 IDE 中的错误,不影响编译结果。

@Blinue
Copy link
Owner Author

Blinue commented Jan 3, 2025

我分别使用 N 卡(RTX 4070 Laptop)和 I 卡(Intel UHD)在同样的条件下测试结果如下:

效果 FP32-N FP16-N 性能提升 FP32-I FP16-I 性能提升
ACNet 0.64ms 0.56ms +12.5% 19.5ms 7.6ms +61%
Anime4K_Upscale_L 0.55ms 0.61ms -10.9% 53.9ms 63.3ms -17.4%
CuNNy-6x8C-NVL 0.93ms 1.1ms -18.3% 38.6ms 105ms -172%
Anime4K_Upscale_Denoise_UL 2.67ms 2.85ms -6.7% 490ms 421ms +14.1%
Anime4K_Restore_UL 2.95ms 2.81ms +4.7% 657ms 474ms +27.9%
Anime4K_Restore_Soft_UL 2.95ms 2.81ms +4.7% 657ms 470ms +28.5%
FSRCNNX 0.486ms 0.506ms -4.1% 14.6ms 6.2ms +57.5%

N 卡只有 ACNet 有较大的性能提升,其他效果反而下降;I 卡 ACNet 和 FSRCNNX 提升,其他则下降,而且性能变化幅度非常大。看来不同显卡的 FP16 性能差别很大,正确配置时可以大幅提高性能,反之则会大幅降低。这与我预想的不同,看来不能简单的全局启用或禁用。

@hooke007

This comment was marked as outdated.

@Blinue
Copy link
Owner Author

Blinue commented Jan 4, 2025

我这里串联了三个上了点强度,发现开关fp16的区别只能算误差...都是22.5xx ms波动

因为这几个效果还没做适配,现在都适配了。

@hooke007
Copy link
Collaborator

hooke007 commented Jan 4, 2025

好像还是不算明显

@Blinue
Copy link
Owner Author

Blinue commented Jan 4, 2025

试试 CuNNy-16x16C-NVL,我这里差别比较明显

FP16
image
FP32
image

@hooke007
Copy link
Collaborator

hooke007 commented Jan 4, 2025

。。。更慢了
fp16 -- fp32

@Blinue
Copy link
Owner Author

Blinue commented Jan 6, 2025

鉴于不同显卡 fp16 能力不同,我们应该支持针对单个效果启用或禁用 fp16。我想到两个方案:

  1. 允许用户针对单个效果启用 fp16
  2. 和 TensorRT 类似自动进行性能测试决定是否使用 fp16

我更喜欢第二个方案,虽然它很复杂,但优势很大

  1. 可以将粒度减小到通道,同一个效果内分别测试每个通道决定是否使用 fp16
  2. 不需要用户自己测试,开箱即用
  3. 为 TensorRT 铺路,由于机制类似,代码路径可以共用

@hooke007
Copy link
Collaborator

hooke007 commented Jan 6, 2025

我略作搜索好像确实只能算一点误差和显卡工作时频率影响的区别
image
nvidia的家用卡fp16和fp32似乎就是一个级别,这两代加入的fp16 tensor core和fp16不是一个东西
https://docs.nvidia.com/deeplearning/tensorrt/support-matrix/index.html#hardware-precision-matrix

These support matrices provide an overview of the supported platforms, features, and hardware capabilities of the TensorRT APIs, parsers, and layers.

@Blinue
Copy link
Owner Author

Blinue commented Jan 6, 2025

计算速度上 fp16 和 fp32 是一样的,fp16 的主要优势是驱动可以将 2 个 fp16 打包到一个 32 位 VGPR 寄存器。

  1. 如果驱动支持,一个指令可以同时计算两个 fp16 值,相当于时间减少了一半
  2. 使用的 VGPR 寄存器数量减少一半,VGPR 用的太多会影响并发性能

@Blinue
Copy link
Owner Author

Blinue commented Jan 6, 2025

我研究了一下 ACNet 为什么会有性能提升,发现它主要使用 mad 指令(乘然后加),Anime4K 和 Cunny 主要使用 dp4(向量点积)。于是将 ACNet 移植成了 dp4 版本性能对比如下

指令\精度 fp32-N fp16-N fp32-I fp16-I
dp4 0.588ms 0.634ms 19.9ms 8.2ms
mad 0.626ms 0.537ms 19.4ms 7.5ms
  1. mad+fp16 是最快的,我认为这是最能利用 fp16 优势的配置,A 卡支持 v_pk_mad_f16 指令,N 卡文档很少,但测试结果显示这个配置也是最快的。
  2. 现代显卡上 dp4 比 mad 快,但如果使用 fp16 结果相反。旧 N 卡和集成显卡上 dp4 比 mad 稍慢。

CuNNy-16x16C-NVL 的测试结果

指令\精度 fp32-N fp16-N
dp4 14ms 15ms
mad 7.4ms 6.37ms

@hooke007
Copy link
Collaborator

hooke007 commented Jan 6, 2025

dp4(a) 这个好像是这两代i卡加大宣传的东西?谁有新i卡可以测一测

@Blinue
Copy link
Owner Author

Blinue commented Jan 6, 2025

@hooke007 试试 CuNNy-16x16C-NVL,我这里性能有极大提升

@hooke007
Copy link
Collaborator

hooke007 commented Jan 6, 2025

是的终于感觉到合理的差别了

@Blinue
Copy link
Owner Author

Blinue commented Jan 7, 2025

我研究了一下 ACNet 为什么会有性能提升,发现它主要使用 mad 指令(乘然后加),Anime4K 和 Cunny 主要使用 dp4(向量点积)。于是将 ACNet 移植成了 dp4 版本性能对比如下

当时 mad 实现没有完全优化,现在的测试结果如下:

指令\精度 fp32-N fp16-N fp32-I fp16-I
dp4 0.579ms 0.623ms 19.9ms 8.2ms
mad 0.525ms 0.515ms 19.5ms 7.3ms

在我测试的所有设备上 dp4 都比 mad 慢,只有 A 卡没测试过。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants