Compute shader to test a tensor for NaN values

This commit is contained in:
Konstantin
2023-02-19 22:15:40 +01:00
parent 040faf1ace
commit fe83834252
6 changed files with 111 additions and 28 deletions
+1
View File
@@ -172,6 +172,7 @@
<FxCompile Include="convolutionPrep2.hlsl" /> <FxCompile Include="convolutionPrep2.hlsl" />
<FxCompile Include="copyConvert.hlsl" /> <FxCompile Include="copyConvert.hlsl" />
<FxCompile Include="copyTranspose.hlsl" /> <FxCompile Include="copyTranspose.hlsl" />
<FxCompile Include="dbgFindNaN.hlsl" />
<FxCompile Include="diagMaskInf.hlsl" /> <FxCompile Include="diagMaskInf.hlsl" />
<FxCompile Include="flashAttention.hlsl" /> <FxCompile Include="flashAttention.hlsl" />
<FxCompile Include="flashAttentionCompat1.hlsl" /> <FxCompile Include="flashAttentionCompat1.hlsl" />
@@ -50,6 +50,7 @@
<FxCompile Include="mulMatByRowTiledEx.hlsl" /> <FxCompile Include="mulMatByRowTiledEx.hlsl" />
<FxCompile Include="addRepeatEx.hlsl" /> <FxCompile Include="addRepeatEx.hlsl" />
<FxCompile Include="softMaxLong.hlsl" /> <FxCompile Include="softMaxLong.hlsl" />
<FxCompile Include="dbgFindNaN.hlsl" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="componentwiseBinaryOp.hlsli" /> <None Include="componentwiseBinaryOp.hlsli" />
+76
View File
@@ -0,0 +1,76 @@
// When reset = TRUE, write zero to the output buffer
// When reset = FALSE, test input tensor for NaN, when found at least 1 NaN element, write 1 to the output buffer
// FP32 or FP16 tensor to test for NAN
Buffer<float> tensor: register( t0 );
// A buffer with a single element for the output boolean. Zero means there were no NAN values in the tensor.
RWBuffer<uint> result: register( u0 );
cbuffer Constants: register( b0 )
{
uint elements: packoffset( c0.x );
bool reset : packoffset( c0.y );
}
// Thread group index is 16 bits per coordinate:
// https://learn.microsoft.com/en-us/windows/win32/api/d3d11/nf-d3d11-id3d11devicecontext-dispatch
// We want this shader to support buffers up to 2 GB.
#ifndef THREADS
static const uint THREADS = 512;
#endif
#ifndef ITERATIONS
static const uint ITERATIONS = 128;
#endif
static const uint itemsPerGroup = THREADS * ITERATIONS;
inline bool isNaN( float x )
{
// https://sakibsaikia.github.io/graphics/2022/01/04/Nan-Checks-In-HLSL.html
return ( asuint( x ) & 0x7fffffff ) > 0x7f800000;
}
groupshared uint reductionBuffer;
[numthreads( THREADS, 1, 1 )]
void main( uint3 group: SV_GroupID, uint thread : SV_GroupIndex )
{
if( reset )
{
if( 0 == thread )
result[ 0 ] = 0;
return;
}
uint rsi = group.x * itemsPerGroup;
const uint rsiEnd = min( rsi + itemsPerGroup, elements );
// The main loop updates a local variable. There're THREADS instances of that variable for the group of threads.
bool foundNan = false;
for( rsi += thread; rsi < rsiEnd; rsi += THREADS )
{
const float val = tensor[ rsi ];
if( !isNaN( val ) )
continue;
foundNan = true;
break;
}
// Reduce THREADS booleans to a single one, using group shared memory atomics
if( 0 == thread )
reductionBuffer = 0;
GroupMemoryBarrierWithGroupSync();
if( foundNan )
InterlockedOr( reductionBuffer, 1u );
GroupMemoryBarrierWithGroupSync();
// When found, update output value with global memory atomic
if( 0 != thread )
return;
if( 0 == reductionBuffer )
return;
InterlockedOr( result[ 0 ], 1u );
}
+4 -1
View File
@@ -3,6 +3,7 @@ RWBuffer<float> result: register( u0 );
cbuffer Constants: register( b0 ) cbuffer Constants: register( b0 )
{ {
uint elements: packoffset( c0.x ); uint elements: packoffset( c0.x );
bool writeNan: packoffset( c0.y );
} }
// Thread group index is 16 bits per coordinate: // Thread group index is 16 bits per coordinate:
@@ -22,6 +23,8 @@ void main( uint3 group: SV_GroupID, uint thread : SV_GroupIndex )
{ {
uint rdi = group.x * itemsPerGroup; uint rdi = group.x * itemsPerGroup;
const uint rdiEnd = min( rdi + itemsPerGroup, elements ); const uint rdiEnd = min( rdi + itemsPerGroup, elements );
// https://www.h-schmidt.net/FloatConverter/IEEE754.html
const float pattern = writeNan ? asfloat( 0x7FFFFFFFu ) : 0.0;
for( rdi += thread; rdi < rdiEnd; rdi += THREADS ) for( rdi += thread; rdi < rdiEnd; rdi += THREADS )
result[ rdi ] = 0.0; result[ rdi ] = pattern;
} }
+2 -1
View File
@@ -2,7 +2,7 @@
#include "stdafx.h" #include "stdafx.h"
#include "shaderNames.h" #include "shaderNames.h"
static const std::array<const char*, 40> s_shaderNames = static const std::array<const char*, 41> s_shaderNames =
{ {
"add", "add",
"addInPlace", "addInPlace",
@@ -18,6 +18,7 @@ static const std::array<const char*, 40> s_shaderNames =
"convolutionPrep2", "convolutionPrep2",
"copyConvert", "copyConvert",
"copyTranspose", "copyTranspose",
"dbgFindNaN",
"diagMaskInf", "diagMaskInf",
"flashAttention", "flashAttention",
"flashAttentionCompat1", "flashAttentionCompat1",
+27 -26
View File
@@ -20,32 +20,33 @@ namespace DirectCompute
convolutionPrep2 = 11, convolutionPrep2 = 11,
copyConvert = 12, copyConvert = 12,
copyTranspose = 13, copyTranspose = 13,
diagMaskInf = 14, dbgFindNaN = 14,
flashAttention = 15, diagMaskInf = 15,
flashAttentionCompat1 = 16, flashAttention = 16,
flashAttentionCompat2 = 17, flashAttentionCompat1 = 17,
flashAttentionCompat3 = 18, flashAttentionCompat2 = 18,
fmaRepeat1 = 19, flashAttentionCompat3 = 19,
fmaRepeat2 = 20, fmaRepeat1 = 20,
matReshapePanels = 21, fmaRepeat2 = 21,
mulMatByRow = 22, matReshapePanels = 22,
mulMatByRowTiled = 23, mulMatByRow = 23,
mulMatByRowTiledEx = 24, mulMatByRowTiled = 24,
mulMatByScalar = 25, mulMatByRowTiledEx = 25,
mulMatDotMain = 26, mulMatByScalar = 26,
mulMatDotReshape = 27, mulMatDotMain = 27,
mulMatMadMain = 28, mulMatDotReshape = 28,
mulMatTiled = 29, mulMatMadMain = 29,
mulMatTiledEx = 30, mulMatTiled = 30,
norm = 31, mulMatTiledEx = 31,
normCompat = 32, norm = 32,
normFixed = 33, normCompat = 33,
scaleInPlace = 34, normFixed = 34,
softMax = 35, scaleInPlace = 35,
softMaxCompat = 36, softMax = 36,
softMaxFixed = 37, softMaxCompat = 37,
softMaxLong = 38, softMaxFixed = 38,
zeroMemory = 39, softMaxLong = 39,
zeroMemory = 40,
}; };
const char* computeShaderName( eComputeShader cs ); const char* computeShaderName( eComputeShader cs );