TF 텍스트로 토큰화

TensorFlow.org에서 보기 Google Colab에서 실행 GitHub에서 보기 노트북 다운로드 TF Hub 모델 보기

개요

토큰화는 문자열을 토큰으로 나누는 프로세스입니다. 일반적으로 이러한 토큰은 단어, 숫자 및/또는 구두점입니다. tensorflow_text 패키지는 텍스트를 전처리 할 수 tokenizers의 번호가 텍스트 기반의 모델이 필요합니다. TensorFlow 그래프에서 토큰화를 수행하면 교육 및 추론 워크플로와 사전 처리 스크립트 관리 간의 차이점에 대해 걱정할 필요가 없습니다.

이 가이드에서는 TensorFlow Text에서 제공하는 다양한 토큰화 옵션, 한 옵션을 다른 옵션보다 사용하려는 경우, 모델 내에서 이러한 토크나이저를 호출하는 방법에 대해 설명합니다.

설정

pip install -q tensorflow-text
import requests
import tensorflow as tf
import tensorflow_text as tf_text
2021-08-11 18:54:22.357951: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcudart.so.11.0

스플리터 API

메인 인터페이스는 SplitterSplitterWithOffsets 단일 메소드가 splitsplit_with_offsets . SplitterWithOffsets 변형 (연장하는 Splitter ) 바이트 오프셋을 얻기위한 옵션이 포함되어 있습니다. 이를 통해 호출자는 생성된 토큰이 생성된 원래 문자열의 바이트를 알 수 있습니다.

TokenizerTokenizerWithOffsets 전문의 버전입니다 Splitter 편리한 방법을 제공하는 tokenizetokenize_with_offsets 각각.

일반적으로, 임의의 N 차원 입력 반환 된 토큰은 N + 1 차원에 RaggedTensor 원래 개별 문자열 매핑 토큰의 가장 안쪽 치수.

class Splitter {
  @abstractmethod
  def split(self, input)
}

class SplitterWithOffsets(Splitter) {
  @abstractmethod
  def split_with_offsets(self, input)
}

도있다 Detokenizer 인터페이스. 이 인터페이스를 구현하는 모든 토크나이저는 토큰의 N차원 비정형 텐서를 수락할 수 있으며 일반적으로 주어진 토큰이 함께 조합된 N-1차원 텐서 또는 비정형 텐서를 반환합니다.

class Detokenizer {
  @abstractmethod
  def detokenize(self, input)
}

토크나이저

다음은 TensorFlow Text에서 제공하는 토크나이저 모음입니다. 문자열 입력은 UTF-8로 간주됩니다. 검토하시기 바랍니다 유니 코드 가이드를 UTF-8로 문자열을 변환.

전체 단어 토크나이저

이러한 토크나이저는 문자열을 단어로 분할하려고 시도하며 텍스트를 분할하는 가장 직관적인 방법입니다.

공백토큰나이저

text.WhitespaceTokenizer ICU 정의 공백 문자 (예. 공백, 탭, 줄 바꿈)에 문자열을 분할하는 가장 기본적인 토크 나이입니다. 이는 프로토타입 모델을 빠르게 구축하는 데 종종 유용합니다.

