Files
fanlusky 80b1fc42a1 feat(engine): 词格整句改用 kenlm 三元模型打分
词格原先的整句打分是一份没校准过的启发式 unigram,质量很差。这里内嵌 libime
在用的 kenlm 查询子集,改由它的三元模型 sc.lm 来打路径分。

- engine/ngram 只编 kenlm 的 query / trie-build 路径。不定义 WITH_THREADS,
  parallel_read.cc 因此退化成串行实现,整个子集零 Boost 依赖。
  KENLM_MAX_ORDER=3 必须与建模阶数一致,改它等于读不懂已发布的模型文件。
- ngram::LanguageModel 是唯一 include kenlm 头文件的地方,对外只给出一个纯
  std 的头,_HAS_AUTO_PTR_ETC 和 kenlm 的 include 目录都保持 PRIVATE。
- shared_language_model 按资源路径共享一份 mmap。kenlm 的查询是只读的且把
  上下文放在调用方的 State 里,所以并发会话不需要额外加锁。
- 模型缺失时 valid() 为假,词格退回原来的启发式打分:整句候选只是变差,不会
  停止工作。测试覆盖了缺模型降级与按路径共享。
- 出货的 ARPA 不带 <s>/</s>,所以解码从 null_state() 起算而非 begin_state()。

kenlm 是上游副本,不重排版、不进 clang-format,其 LGPL-2.1+ 与 BSD 例外清单
已补进 THIRD_PARTY_NOTICES.txt。googlepinyinime 那条 Fallback 整句路径不变。
2026-09-19 10:08:39 +08:00

159 lines
3.8 KiB
C++

#ifndef LM_VALUE_H
#define LM_VALUE_H
#include "config.hh"
#include "model_type.hh"
#include "value_build.hh"
#include "weights.hh"
#include "../util/bit_packing.hh"
#include <stdint.h>
namespace lm {
namespace ngram {
// Template proxy for probing unigrams and middle.
template <class Weights> class GenericProbingProxy {
public:
explicit GenericProbingProxy(const Weights &to) : to_(&to) {}
GenericProbingProxy() : to_(0) {}
bool Found() const { return to_ != 0; }
float Prob() const {
util::FloatEnc enc;
enc.f = to_->prob;
enc.i |= util::kSignBit;
return enc.f;
}
float Backoff() const { return to_->backoff; }
bool IndependentLeft() const {
util::FloatEnc enc;
enc.f = to_->prob;
return enc.i & util::kSignBit;
}
protected:
const Weights *to_;
};
// Basic proxy for trie unigrams.
template <class Weights> class GenericTrieUnigramProxy {
public:
explicit GenericTrieUnigramProxy(const Weights &to) : to_(&to) {}
GenericTrieUnigramProxy() : to_(0) {}
bool Found() const { return to_ != 0; }
float Prob() const { return to_->prob; }
float Backoff() const { return to_->backoff; }
float Rest() const { return Prob(); }
protected:
const Weights *to_;
};
struct BackoffValue {
typedef ProbBackoff Weights;
static const ModelType kProbingModelType = PROBING;
class ProbingProxy : public GenericProbingProxy<Weights> {
public:
explicit ProbingProxy(const Weights &to) : GenericProbingProxy<Weights>(to) {}
ProbingProxy() {}
float Rest() const { return Prob(); }
};
class TrieUnigramProxy : public GenericTrieUnigramProxy<Weights> {
public:
explicit TrieUnigramProxy(const Weights &to) : GenericTrieUnigramProxy<Weights>(to) {}
TrieUnigramProxy() {}
float Rest() const { return Prob(); }
};
struct ProbingEntry {
typedef uint64_t Key;
typedef Weights Value;
uint64_t key;
ProbBackoff value;
uint64_t GetKey() const { return key; }
};
struct TrieUnigramValue {
Weights weights;
uint64_t next;
uint64_t Next() const { return next; }
};
const static bool kDifferentRest = false;
template <class Model, class C> void Callback(const Config &, unsigned int, typename Model::Vocabulary &, C &callback) {
NoRestBuild build;
callback(build);
}
};
struct RestValue {
typedef RestWeights Weights;
static const ModelType kProbingModelType = REST_PROBING;
class ProbingProxy : public GenericProbingProxy<RestWeights> {
public:
explicit ProbingProxy(const Weights &to) : GenericProbingProxy<RestWeights>(to) {}
ProbingProxy() {}
float Rest() const { return to_->rest; }
};
class TrieUnigramProxy : public GenericTrieUnigramProxy<Weights> {
public:
explicit TrieUnigramProxy(const Weights &to) : GenericTrieUnigramProxy<Weights>(to) {}
TrieUnigramProxy() {}
float Rest() const { return to_->rest; }
};
// gcc 4.1 doesn't properly back dependent types :-(.
#pragma pack(push)
#pragma pack(4)
struct ProbingEntry {
typedef uint64_t Key;
typedef Weights Value;
Key key;
Value value;
Key GetKey() const { return key; }
};
struct TrieUnigramValue {
Weights weights;
uint64_t next;
uint64_t Next() const { return next; }
};
#pragma pack(pop)
const static bool kDifferentRest = true;
template <class Model, class C> void Callback(const Config &config, unsigned int order, typename Model::Vocabulary &vocab, C &callback) {
switch (config.rest_function) {
case Config::REST_MAX:
{
MaxRestBuild build;
callback(build);
}
break;
case Config::REST_LOWER:
{
LowerRestBuild<Model> build(config, order, vocab);
callback(build);
}
break;
}
}
};
} // namespace ngram
} // namespace lm
#endif // LM_VALUE_H