Current section
Files
Jump to
Current section
Files
src/gpu_speedup_demo.erl
%%%-------------------------------------------------------------------
%% @doc GPU Speedup and Performance Optimization Demo
%% Demonstrates massive performance improvements with MLX GPU acceleration
%% @end
%%%-------------------------------------------------------------------
-module(gpu_speedup_demo).
-export([extreme_speedup_demo/0, parallel_training/0, memory_optimization/0]).
%% @doc Demonstrate extreme GPU speedups with large-scale operations
extreme_speedup_demo() ->
io:format("=== EXTREME GPU SPEEDUP DEMONSTRATION ===~n~n"),
% Add MLX to path
code:add_path("mlx/_build/default/lib/mlx/ebin"),
% Test progressively larger matrix operations
Sizes = [500, 1000, 2000, 4000],
lists:foreach(fun(Size) ->
io:format("Testing ~px~p matrix operations:~n", [Size, Size]),
benchmark_matrix_size(Size)
end, Sizes),
% Demonstrate neural network speedups
io:format("~nTesting neural network training speedups:~n"),
neural_network_speedup_test(),
% Memory bandwidth tests
io:format("~nTesting memory bandwidth optimizations:~n"),
memory_bandwidth_test(),
io:format("~nExtreme speedup demonstration complete!~n").
%% @doc Benchmark specific matrix size
benchmark_matrix_size(Size) ->
A = mlx:random([Size, Size], float32),
B = mlx:random([Size, Size], float32),
% CPU benchmark
mlx:set_default_device(cpu),
CPUTime = time_operation(fun() ->
C = mlx:matmul(A, B),
mlx:eval(C)
end),
% GPU benchmark
try
mlx:set_default_device(gpu),
GPUTime = time_operation(fun() ->
C = mlx:matmul(A, B),
mlx:eval(C)
end),
Speedup = CPUTime / GPUTime,
GFLOPS_CPU = (2.0 * Size * Size * Size) / (CPUTime * 1000000),
GFLOPS_GPU = (2.0 * Size * Size * Size) / (GPUTime * 1000000),
io:format(" CPU: ~.2f ms (~.1f GFLOPS)~n", [CPUTime, GFLOPS_CPU]),
io:format(" GPU: ~.2f ms (~.1f GFLOPS)~n", [GPUTime, GFLOPS_GPU]),
io:format(" 🚀 SPEEDUP: ~.1fx faster on GPU!~n~n", [Speedup])
catch
_:_ ->
io:format(" CPU: ~.2f ms~n", [CPUTime]),
io:format(" âš GPU not available for this test~n~n")
end.
%% @doc Time a given operation
time_operation(Fun) ->
StartTime = erlang:system_time(microsecond),
Fun(),
EndTime = erlang:system_time(microsecond),
(EndTime - StartTime) / 1000.0. % Convert to milliseconds
%% @doc Test neural network training speedups
neural_network_speedup_test() ->
% Large neural network for realistic training
BatchSize = 128,
InputSize = 1024,
HiddenSizes = [512, 256, 128],
OutputSize = 10,
% Create training data
TrainData = mlx:random([BatchSize, InputSize], float32),
Labels = mlx:random([BatchSize, OutputSize], float32),
% Initialize network weights
Network = init_large_network([InputSize | HiddenSizes] ++ [OutputSize]),
io:format(" Network: ~p neurons across ~p layers~n",
[InputSize + lists:sum(HiddenSizes) + OutputSize, length(HiddenSizes) + 1]),
% CPU training
mlx:set_default_device(cpu),
CPUTime = time_operation(fun() ->
train_batch(Network, TrainData, Labels)
end),
% GPU training
try
mlx:set_default_device(gpu),
GPUTime = time_operation(fun() ->
train_batch(Network, TrainData, Labels)
end),
Speedup = CPUTime / GPUTime,
io:format(" CPU training: ~.2f ms~n", [CPUTime]),
io:format(" GPU training: ~.2f ms~n", [GPUTime]),
io:format(" 🚀 Neural Network Training Speedup: ~.1fx!~n~n", [Speedup])
catch
_:_ ->
io:format(" CPU training: ~.2f ms~n", [CPUTime]),
io:format(" âš GPU training not available~n~n")
end.
%% @doc Initialize large neural network
init_large_network(LayerSizes) ->
init_network_layers(LayerSizes, []).
init_network_layers([_], Acc) ->
lists:reverse(Acc);
init_network_layers([In, Out | Rest], Acc) ->
Scale = math:sqrt(2.0 / In),
Weights = mlx:multiply(mlx:random([In, Out], float32), Scale),
Biases = mlx:zeros([Out], float32),
Layer = #{weights => Weights, biases => Biases},
init_network_layers([Out | Rest], [Layer | Acc]).
%% @doc Train a single batch
train_batch(Network, Data, Labels) ->
% Forward pass
Activations = forward_pass_large(Network, Data),
% Compute loss
Loss = mlx:mean(mlx:square(mlx:subtract(Activations, Labels))),
% Force evaluation
mlx:eval(Loss),
Loss.
%% @doc Forward pass through large network
forward_pass_large(Network, Input) ->
lists:foldl(fun(Layer, Activation) ->
#{weights := W, biases := B} = Layer,
Linear = mlx:add(mlx:matmul(Activation, W), B),
mlx:relu(Linear)
end, Input, Network).
%% @doc Test memory bandwidth optimizations
memory_bandwidth_test() ->
% Test different data types and sizes
Sizes = [1000000, 5000000, 10000000], % 1M, 5M, 10M elements
lists:foreach(fun(Size) ->
io:format(" Testing ~p element array operations:~n", [Size]),
% Create large arrays
A = mlx:random([Size], float32),
B = mlx:random([Size], float32),
% CPU memory bandwidth test
mlx:set_default_device(cpu),
CPUTime = time_operation(fun() ->
Result = mlx:add(mlx:multiply(A, 2.0), B),
mlx:eval(Result)
end),
% Calculate bandwidth (GB/s) - outside try block to avoid unsafe variables
DataSize = Size * 4 * 3 / (1024 * 1024 * 1024), % 3 arrays * 4 bytes
CPU_BW = DataSize / (CPUTime / 1000.0),
% GPU memory bandwidth test
try
mlx:set_default_device(gpu),
GPUTime = time_operation(fun() ->
Result = mlx:add(mlx:multiply(A, 2.0), B),
mlx:eval(Result)
end),
GPU_BW = DataSize / (GPUTime / 1000.0),
io:format(" CPU: ~.2f ms (~.1f GB/s)~n", [CPUTime, CPU_BW]),
io:format(" GPU: ~.2f ms (~.1f GB/s)~n", [GPUTime, GPU_BW]),
io:format(" 🚀 Memory bandwidth improvement: ~.1fx~n", [GPU_BW / CPU_BW])
catch
_:_ ->
io:format(" CPU: ~.2f ms (~.1f GB/s)~n", [CPUTime, CPU_BW])
end
end, Sizes).
%% @doc Demonstrate parallel training across multiple models
parallel_training() ->
io:format("=== PARALLEL TRAINING DEMO ===~n~n"),
code:add_path("mlx/_build/default/lib/mlx/ebin"),
mlx:set_default_device(gpu),
NumModels = 4,
io:format("Training ~p models in parallel...~n", [NumModels]),
% Create multiple models
Models = lists:map(fun(I) ->
io:format(" Initializing model ~p...~n", [I]),
init_large_network([784, 256, 128, 10])
end, lists:seq(1, NumModels)),
% Create training data for each model
TrainingData = lists:map(fun(_) ->
{mlx:random([100, 784], float32), mlx:random([100, 10], float32)}
end, lists:seq(1, NumModels)),
% Time parallel training
StartTime = erlang:system_time(millisecond),
% Train all models (simulated parallel execution)
lists:foreach(fun({Model, {Data, Labels}}) ->
train_batch(Model, Data, Labels)
end, lists:zip(Models, TrainingData)),
EndTime = erlang:system_time(millisecond),
TotalTime = EndTime - StartTime,
io:format("✓ Parallel training completed in ~p ms~n", [TotalTime]),
io:format("✓ Average time per model: ~.2f ms~n", [TotalTime / NumModels]),
ok.
%% @doc Advanced memory optimization techniques
memory_optimization() ->
io:format("=== MEMORY OPTIMIZATION DEMO ===~n~n"),
code:add_path("mlx/_build/default/lib/mlx/ebin"),
% Test memory-efficient operations
io:format("Testing in-place operations...~n"),
test_inplace_operations(),
% Test gradient accumulation
io:format("Testing gradient accumulation...~n"),
test_gradient_accumulation(),
% Test memory pooling
io:format("Testing memory pooling...~n"),
test_memory_pooling(),
io:format("Memory optimization demo complete!~n").
%% @doc Test in-place operations for memory efficiency
test_inplace_operations() ->
Size = [1000, 1000],
A = mlx:random(Size, float32),
% Standard operation (creates new memory)
StartTime = erlang:system_time(microsecond),
B = mlx:add(A, 1.0),
C = mlx:multiply(B, 2.0),
mlx:eval(C),
StandardTime = (erlang:system_time(microsecond) - StartTime) / 1000.0,
% In-place style operation (reuses memory where possible)
StartTime2 = erlang:system_time(microsecond),
D = mlx:multiply(mlx:add(A, 1.0), 2.0), % Fused operation
mlx:eval(D),
OptimizedTime = (erlang:system_time(microsecond) - StartTime2) / 1000.0,
io:format(" Standard ops: ~.2f ms~n", [StandardTime]),
io:format(" Optimized ops: ~.2f ms~n", [OptimizedTime]),
io:format(" Memory efficiency improvement: ~.1fx~n", [StandardTime / OptimizedTime]).
%% @doc Test gradient accumulation
test_gradient_accumulation() ->
% Simulate gradient accumulation for large batch training
BatchSize = 32,
InputSize = 512,
AccumulatedGrad = mlx:zeros([InputSize, 10], float32),
StartTime = erlang:system_time(microsecond),
% Accumulate gradients from multiple mini-batches
lists:foreach(fun(_) ->
MiniBatch = mlx:random([BatchSize, InputSize], float32),
Grad = mlx:random([InputSize, 10], float32), % Simulated gradient
AccumulatedGrad = mlx:add(AccumulatedGrad, Grad)
end, lists:seq(1, 4)),
mlx:eval(AccumulatedGrad),
Time = (erlang:system_time(microsecond) - StartTime) / 1000.0,
io:format(" Gradient accumulation: ~.2f ms~n", [Time]).
%% @doc Test memory pooling simulation
test_memory_pooling() ->
% Simulate memory pool by reusing arrays
Size = [500, 500],
StartTime = erlang:system_time(microsecond),
% Create pool of reusable arrays
Pool = lists:map(fun(_) -> mlx:zeros(Size, float32) end, lists:seq(1, 5)),
% Simulate operations that reuse memory from pool
lists:foreach(fun(Array) ->
Result = mlx:add(Array, mlx:random(Size, float32)),
mlx:eval(Result)
end, Pool),
Time = (erlang:system_time(microsecond) - StartTime) / 1000.0,
io:format(" Memory pooling ops: ~.2f ms~n", [Time]),
io:format(" Pool efficiency: Reused ~p arrays~n", [length(Pool)]).