tokenizer = tf_text.WhitespaceTokenizer()
tokens = tokenizer.tokenize(["What you know you can't explain, but you feel it."])
print(tokens.to_list())
2021-08-11 18:54:24.101492: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcuda.so.1
2021-08-11 18:54:24.764294: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-08-11 18:54:24.765226: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1733] Found device 0 with properties: 
pciBusID: 0000:00:05.0 name: Tesla V100-SXM2-16GB computeCapability: 7.0
coreClock: 1.53GHz coreCount: 80 deviceMemorySize: 15.78GiB deviceMemoryBandwidth: 836.37GiB/s
2021-08-11 18:54:24.765257: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcudart.so.11.0
2021-08-11 18:54:24.768994: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcublas.so.11
2021-08-11 18:54:24.769093: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcublasLt.so.11
2021-08-11 18:54:24.770272: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcufft.so.10
2021-08-11 18:54:24.770599: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcurand.so.10
2021-08-11 18:54:24.771810: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcusolver.so.11
2021-08-11 18:54:24.772737: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcusparse.so.11
2021-08-11 18:54:24.772912: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcudnn.so.8
2021-08-11 18:54:24.773009: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-08-11 18:54:24.773989: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-08-11 18:54:24.774867: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1871] Adding visible gpu devices: 0
2021-08-11 18:54:24.775527: I tensorflow/core/platform/cpu_feature_guard.cc:142] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations:  AVX2 AVX512F FMA
To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.
2021-08-11 18:54:24.776134: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-08-11 18:54:24.777106: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1733] Found device 0 with properties: 
pciBusID: 0000:00:05.0 name: Tesla V100-SXM2-16GB computeCapability: 7.0
coreClock: 1.53GHz coreCount: 80 deviceMemorySize: 15.78GiB deviceMemoryBandwidth: 836.37GiB/s
2021-08-11 18:54:24.777201: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-08-11 18:54:24.778110: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-08-11 18:54:24.779002: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1871] Adding visible gpu devices: 0
2021-08-11 18:54:24.779041: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcudart.so.11.0
2021-08-11 18:54:25.384624: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1258] Device interconnect StreamExecutor with strength 1 edge matrix:
2021-08-11 18:54:25.384660: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1264]      0 
2021-08-11 18:54:25.384668: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1277] 0:   N 
2021-08-11 18:54:25.384904: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-08-11 18:54:25.385835: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-08-11 18:54:25.386827: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-08-11 18:54:25.387653: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1418] Created TensorFlow device (/job:localhost/replica:0/task:0/device:GPU:0 with 14646 MB memory) -> physical GPU (device: 0, name: Tesla V100-SXM2-16GB, pci bus id: 0000:00:05.0, compute capability: 7.0)
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/python/util/dispatch.py:206: batch_gather (from tensorflow.python.ops.array_ops) is deprecated and will be removed after 2017-10-25.
Instructions for updating:
`tf.batch_gather` is deprecated, please use `tf.gather` with `batch_dims=-1` instead.
[[b'What', b'you', b'know', b'you', b"can't", b'explain,', b'but', b'you', b'feel', b'it.']]

이 토크나이저의 단점은 구두점이 토큰을 구성하는 단어에 포함된다는 것입니다. 별도의 토큰으로 단어와 문장을 분할하려면 UnicodeScriptTokenizer 사용되어야한다.

유니코드스크립트토큰나이저

UnicodeScriptTokenizer 유니 코드 스크립트 경계를 기반으로 문자열을 분할합니다. 사용된 스크립트 코드는 ICU(International Components for Unicode) UScriptCode 값에 해당합니다. 참조 : http://icu-project.org/apiref/icu4c/uscript_8h.html

실제로, 이것은 유사하다 WhitespaceTokenizer 는 언어 텍스트 (예. USCRIPT_LATIN, USCRIPT_CYRILLIC 등) 또한 서로 언어 텍스트를 분리하는 동안에서 문장 부호 (USCRIPT_COMMON를) 분할 것이다 가장 명백한 차이의 존재와. 이것은 또한 축약어를 별도의 토큰으로 나눕니다.

tokenizer = tf_text.UnicodeScriptTokenizer()
tokens = tokenizer.tokenize(["What you know you can't explain, but you feel it."])
print(tokens.to_list())
[[b'What', b'you', b'know', b'you', b'can', b"'", b't', b'explain', b',', b'but', b'you', b'feel', b'it', b'.']]

하위 단어 토크나이저

하위 단어 토크나이저는 더 작은 어휘와 함께 사용할 수 있으며 모델이 하위 단어를 생성하는 하위 단어에서 새로운 단어에 대한 정보를 가질 수 있도록 합니다.

