#include
#include "GLiNER/processor.hpp"
using namespace gliner;
Processor::Processor(const Config& config, const std::string& tokenizer_path)
: config(config), wordSplitter(WhitespaceTokenSplitter()) {
const std::string blob = LoadBytesFromFile(tokenizer_path);
tokenizer = tokenizers::Tokenizer::FromBlobJSON(blob);
int32_t tokenizerClsTokenId = tokenizer->TokenToId("[CLS]");
int32_t tokenizerSepTokenId = tokenizer->TokenToId("[SEP]");
if (tokenizerClsTokenId >= 0) {
clsTokenId = tokenizerClsTokenId;
}
if (tokenizerSepTokenId >= 0) {
sepTokenId = tokenizerSepTokenId;
}
}
std::vector Processor::tokenizeText(const std::string& text) {
return wordSplitter.call(text);
}
std::vector Processor::batchTokenizeText(const std::vector& texts) {
std::vector res;
res.reserve(texts.size());
for (const auto& text : texts) {
res.push_back(tokenizeText(text));
}
return res;
}
void Processor::prepareTextInputs(
const std::vector& entities,
Batch* output,
std::vector& prompts
) {
std::vector entities_prompt;
entities_prompt.reserve(entities.size()*2+1);
for (const auto& ent : entities) {
entities_prompt.push_back("");
entities_prompt.push_back(ent);
}
entities_prompt.push_back("");
auto promptLength = entities_prompt.size();
output->textLengths = new int64_t[output->batchSize];
output->textLengthsShape = new int64_t[2]{output->batchSize, 1};
output->numWords = 0;
for (size_t i = 0; i < static_cast(output->batchSize); ++i) {
const std::vector& currTokens = output->batchTokens[i];
std::vector inputText;
inputText.reserve(currTokens.size() + promptLength);
inputText.insert(inputText.end(), entities_prompt.begin(), entities_prompt.end());
for (auto t : currTokens) {
inputText.push_back(t.text);
}
output->textLengths[i] = int64_t(currTokens.size());
prompts.push_back({
int64_t(currTokens.size()),
int64_t(promptLength),
inputText,
});
output->numWords = std::max(prompts[i].textLength, output->numWords);
}
}
void Processor::encodeInputs(const std::vector& prompts, Batch* output) {
std::vector tmp;
tmp.reserve(prompts.size());
output->numTokens = 0;
for (const Prompt& p: prompts) {
std::vector pt;
pt.reserve(p.prompt.size());
int64_t s = 2; // padding tokens
for (const std::string& word : p.prompt) {
pt.push_back(tokenizer->Encode(word));
s += pt.back().size();
}
tmp.push_back(pt);
output->numTokens = std::max(output->numTokens, s);
}
output->inputsSize = output->numTokens*output->batchSize;
output->inputsShape = new int64_t[2]{output->batchSize, output->numTokens};
output->inputsIds = new int64_t[output->inputsSize]();
output->attentionMasks = new int64_t[output->inputsSize]();
output->wordsMasks = new int64_t[output->inputsSize]();
for (size_t p = 0; p < tmp.size(); p++) {
int64_t promptLength = prompts[p].promptLength;
size_t idx = p * output->numTokens;
output->inputsIds[idx] = clsTokenId;
output->attentionMasks[idx] = 1;
idx++;
for (size_t tokenId = 0, wordId = 1; tokenId < tmp[p].size(); ++tokenId) {
const auto& word = tmp[p][tokenId];
if (tokenId >= static_cast(promptLength)) {
output->wordsMasks[idx] = wordId;
wordId++;
}
for (int t : word) {
output->inputsIds[idx] = t;
output->attentionMasks[idx] = 1;
idx++;
}
}
output->attentionMasks[idx] = 1;
output->inputsIds[idx] = sepTokenId;
}
}
SpanProcessor::SpanProcessor(const Config& config, const std::string& tokenizer_path)
: Processor(config, tokenizer_path) {};
// SpanProcessor::SpanProcessor(const Config& config, Tokenizer& tokenizer, const WhitespaceTokenSplitter& wordSplitter)
// : Processor(config, tokenizer, wordSplitter) {};
void SpanProcessor::prepareSpans(const std::vector& prompts, SpanBatch* output) {
output->numSpans = output->numWords*output->maxWidth;
output->spanIdxsSize = output->batchSize*output->numSpans*2;
output->spanIdxs = new int64_t[output->spanIdxsSize]();
output->spanIdxsShape = new int64_t[3]{output->batchSize, output->numSpans, 2};
output->spanMasksSize = output->batchSize*output->numSpans;
output->spanMasks = new bool[output->spanMasksSize]();
output->spanMasksShape = new int64_t[2]{output->batchSize, output->numSpans};
for (size_t p = 0; p < prompts.size(); p++) {
for (int64_t i = 0; i < prompts[p].textLength; i++) {
int64_t m = std::min(output->maxWidth, prompts[p].textLength - i);
for (int64_t j = 0; j < m; j++) {
size_t idx = p*output->numSpans + i*output->maxWidth + j;
output->spanIdxs[2*idx] = i;
output->spanIdxs[2*idx+1] = i + j;
output->spanMasks[idx] = 1;
}
}
}
}
Batch* SpanProcessor::prepareBatch(
const std::vector& texts,
const std::vector& entities
) {
SpanBatch* output = new SpanBatch;
output->maxWidth = config.maxWidth;
output->batchSize = texts.size();
output->batchTokens = batchTokenizeText(texts);
std::vector prompts;
prompts.reserve(output->batchSize);
prepareTextInputs(entities, output, prompts);
encodeInputs(prompts, output);
prepareSpans(prompts, output);
return output;
}
TokenProcessor::TokenProcessor(const Config& config, const std::string& tokenizer_path)
: Processor(config, tokenizer_path) {};
Batch* TokenProcessor::prepareBatch(
const std::vector& texts,
const std::vector& entities
) {
TokenBatch* output = new TokenBatch;
output->batchSize = texts.size();
output->batchTokens = batchTokenizeText(texts);
std::vector prompts;
prompts.reserve(output->batchSize);
prepareTextInputs(entities, output, prompts);
encodeInputs(prompts, output);
return output;
}