Skip to content

Commit feca41d

Browse files
committed
Modification for new SOFIE repo
1 parent a88675f commit feca41d

3 files changed

Lines changed: 40 additions & 37 deletions

File tree

‎GPU/GPUTracking/CMakeLists.txt‎

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,7 @@ if(NOT GPUCA_BUILD_ORT)
1616
set(onnxruntime_FOUND OFF)
1717
endif()
1818
if(GPUCA_BUILD_SOFIE)
19-
find_package(ROOT CONFIG REQUIRED COMPONENTS ROOTTMVASofie ROOTTMVASofieParser)
20-
find_path(GPUCA_SOFIE_GPU_INCLUDE TMVA/RGPUModel.hxx HINTS ${ROOT_INCLUDE_DIRS} NO_DEFAULT_PATH)
21-
if(NOT GPUCA_SOFIE_GPU_INCLUDE)
22-
message(FATAL_ERROR "SOFIE GPU requires the ROOT development package with RGPUModel support")
23-
endif()
19+
find_package(SOFIE CONFIG REQUIRED)
2420
endif()
2521

2622
# set(CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE_UPPER} "${CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE_UPPER}} -O0") # to uncomment if needed, tired of typing this...
@@ -468,7 +464,7 @@ endif()
468464
target_link_libraries(${targetName} PRIVATE TBB::tbb)
469465
if(GPUCA_BUILD_SOFIE)
470466
target_compile_definitions(${targetName} PRIVATE GPUCA_HAS_SOFIE=1)
471-
target_link_libraries(${targetName} PRIVATE ROOT::ROOTTMVASofie ROOT::ROOTTMVASofieParser)
467+
target_link_libraries(${targetName} PRIVATE SOFIE::SOFIE_core SOFIE::SOFIE_parsers)
472468
endif()
473469

474470
target_compile_options(${targetName} PRIVATE -Wno-instantiation-after-specialization)

‎GPU/GPUTracking/TPCClusterFinder/GPUTPCNNClusterizerHost.cxx‎

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,6 @@
1212
/// \file GPUTPCNNClusterizerHost.cxx
1313
/// \author Christian Sonnabend
1414

15-
#ifdef GPUCA_HAS_SOFIE
16-
#include "Rtypes.h"
17-
#endif
18-
1915
#include <CommonUtils/StringUtils.h>
2016

2117
#include "GPUTPCNNClusterizerHost.h"
@@ -33,8 +29,8 @@
3329
#endif
3430

3531
#ifdef GPUCA_HAS_SOFIE
36-
#include <TMVA/RGPUModel.hxx>
37-
#include <TMVA/RModelParser_ONNX.hxx>
32+
#include <SOFIE/RGPUModel.hxx>
33+
#include <SOFIE/RModelParser_ONNX.hxx>
3834
#endif
3935
#include <array>
4036
#include <limits>
@@ -44,8 +40,8 @@ using namespace o2::gpu;
4440

