Skip to main content

Python package for dictionary-based inline tokenization preprocessing

Project description

InFlags

Python package for dictionary-based inline tokenization preprocessing (featuring Inline Flags).

Overview

InCa is a system that is used prior to training your subword tokenizer in order to make encoding of differently cased words consistent. This is done through inline casing approach: the information about the casing of a word is re-allocated to the left of the word with a specific flag. The special feature of our method is that we only allocate the flags to the casings of the words which are not the most frequent ones. This is done through keeping the information about the most frequent casing for each word in a pre-trained dictionary.

Here is a short demonstration of the main InCa principle:

Similarly to InCa, this is an inline diacritization approach based on dictionary. Firstly, we collect information about which diacritization is most frequent for each base (unique non-diacritized character sequence), and then at encoding we only mark the characters that are differing from the most frequent diacritization or are out of dictionary.

An important difference: while in InCa, the flags could be stored as single characters, here they are multi-character because we need to deterministically show which character IDs have which diacritics. The syntax of a flag is as follows:

DICT_FLAG k1 KEY_FLAG k2 ... KEY_FLAG kn DICT_FLAG v1 v2 ... vn. For example: ꕑ3ꕐ4ꕑⒷⒶ konci.

where:

  • is a DICT_FLAG used to indicate two things:
    • the beginning of the sequence of diacritization-related flags (first occurrence)
    • the border between the key sequence and value sequence (second occurrence)
  • is a KEY_FLAG separating the character IDs (because they are encoded in regular numbers)
  • and are flags showing that the characters with IDs 3 and 4, respectively, should be diacritized in a particular way
  • konci is a word to be diacritized

For more details, please refer to:

  1. paper presented at Tokenization Workshop @ICML2025,
  2. video demonstration,
  3. summarizing poster

We'll be happy to hear from you!

This project was created for the task of Czech-Ukrainian MT. Both languages are Slavic, both use similar writing systems (Latin and Cyrillic) and similar orthographical principles.

Therefore, it will be very interesting to understand the scalability and (possibly) limits of these approaches, both to new languages and to new NLP tasks. If you do any of such experiments, please tell us about that, feel free to drop PR's and open issues! (And, of course, please cite us if you find the project interesting😉)

Installation

The project is available at GitHub and PyPI

For GitHub, run:

python3 -m pip install git+https://github.com/Kiryukhasemenov/InFlags.git

For PyPI, run

pip install InFlags

InCa - Inline Casing

Python API ||| Command line tool

Quick Start - InCa API:

0. Import package

from inflags.inca import InCa

1. Train or import dictionary

First, you need to have the dictionary where the most frequent casing of each word is stored.

If you don't have a dictionary yet, you can train it with the following code:

inca = InCa(pretrained_dictionary=False)

inca.train_dictionary('path/to/training/data', 'path/to/dictionary.json')

If you already have a pre-trained dictionary, you can import it at the instantiation of the InCa class:

inca = InCa(pretrained_dictionary=True, dictionary_file='path/to/dictionary.json')
Additional parameters:
  • min_count: str, defaults to 1. Minimal number of occurrences of a particular casing to be included into the dictionary.
  • flags: dict[str: str], defaults to {'upper': 'ꔅ', 'title': 'ꔆ', 'lower': 'ꔪ', 'allcaps': 'ꔫ'}. The inventory of flags to use. In default implementation, all flags are single-character (this ensures that they are atomic in any subword tokenizer).
  • include_allcaps: bool, defaults to False. Whether to include all-caps sentences in counts while building the dictionary.
  • include_sent_initial: bool, defaults to False. Whether to include sentence initial words while building the dictionary.

2. Encode text

When the dictionary is trained, you can apply it to your input.

If you have a long document to be encoded, use the encode method:

inca.encode('path/to/input/file', 'path/to/output/file')

If you have shorter sequences and want to process them later in the code, use the encode_string method:

inca.encode_string('Encode this SHORT string in English.')

If you trained the dictionary on English data, then "English" would probably be in the dictionary with title-cased spelling as most frequent; and "SHORT" would not. So most probably the output would be as follows:

> 'encode this ꔅ short string in english.'

, where is an upper-case flag. The word "Encode" is not marked since it's sentence-initial, the word "English" is not marked since it is its most frequent spelling.

Additional paramters:
  • naive_encoding: bool, defaults to False. Encoding the string or document ignoring the dictionary, i.e. putting explicit flags wherever the word is not lower-cased.

3. Decode

The algorithm is reversible, so you can decode such a string to a traditional cased sequence.

For files, use the following command:

inca.decode('path/to/encoded/file', 'path/to/decoded/file')

For string variables in the code, use:

inca.decode_string('encode this ꔅ short string in english.')
> 'Encode this SHORT string in English.'
Additional paramters:
  • naive_decoding: bool, defaults to False. Decoding the string or document ignoring the dictionary, i.e. putting explicit flags wherever the word is not lower-cased.

InCa: Command Line Tool

There is a wrapper for all commands described above, you can find them in the scripts file.

