1+ // ===----------------------------------------------------------------------===//
2+ //
3+ // Peloton
4+ //
5+ // model_util.cpp
6+ //
7+ // Identification: src/brain/util/model_util.cpp
8+ //
9+ // Copyright (c) 2015-2018, Carnegie Mellon University Database Group
10+ //
11+ // ===----------------------------------------------------------------------===//
12+
13+ #include " brain/util/model_util.h"
14+ #include " brain/workload/base_tf.h"
15+
16+ namespace peloton {
17+ namespace brain {
18+ float ModelUtil::MeanSqError (const matrix_eig &ytrue, const matrix_eig &ypred) {
19+ PELOTON_ASSERT (ytrue.rows () == ypred.rows () && ytrue.cols () == ypred.cols ());
20+ return (ytrue - ypred).array ().square ().mean ();
21+ }
22+
23+ void ModelUtil::GetBatch (const BaseForecastModel &model, const matrix_eig &mat,
24+ size_t batch_offset, size_t bsz,
25+ std::vector<matrix_eig> &data,
26+ std::vector<matrix_eig> &target, bool time_major) {
27+ if (time_major) {
28+ size_t samples_per_batch = mat.rows () / bsz;
29+ size_t seq_len = std::min<size_t >(
30+ model.GetBPTT (), samples_per_batch - model.GetHorizon () - batch_offset);
31+ // bsz vector of <seq_len, feat_len> = (bsz, seq_len, feat_len)
32+ for (size_t seq_idx = 0 ; seq_idx < bsz; seq_idx++) {
33+ size_t seqblock_start = seq_idx * samples_per_batch;
34+ size_t seq_offset = seqblock_start + batch_offset;
35+ // train mat[row_idx:row_idx + seq_len, :)
36+ matrix_eig data_batch = mat.block (seq_offset, 0 , seq_len, mat.cols ());
37+ // target mat[row_idx + horizon_: row_idx + seq_len + horizon_ , :]
38+ matrix_eig target_batch =
39+ mat.block (seq_offset + model.GetHorizon (), 0 , seq_len, mat.cols ());
40+ // Push batches into containers
41+ data.push_back (data_batch);
42+ target.push_back (target_batch);
43+ }
44+ } else {
45+ size_t seq_len = model.GetBPTT ();
46+ // bsz vector of <seq_len, feat_len> = (bsz, seq_len, feat_len)
47+ for (size_t seq_idx = 0 ; seq_idx < bsz; seq_idx++) {
48+ size_t seq_start = seq_idx * seq_len + batch_offset;
49+ matrix_eig data_batch = mat.block (seq_start, 0 , seq_len, mat.cols ());
50+ matrix_eig target_batch =
51+ mat.block (seq_start + model.GetHorizon (), 0 , seq_len, mat.cols ());
52+ data.push_back (data_batch);
53+ target.push_back (target_batch);
54+ }
55+ }
56+ }
57+
58+ void ModelUtil::GetBatches (const BaseForecastModel &model,
59+ const matrix_eig &mat, size_t batch_size,
60+ std::vector<std::vector<matrix_eig>> &data,
61+ std::vector<std::vector<matrix_eig>> &target,
62+ bool time_major) {
63+ if (time_major) {
64+ // Obtain relevant metadata
65+ int max_allowed_bsz = mat.rows () / (model.GetHorizon () + model.GetBPTT ());
66+ int min_allowed_bsz = 1 ;
67+ int bsz =
68+ std::max (min_allowed_bsz, std::min<int >(batch_size, max_allowed_bsz));
69+ int samples_per_input = mat.rows () / bsz;
70+ int num_feats = mat.cols ();
71+
72+ // Trim the data for equal sized inputs per batch
73+ matrix_eig mat_adjusted =
74+ mat.block (0 , 0 , samples_per_input * bsz, num_feats);
75+
76+ for (int batch_offset = 0 ;
77+ batch_offset < samples_per_input - model.GetHorizon ();
78+ batch_offset += model.GetBPTT ()) {
79+ std::vector<matrix_eig> data_batch_eig, target_batch_eig;
80+ ModelUtil::GetBatch (model, mat_adjusted, batch_offset, bsz,
81+ data_batch_eig, target_batch_eig);
82+ data.push_back (data_batch_eig);
83+ target.push_back (target_batch_eig);
84+ }
85+ } else {
86+ int max_rows_in = mat.rows () - model.GetHorizon ();
87+ int num_samples = max_rows_in / model.GetBPTT ();
88+ // Obtain batch size
89+ int max_allowed_bsz = num_samples;
90+ int min_allowed_bsz = 1 ;
91+ int bsz =
92+ std::max (min_allowed_bsz, std::min<int >(batch_size, max_allowed_bsz));
93+ int samples_per_batch = bsz * model.GetBPTT ();
94+ int samples_per_seq = model.GetBPTT ();
95+ int batch_offset = 0 ;
96+ for (batch_offset = 0 ; batch_offset < max_rows_in - samples_per_batch;
97+ batch_offset += samples_per_batch) {
98+ std::vector<matrix_eig> data_batch_eig, target_batch_eig;
99+ ModelUtil::GetBatch (model, mat, batch_offset, bsz, data_batch_eig,
100+ target_batch_eig, time_major);
101+ data.push_back (data_batch_eig);
102+ target.push_back (target_batch_eig);
103+ }
104+ int rem_bsz = (max_rows_in - batch_offset) / samples_per_seq;
105+ if (rem_bsz > 0 ) {
106+ std::vector<matrix_eig> data_batch_eig, target_batch_eig;
107+ ModelUtil::GetBatch (model, mat, batch_offset, rem_bsz, data_batch_eig,
108+ target_batch_eig, time_major);
109+ data.push_back (data_batch_eig);
110+ target.push_back (target_batch_eig);
111+ }
112+ }
113+ }
114+
115+ void ModelUtil::GetBatches (const BaseForecastModel &model,
116+ const matrix_eig &mat, size_t batch_size,
117+ std::vector<std::vector<matrix_eig>> &data_batches) {
118+ int num_seq = mat.rows () / model.GetBPTT ();
119+ // Obtain batch size
120+ int max_allowed_bsz = num_seq;
121+ int min_allowed_bsz = 1 ;
122+ int bsz =
123+ std::max (min_allowed_bsz, std::min<int >(batch_size, max_allowed_bsz));
124+ int samples_per_batch = bsz * model.GetBPTT ();
125+ int samples_per_seq = model.GetBPTT ();
126+ int batch_offset = 0 ;
127+ for (batch_offset = 0 ; batch_offset < mat.rows () - samples_per_batch;
128+ batch_offset += samples_per_batch) {
129+ std::vector<matrix_eig> data_batch;
130+ for (int seq_idx = 0 ; seq_idx < bsz; seq_idx++) {
131+ int seq_offset = batch_offset + seq_idx * samples_per_seq;
132+ data_batch.push_back (mat.middleRows (seq_offset, samples_per_seq));
133+ }
134+ data_batches.push_back (data_batch);
135+ }
136+ // Push remaining samples into smaller batch
137+ int rem_bsz = (mat.rows () - batch_offset) / samples_per_seq;
138+ if (rem_bsz > 0 ) {
139+ std::vector<matrix_eig> data_batch;
140+ for (int seq_idx = 0 ; seq_idx < rem_bsz; seq_idx++) {
141+ int seq_offset = batch_offset + seq_idx * samples_per_seq;
142+ data_batch.push_back (mat.middleRows (seq_offset, samples_per_seq));
143+ }
144+ data_batches.push_back (data_batch);
145+ }
146+ batch_offset += rem_bsz * samples_per_seq;
147+ int rem_seq_len = mat.rows () - batch_offset;
148+ // Push anything further remaining into a single batch of size < BPTT
149+ data_batches.push_back ({mat.bottomRows (rem_seq_len)});
150+ }
151+
152+ void ModelUtil::FeatureLabelSplit (const BaseForecastModel &model,
153+ const matrix_eig &data, matrix_eig &X,
154+ matrix_eig &y) {
155+ size_t offset_train = data.rows () - model.GetHorizon ();
156+ X = data.topRows (offset_train);
157+ size_t offset_label = model.GetBPTT () + model.GetHorizon () - 1 ;
158+ y = data.middleRows (offset_label, data.rows () - offset_label);
159+ }
160+
161+ void ModelUtil::GenerateFeatureMatrix (const BaseForecastModel &model,
162+ const matrix_eig &data,
163+ matrix_eig &processed_features) {
164+ size_t timesteps = data.rows ();
165+ std::vector<matrix_eig> feat_matrix;
166+ for (size_t idx = 0 ; idx <= timesteps - model.GetBPTT (); idx++) {
167+ feat_matrix.push_back (EigenUtil::ToEigenMat (
168+ {EigenUtil::Flatten (data.middleRows (idx, model.GetBPTT ()))}));
169+ }
170+ processed_features = EigenUtil::VStack (feat_matrix);
171+ }
172+
173+ bool ModelUtil::EarlyStop (vector_t val_losses, size_t patience, float delta) {
174+ // Check for edge cases
175+ PELOTON_ASSERT (patience > 1 );
176+ PELOTON_ASSERT (delta > 0 );
177+ if (val_losses.size () < patience) return false ;
178+ float cur_loss = val_losses[val_losses.size () - 1 ];
179+ float pat_loss = val_losses[val_losses.size () - patience];
180+ // Loss should have at least dropped by delta at this point
181+ return (pat_loss - cur_loss) < delta;
182+ }
183+
184+ } // namespace brain
185+ } // namespace peloton
0 commit comments