9/30/2024

How Gradient calculation in batch size.

 Let's use a simplified example with just 2 data points and walk through the process with actual numbers. This will help illustrate how gradients are calculated and accumulated for a batch.

Let's assume we have a very simple model with one parameter w, currently set to 1.0. Our loss function is the square error, and we're using basic gradient descent with a learning rate of 0.1.

Data points:

  1. x1 = 2, y1 = 4
  2. x2 = 3, y2 = 5

Batch size = 2 (both data points in one batch)

Step 1: Forward pass

  • For x1: prediction = w * x1 = 1.0 * 2 = 2
  • For x2: prediction = w * x2 = 1.0 * 3 = 3

Step 2: Calculate losses

  • Loss1 = (prediction1 - y1)^2 = (2 - 4)^2 = 4
  • Loss2 = (prediction2 - y2)^2 = (3 - 5)^2 = 4
  • Total batch loss = (Loss1 + Loss2) / 2 = (4 + 4) / 2 = 4

Step 3: Backward pass (calculate gradients)

  • Gradient1 = 2 * (prediction1 - y1) * x1 = 2 * (2 - 4) * 2 = -8
  • Gradient2 = 2 * (prediction2 - y2) * x2 = 2 * (3 - 5) * 3 = -12

Step 4: Accumulate gradients

  • Total gradient = (Gradient1 + Gradient2) / 2 = (-8 + -12) / 2 = -10

Step 5: Update weight (once for the batch)

  • New w = old w - learning_rate * total gradient
  • New w = 1.0 - 0.1 * (-10) = 2.0

So, after processing this batch of 2 data points:

  • We calculated 2 individual gradients (-8 and -12)
  • We accumulated these into one total gradient (-10)
  • We performed one weight update, changing w from 1.0 to 2.0

This process would then repeat for the next batch. In this case, we've processed all our data, so this completes one epoch.

9/28/2024

How many GPUs do I need to train a LLM?



How many GPUs do I need to train a LLM?

This is a complicated question in general, but if we assume that you are using FSDP with 
FULL_SHARD, activation checkpointing, and DecoupledLionW, then a good rule of thumb is:

