Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RClusterLoader.hxx
Go to the documentation of this file.
1// Author: Dante Niewenhuis, VU Amsterdam 07/2023
2// Author: Kristupas Pranckietis, Vilnius University 05/2024
3// Author: Nopphakorn Subsa-Ard, King Mongkut's University of Technology Thonburi (KMUTT) (TH) 08/2024
4// Author: Vincenzo Eduardo Padulano, CERN 10/2024
5// Author: Silia Taider, CERN 03/2026
6
7/*************************************************************************
8 * Copyright (C) 1995-2025, Rene Brun and Fons Rademakers. *
9 * All rights reserved. *
10 * *
11 * For the licensing terms see $ROOTSYS/LICENSE. *
12 * For the list of contributors see $ROOTSYS/README/CREDITS. *
13 *************************************************************************/
14
15#ifndef ROOT_INTERNAL_ML_RCLUSTERLOADER
16#define ROOT_INTERNAL_ML_RCLUSTERLOADER
17
18#include <algorithm>
19#include <numeric>
20#include <random>
21#include <string>
22#include <utility>
23#include <vector>
24
27#include "ROOT/RDataFrame.hxx"
28#include "ROOT/RDFHelpers.hxx"
29#include "ROOT/RDF/Utils.hxx"
30
32
33/**
34 * \struct RClusterRange
35 * \brief Describes a contiguous range of entries within a single RDataFrame,
36 * corresponding to one TTree/RNTuple cluster boundary.
37 *
38 * For filtered RDataFrames the \p numEntries field may be smaller than `end - start`
39 * because it tracks the number of entries that actually pass the filter,
40 * discovered and set lazily during the first epoch.
41 */
43 std::size_t rdfIdx; // which rdf this cluster belongs to
44 std::uint64_t start; // first raw entry (incl)
45 std::uint64_t end; // one-past-last entry (excl)
46 std::size_t numEntries{
47 static_cast<std::size_t>(end - start)}; // number of entries in the cluster (that pass filters, if any)
48
49 std::size_t GetNumEntries() const { return numEntries; }
50 void SetNumEntries(std::size_t num) { numEntries = num; }
51};
52
53/**
54 * \class ROOT::Experimental::Internal::ML::RClusterLoader
55 * \brief Loads TTree/RNTuple clusters from one or more RDataFrames into RFlat2DMatrix
56 * buffers for ML training and validation.
57 *
58 * ### Overview
59 * At construction the loader scans the cluster boundaries of every
60 * provided RDataFrame and stores them as a flat list of \ref RClusterRange objects.
61 * SplitDataset() then partitions those ranges into training and validation sets according to \p validationSplit.
62 *
63 * ### The split strategy depends on whether shuffling is enabled or not
64 * - **Unshuffled**: one cut is made so that the first `(1 - validationSplit)`
65 * fraction of entries goes to training. At most one cluster is split at the boundary.
66 * - **Shuffled**: each cluster is split proportionally (according to `validationSplit`)
67 * so both sets draw entries from every part of the dataset. ShuffleTrainingClusters()
68 * and ShuffleValidationClusters() re-order the cluster lists at the start of each epoch.
69 * A second shuffling step, at the entries level, happens inside LoadTrainingClusterInto()
70 * and LoadValidationClusterInto() when loading the data into the tensors.
71 *
72 * ### Filtered RDataFrames
73 * When any RDataFrame carries a filter, the true entry count is not known
74 * until the computation graph is executed. In this case SplitDataset() is a
75 * no-op and the split is discovered lazily inside LoadTrainingClusterInto()
76 * during the first epoch.
77 * After the first epoch FinaliseSplitDiscovery() marks the split as stable and
78 * all subsequent epochs use the same pre-computed ranges.
79 */
81private:
82 std::vector<ROOT::RDF::RNode> &fRdfs;
83 std::vector<std::size_t> fRdfSizes;
84 std::vector<std::string> fCols;
85 std::vector<std::size_t> fVecSizes;
89 std::size_t fSetSeed;
90
91 std::size_t fNumCols;
92 std::size_t fSumVecSizes;
93 std::size_t fNumChunkCols;
94
95 std::vector<RClusterRange> fAllClusters;
96 std::vector<RClusterRange> fTrainingClusters;
97 std::vector<RClusterRange> fValidationClusters;
98
99 std::size_t fTotalEntries{0};
100 std::size_t fNumTrainingEntries{0};
101 std::size_t fNumValidationEntries{0};
102
103 bool fIsFiltered{false};
104 bool fSplitDiscovered{false};
107
108public:
109 RClusterLoader(std::vector<ROOT::RDF::RNode> &rdfs, const std::vector<std::string> &cols,
110 const std::vector<std::size_t> &vecSizes, float vecPadding, float validationSplit, bool shuffle,
111 std::size_t setSeed);
112
113 void SplitDataset();
114
115 void ShuffleTrainingClusters(std::size_t epochIdx);
116
117 void ShuffleValidationClusters(std::size_t epochIdx);
118
119 void LoadClusterInto(RFlat2DMatrix &dest, std::size_t rdfIdx, std::uint64_t startRow, std::uint64_t endRow);
120
121 std::size_t
122 LoadTrainingClusterInto(RFlat2DMatrix &dest, std::size_t rdfIdx, std::uint64_t startRow, std::uint64_t endRow);
123
124 void
125 LoadValidationClusterInto(RFlat2DMatrix &dest, std::size_t rdfIdx, std::uint64_t startRow, std::uint64_t endRow);
126
128
129 bool IsSplitDiscovered() const { return !fIsFiltered || fSplitDiscovered; }
130
131 //////////////////////////////////////////////////////////////////////////
132 // Accessors
133 std::size_t GetNumTrainingEntries() const { return fNumTrainingEntries; }
134 std::size_t GetNumValidationEntries() const { return fNumValidationEntries; }
135 std::size_t GetNumChunkCols() const { return fNumChunkCols; }
136
137 const std::vector<RClusterRange> &GetTrainingClusters() const
138 {
140 }
141 const std::vector<RClusterRange> &GetValidationClusters() const { return fValidationClusters; }
142
143 std::size_t GetNumTrainingClusters() const
144 {
145 return (fIsFiltered && !fSplitDiscovered) ? fAllClusters.size() : fTrainingClusters.size();
146 }
147 std::size_t GetNumValidationClusters() const { return fValidationClusters.size(); }
148 std::size_t GetNmTotalClusters() const { return fAllClusters.size(); }
149};
150
151} // namespace ROOT::Experimental::Internal::ML
152#endif // ROOT_INTERNAL_ML_RCLUSTERLOADER
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t dest
Loads TTree/RNTuple clusters from one or more RDataFrames into RFlat2DMatrix buffers for ML training ...
const std::vector< RClusterRange > & GetValidationClusters() const
void FinaliseSplitDiscovery()
Mark the train/val split as finalised after the first epoch.
void SplitDataset()
Distribute the clusters into training and validation datasets No-op for filtered RDataFrames,...
void LoadClusterInto(RFlat2DMatrix &dest, std::size_t rdfIdx, std::uint64_t startRow, std::uint64_t endRow)
std::size_t LoadTrainingClusterInto(RFlat2DMatrix &dest, std::size_t rdfIdx, std::uint64_t startRow, std::uint64_t endRow)
Load one training cluster and return the number of rows written.
void ShuffleValidationClusters(std::size_t epochIdx)
Re-order validation clusters for the upcoming epoch.
void LoadValidationClusterInto(RFlat2DMatrix &dest, std::size_t rdfIdx, std::uint64_t startRow, std::uint64_t endRow)
Load one validation cluster at the end of dest.
RClusterLoader(std::vector< ROOT::RDF::RNode > &rdfs, const std::vector< std::string > &cols, const std::vector< std::size_t > &vecSizes, float vecPadding, float validationSplit, bool shuffle, std::size_t setSeed)
void ShuffleTrainingClusters(std::size_t epochIdx)
Re-order training clusters for the upcoming epoch.
const std::vector< RClusterRange > & GetTrainingClusters() const
Describes a contiguous range of entries within a single RDataFrame, corresponding to one TTree/RNTupl...
Wrapper around ROOT::RVec<float> representing a 2D matrix.