# 1. Train the dictionary:
python inca-script.py -t -i path/to/training/text -o path/to/dictionary.json
# 2. Encode a file:
python inca-script.py -e -dict path/to/dictionary.json -i path/to/input/text -o path/to/encoded/text
# 3. Decode a file:
python inca-script.py -d -dict path/to/dictionary.json -i path/to/encoded/text -o path/to/decoded/text

TODO:

  • add unit tests
  • add naive encoding/decoding without initializing the dictionary
  • handle OOV mixed-cased words in a more consistent manner
  • handle the Turkish letters "İ"/"i" VS "I"/"ı" (at the moment this is not fully reversible)
  • test the multi-character flags (for the compatibility with the Sentencepiece's user-defined symbols)

InDia - Inline Diacritization

Python API ||| Command line tool

Quick Start - InDia API:

0. Import package

from inflags.india import InDia

1. Train or import dictionary

ATTENTION: Contrary to InCa, this package is quite language-specific for Czech. Therefore, if you are using it for other language, you should first define what variety of the diacritics you will be working with. This will be explicitly fed as diacr_list parameter (see in additional parameters below)

First, you need to have the dictionary where the most frequent casing of each word is stored.

If you don't have a dictionary yet, you can train it with the following code:

india = InDia(pretrained_dictionary=False)

india.train_dictionary('path/to/training/data', 'path/to/dictionary.json')

If you already have a pre-trained dictionary, you can import it at the instantiation of the InCa class:

india = InDia(pretrained_dictionary=True, dictionary_file='path/to/dictionary.json')
Additional parameters:
  • min_count: str, defaults to 1. Minimal number of occurrences of a particular casing to be included into the dictionary.
  • diacr_list: list[str], defaults to Czech diacritics ['COMBINING ACUTE ACCENT', 'COMBINING CARON', 'COMBINING RING ABOVE']. The inventory of diacritics that would be stripped away and flagged (the others will be kept untouched). If you are working with the language other than Czech, first define the list of language-specific diacritics. You can do it with unicodedata.name(char) to get the name of each diacritic sign.

2. Encode text

If you have a long document to be encoded, use the encode method:

india.encode('path/to/input/file', 'path/to/output/file')

If you have shorter sequences and want to process them later in the code, use the encode_string method:

india.encode_string('Vyrobil více než 1 000 známek pro Švédsko a 28 dalších zemí.')

If you trained the dictionary on Czech FLORES data, then "Švédsko" would be in the dictionary with such a diacritization; and "zemí" would not. So the output would be as follows:

> 'Vyrobil vice nez 1 000 znamek pro Svedsko a 28 dalsich ꕑ3ꕑⒶ zemi.'

, where ꕑ3ꕑⒶ is a flag saying that character with ID 3 should be assigned with the diacritic "čárka".

3. Decode

The algorithm is reversible, so you can decode such a string to a traditional cased sequence.

For files, use the following command:

india.decode('path/to/encoded/file', 'path/to/decoded/file')

For string variables in the code, use:

india.decode_string('Vyrobil vice nez 1 000 znamek pro Svedsko a 28 dalsich ꕑ3ꕑⒶ zemi.')
> 'Vyrobil více než 1 000 známek pro Švédsko a 28 dalších zemí.'

InDia: Command Line Tool

There is a wrapper for all commands described above, you can find them in the scripts file.

# 1. Train the dictionary:
python india-script.py -t -i path/to/training/text -o path/to/dictionary.json
# 2. Encode a file:
python india-script.py -e -dict path/to/dictionary.json -i path/to/input/text -o path/to/encoded/text
# 3. Decode a file:
python india-script.py -d -dict path/to/dictionary.json -i path/to/encoded/text -o path/to/decoded/text

TODO:

  • add unit tests
  • refactor code for speed
  • add naive encoding/decoding option without setting min_count to 10000000000
  • introduce the word- or even sentence-level flags (e.g. "fully de-diacritized word")

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

inflags-1.0.0.tar.gz (23.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

inflags-1.0.0-py3-none-any.whl (23.6 kB view details)

Uploaded Python 3

File details

Details for the file inflags-1.0.0.tar.gz.

File metadata

  • Download URL: inflags-1.0.0.tar.gz
  • Upload date:
  • Size: 23.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for inflags-1.0.0.tar.gz
Algorithm Hash digest
SHA256 ea4c1d25085b454a15419ff10da38dda5206211ff805d371b298ccf831db8212
MD5 1398b0806cb43a79dd294eb4d8f32573
BLAKE2b-256 1e8ebd84523751b92ef377e00142fdf759d49378b3c41da9957c3875f4b3960a

See more details on using hashes here.

Provenance

The following attestation bundles were made for inflags-1.0.0.tar.gz:

Publisher: publish.yml on Kiryukhasemenov/InFlags

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file inflags-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: inflags-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 23.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for inflags-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 6e8971cd0f8653164cdf5386ce35a3f204611ef54c20d45cb9632eea415910b8
MD5 c4f2a4cf9a0f6e46d592c04f3ac6ab33
BLAKE2b-256 9211814e5db33382e2d629118df3338193276aaced9645df577f7331126a82a9

See more details on using hashes here.

Provenance

The following attestation bundles were made for inflags-1.0.0-py3-none-any.whl:

Publisher: publish.yml on Kiryukhasemenov/InFlags

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page