Coverage Report

Created: 2026-09-03 06:30

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/sentencepiece/build/root/include/sentencepiece_processor.h
Line
Count
Source
1
// Copyright 2016 Google Inc.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.!
14
15
#ifndef SENTENCEPIECE_PROCESSOR_H_
16
#define SENTENCEPIECE_PROCESSOR_H_
17
18
#include <cstdint>
19
#include <functional>
20
#include <memory>
21
#include <string>
22
#include <utility>
23
#include <vector>
24
25
#include "absl/status/status.h"
26
#include "absl/strings/string_view.h"
27
#include "absl/types/span.h"
28
29
namespace sentencepiece {
30
31
// SentencePieceProcessor:
32
// Simple and language independent tokenizer and de-tokenizer for
33
// Neural Network Machine Translation.
34
//
35
// SentencePieceProcessor provides Encode() and Decode() methods,
36
// which correspond to tokenization and de-tokenization respectively.
37
//
38
// - Encode:
39
//   Given a raw source sentence, encode it into a sequence
40
//   of pieces or vocabulary ids.
41
//
42
// - Decode:
43
//   Given a sequence of pieces or vocabulary ids, decode it
44
//   into a de-tokenized raw sentence.
45
//
46
// SentencePieceProcessor provides a lossless data conversion
47
// that allows the original raw sentence to be perfectly reconstructed
48
// from the encoded data, i.e., Decode(Encode(input)) == input.
49
// This characteristics is useful, as we can make the de-tokenization
50
// completely language independent.
51
//
52
// Usage:
53
//   SentencePieceProcessor sp;
54
//   sp.Load("//path/to/model");
55
//
56
//   vector<string> sps;
57
//   sp.Encode("hello world.", &sps).IgnoreError();
58
//
59
//   vector<int> ids;
60
//   sp.Encode("hello world.", &ids).IgnoreError();
61
//
62
//   string detok;
63
//   sp.Decode(sps, &detok);
64
//   CHECK_EQ("hello world.", detok).IgnoreError();
65
//
66
//   sp.Decode(ids, &detok);
67
//   CHECK_EQ("hello world.", detok).IgnoreError();
68
//
69
//  We can also use SentencePieceText which manages the byte-offsets
70
//  between user input (output) and internal sentence pieces.
71
//
72
//   SentencePieceText spt;
73
//   sp.Encode("hello world.", &spt);
74
//   // Emits the byte range of each piece.
75
//   for (const auto &piece : spt.pieces()) {
76
//      LOG(INFO) << piece.begin() << " " << piece.end();
77
//   }
78
//
79
//   sp.Decode({0, 1, 2, 3..}, &spt);
80
//   for (const auto &piece : spt.pieces()) {
81
//      LOG(INFO) << piece.begin() << " " << piece.end();
82
//   }
83
//
84
85
class NBestSentencePieceText;
86
class ModelInterface;
87
class SentencePieceText;
88
class ModelProto;
89
class NormalizerSpec;
90
91
namespace normalizer {
92
class Normalizer;
93
}  // namespace normalizer
94
95
// Default ThreadPool implemented using Abseil functionality.
96
// If you want to use a custom implementation, please inherit from it.
97
//
98
// Note: This ThreadPool does not support recursive calls. Scheduling a new task
99
// on the same ThreadPool from within an already scheduled task will cause a
100
// severe deadlock. Please use a different ThreadPool instance instead.
101
class ThreadPool {
102
 public:
103
  ThreadPool() = delete;
104
  explicit ThreadPool(size_t num_threads);
105
  virtual ~ThreadPool();
106
107
  virtual void Schedule(std::function<void()> func);
108
  [[nodiscard]] virtual size_t num_threads() const;
109
110
 private:
111
  class Impl;
112
  std::unique_ptr<Impl> impl_;
113
};
114
115
// Currently, the C++ API does not include a dedicated batch processing API.
116
// However, you can safely perform batch processing in coordination with the
117
// existing ThreadPool by using the RunBatch utility below.
118
//
119
// Executes tasks concurrently with dynamic load-balancing. Stops early if any
120
// task returns an error.
121
// `total_tasks`: Number of tasks to execute (= batch size)
122
// `task_func`:   Function to process a task by index.
123
// `pool`:        ThreadPool for scheduling workers.
124
//
125
// Sample:
126
//
127
// ThreadPool pool(32);
128
// std::vector<std::string> ins = {...};
129
// std::vector<std::vector<int>> outs(ins.size());
130
// auto status = sentencepiece::RunBatch(inputs.size(), [&](size_t i) {
131
//   return spm.Encode(ins[i], &outs[i]);
132
// }, pool);
133
absl::Status RunBatch(size_t total_tasks,
134
                      std::function<absl::Status(size_t index)> task_func,
135
                      ThreadPool& pool);
136
137
namespace util {
138
using bytes = std::string;
139
}  // namespace util
140
141
class NBestSentencePieceText;
142
class ModelInterface;
143
class SentencePieceText;
144
145
class SentencePieceProcessor {
146
 public:
147
  SentencePieceProcessor();
148
  virtual ~SentencePieceProcessor();
149
150
  // Loads model from `filename`.
151
  // Returns false if `filename` cannot be loaded.
152
  virtual absl::Status Load(absl::string_view filename);
153
154
  // Loads model from `filename`.
155
  // Crash if `filename` cannot be loaded.
156
  virtual void LoadOrDie(absl::string_view filename);
157
158
  // Loads model from `model_proto`.
159
  // `model_proto` is copied.
160
  virtual absl::Status Load(const ModelProto& model_proto);
161
162
  // Loads model from `model_proto`.
163
  // `model_proto` is moved.
164
  virtual absl::Status Load(std::unique_ptr<ModelProto> model_proto);
165
166
  // Loads model from `serialized`, which is a string-serialized model proto.
167
  // Useful to load the model from a platform independent blob object.
168
  virtual absl::Status LoadFromSerializedProto(absl::string_view serialized);
169
170
  // Returns the status. Encode/Decode methods are valid when status is OK.
171
  virtual absl::Status status() const;
172
173
  // Sets encode extra_option sequence.
174
  virtual absl::Status SetEncodeExtraOptions(absl::string_view extra_option);
175
176
  // Sets decode extra_option sequence.
177
  virtual absl::Status SetDecodeExtraOptions(absl::string_view extra_option);
178
179
  //////////////////////////////////////////////////////////////
180
  // Simple Encode and Decode API.
181
  //
182
  // Given a UTF8 input, encodes it into a sequence of sentence pieces.
183
  virtual absl::Status Encode(absl::string_view input,
184
                              std::vector<std::string>* pieces) const;
185
186
  // Given a UTF8 input, encodes it into a sequence of ids.
187
  virtual absl::Status Encode(absl::string_view input,
188
                              std::vector<int>* ids) const;
189
190
  // Given a sequence of pieces, decodes it into a detokenized output.
191
  virtual absl::Status Decode(absl::Span<const std::string> pieces,
192
                              std::string* detokenized) const;
193
194
  // Given a sequence of pieces, decodes it into a detokenized output.
195
  virtual absl::Status Decode(absl::Span<const absl::string_view> pieces,
196
                              std::string* detokenized) const;
197
198
  // Given a sequence of ids, decodes it into a detokenized output.
199
  virtual absl::Status Decode(absl::Span<const int> ids,
200
                              std::string* detokenized) const;
201
202
  //////////////////////////////////////////////////////////////
203
  // NBest API.
204
  //
205
  // Same as Encode, but returns nbest results.
206
  virtual absl::Status NBestEncode(
207
      absl::string_view input, int nbest_size,
208
      std::vector<std::vector<std::string>>* pieces) const;
209
210
  // Same as Encode, but returns nbest results.
211
  virtual absl::Status NBestEncode(absl::string_view input, int nbest_size,
212
                                   std::vector<std::vector<int>>* ids) const;
213
214
  //////////////////////////////////////////////////////////////
215
  // Sampling API.
216
  //
217
  // Unigram and BPE support sampling mode.
218
  // - Unigram (--model_type=unigram):
219
  // `nbest_size`: When `nbest_size` is positive value, approximately samples
220
  // one segmentation from nbest candidates. When `nbest_size` is negative
221
  // value, samples one segmentation from the hypotheses (Lattice) according to
222
  // the generation probabilities using forward-filtering and backward-sampling
223
  // algorithm.
224
  // `alpha`: Smoothing parameter (inverse temperature). The best segmentation
225
  // (Viterbi segmentation) is more likely sampled when setting larger alpha.
226
  // When alpha is 0.0, one segmentation is uniformly sampled from the nbest or
227
  // lattice. `nbest_size` and `alpha` correspond to parameters `l` and `alpha`
228
  // in https://arxiv.org/abs/1804.10959  (nbest_size < 0 means l = infinity)
229
  //
230
  // - BPE (--model_type=bpe):
231
  // `alpha`: The dropout probability `p` of bpe merge operations in
232
  // https://arxiv.org/abs/1910.13267 Nbest-based sampling is not supported so
233
  // nbest_size parameter is ignored in BPE.
234
  virtual absl::Status SampleEncode(absl::string_view input, int nbest_size,
235
                                    float alpha,
236
                                    std::vector<std::string>* pieces) const;
237
238
  // Same as above, but returns a sequence of ids.
239
  virtual absl::Status SampleEncode(absl::string_view input, int nbest_size,
240
                                    float alpha, std::vector<int>* ids) const;
241
242
  //////////////////////////////////////////////////////////////
243
  // Advanced API returning SentencePieceText, which manages
244
  // utf8-byte alignments between user-input/detokenized text
245
  // and internal sentencepiece sequence.
246
  //
247
  // Given a UTF8 input, encodes it into SentencePieceText.
248
  //
249
  // When using these APIs, sentencepiece.pb.h header files must be included.
250
251
  virtual absl::Status Encode(absl::string_view input,
252
                              SentencePieceText* spt) const;
253
254
  virtual absl::Status NBestEncode(absl::string_view input, int nbest_size,
255
                                   NBestSentencePieceText* nbest_spt) const;
256
257
  virtual absl::Status SampleEncode(absl::string_view input, int nbest_size,
258
                                    float alpha, SentencePieceText* spt) const;
259
260
  virtual absl::Status Decode(absl::Span<const absl::string_view> pieces,
261
                              SentencePieceText* spt) const;
262
263
  virtual absl::Status Decode(absl::Span<const int> ids,
264
                              SentencePieceText* spt) const;
265
266
  //////////////////////////////////////////////////////////////
267
  // API methods for encoding sequences in parallel.
268
  // This is particularly useful for long inputs.
269
270
  // chunk_len controls how long each chunk to be tokenized in parallel is.
271
  // For best results, set this to ~10000.
272
273
  // WARNING: ParallelEncode with SentencePieceText * inputs currently does not
274
  // copy the UNK surface form correctly. Use at your own risk!
275
  virtual absl::Status ParallelEncode(absl::string_view input, int chunk_len,
276
                                      ThreadPool& thread_pool,
277
                                      std::vector<std::string>* pieces) const;
278
  virtual absl::Status ParallelEncode(absl::string_view input, int chunk_len,
279
                                      ThreadPool& thread_pool,
280
                                      std::vector<int>* ids) const;
281
  virtual absl::Status ParallelEncode(absl::string_view input, int chunk_len,
282
                                      ThreadPool& thread_pool,
283
                                      SentencePieceText* spt) const;
284
285
#define DEFINE_SPP_DIRECT_FUNC_IMPL(FuncName, OutType, ...) \
286
126
  OutType output;                                           \
287
126
  const auto status = FuncName(__VA_ARGS__, &output);       \
288
126
  return output;
289
290
  //////////////////////////////////////////////////////////////
291
  // Handy methods that return the result directly.
292
  // These functions ignore internal errors.
293
  [[nodiscard]] virtual std::vector<std::string> EncodeAsPieces(
294
0
      absl::string_view input) const {
295
0
    DEFINE_SPP_DIRECT_FUNC_IMPL(Encode, std::vector<std::string>, input);
296
0
  }
297
298
  [[nodiscard]] virtual std::vector<int> EncodeAsIds(
299
      absl::string_view input) const {
300
    DEFINE_SPP_DIRECT_FUNC_IMPL(Encode, std::vector<int>, input);
301
  }
302
303
  [[nodiscard]] virtual std::vector<std::vector<std::string>>
304
  NBestEncodeAsPieces(absl::string_view input, int nbest_size) const {
305
    DEFINE_SPP_DIRECT_FUNC_IMPL(
306
        NBestEncode, std::vector<std::vector<std::string>>, input, nbest_size);
307
  }
308
309
  [[nodiscard]] virtual std::vector<std::vector<int>> NBestEncodeAsIds(
310
      absl::string_view input, int nbest_size) const {
311
    DEFINE_SPP_DIRECT_FUNC_IMPL(NBestEncode, std::vector<std::vector<int>>,
312
                                input, nbest_size);
313
  }
314
315
  [[nodiscard]] virtual std::vector<std::string> SampleEncodeAsPieces(
316
126
      absl::string_view input, int nbest_size, float alpha) const {
317
126
    DEFINE_SPP_DIRECT_FUNC_IMPL(SampleEncode, std::vector<std::string>, input,
318
126
                                nbest_size, alpha);
319
0
  }
320
321
  [[nodiscard]] virtual std::vector<int> SampleEncodeAsIds(
322
      absl::string_view input, int nbest_size, float alpha) const {
323
    DEFINE_SPP_DIRECT_FUNC_IMPL(SampleEncode, std::vector<int>, input,
324
                                nbest_size, alpha);
325
  }
326
327
  virtual std::vector<std::string> ParallelEncodeAsPieces(
328
      absl::string_view input, int chunk_len, ThreadPool& therad_pool) const {
329
    DEFINE_SPP_DIRECT_FUNC_IMPL(ParallelEncode, std::vector<std::string>, input,
330
                                chunk_len, therad_pool);
331
  }
332
333
  virtual std::vector<int> ParallelEncodeAsIds(absl::string_view input,
334
                                               int chunk_len,
335
                                               ThreadPool& therad_pool) const {
336
    DEFINE_SPP_DIRECT_FUNC_IMPL(ParallelEncode, std::vector<int>, input,
337
                                chunk_len, therad_pool);
338
  }
339
340
  [[nodiscard]] virtual std::string DecodePieces(
341
      const std::vector<absl::string_view>& pieces) const {
342
    DEFINE_SPP_DIRECT_FUNC_IMPL(Decode, std::string, pieces);
343
  }
344
345
  [[nodiscard]] virtual std::string DecodeIds(
346
      const std::vector<int>& ids) const {
347
    DEFINE_SPP_DIRECT_FUNC_IMPL(Decode, std::string, ids);
348
  }
349
350
#undef DEFINE_SPP_DIRECT_FUNC_IMPL
351
352
  //////////////////////////////////////////////////////////////
353
  // Normalization methods.
354
355
  // Normalize `input`.
356
  virtual absl::Status Normalize(absl::string_view input,
357
                                 std::string* normalized) const;
358
359
  // Normalize `input`. Stores the utf8-byte offset from
360
  // the normalized string to the original input.
361
  virtual absl::Status Normalize(absl::string_view input,
362
                                 std::string* normalized,
363
                                 std::vector<size_t>* norm_to_orig) const;
364
365
  [[nodiscard]] virtual std::string Normalize(absl::string_view input) const;
366
367
  //////////////////////////////////////////////////////////////
368
  // Vocabulary management methods.
369
  //
370
  // Returns the size of sentence pieces, which is the same as
371
  // the size of vocabulary for NMT.
372
  [[nodiscard]] virtual int GetPieceSize() const;
373
374
  // Returns the vocab id of `piece`.
375
  // Returns UNK(0) if `piece` is unknown.
376
  [[nodiscard]] virtual int PieceToId(absl::string_view piece) const;
377
378
  // Returns the string representation of vocab with `id`.
379
  [[nodiscard]] virtual const std::string& IdToPiece(int id) const;
380
381
  // Returns the string representation of vocab with `id`.
382
  // Returns false when id is out of range.
383
  virtual bool SafeIdToPiece(int id, std::string* piece) const;
384
385
  // Returns the score of `id`.
386
  // Usually score is an emission log probability of unigram language
387
  // model.
388
  [[nodiscard]] virtual float GetScore(int id) const;
389
390
  // Returns true if `id` is unknown symbol.
391
  [[nodiscard]] virtual bool IsUnknown(int id) const;
392
393
  // Returns true if `id` is control symbol.
394
  [[nodiscard]] virtual bool IsControl(int id) const;
395
396
  // Returns true if `id` is unused symbol.
397
  [[nodiscard]] virtual bool IsUnused(int id) const;
398
399
  // Returns true if `id` is byte symbol.
400
  [[nodiscard]] virtual bool IsByte(int id) const;
401
402
  // Returns the reserved id.
403
  // Returns -1 if not defined.
404
  //
405
  // Note: Valid IDs are returned only when they are strictly defined as
406
  // CONTROL tokens (or UNKNOWN for unk_id). If they are defined as
407
  // USER_DEFINED, these methods will return -1, as USER_DEFINED symbols
408
  // are treated as normal symbols (protected from segmentation) rather
409
  // than strict special control symbols.
410
  //
411
  // Consequently, encoding extra options (like "bos" / "eos") and Python
412
  // wrapper flags (like add_bos=True / add_eos=True) will be IGNORED if
413
  // the corresponding tokens are not strictly defined as CONTROL tokens.
414
415
  // Returns unknown (<unk>) id.
416
  [[nodiscard]] virtual int unk_id() const;
417
418
  // Returns BOS (<s>) id.
419
  [[nodiscard]] virtual int bos_id() const;
420
421
  // Returns EOS (</s>) id.
422
  [[nodiscard]] virtual int eos_id() const;
423
424
  // Returns PAD (<pad>) id.
425
  [[nodiscard]] virtual int pad_id() const;
426
427
  //////////////////////////////////////////////////////////////
428
  // Model management.
429
  //
430
  // Allows injection of a mock model instance. `model` is moved.
431
  void SetModel(std::unique_ptr<ModelInterface>&& model);
432
433
  // Allows injection of a normalizer instance. `normalizer` is moved.
434
  void SetNormalizer(std::unique_ptr<normalizer::Normalizer>&& normalizer);
435
436
  // Returns immutable model proto. Useful to obtain extended
437
  // or experimental parameters encoded in model_proto.
438
  [[nodiscard]] const ModelProto& model_proto() const;
439
440
  // returns immutable model proto as std::string.
441
  // Useful to save the state of this instance via Python's pickle object.
442
  [[nodiscard]] util::bytes serialized_model_proto() const;
443
444
 private:
445
  enum ExtraOption { REVERSE, BOS, EOS, UNK_PIECE };
446
447
  absl::Status ParseExtraOptions(absl::string_view extra_option,
448
                                 std::vector<ExtraOption>* extra_options) const;
449
450
  template <typename T>
451
  absl::Status ApplyExtraOptions(absl::Span<const ExtraOption> extra_options,
452
                                 T* output) const;
453
454
  template <typename T>
455
  absl::Status EncodeOptimized(absl::string_view input,
456
                               std::vector<T>* output) const;
457
458
  template <typename T>
459
  absl::Status DecodeOptimized(absl::Span<const T> input,
460
                               std::string* detokenized) const;
461
462
  bool HasUnkPieceOption() const;
463
464
  absl::Status PopulateSentencePieceText(
465
      absl::string_view input, absl::string_view normalized,
466
      absl::Span<const size_t> norm_to_orig,
467
      const std::vector<std::pair<absl::string_view, int>>& result,
468
      SentencePieceText* spt, bool skip_surface = false,
469
      size_t input_start_offset = 0) const;
470
471
  absl::Status ParallelEncodeInternal(absl::string_view input, size_t chunk_len,
472
                                      ThreadPool& thread_pool,
473
                                      std::vector<std::string>* pieces,
474
                                      std::vector<int>* ids,
475
                                      SentencePieceText* spt) const;
476
477
  std::unique_ptr<ModelInterface> model_;
478
  std::unique_ptr<normalizer::Normalizer> normalizer_;
479
  std::unique_ptr<normalizer::Normalizer> denormalizer_;
480
481
  // Cached IDs.
482
  // Note that these IDs are not always the same as the IDs in TrainerSpec.
483
  // The TrainerSpec defines the training-time configuration, while these
484
  // IDs reflect the actual IDs in the loaded model, which might be different
485
  // or disabled (set to -1).
486
  int unk_id_ = -1;
487
  int bos_id_ = -1;
488
  int eos_id_ = -1;
489
  int pad_id_ = -1;
490
491
  // Underlying model protocol buffer. The same lifetime as model_.
492
  std::unique_ptr<ModelProto> model_proto_;
493
494
  std::vector<ExtraOption> encode_extra_options_;
495
  std::vector<ExtraOption> decode_extra_options_;
496
};
497
498
// Set seed value of random generator.
499
// Do not set static_cast<unique_int>(-1),
500
// as this seed is reserved for initializing from
501
// std::random_device.
502
void SetRandomGeneratorSeed(unsigned int seed);
503
504
// Set the global log level. The default loglevel is 0.
505
// The log is emitted only when min_log_level >= output_log_level.
506
void SetMinLogLevel(int v);
507
508
// Sets global timeout in milliseconds for NBestEncode.
509
// If timeout is reached, the search falls back to Viterbi.
510
// The default value is 30000 (30 seconds).
511
// 0 or negative value means no timeout.
512
void SetNBestTimeout(int timeout_ms);
513
514
// IO related functions to absorb model formats.
515
namespace io {
516
// Loads `model_proto` from `filename`.
517
// We can instantiate SentencePieceProcessor as follows:
518
//
519
//  auto model_proto = absl::make_unique<ModelProto>();
520
//  io::LoadModelProto("//path/spm.model", model_proto.get());
521
//  SentencePieceProcessor sp;
522
//  CHECK_OK(sp.Load(std::move(model_proto)));
523
absl::Status LoadModelProto(absl::string_view, ModelProto* model_proto);
524
525
// Saves `model_proto` as `filename`.
526
absl::Status SaveModelProto(absl::string_view, const ModelProto& model_proto);
527
}  // namespace io
528
}  // namespace sentencepiece
529
#endif  // SENTENCEPIECE_PROCESSOR_H_