Source browser

examples/shaders/lenet_conv.cpp

Read the complete file below or download its original bytes. Line numbers provide stable links to a declaration or processing step.

File fingerprint
1// Apply a valid convolution with optional zero padding and ReLU.
2#ifdef __cplusplus // Include the runtime only when building the CPU adapter.
3#include "shdr.h" // Share resource and math types with the application.
4#endif // Finish header inclusion for the generated C++ build.
5layout(local_size_x = 64) in; // Give each invocation one output feature value.
6layout(std430, binding = 0) readonly buffer Inputs { // Read the previous layer in NCHW order.
7    float input_values[]; // Store complete channel planes inside each image.
8}; // Finish the input resource declaration.
9layout(std430, binding = 1) readonly buffer Parameters { // Read flattened model weights and biases.
10    float parameters[]; // Match the offline model parameter order.
11}; // Finish the parameter resource declaration.
12layout(std430, binding = 2) // Use the third tightly packed shader storage binding.
13    writeonly buffer Outputs { // Store each next-layer feature in its own output position.
14    float output_values[]; // Keep the next layer in the same NCHW order.
15}; // Finish the output resource declaration.
16uniform uint batch_count; // Receive the number of independent images.
17uniform uint input_width; // Receive the width of each input channel plane.
18uniform uint input_height; // Receive the height of each input channel plane.
19uniform uint input_channels; // Receive the number of input feature planes.
20uniform uint output_channels; // Receive the number of learned convolution filters.
21uniform uint kernel_size; // Receive the side length of each square filter.
22uniform uint padding; // Receive the number of implicit zero pixels on each edge.
23uniform uint weight_offset; // Receive the first convolution weight in the flat model.
24uniform uint bias_offset; // Receive the first convolution bias in the flat model.
25void main() { // Compute the output feature value assigned to this invocation.
26    uint width = // Compute the output width after kernel extent and zero padding.
27        input_width + 2u * padding - kernel_size + 1u; // Find the valid padded output width.
28    uint height = // Compute the output height after kernel extent and zero padding.
29        input_height + 2u * padding - kernel_size + 1u; // Find the valid padded output height.
30    uint plane = width * height, // Count values per output plane before identifying the image.
31         index = gl_GlobalInvocationID.x; // Find this output within the flattened layer.
32    if (index >= batch_count * output_channels * plane) // Ignore excess invocations beyond the final convolution output.
33        return; // Ignore unused invocations after the layer.
34    uint row = index / (output_channels * plane); // Find the independent image in this batch.
35    uint channel = // Select the learned output feature plane.
36        (index / plane) % output_channels; // Find the learned filter producing this feature.
37    uint x = index % width, // Decode the horizontal and vertical output coordinates.
38         y = (index % plane) / width; // Recover the pixel coordinates in the output plane.
39    float value = // Begin convolution accumulation with the learned channel bias.
40        parameters[bias_offset + channel]; // Start the feature value with its learned bias.
41    for (uint source = 0u; source < input_channels; // Visit every input feature plane connected to this output.
42         ++source) { // Accumulate contributions from every input plane.
43        for (uint ky = 0u; ky < kernel_size; ++ky) { // Visit each row of the convolution kernel.
44            for (uint kx = 0u; kx < kernel_size; // Visit every horizontal position in the learned kernel.
45                 ++kx) { // Visit each column of the convolution kernel.
46                int sx = int(x + kx) - // Move the kernel position into signed padded input coordinates.
47                         int(padding); // Place the kernel column inside the unpadded input.
48                int sy = // Move the vertical kernel position into signed padded input coordinates.
49                    int(y + ky) - int(padding); // Place the kernel row inside the unpadded input.
50                if (sx < 0 || sy < 0 || sx >= int(input_width) || sy >= int(input_height)) // Treat positions outside the original feature plane as zero.
51                    continue; // Use zero outside the input image.
52                uint sample_index = (row * input_channels + source) * input_width * input_height + // Locate this image and source channel in NCHW storage.
53                                    uint(sy) * input_width + // Move to the selected row of the source feature plane.
54                                    uint(sx); // Select the NCHW input feature.
55                uint coefficient = // Locate this learned kernel coefficient.
56                    weight_offset + // Begin at the first weight of this convolution layer.
57                    ((channel * input_channels + source) * kernel_size + ky) * kernel_size + // Select the output channel, input channel and kernel row.
58                    kx; // Select the matching learned kernel coefficient.
59                value += parameters[coefficient] * // Multiply the learned coefficient by the selected source feature.
60                         input_values[sample_index]; // Accumulate this convolution contribution.
61            } // Finish this kernel row.
62        } // Finish this source plane's kernel.
63    } // Finish the sum over input feature planes.
64    output_values[index] = // Store the completed feature with the chosen activation.
65        max(value, 0.0); // Apply ReLU once after the complete learned projection.
66} // Finish this convolution invocation.