LIMA
Libre Multilingual Analyzer — C++ API
Loading...
Searching...
No Matches
word_seq_embd_vectorizer.h
Go to the documentation of this file.
1// Copyright 2021 CEA LIST
2// SPDX-FileCopyrightText: 2022 CEA LIST <gael.de-chalendar@cea.fr>
3//
4// SPDX-License-Identifier: MIT
5
6#ifndef DEEPLIMA_EIGEN_WRP_WORD_SEQ_EMBD_VECTORIZER_H
7#define DEEPLIMA_EIGEN_WRP_WORD_SEQ_EMBD_VECTORIZER_H
8
9#include <string>
10#include <memory>
11#include <vector>
12#include <boost/functional/hash.hpp>
13
16
17namespace deeplima
18{
19namespace vectorizers
20{
21
22template <class DataSet, class StrFeatExtractor, class UIntFeatExtractor, class MatrixFloat, class Idx=uint64_t>
24{
25public:
26 void set_model(void* ) {}
27 typedef DataSet dataset_t;
28 typedef typename DataSet::token_t token_t;
29
30 enum feature_type_t : unsigned char
31 {
36 };
37
39 {
41 int m_dim; // 0 means "ask feature extractor"
42 std::string m_name;
43 size_t m_feat_id = 0;
44
45 feature_descr_base_t(feature_type_t type, const std::string& name, int dim = 0)
46 : m_type(type), m_dim(dim), m_name(name) {}
47 };
48
50 {
51 std::shared_ptr<FeatureVectorizerBase<Idx>> m_pvectorizer; // feature extractor
52
53 feature_descr_t(feature_type_t type, const std::string& name, std::shared_ptr<FeatureVectorizerBase<Idx>> pvectorizer)
54 : feature_descr_base_t(type, name, 0), m_pvectorizer(pvectorizer) {}
55 };
56
57protected:
58 std::vector<feature_descr_t> m_features;
59
61
62 std::vector<uint32_t> m_features_pos;
63
66
67 const StrFeatExtractor m_str_feat_extractor;
68 UIntFeatExtractor m_uint_feat_extractor;
69
70 std::vector<std::pair<std::shared_ptr<uint_vectorizer_t>, size_t>> m_uint_vectorizers; // pointer to vectorizer, feat_idx
71 std::vector<std::pair<std::shared_ptr<str_vectorizer_t>, size_t>> m_str_vectorizers;
72
73public:
74
77
78 WordSeqEmbdVectorizer(const std::vector<feature_descr_t>& features)
80 {
81 init_features(features);
82 }
83
84 WordSeqEmbdVectorizer(const std::vector<feature_descr_t>& features,
85 const StrFeatExtractor& str_feat_extractor)
86 : m_features_size(0),
87 m_str_feat_extractor(str_feat_extractor)
88 {
89 init_features(features);
90 }
91
92 bool is_precomputing() const
93 {
94 return false;
95 }
96
97 inline void precompute(const DataSet& /*dataset*/)
98 {
99 }
100
101 typedef UIntFeatExtractor uint_feat_extractor_t;
102
103 UIntFeatExtractor& get_uint_feat_extractor()
104 {
106 }
107
108 void init_features(const std::vector<feature_descr_t>& features)
109 {
110 m_features = features;
111 m_features_size = 0;
112 m_features_pos.reserve(m_features.size());
113
114 for (auto& feat_descr : m_features)
115 {
116 if (str_feature == feat_descr.m_type)
117 {
118 auto pfv = std::dynamic_pointer_cast<str_vectorizer_t>(feat_descr.m_pvectorizer);
119 assert(nullptr != pfv);
120 feat_descr.m_feat_id = m_str_feat_extractor.get_feat_id(feat_descr.m_name);
121 m_str_vectorizers.emplace_back(std::make_pair(pfv, feat_descr.m_feat_id));
122
124
125 if (0 == feat_descr.m_dim)
126 {
127 m_features_size += feat_descr.m_pvectorizer->dim();
128 }
129 else
130 {
131 m_features_size += feat_descr.m_dim;
132 }
133 }
134 else if (int_feature == feat_descr.m_type)
135 {
136 auto pfv = std::dynamic_pointer_cast<uint_vectorizer_t>(feat_descr.m_pvectorizer);
137 assert(nullptr != pfv);
138 feat_descr.m_feat_id = m_uint_feat_extractor.get_feat_id(feat_descr.m_name);
139 m_uint_vectorizers.emplace_back(std::make_pair(pfv, feat_descr.m_feat_id));
140
142
143 if (0 == feat_descr.m_dim)
144 {
145 m_features_size += feat_descr.m_pvectorizer->dim();
146 }
147 else
148 {
149 m_features_size += feat_descr.m_dim;
150 }
151 }
152 }
153
154 for (const auto& feat_descr : m_features)
155 {
156 if (float_feature == feat_descr.m_type)
157 {
158 throw std::runtime_error("Unsupported");
159 }
160 }
161
162 if (m_features.size() != (m_uint_vectorizers.size() + m_str_vectorizers.size()))
163 {
164 throw std::runtime_error("Unknown vectorizer used");
165 }
166 }
167
168 int dim() const
169 {
170 return m_features_size;
171 }
172
173 inline void vectorize_timepoint(MatrixFloat& target, uint64_t timepoint, const typename DataSet::token_t& token) const
174 {
175 for (size_t feat_idx = 0; feat_idx < m_features.size(); ++feat_idx)
176 {
177 const auto& feat_descr = m_features[feat_idx];
178
179 if (feature_type_t::int_feature == feat_descr.m_type)
180 {
181 auto pfv = std::dynamic_pointer_cast<uint_vectorizer_t>(feat_descr.m_pvectorizer);
182 const float feat_val = m_uint_feat_extractor.feat_value(token, feat_descr.m_feat_id);
183 pfv->get(feat_val, target, timepoint, m_features_pos[feat_idx]);
184 }
185 else if (feature_type_t::str_feature == feat_descr.m_type)
186 {
187 auto pfv = std::dynamic_pointer_cast<str_vectorizer_t>(feat_descr.m_pvectorizer);
188 const std::string& feat_val = m_str_feat_extractor.feat_value(token, feat_descr.m_feat_id);
189 pfv->get(feat_val, target, timepoint, m_features_pos[feat_idx]);
190 }
191 }
192 }
193};
194
195template <class DataSet,
196 class StrFeatExtractor,
197 class UIntFeatExtractor,
198 class MatrixFloat,
199 class Idx=uint64_t,
200 size_t NUM_BUCKETS=32,
201 size_t BUCKET_SIZE=1024*64>
203 : public WordSeqEmbdVectorizer<DataSet, StrFeatExtractor, UIntFeatExtractor, MatrixFloat, Idx>
204{
205protected:
207
210 {
211 protected:
212 std::vector<uint64_t> m_uint_feats;
213 std::string m_str_feats; // concatenated string features with \0 as separator
214
215 public:
216 void set_model(void* ) {}
217
218 timepoint_features_t(size_t num_uint_feats)
219 : m_uint_feats(num_uint_feats, 0) { }
220
221 inline void set_uint_feat(size_t idx, uint64_t val)
222 {
223 assert(idx < m_uint_feats.size());
224 m_uint_feats[idx] = val;
225 }
226
227 inline uint64_t get_uint_feat(size_t idx) const
228 {
229 assert(idx < m_uint_feats.size());
230 return m_uint_feats[idx];
231 }
232
233 inline void append_str_feat(const std::string& val)
234 {
235 if (!m_str_feats.empty())
236 {
237 m_str_feats.push_back(0);
238 }
239 m_str_feats.append(val);
240 }
241
242 inline void append_str_feat(char val)
243 {
244 m_str_feats.push_back(val);
245 }
246
247 inline const std::string& get_str_feat() const
248 {
249 return m_str_feats;
250 }
251
252 inline bool operator==(const timepoint_features_t& other) const
253 {
254 assert(m_uint_feats.size() == other.m_uint_feats.size());
255 return (m_uint_feats == other.m_uint_feats) && (m_str_feats == other.m_str_feats);
256 }
257
259 };
260
262 {
263 std::size_t operator()(timepoint_features_t const& a) const noexcept
264 {
265 std::size_t h = 0;
266 if (!a.m_uint_feats.empty())
267 {
268 h = boost::hash_range(a.m_uint_feats.begin(), a.m_uint_feats.end());
269 }
270 boost::hash_combine(h, a.m_str_feats);
271 return h;
272 }
273 };
274
275 std::unordered_map<timepoint_features_t, Idx, timepoint_features_hash> m_precomputed_index;
276 std::vector<eigen_wrp::EigenMatrixXf::matrix_t> m_precomputed_vectors;
281
283 {
284 auto it = m_precomputed_index.find(key);
285 if (m_precomputed_index.end() != it)
286 {
287 Idx i = it->second;
288 Idx bucket_id = i / m_bucket_size;
289 assert(bucket_id < m_precomputed_vectors.size());
290 i = i % m_bucket_size;
291 *matrix = &(m_precomputed_vectors[bucket_id]);
292 return i;
293 }
294
296 {
298 {
301 {
303 }
304 m_next_free_idx = 0;
305 }
306
308 {
310 }
311
315 Idx key_idx = m_next_free_idx;
317
318 return key_idx;
319 }
320
322 *matrix = &m_temp_vectors;
323 return 0;
324 }
325
327 {
328 assert(dim > 0);
330 = eigen_wrp::EigenMatrixXf::matrix_t::Zero(dim, m_bucket_size);
331 }
332
334 {
335 size_t feat_idx = 0;
336 for (size_t i = 0; i < Parent::m_uint_vectorizers.size(); ++i)
337 {
338 Parent::m_uint_vectorizers[i].first->get(float(key.get_uint_feat(i)), matrix, idx, Parent::m_features_pos[feat_idx]);
339 feat_idx++;
340 }
341
342 const std::string& str = key.get_str_feat();
343 const char* p = str.data();
344 for (size_t i = 0; i < Parent::m_str_vectorizers.size(); ++i)
345 {
346 Parent::m_str_vectorizers[i].first->get(p, matrix, idx, Parent::m_features_pos[feat_idx]);
347 feat_idx++;
348 p = strchr(p, 0) + 1;
349 assert(nullptr != p);
350 }
351 }
352
353 virtual void init_cache(size_t dim)
354 {
355 if (m_precomputed_vectors.empty())
356 {
357
358 if (dim > 0)
359 {
361 = eigen_wrp::EigenMatrixXf::matrix_t::Zero(dim, 2);
362 }
363 }
364 }
365
366public:
368
369 WordSeqEmbdVectorizerWithCache(size_t bucket_size = BUCKET_SIZE)
370 : Parent(),
371 m_bucket_size(bucket_size),
374 {
375 m_precomputed_vectors.resize(NUM_BUCKETS);
376 }
377
378 WordSeqEmbdVectorizerWithCache(const std::vector<feature_descr_t>& features, size_t bucket_size = BUCKET_SIZE)
379 : Parent(),
380 m_bucket_size(bucket_size),
383 {
384 init_features(features);
385 m_precomputed_vectors.resize(NUM_BUCKETS);
386 }
387
388 bool is_precomputing() const
389 {
390 return false;
391 }
392
393
394 inline void precompute(const DataSet& dataset)
395 {
396 }
397
398 virtual void init_features(const std::vector<feature_descr_t>& features)
399 {
400 Parent::init_features(features);
401 }
402
403 inline void create_key(timepoint_features_t& timepoint_features, const typename DataSet::token_t& token)
404 {
405 size_t feat_idx = 0;
406 for (size_t i = 0; i < Parent::m_uint_vectorizers.size(); ++i)
407 {
408 const uint64_t feat_val = Parent::m_uint_feat_extractor.feat_value(token, Parent::m_uint_vectorizers[i].second);
409 timepoint_features.set_uint_feat(i, feat_val);
410 feat_idx++;
411 }
412
413 for (size_t i = 0; i < Parent::m_str_vectorizers.size(); ++i)
414 {
415 const std::string& feat_val = Parent::m_str_feat_extractor.feat_value(token, Parent::m_str_vectorizers[i].second);
416 timepoint_features.append_str_feat(feat_val);
417 feat_idx++;
418 }
419 timepoint_features.append_str_feat(0);
420 }
421
422 inline void vectorize_timepoint(MatrixFloat& target, uint64_t timepoint, const typename DataSet::token_t& token)
423 {
424 timepoint_features_t timepoint_features(Parent::m_uint_vectorizers.size());
425
426 create_key(timepoint_features, token);
427
428 eigen_wrp::EigenMatrixXf::matrix_t* p_matrix = nullptr;
429 Idx idx = get_vector(timepoint_features, &p_matrix);
430 assert(nullptr != p_matrix);
431 target.col(timepoint) = p_matrix->col(idx);
432 }
433};
434
435template <class Model,
436 class DataSet,
437 class StrFeatExtractor,
438 class UIntFeatExtractor,
439 class MatrixFloat,
440 class Idx=uint64_t,
441 size_t NUM_BUCKETS=32,
442 size_t BUCKET_SIZE=1024*64>
444 : public WordSeqEmbdVectorizerWithCache<DataSet,
445 StrFeatExtractor,
446 UIntFeatExtractor,
447 MatrixFloat,
448 Idx,
449 NUM_BUCKETS,
450 BUCKET_SIZE>
451{
452protected:
453 typedef WordSeqEmbdVectorizerWithCache<DataSet,
454 StrFeatExtractor,
455 UIntFeatExtractor,
456 MatrixFloat,
457 Idx,
458 NUM_BUCKETS,
459 BUCKET_SIZE> Parent;
460
461 Model* m_pModel;
463
464 virtual void init_cache(size_t dim)
465 {
466 Parent::m_precomputed_vectors.resize(NUM_BUCKETS);
469 = eigen_wrp::EigenMatrixXf::matrix_t::Zero(dim, 2);
470 }
471
472public:
473
474 WordSeqEmbdVectorizerWithPrecomputing(size_t bucket_size = BUCKET_SIZE)
475 : Parent(bucket_size),
476 m_pModel(nullptr),
478 {
479 }
480
481 WordSeqEmbdVectorizerWithPrecomputing(const std::vector<typename Parent::feature_descr_t>& features, size_t bucket_size = 1024*64)
482 : Parent(features, bucket_size),
483 m_pModel(nullptr),
485 {
486 }
487
488 bool is_precomputing() const
489 {
490 return true;
491 }
492
493 void set_model(Model* pModel)
494 {
495 assert(nullptr != pModel);
496 m_pModel = pModel;
497 m_precomputed_dim = pModel->get_precomputed_dim();
498 }
499
500 inline size_t dim()
501 {
502 return m_precomputed_dim;
503 }
504
505 inline void precompute(const DataSet& dataset)
506 {
507 assert(nullptr != m_pModel);
508
510 = eigen_wrp::EigenMatrixXf::matrix_t::Zero(Parent::dim(), Parent::m_bucket_size);
512 = eigen_wrp::EigenMatrixXf::matrix_t::Zero(Parent::dim(), 1);
513
514 uint64_t curr = 0;
515 while (curr < dataset.size())
516 {
517 if (Parent::m_curr_bucket_id > 2) break;
518
519 for (long int i = 0; i < Parent::m_bucket_size && curr < dataset.size(); ++i)
520 {
521 const typename DataSet::token_t& token = dataset[curr];
522 typename Parent::timepoint_features_t timepoint_features(Parent::m_uint_vectorizers.size());
523 Parent::create_key(timepoint_features, token);
524 Parent::compute_vector(timepoint_features, input, i);
525 Parent::m_precomputed_index[timepoint_features] = curr;
526
527 curr++;
528 }
529
531 {
533 }
536
538 {
540 }
541 }
542 }
543
545 {
546 auto it = Parent::m_precomputed_index.find(key);
547 if (Parent::m_precomputed_index.end() != it)
548 {
549 Idx i = it->second;
550 auto bucket_id = i / Parent::m_bucket_size;
551 assert(size_t(bucket_id) < Parent::m_precomputed_vectors.size());
552 i = i % Parent::m_bucket_size;
553 *matrix = &(Parent::m_precomputed_vectors[bucket_id]);
554 return i;
555 }
556
558 {
560 {
563 {
565 }
567 }
568
570 {
572 }
573
575 m_pModel->precompute_inputs(Parent::m_temp_vectors,
580 Idx key_idx = Parent::m_next_free_idx;
582
583 return key_idx;
584 }
585
587 *matrix = &(Parent::m_temp_vectors);
588 return 0;
589 }
590
591 inline void vectorize_timepoint(MatrixFloat& target, uint64_t timepoint, const typename DataSet::token_t& token)
592 {
593 typename Parent::timepoint_features_t timepoint_features(Parent::m_uint_vectorizers.size());
594
595 Parent::create_key(timepoint_features, token);
596
597 eigen_wrp::EigenMatrixXf::matrix_t* p_matrix = nullptr;
598 Idx idx = get_vector(timepoint_features, &p_matrix);
599 assert(nullptr != p_matrix);
600 target.col(timepoint) = p_matrix->col(idx);
601 }
602};
603
604} // namespace vectorizers
605} // namespace deeplima
606
607#endif
WordSeqEmbdVectorizer< DataSet, StrFeatExtractor, UIntFeatExtractor, MatrixFloat, Idx > Parent
Idx get_vector(const timepoint_features_t &key, eigen_wrp::EigenMatrixXf::matrix_t **matrix)
std::unordered_map< timepoint_features_t, Idx, timepoint_features_hash > m_precomputed_index
WordSeqEmbdVectorizerWithCache(const std::vector< feature_descr_t > &features, size_t bucket_size=BUCKET_SIZE)
void create_key(timepoint_features_t &timepoint_features, const typename DataSet::token_t &token)
void compute_vector(const timepoint_features_t &key, eigen_wrp::EigenMatrixXf::matrix_t &matrix, Idx idx)
virtual void init_features(const std::vector< feature_descr_t > &features)
void vectorize_timepoint(MatrixFloat &target, uint64_t timepoint, const typename DataSet::token_t &token)
std::vector< eigen_wrp::EigenMatrixXf::matrix_t > m_precomputed_vectors
void vectorize_timepoint(MatrixFloat &target, uint64_t timepoint, const typename DataSet::token_t &token)
Idx get_vector(const typename Parent::timepoint_features_t &key, eigen_wrp::EigenMatrixXf::matrix_t **matrix)
WordSeqEmbdVectorizerWithCache< DataSet, StrFeatExtractor, UIntFeatExtractor, MatrixFloat, Idx, NUM_BUCKETS, BUCKET_SIZE > Parent
WordSeqEmbdVectorizerWithPrecomputing(const std::vector< typename Parent::feature_descr_t > &features, size_t bucket_size=1024 *64)
FeatureVectorizerToMatrix< MatrixFloat, const std::string &, Idx > str_vectorizer_t
void vectorize_timepoint(MatrixFloat &target, uint64_t timepoint, const typename DataSet::token_t &token) const
std::vector< std::pair< std::shared_ptr< str_vectorizer_t >, size_t > > m_str_vectorizers
std::vector< std::pair< std::shared_ptr< uint_vectorizer_t >, size_t > > m_uint_vectorizers
FeatureVectorizerToMatrix< MatrixFloat, uint64_t, Idx > uint_vectorizer_t
WordSeqEmbdVectorizer(const std::vector< feature_descr_t > &features)
WordSeqEmbdVectorizer(const std::vector< feature_descr_t > &features, const StrFeatExtractor &str_feat_extractor)
void init_features(const std::vector< feature_descr_t > &features)
feature_descr_base_t(feature_type_t type, const std::string &name, int dim=0)
feature_descr_t(feature_type_t type, const std::string &name, std::shared_ptr< FeatureVectorizerBase< Idx > > pvectorizer)
std::shared_ptr< FeatureVectorizerBase< Idx > > m_pvectorizer