module mlp_sw; import common; __include mlvec_sw; public struct FeedForwardLayer { public NFloat* weights; public NFloat* weightsGrad; public NFloat* biases; public NFloat* biasesGrad; [BackwardDerivative(evalBwd)] public MLVec eval(MLVec input) { var output = matMulAdd( input, weights, biases); // ReLU activation for (int i = 0; i < OutputSize; i++) if (output.data[i] < 0.0) output.data[i] *= 0.001h; return output; } public void evalBwd( inout DifferentialPair> input, MLVec resultGrad) { let fwd = eval(input.p); // Back-prop resultGrad through activation. for (int i = 0; i < OutputSize; i++) { if (fwd.data[i] < 0.0) resultGrad.data[i] *= 0.01h; } // Back-prop gradients to the weights matrix. outerProductAccumulate( resultGrad, input.p, weightsGrad); // Back-prop gradients to the biases vector. for (int i = 0; i < OutputSize; i++) { NFloat originalValue; InterlockedAddF16Emulated(biasesGrad + i, resultGrad.data[i], originalValue); } // Back-prop gradients to the input vector. let dInput = matMulTransposed(resultGrad, weights); input = {input.p, dInput}; } }