Skip to content

Commit 955b828

Browse files
authored
Cladtorch and GPT-2 implementation (#1463)
* Tensor implementation * GPT-2 implmentation: Add optimized training implementation for clad --------- Co-authored-by: Rohan-T144 <74475417+Rohan-T144@users.noreply.github.com>
1 parent daf40c1 commit 955b828

16 files changed

Lines changed: 5758 additions & 3 deletions

File tree

.github/workflows/ci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ jobs:
115115
compiler: gcc-13
116116
clang-runtime: '20'
117117
extra_cmake_options: '-DCLAD_ENABLE_BENCHMARKS=On -DCLAD_ENABLE_ENZYME_BACKEND=On'
118+
extra_packages: "libomp-20-dev libopenblas-dev"
118119
benchmark: true
119120

120121
- name: ubu22-clang13-runtime13-cuda

.github/workflows/clang-tidy-review.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ jobs:
3434
id: review
3535
with:
3636
build_dir: build
37-
apt_packages: cmake,libxml2,libxml2-dev,libtinfo-dev,zlib1g-dev,libzstd-dev,libthrust-dev,libbenchmark-dev
37+
apt_packages: cmake,libxml2,libxml2-dev,libtinfo-dev,zlib1g-dev,libzstd-dev,libthrust-dev,libbenchmark-dev,libomp-20-dev,libopenblas-dev
3838
exclude: "test/*,unittests/*"
3939
split_workflow: true
4040
cmake_command: >
@@ -44,6 +44,7 @@ jobs:
4444
-DCMAKE_BUILD_TYPE="Release"
4545
-DLLVM_EXTERNAL_LIT="`which lit`"
4646
-DCMAKE_EXPORT_COMPILE_COMMANDS=On
47+
-DCMAKE_CXX_FLAGS="-fexceptions" # Clad demos can have exceptions
4748
4849
- name: Upload artifacts
4950
uses: ZedThree/clang-tidy-review/upload@v0.20.1

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ endif()
66

77
enable_language(CXX)
88
set(CMAKE_CXX_EXTENSIONS NO)
9-
9+
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
1010
include(GNUInstallDirs)
1111

1212
# MUST be done before call to clad project

benchmark/CMakeLists.txt

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,33 @@ target_compile_definitions(tapenade_support PRIVATE
3232
CB_ADD_GBENCHMARK(VectorModeComparison VectorModeComparison.cpp)
3333
CB_ADD_GBENCHMARK(MemoryComplexity_tapenade MemoryComplexity.cpp)
3434
CB_ADD_GBENCHMARK(Multithreading Multithreading.cpp)
35+
CB_ADD_GBENCHMARK(Hessians Hessians.cpp)
36+
CB_ADD_GBENCHMARK(GPT2Training GPT2Training.cpp)
37+
38+
if(APPLE)
39+
# On macOS, we want to explicitly use the high-performance Accelerate framework for BLAS.
40+
# We also need to give CMake a hint to find the Homebrew OpenMP library.
41+
list(APPEND CMAKE_PREFIX_PATH "/opt/homebrew/opt/libomp")
42+
find_package(OpenMP REQUIRED)
43+
# Link explicitly against Accelerate and the found OpenMP library.
44+
target_link_libraries(GPT2Training PRIVATE "-framework Accelerate" OpenMP::OpenMP_CXX)
45+
else()
46+
# On all other platforms (e.g., Linux), find the best available BLAS and OpenMP.
47+
find_package(BLAS REQUIRED)
48+
find_package(OpenMP REQUIRED)
49+
# find_package(MKL CONFIG REQUIRED)
50+
target_link_libraries(GPT2Training PRIVATE ${BLAS_LIBRARIES} "-fopenmp=libomp" OpenMP::OpenMP_CXX)
51+
target_compile_options(GPT2Training PRIVATE -I/usr/include/mkl)
52+
endif()
53+
target_compile_options(GPT2Training PRIVATE -O3 -ffast-math)
54+
target_compile_definitions(GPT2Training PRIVATE OMP)
55+
if (BLAS_FOUND)
56+
target_compile_definitions(GPT2Training PRIVATE HAVE_CBLAS)
57+
endif()
3558

3659
target_link_libraries(MemoryComplexity_tapenade PRIVATE tapenade_support)
3760

3861
add_custom_target(benchmark-clad COMMAND ${CMAKE_CTEST_COMMAND} -V
3962
DEPENDS ${CLAD_BENCHMARK_DEPS} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
4063

41-
set_target_properties(benchmark-clad PROPERTIES FOLDER "Clad benchmarks")
64+
set_target_properties(benchmark-clad PROPERTIES FOLDER "Clad benchmarks")

benchmark/GPT2Training.cpp

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
#include "benchmark/benchmark.h"
2+
3+
#include <clad/Differentiator/CladtorchBuiltins.h>
4+
#include <clad/Differentiator/Differentiator.h>
5+
#include <clad/Differentiator/STLBuiltins.h>
6+
#include <cstddef>
7+
#include <string>
8+
#include "../demos/cladtorch/llm.hpp"
9+
#include "../demos/cladtorch/llm_opt.hpp"
10+
11+
// NOLINTBEGIN(cppcoreguidelines-*)
12+
class GPT2Optimized : public benchmark::Fixture {
13+
public:
14+
GPT2* model;
15+
GPT2* d_model;
16+
int* inputs;
17+
int* targets;
18+
19+
void SetUp(const ::benchmark::State& state) override {
20+
GPT2Config config{};
21+
config.max_seq_len = 1024;
22+
config.vocab_size = 50257;
23+
config.padded_vocab_size = 50304;
24+
config.num_layers = 12;
25+
config.num_heads = 12;
26+
config.channels = 768;
27+
28+
model = new GPT2(config);
29+
d_model = new GPT2(config);
30+
31+
// Get batch size (B) and sequence length (T) from the benchmark state
32+
int B = (int)state.range(0);
33+
int T = (int)state.range(1);
34+
35+
model->allocate(B, T);
36+
d_model->allocate(B, T);
37+
38+
// Allocate and fill dummy input data
39+
inputs = new int[B * T];
40+
targets = new int[B * T];
41+
for (int i = 0; i < B * T; ++i) {
42+
inputs[i] = i % model->config.vocab_size;
43+
targets[i] = (i + 1) % model->config.vocab_size;
44+
}
45+
}
46+
47+
void TearDown(const ::benchmark::State& state) override {
48+
// This runs once after each benchmark test
49+
delete model;
50+
delete d_model;
51+
delete[] inputs;
52+
delete[] targets;
53+
}
54+
};
55+
56+
static float gpt2forw_opt(GPT2* model, const int* inputs, const int* targets) {
57+
model->forward(inputs, targets);
58+
return model->mean_loss;
59+
}
60+
61+
// The benchmark itself
62+
BENCHMARK_DEFINE_F(GPT2Optimized, FullTrainingIteration)
63+
(benchmark::State& state) {
64+
auto grad = clad::gradient(gpt2forw_opt, "0");
65+
int B = state.range(0);
66+
int T = state.range(1);
67+
68+
for (auto _ : state) {
69+
state.PauseTiming();
70+
d_model->zero_all();
71+
72+
state.ResumeTiming();
73+
// The single training iteration:
74+
// forward pass (calculated as part of gradient), backward pass, and
75+
// update
76+
grad.execute(model, inputs, targets, d_model);
77+
model->update(d_model, /*lr=*/1e-3F);
78+
}
79+
state.SetLabel("B=" + std::to_string(B) + " T=" + std::to_string(T));
80+
}
81+
82+
BENCHMARK_REGISTER_F(GPT2Optimized, FullTrainingIteration)
83+
->Args({1, 16}) // B=1, T=16
84+
->Args({1, 32}) // B=1, T=32
85+
->Args({2, 16}) // B=2, T=16
86+
->Args({1, 64}) // B=1, T=64
87+
->Args({2, 32})
88+
->Args({4, 32})
89+
->Args({4, 64}) // B=4, T=64
90+
->Unit(benchmark::kMillisecond);
91+
92+
class GPT2Cladtorch : public benchmark::Fixture {
93+
public:
94+
gpt2::GPT2* model;
95+
gpt2::GPT2* d_model;
96+
int* inputs;
97+
int* targets;
98+
99+
void SetUp(const ::benchmark::State& state) override {
100+
const gpt2::Config config = {
101+
.max_seq_len = 1024,
102+
.vocab_size = 50257,
103+
.padded_vocab_size = 50304,
104+
.num_layers = 12,
105+
.num_heads = 12,
106+
.channels = 768,
107+
};
108+
model = new gpt2::GPT2(config);
109+
d_model = new gpt2::GPT2(config);
110+
111+
// Get batch size (B) and sequence length (T) from the benchmark state
112+
int B = state.range(0);
113+
int T = state.range(1);
114+
115+
// Allocate and fill dummy input data
116+
inputs = new int[B * T];
117+
targets = new int[B * T];
118+
for (int i = 0; i < B * T; ++i) {
119+
inputs[i] = i % model->config.vocab_size;
120+
targets[i] = (i + 1) % model->config.vocab_size;
121+
}
122+
}
123+
124+
void TearDown(const ::benchmark::State& state) override {
125+
// This runs once after each benchmark test
126+
delete model;
127+
delete d_model;
128+
delete[] inputs;
129+
delete[] targets;
130+
}
131+
};
132+
133+
static float gpt2_loss(const gpt2::GPT2& model, const gpt2::ITensor& input,
134+
const gpt2::ITensor& targets) {
135+
auto probs = model.forward(input);
136+
auto loss = cross_entropy_loss(probs, targets);
137+
return loss.scalar();
138+
}
139+
140+
// The benchmark itself
141+
BENCHMARK_DEFINE_F(GPT2Cladtorch, FullTrainingIteration)
142+
(benchmark::State& state) {
143+
auto grad = clad::gradient(gpt2_loss, "0");
144+
int B = (int)state.range(0);
145+
int T = (int)state.range(1);
146+
const gpt2::ITensor inp({B, T}, inputs);
147+
const gpt2::ITensor tar({B, T}, targets);
148+
for (auto _ : state) {
149+
state.PauseTiming();
150+
d_model->for_each_parameter([&](gpt2::FTensor* t) { t->fill(0); });
151+
state.ResumeTiming();
152+
// The single training iteration: forward pass, backward pass, and update
153+
grad.execute(*model, inp, tar, d_model);
154+
std::vector<gpt2::FTensor*> params = model->get_parameter_tensors();
155+
std::vector<gpt2::FTensor*> grads = d_model->get_parameter_tensors();
156+
for (size_t i = 0; i < params.size(); ++i) {
157+
// Update parameters with a learning rate of 1e-4
158+
*params[i] += (*grads[i]) * -1e-3F;
159+
}
160+
}
161+
162+
// You can set custom counters to report B and T
163+
state.SetLabel("B=" + std::to_string(B) + " T=" + std::to_string(T));
164+
}
165+
166+
// Register the benchmark with different arguments
167+
// This will run the benchmark for various combinations of batch size (B) and
168+
// sequence length (T)
169+
BENCHMARK_REGISTER_F(GPT2Cladtorch, FullTrainingIteration)
170+
->Args({1, 16}) // B=1, T=16
171+
->Args({1, 32}) // B=1, T=32
172+
->Args({2, 16}) // B=2, T=16
173+
->Args({1, 64}) // B=1, T=64
174+
->Args({2, 32})
175+
->Unit(benchmark::kMillisecond);
176+
177+
// Define our main.
178+
BENCHMARK_MAIN();
179+
// NOLINTEND(cppcoreguidelines-*)

0 commit comments

Comments
 (0)