Triton Row Max Reduction
Problem Statement
Compute the maximum of each row of a (M, N) tensor. Pad masked lanes with -inf so they never win the max.
Background
Identical structure to the row sum, but use other=-float('inf') on the load and tl.max(row, axis=0).
Your Task
Implement row_max_kernel and run(M=64, N=300) comparing to x.max(dim=1).values.
How it is tested
Your solution must define a top-level function run(...) that allocates inputs on the GPU, launches your Triton kernel, and returns a boolean from torch.allclose(triton_out, torch_reference, ...). The grader prints run(...); the expected output is True.
Example:
M = 64, N = 300
True
- The input values
M = 64andN = 300define the size of the tensor, with 64 rows and 300 columns. - The
row_max_kernelfunction computes the maximum of each row, replacing masked lanes with โinf to ensure they don't affect the result. - The
runfunction allocates the input tensor on the GPU, launches therow_max_kernel, and calculates the reference result usingx.max(dim=1).values. - The output
Trueindicates that the result from therow_max_kernelis identical to the reference result, within a certain tolerance, as verified bytorch.allclose.
Constraints:
- Load masked lanes with other=-float('inf')
- Reduce with tl.max(row, axis=0)
- One program per row
Background Knowledge
The problem involves computing the maximum of each row of a (M, N) tensor, which is a fundamental operation in linear algebra and machine learning. In the context of Triton Programming, this problem is related to reductions, which are operations that reduce a tensor to a smaller size while preserving some property of the original data. In this case, we want to reduce each row to a single value, which is the maximum value in that row. The problem also mentions masking lanes with -inf, which means that any lane (or row) that is masked should be treated as if it has a value of negative infinity, so it will never be chosen as the maximum.
The Triton Programming framework is designed to work with GPU acceleration, which allows for fast and efficient computation of large tensors. The problem requires implementing a kernel function, row_max_kernel, which will be executed on the GPU to compute the maximum of each row. The result will be compared to a reference implementation using PyTorch, which is a popular deep learning framework. The comparison will be done using the torch.allclose function, which checks if two tensors are close to each other within a certain tolerance.
The problem also involves parallel computing, since the kernel function will be executed on multiple rows of the tensor simultaneously. This requires careful consideration of how to divide the work among multiple threads or processes, and how to synchronize the results. The Triton Programming framework provides a set of tools and APIs to help with this, including the ability to launch kernels on the GPU and manage memory allocation.
Algorithm/Approach
The general approach to solving this type of problem involves the following steps:
- Divide the tensor into smaller blocks or tiles, which can be processed independently.
- Launch a kernel function on each block, which computes the maximum of each row in that block.
- Use a reduction operation to combine the results from each block, and produce the final output.
- Use masking to handle lanes that are masked, by replacing their values with -inf.
The algorithm can be parallelized by launching multiple kernel functions simultaneously, each of which processes a different block of the tensor. The results from each block can then be combined using a reduction operation, such as a max reduction.
Step-by-Step Strategy
To implement the solution, follow these steps:
- Define the row_max_kernel function, which takes a tensor as input and computes the maximum of each row.
- Launch the kernel function on the GPU, using the Triton Programming framework.
- Allocate memory for the output tensor, which will store the maximum of each row.
- Use a reduction operation to combine the results from each block, and produce the final output.
- Compare the result to a reference implementation using PyTorch, using the torch.allclose function.
- Define the run function, which allocates inputs on the GPU, launches the kernel function, and returns a boolean indicating whether the result is close to the reference implementation.
Common Pitfalls
Some common pitfalls to watch out for when implementing this solution include:
- Failing to handle masked lanes correctly, by not replacing their values with -inf.
- Not synchronizing the results from each block correctly, which can lead to incorrect results.
- Not allocating enough memory for the output tensor, which can lead to memory errors.
- Not using the correct reduction operation, which can lead to incorrect results.
Time & Space Complexity
The expected time complexity of the solution is O(MรN), where M is the number of rows and N is the number of columns. This is because the kernel function needs to process each element of the tensor once. The expected space complexity is O(M), which is the size of the output tensor. This is because we need to store the maximum of each row, which requires a tensor of size M.