Your total cluster memory in GB should be larger than 12 * N (# billions of params).

E.g. To train a GPT-13B model which has ~13 billion params, 
have at least 12 * 13 = 156 GB of total memory across your GPUs. 
You can accomplish this with 4xA100-40GB, or 2xA100-80GB, etc.

If you run into OOM errors when using small device counts, 
reduce device_train_microbatch_size until it succeeds.

Keep in mind: even though training will work in these minimalist settings, 
you will get much better throughput_per_device 
if you use a larger cluster or devices with higher memory capacity, 
because this will enable you to use larger microbatch sizes.

9/22/2024

What is TorchOps.cpp.inc in torch-mlir

 

What is TorchOps.cpp.inc?

  • TorchOps.cpp.inc: This file contains implementations of the operations for the torch-mlir dialect. It is typically generated from .td (TableGen) files that define the dialect and its operations.
  • The .td (TableGen) files describe MLIR operations in a high-level, declarative form, and the cmake build process automatically generates .cpp.inc files (like TorchOps.cpp.inc) from these .td files.

How it gets generated:

  1. TableGen: The TableGen tool processes .td files that define the operations and attributes for the torch dialect.
  2. CMake Build: During the CMake build process, the mlir-tblgen tool is invoked to generate various .inc files, including TorchOps.cpp.inc.

Where It Is Generated:

The TorchOps.cpp.inc file is usually generated in the build directory under the subdirectories for the torch-mlir project. For example:


build/tools/torch-mlir/lib/Dialect/Torch/IR/TorchOps.cpp.inc

This file gets included in the compiled source code to provide the implementation of the Torch dialect operations.

How to Ensure It Is Generated:

If the file is missing, it's likely because there was an issue in the build process. Here’s how to ensure it’s generated:

  1. Ensure CMake and Ninja Build: Make sure the CMake and Ninja build process is working correctly by following the steps we discussed earlier. You can check that the TorchOps.cpp.inc file is generated by looking in the build directory:

    ls build/tools/torch-mlir/lib/Dialect/Torch/IR/
  2. Check for TableGen Files: Make sure that the .td files (such as TorchOps.td) are present in the source directory. These are used by mlir-tblgen to generate the .cpp.inc files.

Debugging if Not Generated:

If TorchOps.cpp.inc or similar files are not generated, ensure:

  • You are running the full build using ninja or make.
  • mlir-tblgen is being invoked during the build process (you should see log messages referencing mlir-tblgen).

IREE test code and explanation

.

from iree import compiler, runtime
import numpy as np
import sys

def print_step(step):
print(f'Step: {step}', file=sys.stderr)

# MLIR code as a string
module_str = '''
func.func @simple_add(%arg0: tensor<4xf32>, %arg1: tensor<4xf32>) -> tensor<4xf32> {
%0 = arith.addf %arg0, %arg1 : tensor<4xf32>
return %0 : tensor<4xf32>
}
'''

print_step('Compiling module')
compiled_module = compiler.compile_str(module_str, target_backends=['llvm-cpu'])

print_step('Creating runtime config')
config = runtime.Config('local-task')

print_step('Creating system context')
ctx = runtime.SystemContext(config=config)

print_step('Creating VM instance')
vm_instance = runtime.VmInstance()

print_step('Creating VM module')
vm_module = runtime.VmModule.from_flatbuffer(vm_instance, compiled_module, warn_if_copy=False)

print_step('Adding VM module to context')
ctx.add_vm_module(vm_module)

print_step('Getting device')
device = runtime.get_driver('local-task').create_default_device()
print(f'Device: {device}', file=sys.stderr)

print_step('Getting function')
f = ctx.modules.module.simple_add

print_step('Creating device arrays')
arg1 = runtime.asdevicearray(device, np.array([1.0, 2.0, 3.0, 4.0], dtype=np.float32))
arg2 = runtime.asdevicearray(device, np.array([5.0, 6.0, 7.0, 8.0], dtype=np.float32))

print_step('Calling function')
result = f(arg1, arg2)

print_step('Getting result')
print(result.to_host())

print_step('Script completed successfully')

..

To run this code:

  1. Save it to a file, e.g., test_iree.py.
  2. Make sure you have IREE and its Python bindings installed and properly set up in your environment.
  3. Run the script using Python:
    python test_iree.py

This script will:

  1. Define a simple MLIR function that adds two 4-element float32 tensors.
  2. Compile this MLIR code to an IREE module.
  3. Set up the IREE runtime environment.
  4. Create input data as NumPy arrays.
  5. Execute the compiled function with the input data.
  6. Print the result.

The output should show each step of the process and finally print the result, which should be [ 6. 8. 10. 12.].

This example demonstrates the basic workflow for testing MLIR code with IREE using Python. You can modify the MLIR code string and input data to test different functions and operations as needed.



9/20/2024

mlir build and test

To build and run your toy1.cpp code with MLIR, you need to follow these steps. This assumes you are using the Toy language tutorial from MLIR as a base.

1. Setup MLIR Development Environment

If you haven’t done this already, you’ll need to clone and build the LLVM project with MLIR enabled. Here are the steps:

a. Clone LLVM with MLIR

git clone https://github.com/llvm/llvm-project.git
cd llvm-project

b. Build MLIR

mkdir build
cd build
cmake -G Ninja ../llvm \
  -DLLVM_ENABLE_PROJECTS=mlir \
  -DLLVM_BUILD_EXAMPLES=ON \
  -DCMAKE_BUILD_TYPE=Release \
  -DLLVM_ENABLE_ASSERTIONS=ON
cmake --build . --target check-mlir

You can also follow the full guide for building MLIR from the official MLIR Getting Started guide【19†source】.

2. Implementing the Toy Language (toy1.cpp)

You are using a simplified example of the Toy Language from the MLIR tutorial. For this code to work, you need to create a proper Toy dialect and Toy compiler.

a. Writing the toy1.cpp

Save your example code as toy1.cpp inside your MLIR directory.

#include "toy/Dialect.h"
#include "toy/Parser.h"
#include "toy/Passes.h"
#include "toy/Lowering.h"
#include <mlir/IR/MLIRContext.h>
#include <mlir/Pass/PassManager.h>
#include <mlir/ExecutionEngine/ExecutionEngine.h>
#include <mlir/IR/Verifier.h>
#include <mlir/Parser/Parser.h>
#include <mlir/Support/FileUtilities.h>
#include <mlir/Support/LogicalResult.h>
#include <mlir/Support/ToolUtilities.h>
#include <mlir/Support/LLVM.h>
#include <mlir/Target/LLVMIR/ModuleTranslation.h>

int main(int argc, char **argv) {
  mlir::MLIRContext context;
  mlir::PassManager pm(&context);
  
  // Define your toy program in MLIR (using Toy dialect)
  // "var a = [[1, 2, 3], [4, 5, 6]]; var b<2, 3> = ..."

  // Parse it, verify, and run it
  // Example: Create a pass that optimizes or lowers the Toy language IR into MLIR
  
  return 0;
}

You will need to modify this template to use the Toy language's parser and lower the Toy code into MLIR.

3. Integrating with the MLIR Pass Pipeline

You’ll need to define and register your passes. This step lowers Toy language constructs (like variable assignments, matrix multiplication, and transposing) into the MLIR representation.

b. Register Toy Passes and Dialect

You can define passes to lower your Toy language to MLIR:

// In your main, define the following steps:
pm.addPass(toy::createShapeInferencePass());
pm.addPass(mlir::createCSEPass());
pm.addPass(mlir::createCanonicalizerPass());
pm.addPass(toy::createLowerToAffinePass());
pm.addPass(toy::createLowerToLLVMPass());

4. Running Your Toy Code in MLIR

Once you've written the Toy language logic and set up the passes, you can now run and test it using the MLIR tools.

a. Compile toy1.cpp

After you set up your CMakeLists.txt file (using the MLIR Toy Tutorial) and ensure that the Toy dialect is registered, you can compile the Toy language.

cd build
cmake --build . --target toy-compiler

b. Run Toy Compiler

To run your Toy code and compile it into MLIR:

./toy-compiler toy1.cpp -o output.mlir

This will generate MLIR code for your Toy program.

5. Testing and Debugging

Once you've compiled your Toy language code to MLIR, you can use MLIR’s optimization and debugging tools:

mlir-opt output.mlir --canonicalize --cse
mlir-translate --mlir-to-llvmir output.mlir | llc -filetype=obj -o output.o

This will optimize and translate your Toy program into LLVM IR and finally to machine code that can be executed.

References:

This setup will help you compile and run Toy language code through MLIR!

9/18/2024

AMD Distributed Training Overview

# AMD Distributed Training Overview

AMD's approach to distributed training leverages its high-performance CPUs and GPUs, along with software frameworks, to enable efficient scaling of machine learning workloads across multiple nodes. Key aspects include:

1. **Hardware Solutions:**
   - AMD EPYC CPUs: Provide high core counts and memory bandwidth.
   - AMD Instinct GPUs: Accelerators designed for HPC and AI workloads.
   - AMD Infinity Fabric: High-speed interconnect for multi-GPU and multi-node systems.

2. **Software Framework:**
   - ROCm (Radeon Open Compute): Open-source software stack for GPU computing.
   - HIP (Heterogeneous-Compute Interface for Portability): C++ runtime API for GPU programming.
   - AMD's optimized libraries for deep learning frameworks like TensorFlow and PyTorch.

3. **Distributed Training Techniques:**
   - Data Parallelism: Distributing batches of training data across multiple GPUs or nodes.
   - Model Parallelism: Splitting large models across multiple devices.
   - Pipeline Parallelism: Dividing model layers across devices and processing in a pipelined fashion.

4. **Communication Optimization:**
   - RCCL (ROCm Communication Collectives Library): Optimized multi-GPU and multi-node collective communications.
   - Support for high-speed networking technologies like InfiniBand.

5. **Scalability:**
   - Support for scaling from single-node multi-GPU systems to large clusters.
   - Integration with job schedulers and resource managers for cluster environments.

6. **Ecosystem Integration:**
   - Compatibility with popular ML frameworks and distributed training tools.
   - Support for containers and orchestration platforms like Docker and Kubernetes.

7. **Performance Optimization:**
   - Mixed-precision training support.
   - Memory management techniques for large model training.
   - Automatic performance tuning tools.

AMD's distributed training solutions aim to provide high performance, scalability, and ease of use for researchers and organizations working on large-scale machine learning projects.

9/17/2024

What is IREE turbine

 IREE-Turbine is a package or toolset that combines PyTorch, Torch-MLIR, IREE, and additional tools to provide a comprehensive solution for compiling, optimizing, and executing PyTorch models using IREE's infrastructure. Based on the information in the image, IREE-Turbine offers the following key features:


1. AOT Export: This allows for Ahead-Of-Time compilation of PyTorch modules (nn.Modules) into deployment-ready artifacts. These compiled artifacts can then take full advantage of IREE's runtime features.


2. Eager Execution: It provides a torch.compile backend and a Turbine Tensor/Device for interactive PyTorch sessions. This enables users to work with PyTorch in a familiar environment while leveraging IREE's optimization capabilities.


3. Custom Ops: IREE-Turbine offers integration for defining custom PyTorch operations and implementing them using either IREE's backend IR or the Pythonic kernel language. This allows for extending PyTorch's functionality while maintaining compatibility with IREE's optimization pipeline.


In essence, IREE-Turbine acts as a bridge between PyTorch and IREE, allowing PyTorch users to benefit from IREE's advanced compilation and runtime features while maintaining a familiar PyTorch-based workflow. It aims to provide a seamless experience for compiling PyTorch models to run efficiently on various hardware targets supported by IREE.