SentencePiece é um tokenizador e destokenizador de texto não supervisionado, principalmente para sistemas de geração de texto baseados em redes neurais, onde o tamanho do vocabulário é predeterminado antes do treinamento do modelo neural. SentencePiece implementa unidades de subpalavras (por exemplo, codificação de pares de bytes (BPE) [Sennrich et al.]) e modelo de linguagem unigrama [Kudo.]) com a extensão do treinamento direto a partir de sentenças brutas. O SentencePiece nos permite criar um sistema puramente ponta a ponta que não depende de pré/pós-processamento específico da linguagem.
Este não é um produto oficial do Google.
Para aqueles que não estão familiarizados com o SentencePiece como software/algoritmo, pode-se ler uma introdução gentil aqui.
Recurso | Peça de frase | subpalavra-nmt | Peça de palavra |
---|---|---|---|
Algoritmo suportado | BPE, unigrama, char, palavra | BPE | EBP* |
OSS? | Sim | Sim | Interno do Google |
Regularização de subpalavras | Sim | Não | Não |
Biblioteca Python (pip) | Sim | Não | N / D |
Biblioteca C++ | Sim | Não | N / D |
É necessária pré-segmentação? | Não | Sim | Sim |
Normalização personalizável (por exemplo, NFKC) | Sim | Não | N / D |
Geração direta de ID | Sim | Não | N / D |
Observe que o algoritmo BPE usado no WordPiece é ligeiramente diferente do BPE original.
SentencePiece é uma reimplementação de unidades de subpalavras , uma forma eficaz de aliviar os problemas de vocabulário aberto na tradução automática neural. SentencePiece suporta dois algoritmos de segmentação, codificação de pares de bytes (BPE) [Sennrich et al.] e modelo de linguagem unigrama [Kudo.]. Aqui estão as diferenças de alto nível em relação a outras implementações.
Os modelos de tradução automática neural normalmente operam com um vocabulário fixo. Ao contrário da maioria dos algoritmos de segmentação de palavras não supervisionados, que assumem um vocabulário infinito, o SentencePiece treina o modelo de segmentação de modo que o tamanho do vocabulário final seja fixo, por exemplo, 8k, 16k ou 32k.
Observe que SentencePiece especifica o tamanho final do vocabulário para treinamento, que é diferente de subword-nmt que usa o número de operações de mesclagem. O número de operações de mesclagem é um parâmetro específico do BPE e não aplicável a outros algoritmos de segmentação, incluindo unigrama, palavra e caractere.
As implementações anteriores de subpalavras assumem que as sentenças de entrada são pré-tokenizadas. Essa restrição era necessária para um treinamento eficiente, mas torna o pré-processamento complicado, pois precisamos executar tokenizadores dependentes do idioma com antecedência. A implementação do SentencePiece é rápida o suficiente para treinar o modelo a partir de frases brutas. Isso é útil para treinar o tokenizador e o destokenizador para chinês e japonês, onde não existem espaços explícitos entre as palavras.
A primeira etapa do processamento de linguagem natural é a tokenização de texto. Por exemplo, um tokenizer padrão em inglês segmentaria o texto “Olá, mundo”. nos três tokens a seguir.
[Olá] [Mundo] [.]
Uma observação é que a entrada original e a sequência tokenizada NÃO são reversivelmente conversíveis . Por exemplo, a informação que não há espaço entre “Mundo” e “.” é eliminado da sequência tokenizada, pois, por exemplo, Tokenize(“World.”) == Tokenize(“World .”)
SentencePiece trata o texto de entrada apenas como uma sequência de caracteres Unicode. O espaço em branco também é tratado como um símbolo normal. Para lidar explicitamente com o espaço em branco como um token básico, SentencePiece primeiro escapa do espaço em branco com um meta-símbolo " " (U+2581) como segue.
Olá mundo.
Depois, esse texto é segmentado em pequenos pedaços, por exemplo:
[Olá] [ Wor] [ld] [.]
Como o espaço em branco é preservado no texto segmentado, podemos destokenizar o texto sem ambigüidades.
detokenized = ''.join(pieces).replace('▁', ' ')
Esse recurso possibilita realizar a destokenização sem depender de recursos específicos da linguagem.
Observe que não podemos aplicar as mesmas conversões sem perdas ao dividir a frase com segmentadores de palavras padrão, pois eles tratam o espaço em branco como um símbolo especial. As sequências tokenizadas não preservam as informações necessárias para restaurar a frase original.
Regularização de subpalavras [Kudo.] E Provilkov et al de abandono de BPE são métodos simples de regularização que virtualmente aumentam os dados de treinamento com amostragem de subpalavras em tempo real, o que ajuda a melhorar a precisão e também a robustez dos modelos NMT.
Para habilitar a regularização de subpalavras, você gostaria de integrar a biblioteca SentencePiece (C++/Python) ao sistema NMT para amostrar uma segmentação para cada atualização de parâmetro, que é diferente das preparações de dados off-line padrão. Aqui está o exemplo da biblioteca Python. Você pode descobrir que 'New York' é segmentado de forma diferente em cada SampleEncode (C++)
ou encode with enable_sampling=True (Python)
. Os detalhes dos parâmetros de amostragem são encontrados em sentençapiece_processor.h.
>>> import sentencepiece as spm
>>> s = spm.SentencePieceProcessor(model_file='spm.model')
>>> for n in range(5):
... s.encode('New York', out_type=str, enable_sampling=True, alpha=0.1, nbest_size=-1)
...
['▁', 'N', 'e', 'w', '▁York']
['▁', 'New', '▁York']
['▁', 'New', '▁Y', 'o', 'r', 'k']
['▁', 'New', '▁York']
['▁', 'New', '▁York']
SentencePiece fornece wrapper Python que suporta treinamento e segmentação de SentencePiece. Você pode instalar o pacote binário Python do SentencePiece com.
pip install sentencepiece
Para mais detalhes, consulte Módulo Python
As seguintes ferramentas e bibliotecas são necessárias para construir o SentencePiece:
No Ubuntu, as ferramentas de construção podem ser instaladas com o apt-get:
% sudo apt-get install cmake build-essential pkg-config libgoogle-perftools-dev
Em seguida, você pode criar e instalar ferramentas de linha de comando da seguinte maneira.
% git clone https://github.com/google/sentencepiece.git
% cd sentencepiece
% mkdir build
% cd build
% cmake ..
% make -j $(nproc)
% sudo make install
% sudo ldconfig -v
No OSX/macOS, substitua o último comando por sudo update_dyld_shared_cache
Você pode baixar e instalar o sentença usando o gerenciador de dependência vcpkg:
git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh
./vcpkg integrate install
./vcpkg install sentencepiece
A porta da frase no vcpkg é mantida atualizada pelos membros da equipe da Microsoft e colaboradores da comunidade. Se a versão estiver desatualizada, crie um problema ou solicitação pull no repositório vcpkg.
Você pode baixar a roda na página de lançamentos do GitHub. Geramos assinaturas SLSA3 usando o slsa-framework/slsa-github-generator do OpenSSF durante o processo de lançamento. Para verificar um binário de lançamento:
attestation.intoto.jsonl
na página de lançamentos do GitHub.slsa-verifier -artifact-path < the-wheel > -provenance attestation.intoto.jsonl -source github.com/google/sentencepiece -tag < the-tag >
pip instalar wheel_file.whl
% spm_train --input=<input> --model_prefix=<model_name> --vocab_size=8000 --character_coverage=1.0 --model_type=<type>
--input
: arquivo corpus bruto de uma frase por linha. Não há necessidade de executar tokenizador, normalizador ou pré-processador. Por padrão, SentencePiece normaliza a entrada com Unicode NFKC. Você pode passar uma lista de arquivos separados por vírgula.--model_prefix
: prefixo do nome do modelo de saída. <model_name>.model
e <model_name>.vocab
são gerados.--vocab_size
: tamanho do vocabulário, por exemplo, 8.000, 16.000 ou 32.000--character_coverage
: quantidade de caracteres cobertos pelo modelo, bons padrões são: 0.9995
para idiomas com conjunto de caracteres rico como japonês ou chinês e 1.0
para outros idiomas com conjunto de caracteres pequeno.--model_type
: tipo de modelo. Escolha entre unigram
(padrão), bpe
, char
ou word
. A frase de entrada deve ser pretakenizada ao usar o tipo word
. Use o sinalizador --help
para exibir todos os parâmetros de treinamento ou veja aqui uma visão geral.
% spm_encode --model=<model_file> --output_format=piece < input > output
% spm_encode --model=<model_file> --output_format=id < input > output
Use o sinalizador --extra_options
para inserir os marcadores BOS/EOS ou reverter a sequência de entrada.
% spm_encode --extra_options=eos (add </s> only)
% spm_encode --extra_options=bos:eos (add <s> and </s>)
% spm_encode --extra_options=reverse:bos:eos (reverse input and add <s> and </s>)
SentencePiece suporta segmentação nbest e amostragem de segmentação com sinalizadores --output_format=(nbest|sample)_(piece|id)
.
% spm_encode --model=<model_file> --output_format=sample_piece --nbest_size=-1 --alpha=0.5 < input > output
% spm_encode --model=<model_file> --output_format=nbest_id --nbest_size=10 < input > output
% spm_decode --model=<model_file> --input_format=piece < input > output
% spm_decode --model=<model_file> --input_format=id < input > output
Use o sinalizador --extra_options
para decodificar o texto na ordem inversa.
% spm_decode --extra_options=reverse < input > output
% spm_train --input=data/botchan.txt --model_prefix=m --vocab_size=1000
unigram_model_trainer.cc(494) LOG(INFO) Starts training with :
input: "../data/botchan.txt"
... <snip>
unigram_model_trainer.cc(529) LOG(INFO) EM sub_iter=1 size=1100 obj=10.4973 num_tokens=37630 num_tokens/piece=34.2091
trainer_interface.cc(272) LOG(INFO) Saving model: m.model
trainer_interface.cc(281) LOG(INFO) Saving vocabs: m.vocab
% echo "I saw a girl with a telescope." | spm_encode --model=m.model
▁I ▁saw ▁a ▁girl ▁with ▁a ▁ te le s c o pe .
% echo "I saw a girl with a telescope." | spm_encode --model=m.model --output_format=id
9 459 11 939 44 11 4 142 82 8 28 21 132 6
% echo "9 459 11 939 44 11 4 142 82 8 28 21 132 6" | spm_decode --model=m.model --input_format=id
I saw a girl with a telescope.
Você pode descobrir que a frase de entrada original foi restaurada a partir da sequência de identificação do vocabulário.
% spm_export_vocab --model=<model_file> --output=<output file>
<output file>
armazena uma lista de vocabulário e probabilidades de log de emissão. O ID do vocabulário corresponde ao número da linha neste arquivo.
Por padrão, os tokens desconhecidos (<NUNK>), BOS (<s>) e EOS (</s>) que possuem os IDs de 0, 1 e 2, respectivamente. Podemos redefinir esse mapeamento na fase de treinamento da seguinte forma.
% spm_train --bos_id=0 --eos_id=1 --unk_id=5 --input=... --model_prefix=... --character_coverage=...
Ao definir -1 id, por exemplo, bos_id=-1
, este token especial é desabilitado. Observe que o ID desconhecido não pode ser desativado. Podemos definir um id para preenchimento (<pad>) como --pad_id=3
.
Se você deseja atribuir outros tokens especiais, consulte Usar símbolos personalizados.
spm_encode
aceita uma opção --vocabulary
e --vocabulary_threshold
para que spm_encode
produza apenas símbolos que também aparecem no vocabulário (com pelo menos alguma frequência). O histórico desse recurso é descrito na página subword-nmt.
O uso é basicamente o mesmo de subword-nmt
. Supondo que L1 e L2 são os dois idiomas (idiomas de origem/destino), treine o modelo spm compartilhado e obtenha o vocabulário resultante para cada um:
% cat {train_file}.L1 {train_file}.L2 | shuffle > train
% spm_train --input=train --model_prefix=spm --vocab_size=8000 --character_coverage=0.9995
% spm_encode --model=spm.model --generate_vocabulary < {train_file}.L1 > {vocab_file}.L1
% spm_encode --model=spm.model --generate_vocabulary < {train_file}.L2 > {vocab_file}.L2
O comando shuffle
é usado apenas para garantir, porque spm_train
carrega as primeiras 10 milhões de linhas do corpus por padrão.
Em seguida, segmente o corpus de treinamento/teste com a opção --vocabulary
% spm_encode --model=spm.model --vocabulary={vocab_file}.L1 --vocabulary_threshold=50 < {test_file}.L1 > {test_file}.seg.L1
% spm_encode --model=spm.model --vocabulary={vocab_file}.L2 --vocabulary_threshold=50 < {test_file}.L2 > {test_file}.seg.L2