Clamp the patch merge to ±2π in the native Swin encoders
NVIDIA's enc1 and enc2 clamp the patch merge's result to ±2π (as f16) before its e4m3 encoding (max.f16x2 / min.f16x2 with 0fC0C90FDB / 0f40C90FDB after the merge's last MMA). The native layers did not, in either template or set: merge_clamp (swin_common.h) now does, at the three sites that encode the merged tokens (swin_block.h's e4m3-activation and f16 paths, swin_tok.h), and swin_check.py's model clamps the same way. Measured on an RX 9070 XT against a run with no native kernels (preset L, accuracy set, the flags of Ghost of Tsushima, 1280x720 -> 3840x2160, one frame): native enc1 alone 34 dB and enc2 alone 31 dB from the translated kernels before, byte-identical after; the whole native set 28 -> 80 dB (the rest is dec1, 0.09% of the output values). Preset M's fast set against translated M: 30.8 -> 35.1 dB after 30 frames. The gfx11 path has the same change and was not run on hardware. The repo's tests pass (36, 3 skipped).
This commit is contained in:
1 parent
62738a01cc
commit
934fb486c7
5 files changed
+22
-4
No files matched your search
@@ -975,7 +975,8 @@ __device__ __forceinline__ void swin_block(const CommonParams& p, const TubePara
|
||||
continue;
|
||||
const int ch = ginv(16 * (wv * NTP + j) + l16);
|
||||
#ifdef SWIN_A8
|
||||
const uint32_t code[2] = {codes4(y[j].pair(0), y[j].pair(1)), codes4(y[j].pair(2), y[j].pair(3))};
|
||||
const uint32_t code[2] = {codes4(merge_clamp(y[j].pair(0)), merge_clamp(y[j].pair(1))),
|
||||
codes4(merge_clamp(y[j].pair(2)), merge_clamp(y[j].pair(3)))};
|
||||
#endif
|
||||
#pragma unroll
|
||||
for (int i = 0; i < 8; ++i)
|
||||
@@ -988,7 +989,7 @@ __device__ __forceinline__ void swin_block(const CommonParams& p, const TubePara
|
||||
#ifdef SWIN_A8
|
||||
(uint8_t)(code[i >> 2] >> (8 * (i & 3)));
|
||||
#else
|
||||
(uint8_t)enc8(y[j].get(i));
|
||||
(uint8_t)enc8(merge_clamp(y[j].get(i)));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -274,6 +274,18 @@ __device__ __forceinline__ half_t recip16(half_t s)
|
||||
#endif
|
||||
}
|
||||
|
||||
// NVIDIA's encoders clamp the patch merge's result to +-2 pi (as f16) before its e4m3 encoding
|
||||
// (max.f16x2 / min.f16x2 with 0fC0C90FDB / 0f40C90FDB after the merge's last MMA).
|
||||
__device__ __forceinline__ hv2 merge_clamp(hv2 v)
|
||||
{
|
||||
const hv2 lim = {(half_t)6.2831855f, (half_t)6.2831855f};
|
||||
return __builtin_elementwise_minimumnum(__builtin_elementwise_maximumnum(v, -lim), lim);
|
||||
}
|
||||
__device__ __forceinline__ half_t merge_clamp(half_t v)
|
||||
{
|
||||
return merge_clamp((hv2){v, v})[0];
|
||||
}
|
||||
|
||||
// natural channel c -> pair-order column, and inverse (per 32-channel group)
|
||||
__device__ __forceinline__ int gperm(int c)
|
||||
{
|
||||
|
||||
@@ -738,7 +738,8 @@ __device__ __forceinline__ void swin_tok_block(const CommonParams& p, const Tube
|
||||
#pragma unroll
|
||||
for (int kc = 0; kc < C / 8; ++kc)
|
||||
k32(y, wt(K::PM, NTP, kc, 0, u), as[kc][0], wt(K::PM, NTP, kc, 1, u), as[kc][1]);
|
||||
const u2v code = tok_codes(y);
|
||||
const u2v code = {codes4(merge_clamp(y.pair(0)), merge_clamp(y.pair(1))),
|
||||
codes4(merge_clamp(y.pair(2)), merge_clamp(y.pair(3)))};
|
||||
if (inside)
|
||||
*(u2v*)(p.p48 + ((size_t)((u >> 1) * H2 + MY) * W2 + MX) * 32 + 16 * (u & 1) + 8 * hf) = code;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user