우리는 간단하게 아래 Subword의 토큰 옵션을 논의하지만, Subword 토큰 화 튜토리얼은 더 깊이 들어가고 또한 Vocab의 파일을 생성하는 방법에 대해 설명합니다.

WordpieceTokenizer

WordPiece 토큰화는 하위 토큰 집합을 생성하는 데이터 기반 토큰화 체계입니다. 이러한 하위 토큰은 언어 형태소에 해당할 수 있지만 그렇지 않은 경우가 많습니다.

WordpieceTokenizer는 입력이 이미 토큰으로 분할될 것으로 예상합니다. 이 전제 조건의 때문에 종종 사용하여 분할 할 것 WhitespaceTokenizer 또는 UnicodeScriptTokenizer 사전을.

tokenizer = tf_text.WhitespaceTokenizer()
tokens = tokenizer.tokenize(["What you know you can't explain, but you feel it."])
print(tokens.to_list())
[[b'What', b'you', b'know', b'you', b"can't", b'explain,', b'but', b'you', b'feel', b'it.']]

문자열을 토큰으로 분리 된 후, WordpieceTokenizer subtokens로 분할 할 수 있습니다.

url = "https://github.com/tensorflow/text/blob/master/tensorflow_text/python/ops/test_data/test_wp_en_vocab.txt?raw=true"
r = requests.get(url)
filepath = "vocab.txt"
open(filepath, 'wb').write(r.content)
52382
subtokenizer = tf_text.UnicodeScriptTokenizer(filepath)
subtokens = tokenizer.tokenize(tokens)
print(subtokens.to_list())
[[[b'What'], [b'you'], [b'know'], [b'you'], [b"can't"], [b'explain,'], [b'but'], [b'you'], [b'feel'], [b'it.']]]

BertTokenizer

BertTokenizer는 BERT 문서의 원래 토큰화 구현을 반영합니다. 이것은 WordpieceTokenizer에 의해 지원되지만 정규화 및 단어로의 토큰화와 같은 추가 작업도 먼저 수행합니다.

tokenizer = tf_text.BertTokenizer(filepath, token_out_type=tf.string, lower_case=True)
tokens = tokenizer.tokenize(["What you know you can't explain, but you feel it."])
print(tokens.to_list())
[[[b'what'], [b'you'], [b'know'], [b'you'], [b'can'], [b"'"], [b't'], [b'explain'], [b','], [b'but'], [b'you'], [b'feel'], [b'it'], [b'.']]]

SentencepieceTokenizer

SentencepieceTokenizer는 고도로 구성 가능한 하위 토큰 토크나이저입니다. 이것은 Sentencepiece 라이브러리에 의해 뒷받침됩니다. BertTokenizer와 마찬가지로 하위 토큰으로 분할하기 전에 정규화 및 토큰 분할을 포함할 수 있습니다.

url = "https://github.com/tensorflow/text/blob/master/tensorflow_text/python/ops/test_data/test_oss_model.model?raw=true"
sp_model = requests.get(url).content
tokenizer = tf_text.SentencepieceTokenizer(sp_model, out_type=tf.string)
tokens = tokenizer.tokenize(["What you know you can't explain, but you feel it."])
print(tokens.to_list())
[[b'\xe2\x96\x81What', b'\xe2\x96\x81you', b'\xe2\x96\x81know', b'\xe2\x96\x81you', b'\xe2\x96\x81can', b"'", b't', b'\xe2\x96\x81explain', b',', b'\xe2\x96\x81but', b'\xe2\x96\x81you', b'\xe2\x96\x81feel', b'\xe2\x96\x81it', b'.']]

기타 스플리터

유니코드CharTokenizer

이것은 문자열을 UTF-8 문자로 분할합니다. 단어 사이에 공백이 없는 CJK 언어에 유용합니다.

tokenizer = tf_text.UnicodeCharTokenizer()
tokens = tokenizer.tokenize(["What you know you can't explain, but you feel it."])
print(tokens.to_list())
[[87, 104, 97, 116, 32, 121, 111, 117, 32, 107, 110, 111, 119, 32, 121, 111, 117, 32, 99, 97, 110, 39, 116, 32, 101, 120, 112, 108, 97, 105, 110, 44, 32, 98, 117, 116, 32, 121, 111, 117, 32, 102, 101, 101, 108, 32, 105, 116, 46]]