4541
struct GPUTPCNNClusterizerHost::SofieState {
4642
#ifdef GPUCA_HAS_SOFIE
47-
std::array<std::shared_ptr<TMVA::Experimental::SOFIE::RGPUModel>, 3> models;
48-
std::array<std::unique_ptr<TMVA::Experimental::SOFIE::RGPUModel::Session>, 3> sessions;
43+
std::array<std::shared_ptr<SOFIE::RGPUModel>, 3> models;
44+
std::array<std::unique_ptr<SOFIE::RGPUModel::Session>, 3> sessions;
4945
#endif
5046
std::array<std::string, 3> buffers;
5147
size_t workspaceSize = 0;
@@ -168,7 +164,7 @@ void GPUTPCNNClusterizerHost::initClusterizer(const GPUSettingsProcessingNNclust
168164
}
169165
clustererNN.mSofieWorkspaceSize = mSofie->workspaceSize;
170166
for (const auto& model : mSofie->models) {
171-
if (model && ((model->GetPrecision() == TMVA::Experimental::SOFIE::RGPUModel::Precision::Float16) != (clustererNN.mNnInferenceInputDType == 1) || clustererNN.mNnInferenceInputDType != clustererNN.mNnInferenceOutputDType)) {
167+
if (model && ((model->GetPrecision() == SOFIE::RGPUModel::Precision::Float16) != (clustererNN.mNnInferenceInputDType == 1) || clustererNN.mNnInferenceInputDType != clustererNN.mNnInferenceOutputDType)) {
172168
throw std::runtime_error("Changing SOFIE precision requires chain reinitialization");
173169
}
174170
if (model && model->InputSize() != static_cast<size_t>(clustererNN.mNnClusterizerElementSize)) {
@@ -328,7 +324,7 @@ MockedOrtAllocator* GPUTPCNNClusterizerHost::getMockedAllocator()
328324
void GPUTPCNNClusterizerHost::initSofie(const GPUSettingsProcessingNNclusterizer& settings, void* stream, int32_t device, bool hip, const GPUTPCNNClusterizerHost* source, const std::array<std::string_view, 3>& buffers, const GPUTPCNNClusterizerHost* previous)
329325
{
330326
#ifdef GPUCA_HAS_SOFIE
331-
using Model = TMVA::Experimental::SOFIE::RGPUModel;
327+
using Model = SOFIE::RGPUModel;
332328
if (!settings.nnClusterizerBatchedMode || settings.nnClusterizerBatchedMode > static_cast<unsigned>(std::numeric_limits<int32_t>::max())) {
333329
throw std::runtime_error("SOFIE requires a positive batch capacity within int32 range");
334330
}
@@ -339,7 +335,7 @@ void GPUTPCNNClusterizerHost::initSofie(const GPUSettingsProcessingNNclusterizer
339335
if (value == "FP16" || value == "fp16") {
340336
return Model::Precision::Float16;
341337
}
342-
throw std::runtime_error("SOFIE precision must be FP32 or FP16");
338+
throw std::runtime_error("SOFIE supports FP32 or FP16 model precision");
343339
};
344340
const auto inputType = precision(settings.nnInferenceInputDType);
345341
if (inputType != precision(settings.nnInferenceOutputDType)) {
@@ -383,7 +379,7 @@ void GPUTPCNNClusterizerHost::initSofie(const GPUSettingsProcessingNNclusterizer
383379
paths[i + 1] = regression[i];
384380
}
385381
}
386-
TMVA::Experimental::SOFIE::RModelParser_ONNX parser;
382+
SOFIE::RModelParser_ONNX parser;
387383
std::unordered_map<std::string, std::shared_ptr<Model>> compiled;
388384
if (settings.nnLoadFromCCDB && previous && previous->mSofie) {
389385
for (size_t i = 0; i < previous->mSofie->models.size(); i++) {
@@ -413,17 +409,16 @@ void GPUTPCNNClusterizerHost::initSofie(const GPUSettingsProcessingNNclusterizer
413409
inputType == Model::Precision::Float16 ? "FP16" : "FP32");
414410
if (settings.nnLoadFromCCDB) {
415411
std::istringstream input(state->buffers[i], std::ios::in | std::ios::binary);
416-
model = std::make_shared<Model>(parser.ParseGPU(input));
412+
model = std::make_shared<Model>(parser.Parse(input, "clusterizer"));
417413
} else {
418-
model = std::make_shared<Model>(parser.ParseGPU(paths[i]));
414+
model = std::make_shared<Model>(parser.Parse(paths[i]));
419415
}
420416
if (model->GetPrecision() != inputType) {
421417
throw std::runtime_error("SOFIE model precision differs from nnInferenceInputDType: " + paths[i]);
422418
}
423419
if (model->InputSize() != inputSize || model->OutputSize() > static_cast<size_t>(std::numeric_limits<int32_t>::max()) / settings.nnClusterizerBatchedMode) {
424420
throw std::runtime_error("SOFIE model shape does not match the clusterizer window or index range: " + paths[i]);
425421
}
426-
model->WorkspaceSize(settings.nnClusterizerBatchedMode);
427422
model->Compile({hip ? Model::Backend::HIP : Model::Backend::CUDA, settings.sofieCompiler, settings.sofieArchitecture});
428423
GPUInfo("SOFIE: model %zu compilation succeeded, input=%zu, output=%zu",
429424
i, model->InputSize(), model->OutputSize());
@@ -471,14 +466,16 @@ void GPUTPCNNClusterizerHost::bindSofieWorkspace(void* workspace, size_t bytes)
471466
if (!mSofie) {
472467
return;
473468
}
474-
if (!workspace || bytes < mSofie->workspaceSize) {
469+
if ((!workspace && mSofie->workspaceSize) || bytes < mSofie->workspaceSize) {
475470
throw std::runtime_error("O2 supplied insufficient SOFIE workspace");
476471
}
477472
auto* next = static_cast<char*>(workspace);
478473
for (const auto& session : mSofie->sessions) {
479474
if (session) {
480475
session->SetWorkspace(next, session->WorkspaceSize());
481-
next += session->WorkspaceSize();
476+
if (session->WorkspaceSize()) {
477+
next += session->WorkspaceSize();
478+
}
482479
}
483480
}
484481
#endif

‎GPU/README.md‎

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ This module contains the following submodules:
1313

1414
## Experimental SOFIE NN clusterizer
1515

16-
Build against the ROOT development package containing `TMVA/RGPUModel.hxx`:
16+
Build against standalone SOFIE on its `alice-custom` branch, with the
17+
`alpaka` and `sofieBLAS` dependencies supplied by alidist. A custom ROOT
18+
SOFIE implementation is no longer required:
1719

1820
- `GPUCA_BUILD_SOFIE=ON` enables the SOFIE host integration.
1921
- `GPUCA_BUILD_ORT=ON` (default) retains ORT; set it to `OFF` for a SOFIE-only
@@ -27,14 +29,18 @@ Select `ml-framework=SOFIE` (the `mlFramework` field in the NN settings), or
2729
CUDA or `gfx90a` for HIP. `sofie-compiler` (`sofieCompiler`) optionally supplies
2830
an explicit compiler path; otherwise `nvcc`/`hipcc` is found on PATH at runtime.
2931
The compiler and GPU toolkit must be available on the worker at startup.
32+
CUDA requires cuBLAS/cuBLASLt; HIP requires hipBLAS/hipBLASLt. Load the SOFIE
33+
package environment so `SOFIE_ROOT`, `ALPAKA_ROOT`, and `SOFIEBLAS_ROOT` locate
34+
the installed headers when models are compiled at runtime.
3035

3136
Use GPU TPC cluster finding, `nnInferenceDevice=cuda` or `rocm` as appropriate,
3237
local classification/regression ONNX paths with `nnLoadFromCCDB=0`, or
3338
`nnLoadFromCCDB=1` to parse the ONNX buffers fetched by the existing CCDB workflow.
3439
CCDB model slots follow `nnEvalMode` (classification, regression 1, optional regression 2). Set both
35-
`nnInferenceInputDType` and `nnInferenceOutputDType` to `FP32` or `FP16` to match
36-
the model. Mixed input/output precision, unsupported graphs, CPU SOFIE inference
37-
are rejected explicitly.
40+
`nnInferenceInputDType` and `nnInferenceOutputDType` to matching `FP32` or `FP16`
41+
and use ONNX models of that precision. FP16 inputs, weights, intermediate tensors
42+
and outputs stay in binary16, with FP32 GEMM/reduction accumulation. Dense models
43+
use hipBLAS/rocBLAS on HIP, including gfx906, without requiring hipBLASLt kernels. Unsupported graphs and CPU SOFIE inference fail explicitly.
3844

3945
Each distinct local model path is parsed and compiled once during chain initialization.
4046
For CCDB, initialization is deferred until the first event has loaded its calibration
@@ -47,23 +53,27 @@ reload propagates an error without replacing the active sessions. O2 sizes the
4753
workspace for the new models before inference.
4854
Missing or empty required buffers fail explicitly. No temporary ONNX files are needed.
4955
Each lane then gets a session bound to its existing native stream. O2 allocates
50-
input, output, weights and intermediate storage through its registered clusterizer
51-
memory. When O2 recycles the scratch arena, weights are uploaded again on the
52-
lane's stream; this does not recompile the model. Sessions persist until a model
56+
input, output and intermediate tensor storage through its registered clusterizer
57+
memory. When O2 recycles the scratch arena, sessions rebind non-owning views.
58+
Weights, persistent state, shape metadata and BLAS resources remain session-owned;
59+
they are not uploaded again when scratch memory changes. Sessions persist until a model
5360
reload or chain finalization, with GPU synchronization before unloading their libraries.
5461
Changing local model paths, batch capacity, precision or backend requires reinitializing the chain.
5562

56-
The supplied classification/regression networks have six Gemm layers, five Relu
57-
layers, 246 input values and respectively 1/5 output values. The clusterizer's
63+
Model layouts vary between exports, including dense and attention/preprocessing
64+
graphs. Check the deployed model input/output dimensions rather than assuming a
65+
particular layer count. The clusterizer's
5866
input-window and index-data settings must reproduce the training layout;
5967
the default window does not have 246 values. `nnClusterizerBatchedMode` sets
6068
the maximum batch; smaller final batches reuse the same code and workspace.
6169

62-
Validation to run after building: ROOT's `TestSofieGPU` and CUDA/HIP
63-
`TestSofieGPUDevice`, then compare SOFIE against ORT using both supplied
64-
precisions and multiple batch sizes. Check numerical tolerances and downstream
65-
cluster decisions; the scalar dense kernels are not performance tuned. For CCDB,
70+
Validation to run after building: standalone SOFIE's `SOFIEWorkspace` and
71+
`SOFIERuntimeWorkspace` tests (see `SOFIE/core/README.md`), then compare SOFIE
72+
against ORT using FP32 and FP16 models and multiple batch sizes. Check numerical
73+
tolerances and downstream cluster decisions. Inference uses SOFIE's operator
74+
implementations and Alpaka/BLAS backends. For CCDB,
6675
check identical bytes in a new buffer, one changed model, changed hidden-layer
6776
sizes, and invalid replacement data. Only changed contents should compile; an
6877
invalid replacement must fail before switching sessions.
69-
No ROOT/O2 build or GPU test was run while implementing this change.
78+
No ROOT/O2/SOFIE build or generated-model GPU test was run while implementing
79+
this change. Small direct hipBLAS capability probes are not end-to-end validation.

0 commit comments

Comments
 (0)