// Unit test mode is used for unit testing the tiled MMA implementation. // So we can test this single file by providing -DUNIT_TEST to the compiler. implementing neural; // Perf profiling toggles. Override with -DPERF_xxx=0 to disable individual // backward components for decomposed benchmarking. #ifndef PERF_MMA_TRANSPOSE_ACTIVE #define PERF_MMA_TRANSPOSE_ACTIVE 1 #endif #ifndef PERF_BIAS_REDUCE_ACTIVE #define PERF_BIAS_REDUCE_ACTIVE 1 #endif #ifndef PERF_OPA_ACTIVE #define PERF_OPA_ACTIVE 1 #endif // Cooperative matrix is only supported by CUDA and SPIR-V // WaveTangledVector is a vector type that emulates the Cooperative Vector type by using Cooperative Matrix feature which is // supported by CUDA and SPIR-V. [require(cooperative_matrix, subgroup_basic, cuda_spirv)] public struct WaveTangledVector : IVector where T : __BuiltinFloatingPointType where T.Differential == T { public typealias Differential = WaveTangledVector; public static const int Size = N; public typealias ShMemPool = SharedMemoryPool; private typealias DTypeMatC = half; // Since we always use half type for A and B, we want to follow the alignment requirement of half type. internal static const uint ElementCountPerVector = sizeof(uint4) / sizeof(DTypeMatC); internal static const int Uint4AlignedInputSize = ((N + (ElementCountPerVector - 1)) / ElementCountPerVector) * ElementCountPerVector; internal T[Uint4AlignedInputSize] data; public int getCount() { return N; } public __init() { data = {}; } public __init(T value) { for (int i = 0; i < N; i++) this.data[i] = value; cleanPaddingData(); } public __init(T[Size] inData) { for (int i = 0; i < N; i++) this.data[i] = inData[i]; cleanPaddingData(); } internal __init(T[Uint4AlignedInputSize] inData) { this.data = inData; } public __init(This other) { this.data = other.data; } public __init>(InputArray inData) { for (int i = 0; i < N; i++) this.data[i] = inData[i]; cleanPaddingData(); } [ForceInline] [mutating] internal void cleanPaddingData() { const int elementCountPerUint4 = sizeof(uint4) / sizeof(DTypeMatC); const int alignedSize = ((N + (elementCountPerUint4 - 1)) / elementCountPerUint4) * elementCountPerUint4; for (int i = N; i < alignedSize; i++) this.data[i] = T(0.0f); } public __subscript(int index) -> T { [ForceInline] get { return this.data[index]; } [ForceInline] set { this.data[index] = newValue; } } [ForceInline] override internal uint4 readUint4(int uint4Index) { return data.readUint4(uint4Index); } [ForceInline] private OutputVector linearTransformOnTarget( Address weightAddress, Optional
biasAddress) where Address : IPointerLikeAddress where Address.Differential : IPointerLikeAddress where OutputVector : IVector where Layout : IStorageLayout { if (Layout.Layout == LayoutType.Optimal) { typealias TiledMMA = TiledMMAHelper; let resultVec = TiledMMA.forward(This(data), weightAddress, biasAddress); return OutputVector(resultVec.data); } else { typealias MMA = MMAHelper; uint shA = 0; uint shB = MMA.ShMemInfo.SharedMemSizeInVectorMatA; uint shC = shB; const int AlignedOutSize = MMA.TileInfo.Uint4AlignedM; let outputArray = MMA.mma( data, shA, shB, shC, weightAddress, biasAddress); return OutputVector(outputArray); } } [ForceInline] private static void linearTransformBwdOnTarget( inout DifferentialPair dthis, DifferentialPtrPair
dWeightAddress, Optional> biasAddress, OutputVector.Differential doutput) where Address : IPointerLikeAddress where Address.Differential : IPointerLikeAddress where OutputVector : IVector where OutputVector.Differential : IVector where Layout : IStorageLayout { if (Layout.Layout == LayoutType.Optimal) { typealias MMA = TiledMMAHelper; let dInputVec = MMA.backward( dthis.p, doutput, dWeightAddress.p, dWeightAddress.d, Bias ? biasAddress.value.d : dWeightAddress.d); dthis = DifferentialPair(dthis.p, bit_cast(dInputVec)); } else { typealias MMA = MMAHelper; uint shA = 0; uint shB = MMA.ShMemInfo.SharedMemSizeInVectorMatA; uint shC = shB; const int AlignedOutSize = MMA.TileInfo.Uint4AlignedK; // dIn = W^T * dOut (linear layout) let outArray = MMA.mma( doutput, shA, shB, shC, dWeightAddress.p, none); This.Differential dInput = This.Differential(outArray); dthis = DifferentialPair(dthis.p, dInput); GroupMemoryBarrierWithGroupSync(); static const int _outerRows = (MMA.M + MMA.CMShape.ROW_A - 1) / MMA.CMShape.ROW_A; static const int _outerPerWarpA = _outerRows * MMA.CMShape.ROW_A / MMA.CMShape.ElementCountPerVector * SubgroupSize; uint shB_outer = shA + uint(SubgroupCount * _outerPerWarpA); // dW = dOut * input^T, stored in linear layout MMA.outerProductAccumulate( shA, shB_outer, doutput, dthis.p.data, dWeightAddress.d); if (Bias) { const int subgroupIndex = getWaveId(); MMA.sumReduceRows(shA, doutput, subgroupIndex, biasAddress.value.d); } } } // Linear transformation without bias [ForceInline] [HasTrivialForwardDerivative] [BackwardDerivative(linearTransformBwd)] [require(cuda_spirv)] public OutputVector linearTransform( Address weightAddress) where Address : IPointerLikeAddress where Address.Differential : IPointerLikeAddress where Layout : IStorageLayout where OutputVector : IVector { __target_switch { case cuda: return no_diff linearTransformOnTarget(weightAddress, none); case spirv: return no_diff linearTransformOnTarget(weightAddress, none); } } // Backward of linear transformation without bias [ForceInline] static void linearTransformBwd( inout DifferentialPair dthis, DifferentialPtrPair
dWeightAddress, OutputVector.Differential doutput) where Address : IPointerLikeAddress where Address.Differential : IPointerLikeAddress where Layout : IStorageLayout where OutputVector : IVector where OutputVector.Differential : IVector { Optional> biasAddress = {}; __target_switch { case cuda: linearTransformBwdOnTarget(dthis, dWeightAddress, biasAddress, doutput); case spirv: linearTransformBwdOnTarget(dthis, dWeightAddress, biasAddress, doutput); } } [ForceInline] [HasTrivialForwardDerivative] [BackwardDerivative(linearTransformBwd)] [require(cuda_spirv)] public OutputVector linearTransform( Address weightAddress, Address biasAddress) where Address : IPointerLikeAddress where Address.Differential : IPointerLikeAddress where Layout : IStorageLayout where OutputVector : IVector { __target_switch { case cuda: return no_diff linearTransformOnTarget(weightAddress, biasAddress); case spirv: return no_diff linearTransformOnTarget(weightAddress, biasAddress); } } // Backward of linear transformation with bias [ForceInline] static void linearTransformBwd( inout DifferentialPair dthis, DifferentialPtrPair
dWeightAddress, DifferentialPtrPair
dBiasAddress, OutputVector.Differential doutput) where Address : IPointerLikeAddress where Address.Differential : IPointerLikeAddress where Layout : IStorageLayout where OutputVector : IVector where OutputVector.Differential : IVector { __target_switch { case cuda: linearTransformBwdOnTarget(dthis, dWeightAddress, dBiasAddress, doutput); case spirv: linearTransformBwdOnTarget(dthis, dWeightAddress, dBiasAddress, doutput); } } }