출력은 유니코드 코드포인트입니다. 이는 bigram과 같은 문자 ngram을 생성하는 데에도 유용할 수 있습니다. UTF-8 문자로 다시 변환하려면.

characters = tf.strings.unicode_encode(tf.expand_dims(tokens, -1), "UTF-8")
bigrams = tf_text.ngrams(characters, 2, reduction_type=tf_text.Reduction.STRING_JOIN, string_separator='')
print(bigrams.to_list())
[[b'Wh', b'ha', b'at', b't ', b' y', b'yo', b'ou', b'u ', b' k', b'kn', b'no', b'ow', b'w ', b' y', b'yo', b'ou', b'u ', b' c', b'ca', b'an', b"n'", b"'t", b't ', b' e', b'ex', b'xp', b'pl', b'la', b'ai', b'in', b'n,', b', ', b' b', b'bu', b'ut', b't ', b' y', b'yo', b'ou', b'u ', b' f', b'fe', b'ee', b'el', b'l ', b' i', b'it', b't.']]

HubModuleTokenizer

이것은 TF Hub가 현재 비정형 텐서를 지원하지 않기 때문에 호출을 쉽게 하기 위해 TF Hub에 배포된 모델 주변의 래퍼입니다. 모델이 토큰화를 수행하도록 하는 것은 단어로 분할하고 싶지만 경험적 가이드를 제공할 공백이 없을 때 CJK 언어에 특히 유용합니다. 현재 중국어에 대한 단일 세분화 모델이 있습니다.

MODEL_HANDLE = "https://tfhub.dev/google/zh_segmentation/1"
segmenter = tf_text.HubModuleTokenizer(MODEL_HANDLE)
tokens = segmenter.tokenize(["新华社北京"])
print(tokens.to_list())
2021-08-11 18:54:30.368430: I tensorflow/compiler/mlir/mlir_graph_optimization_pass.cc:176] None of the MLIR Optimization Passes are enabled (registered 2)
2021-08-11 18:54:30.369020: I tensorflow/core/platform/profile_utils/cpu_utils.cc:114] CPU Frequency: 2000165000 Hz
2021-08-11 18:54:31.125778: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcudnn.so.8
2021-08-11 18:54:31.579674: I tensorflow/stream_executor/cuda/cuda_dnn.cc:359] Loaded cuDNN version 8100
2021-08-11 18:54:36.707170: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcublas.so.11
[[b'\xe6\x96\xb0\xe5\x8d\x8e\xe7\xa4\xbe', b'\xe5\x8c\x97\xe4\xba\xac']]
2021-08-11 18:54:37.063024: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcublasLt.so.11

UTF-8로 인코딩된 바이트 문자열의 결과를 보는 것이 어려울 수 있습니다. 보기 쉽게 목록 값을 디코딩합니다.

def decode_list(x):
  if type(x) is list:
    return list(map(decode_list, x))
  return x.decode("UTF-8")

def decode_utf8_tensor(x):
  return list(map(decode_list, x.to_list()))

print(decode_utf8_tensor(tokens))
[['新华社', '北京']]

SplitMergeTokenizer

SplitMergeTokenizer & SplitMergeFromLogitsTokenizer 문자열을 분할해야 위치를 표시 제공 값을 기준으로 분할의 대상 목적을 문자열이있다. 이는 이전 Segmentation 예제와 같이 자신의 세분화 모델을 구축할 때 유용합니다.

들어 SplitMergeTokenizer , 0의 값은 새로운 열의 시작을 나타 내기 위해 사용되며, 1의 값은 캐릭터가 현재의 문자열의 일부 나타낸다.

