Ufal-NameTag
view release on metacpan or search on metacpan
nametag/nametag.cpp view on Meta::CPAN
enc.add_4B(feature);
}
}
virtual void process_sentence(ner_sentence& sentence, ner_feature* /*total_features*/, string& buffer) const override {
for (unsigned i = 0; i < sentence.size; i++) {
auto it = map.find(sentence.words[i].raw_lemma);
if (it == map.end()) continue;
// Apply regular gazetteer feature G + unigram gazetteer feature U
for (auto&& feature : gazetteers_info[it->second].features) {
apply_in_window(i, feature + G * (2*window + 1));
apply_in_window(i, feature + U * (2*window + 1));
}
for (unsigned j = i + 1; gazetteers_info[it->second].prefix_of_longer && j < sentence.size; j++) {
if (j == i + 1) buffer.assign(sentence.words[i].raw_lemma);
buffer += ' ';
buffer += sentence.words[j].raw_lemma;
it = map.find(buffer);
if (it == map.end()) break;
// Apply regular gazetteer feature G + position specific gazetteers B, I, L
for (auto&& feature : gazetteers_info[it->second].features)
for (unsigned g = i; g <= j; g++) {
apply_in_window(g, feature + G * (2*window + 1));
apply_in_window(g, feature + (g == i ? B : g == j ? L : I) * (2*window + 1));
}
}
}
}
private:
struct gazetteer_info {
vector<ner_feature> features;
bool prefix_of_longer;
};
vector<gazetteer_info> gazetteers_info;
};
// GazetteersEnhanced
class gazetteers_enhanced : public feature_processor {
public:
enum { G = 0, U = 1, B = 2, L = 3, I = 4, TOTAL = 5 };
virtual bool parse(int window, const vector<string>& args, entity_map& entities,
ner_feature* total_features, const nlp_pipeline& pipeline) override {
if (!feature_processor::parse(window, args, entities, total_features, pipeline)) return false;
gazetteer_metas.clear();
gazetteer_lists.clear();
if (args.size() < 4) return cerr << "Not enough parameters to GazetteersEnhanced!" << endl, false;
if (args.size() & 1) return cerr << "Odd number of parameters to GazetteersEnhanced!" << endl, false;
if (args[0] == "form") match = MATCH_FORM;
else if (args[0] == "rawlemma") match = MATCH_RAWLEMMA;
else if (args[0] == "rawlemmas") match = MATCH_RAWLEMMAS;
else return cerr << "First parameter of GazetteersEnhanced not one of form/rawlemma/rawlemmas!" << endl, false;
if (args[1] == "embed_in_model") embed = EMBED_IN_MODEL;
else if (args[1] == "out_of_model") embed = OUT_OF_MODEL;
else return cerr << "Second parameter of GazetteersEnhanced not one of [embed_in|out_of]_model!" << endl, false;
for (unsigned i = 2; i < args.size(); i += 2) {
gazetteer_metas.emplace_back();
gazetteer_metas.back().basename = args[i];
gazetteer_metas.back().feature = *total_features + window; *total_features += TOTAL * (2 * window + 1);
gazetteer_metas.back().entity = args[i + 1] == "NONE" ? -1 : entities.parse(args[i + 1].c_str(), true);
}
entity_list.clear();
for (entity_type i = 0; i < entities.size(); i++)
entity_list.push_back(entities.name(i));
if (!load_gazetteer_lists(pipeline, embed == EMBED_IN_MODEL)) return false;
return true;
}
virtual void load(binary_decoder& data, const nlp_pipeline& pipeline) override {
feature_processor::load(data, pipeline);
match = data.next_4B();
embed = OUT_OF_MODEL;
gazetteer_metas.resize(data.next_4B());
for (auto&& gazetteer_meta : gazetteer_metas) {
data.next_str(gazetteer_meta.basename);
gazetteer_meta.feature = data.next_4B();
gazetteer_meta.entity = data.next_4B();
}
gazetteer_lists.resize(data.next_4B());
for (auto&& gazetteer_list : gazetteer_lists) {
gazetteer_list.gazetteers.resize(data.next_4B());
for (auto&& gazetteer : gazetteer_list.gazetteers)
data.next_str(gazetteer);
gazetteer_list.feature = data.next_4B();
gazetteer_list.entity = data.next_4B();
gazetteer_list.mode = data.next_4B();
}
entity_list.resize(data.next_4B());
for (auto&& entity : entity_list)
data.next_str(entity);
load_gazetteer_lists(pipeline, false);
}
virtual void save(binary_encoder& enc) override {
feature_processor::save(enc);
enc.add_4B(match);
enc.add_4B(gazetteer_metas.size());
for (auto&& gazetteer_meta : gazetteer_metas) {
enc.add_str(gazetteer_meta.basename);
enc.add_4B(gazetteer_meta.feature);
enc.add_4B(gazetteer_meta.entity);
}
if (embed == EMBED_IN_MODEL) {
enc.add_4B(gazetteer_lists.size());
for (auto&& gazetteer_list : gazetteer_lists) {
enc.add_4B(gazetteer_list.gazetteers.size());
for (auto&& gazetteer : gazetteer_list.gazetteers)
enc.add_str(gazetteer);
enc.add_4B(gazetteer_list.feature);
enc.add_4B(gazetteer_list.entity);
enc.add_4B(gazetteer_list.mode);
}
} else {
enc.add_4B(0);
}
enc.add_4B(entity_list.size());
for (auto&& entity : entity_list)
enc.add_str(entity);
}
virtual void process_sentence(ner_sentence& sentence, ner_feature* /*total_features*/, string& /*buffer*/) const override {
vector<unsigned> nodes, new_nodes;
vector<vector<ner_feature>> features(sentence.size);
vector<vector<string>> recased_match_sources(sentence.size);
for (unsigned i = 0; i < sentence.size; i++)
recase_match_source(sentence.words[i], RECASE_ANY, recased_match_sources[i]);
for (unsigned i = 0; i < sentence.size; i++) {
unsigned hard_pre_length = 0, hard_pre_node = -1;
bool hard_pre_possible = true;
nodes.assign(1, 0);
for (unsigned j = i; j < sentence.size && !nodes.empty(); j++) {
new_nodes.clear();
for (auto&& node : nodes)
if (!gazetteers_trie[node].children.empty())
for (auto&& match_source : recased_match_sources[j]) {
auto range = gazetteers_trie[node].children.equal_range(match_source);
for (auto&& it = range.first; it != range.second; it++)
append_unless_exists(new_nodes, it->second);
}
hard_pre_possible = hard_pre_possible && !sentence.probabilities[j].local_filled;
if (hard_pre_possible)
for (auto&& node : new_nodes)
if (gazetteers_trie[node].mode == HARD_PRE &&
((j - i + 1) > hard_pre_length || node < hard_pre_node))
hard_pre_length = j - i + 1, hard_pre_node = node;
// Fill features
for (auto&& node : new_nodes)
for (auto&& feature : gazetteers_trie[node].features)
for (unsigned k = i; k <= j; k++) {
bilou_type type = j == i ? bilou_type_U : k == i ? bilou_type_B : k == j ? bilou_type_L : bilou_type_I;
append_unless_exists(features[k], feature + G * (2 * window + 1));
append_unless_exists(features[k], feature + type * (2 * window + 1));
}
nodes.swap(new_nodes);
}
if (hard_pre_length)
nametag/nametag.cpp view on Meta::CPAN
vector<vector<string>> recased_match_sources(sentence.size);
for (unsigned i = 0; i < sentence.size; i++)
recase_match_source(sentence.words[i], RECASE_ANY, recased_match_sources[i]);
buffer.clear();
unsigned entity_until = 0;
for (unsigned i = 0, e = 0; i < sentence.size; i++) {
while (e < entities.size() && entities[e].start == i) {
if (i + entities[e].length > entity_until)
entity_until = i + entities[e].length;
buffer.push_back(entities[e++]);
}
if (entity_until <= i) {
// There is place for a possible POST gazetteer
unsigned free_until = e < entities.size() ? entities[e].start : sentence.size;
unsigned hard_post_length = 0, hard_post_node = -1;
nodes.assign(1, 0);
for (unsigned j = i; j < free_until && !nodes.empty(); j++) {
new_nodes.clear();
for (auto&& node : nodes)
if (!gazetteers_trie[node].children.empty())
for (auto&& match_source : recased_match_sources[j]) {
auto range = gazetteers_trie[node].children.equal_range(match_source);
for (auto&& it = range.first; it != range.second; it++)
append_unless_exists(new_nodes, it->second);
}
for (auto&& node : new_nodes)
if (gazetteers_trie[node].mode == HARD_POST &&
((j - i + 1) > hard_post_length || node < hard_post_node))
hard_post_length = j - i + 1, hard_post_node = node;
nodes.swap(new_nodes);
}
if (hard_post_length) {
buffer.emplace_back(i, hard_post_length, entity_list[gazetteers_trie[hard_post_node].entity]);
entity_until = i + hard_post_length;
}
}
}
if (buffer.size() != entities.size())
entities.swap(buffer);
}
virtual void gazetteers(vector<string>& gazetteers, vector<int>* gazetteer_types) const override {
for (auto&& gazetteer_list : gazetteer_lists)
for (auto&& gazetteer : gazetteer_list.gazetteers) {
gazetteers.push_back(gazetteer);
if (gazetteer_types) gazetteer_types->push_back(gazetteer_list.entity);
}
}
private:
enum { MATCH_FORM = 0, MATCH_RAWLEMMA = 1, MATCH_RAWLEMMAS = 2 };
int match;
enum { EMBED_IN_MODEL = 0, OUT_OF_MODEL = 1 };
int embed;
enum { SOFT, HARD_PRE, HARD_POST, MODES_TOTAL };
const static vector<string> basename_suffixes;
struct gazetteer_meta_info {
string basename;
ner_feature feature;
int entity;
};
vector<gazetteer_meta_info> gazetteer_metas;
struct gazetteer_list_info {
vector<string> gazetteers;
ner_feature feature;
int entity;
int mode;
};
vector<gazetteer_list_info> gazetteer_lists;
struct gazetteer_trie_node {
vector<ner_feature> features;
unordered_multimap<string, unsigned> children;
int mode = SOFT, entity = -1;
};
vector<gazetteer_trie_node> gazetteers_trie;
vector<string> entity_list;
template <class T>
inline static void append_unless_exists(vector<T>& array, T value) {
size_t i;
for (i = array.size(); i; i--)
if (array[i - 1] == value)
break;
if (!i)
array.push_back(value);
}
bool load_gazetteer_lists(const nlp_pipeline& pipeline, bool files_must_exist) {
string file_name, line;
// Load raw gazetteers (maybe additional during inference)
for (auto&& gazetteer_meta : gazetteer_metas)
for (int mode = 0; mode < MODES_TOTAL; mode++) {
file_name.assign(gazetteer_meta.basename).append(basename_suffixes[mode]);
ifstream file(path_from_utf8(file_name).c_str());
if (!file.is_open()) {
if (mode == SOFT && files_must_exist)
return cerr << "Cannot open gazetteers file '" << file_name << "'!" << endl, false;
continue;
}
gazetteer_lists.emplace_back();
gazetteer_lists.back().feature = gazetteer_meta.feature;
gazetteer_lists.back().entity = gazetteer_meta.entity;
gazetteer_lists.back().mode = mode;
( run in 2.231 seconds using v1.01-cache-2.11-cpan-0b58ddf2af1 )