strings = ["新华社北京"]
labels = [[0, 1, 1, 0, 1]]
tokenizer = tf_text.SplitMergeTokenizer()
tokens = tokenizer.tokenize(strings, labels)
print(decode_utf8_tensor(tokens))
[['新华社', '北京']]

SplitMergeFromLogitsTokenizer 비슷하지만, 대신 각 문자는 새로운 문자열로 분할 또는 현재에 병합 할 필요가있는 경우 예측 신경망에서 로짓 값 쌍을 받아들입니다.

strings = [["新华社北京"]]
labels = [[[5.0, -3.2], [0.2, 12.0], [0.0, 11.0], [2.2, -1.0], [-3.0, 3.0]]]
tokenizer = tf_text.SplitMergeFromLogitsTokenizer()
tokenizer.tokenize(strings, labels)
print(decode_utf8_tensor(tokens))
[['新华社', '北京']]

정규식 스플리터

RegexSplitter 제공된 정규 표현식에 의해 정의 된 임의의 중단 부분 문자열 수있다.

splitter = tf_text.RegexSplitter("\s")
tokens = splitter.split(["What you know you can't explain, but you feel it."], )
print(tokens.to_list())
[[b'What', b'you', b'know', b'you', b"can't", b'explain,', b'but', b'you', b'feel', b'it.']]

오프셋

문자열을 토큰화할 때 원래 문자열에서 토큰이 어디에서 왔는지 알고 싶은 경우가 많습니다. 따라서 구현 된 각 토크 나이 들어 TokenizerWithOffsets 토큰과 함께 바이트 오프셋을 반환하는 tokenize_with_offsets 방법이있다. start_offsets는 각 토큰이 시작하는 원래 문자열의 바이트를 나열하고 end_offsets는 각 토큰이 끝나는 지점 바로 뒤의 바이트를 나열합니다. 재분석하기 위해 시작 오프셋은 포함되고 끝 오프셋은 제외됩니다.

tokenizer = tf_text.UnicodeScriptTokenizer()
(tokens, start_offsets, end_offsets) = tokenizer.tokenize_with_offsets(['Everything not saved will be lost.'])
print(tokens.to_list())
print(start_offsets.to_list())
print(end_offsets.to_list())
[[b'Everything', b'not', b'saved', b'will', b'be', b'lost', b'.']]
[[0, 11, 15, 21, 26, 29, 33]]
[[10, 14, 20, 25, 28, 33, 34]]

해독

도구 용 Tokenizers Detokenizer 제공 detokenize 방법 문자열을 결합하는 시도를. 이것은 손실될 가능성이 있으므로 토큰화된 문자열이 사전 토큰화된 원래 문자열과 항상 정확히 일치하지 않을 수 있습니다.

tokenizer = tf_text.UnicodeCharTokenizer()
tokens = tokenizer.tokenize(["What you know you can't explain, but you feel it."])
print(tokens.to_list())
strings = tokenizer.detokenize(tokens)
print(strings.numpy())
[[87, 104, 97, 116, 32, 121, 111, 117, 32, 107, 110, 111, 119, 32, 121, 111, 117, 32, 99, 97, 110, 39, 116, 32, 101, 120, 112, 108, 97, 105, 110, 44, 32, 98, 117, 116, 32, 121, 111, 117, 32, 102, 101, 101, 108, 32, 105, 116, 46]]
[b"What you know you can't explain, but you feel it."]

TF 데이터

TF Data는 훈련 모델을 위한 입력 파이프라인을 생성하기 위한 강력한 API입니다. 토큰나이저는 API에서 예상대로 작동합니다.

docs = tf.data.Dataset.from_tensor_slices([['Never tell me the odds.'], ["It's a trap!"]])
tokenizer = tf_text.WhitespaceTokenizer()
tokenized_docs = docs.map(lambda x: tokenizer.tokenize(x))
iterator = iter(tokenized_docs)
print(next(iterator).to_list())
print(next(iterator).to_list())
[[b'Never', b'tell', b'me', b'the', b'odds.']]
[[b"It's", b'a', b'trap!']]