TF Metin ile BERT Ön İşleme

Koleksiyonlar ile düzeninizi koruyun İçeriği tercihlerinize göre kaydedin ve kategorilere ayırın.

TensorFlow.org'da görüntüleyin Google Colab'da çalıştırın GitHub'da görüntüle Not defterini indir

genel bakış

Metin ön işleme, ham metnin bir modelin tamsayı girdilerine uçtan uca dönüştürülmesidir. NLP modellerine genellikle metnin ön işlemesi için yüzlerce (binlerce değilse) Python kodu satırı eşlik eder. Metin ön işleme, genellikle modeller için bir zorluktur çünkü:

  • Eğitim-hizmet çarpıklığı. Modelin girdilerinin ön işleme mantığının model geliştirmenin tüm aşamalarında (örn. ön eğitim, ince ayar, değerlendirme, çıkarım) tutarlı olmasını sağlamak giderek zorlaşıyor. Farklı hiperparametreler, belirteçleştirme, dizi ön işleme algoritmaları veya basitçe model girdilerini farklı aşamalarda tutarsız bir şekilde paketlemek, modelde hata ayıklaması zor ve yıkıcı etkiler yaratabilir.

  • Verimlilik ve esneklik. Ön işleme çevrimdışı yapılabilirken (örneğin, işlenmiş çıktıları diskteki dosyalara yazarak ve ardından söz konusu önceden işlenmiş verileri giriş hattında yeniden kullanarak), bu yöntem ek bir dosya okuma ve yazma maliyetine neden olur. Dinamik olarak gerçekleşmesi gereken ön işleme kararları varsa, çevrimdışı ön işleme de uygun değildir. Farklı bir seçenekle deneme yapmak, veri kümesinin yeniden oluşturulmasını gerektirir.

  • Karmaşık model arayüzü. Metin modelleri, girdileri salt metin olduğunda çok daha anlaşılırdır. Girdileri fazladan, dolaylı bir kodlama adımı gerektirdiğinde bir modeli anlamak zordur. Ön işleme karmaşıklığının azaltılması, özellikle model hata ayıklama, sunma ve değerlendirme için takdir edilmektedir.

Ek olarak, daha basit model arayüzleri, modeli farklı, keşfedilmemiş veri kümeleri üzerinde denemeyi (örn. çıkarım veya eğitim) daha uygun hale getirir.

TF.Text ile metin ön işleme

TF.Text'in metin ön işleme API'lerini kullanarak, bir kullanıcının metin veri setini modelin tamsayı girdilerine dönüştürebilen bir ön işleme işlevi oluşturabiliriz. Kullanıcılar, yukarıda belirtilen sorunları hafifletmek için ön işlemeyi doğrudan modellerinin bir parçası olarak paketleyebilir.

Bu eğitimde "Maskeli LM ve Maskeleme Prosedürü" nün anlatıldığı Bert modeli ve görevi antrenman öncesi maskeleme dil için girişler için girişler içine metin verileri dönüştürmek için TF.Text önişleme ops nasıl kullanılacağını gösterecek Dili Derin Çift yönlü Transformers Öncesi Eğitim: bert anlama . İşlem, metni alt sözcük birimlerine ayırmayı, cümleleri birleştirmeyi, içeriği sabit bir boyuta kırpmayı ve maskeli dil modelleme görevi için etiketleri çıkarmayı içerir.

Kurmak

İlk önce ihtiyacımız olan paketleri ve kütüphaneleri import edelim.

pip install -q -U tensorflow-text
import tensorflow as tf
import tensorflow_text as text
import functools

Bizim veriler iki metin özellikleri içerir ve bir örnek oluşturabilir tf.data.Dataset . Amacımız sağlayabilmektedir bir işlev oluşturmaktır Dataset.map() eğitimde kullanılmak üzere olan.

examples = {
    "text_a": [
      b"Sponge bob Squarepants is an Avenger",
      b"Marvel Avengers"
    ],
    "text_b": [
     b"Barack Obama is the President.",
     b"President is the highest office"
  ],
}

dataset = tf.data.Dataset.from_tensor_slices(examples)
next(iter(dataset))
{'text_a': <tf.Tensor: shape=(), dtype=string, numpy=b'Sponge bob Squarepants is an Avenger'>,
 'text_b': <tf.Tensor: shape=(), dtype=string, numpy=b'Barack Obama is the President.'>}

Tokenleştirme

İlk adımımız, herhangi bir dize ön işlemesini çalıştırmak ve veri kümemizi belirtmektir. Bu kullanılarak yapılabilir text.BertTokenizer a,, text.Splitter için alt-kelimelerin veya wordpieces içine bulundu simgeleştirir olabilir Bert modeli oluşturulmuş bir kelime verilir Wordpiece algoritması . Sen den TF.Text mevcut diğer alt-kelime tokenizers hakkında daha fazla bilgi edinebilirsiniz burada .

Sözcük bilgisi önceden oluşturulmuş bir BERT kontrol noktasından olabilir veya kendi verileriniz üzerinden kendiniz bir tane oluşturabilirsiniz. Bu örneğin amaçları için bir oyuncak sözlüğü oluşturalım:

_VOCAB = [
    # Special tokens
    b"[UNK]", b"[MASK]", b"[RANDOM]", b"[CLS]", b"[SEP]",
    # Suffixes
    b"##ack", b"##ama", b"##ger", b"##gers", b"##onge", b"##pants",  b"##uare",
    b"##vel", b"##ven", b"an", b"A", b"Bar", b"Hates", b"Mar", b"Ob",
    b"Patrick", b"President", b"Sp", b"Sq", b"bob", b"box", b"has", b"highest",
    b"is", b"office", b"the",
]

_START_TOKEN = _VOCAB.index(b"[CLS]")
_END_TOKEN = _VOCAB.index(b"[SEP]")
_MASK_TOKEN = _VOCAB.index(b"[MASK]")
_RANDOM_TOKEN = _VOCAB.index(b"[RANDOM]")
_UNK_TOKEN = _VOCAB.index(b"[UNK]")
_MAX_SEQ_LEN = 8
_MAX_PREDICTIONS_PER_BATCH = 5

_VOCAB_SIZE = len(_VOCAB)

lookup_table = tf.lookup.StaticVocabularyTable(
    tf.lookup.KeyValueTensorInitializer(
      keys=_VOCAB,
      key_dtype=tf.string,
      values=tf.range(
          tf.size(_VOCAB, out_type=tf.int64), dtype=tf.int64),
      value_dtype=tf.int64),
      num_oov_buckets=1
)

Hadi yapı bir text.BertTokenizer yukarıdaki kelimeleri kullanarak ve içine metin girişi tokenize RaggedTensor .`.

bert_tokenizer = text.BertTokenizer(lookup_table, token_out_type=tf.string)
bert_tokenizer.tokenize(examples["text_a"])
<tf.RaggedTensor [[[b'Sp', b'##onge'], [b'bob'], [b'Sq', b'##uare', b'##pants'], [b'is'], [b'an'], [b'A', b'##ven', b'##ger']], [[b'Mar', b'##vel'], [b'A', b'##ven', b'##gers']]]>
bert_tokenizer.tokenize(examples["text_b"])
<tf.RaggedTensor [[[b'Bar', b'##ack'], [b'Ob', b'##ama'], [b'is'], [b'the'], [b'President'], [b'[UNK]']], [[b'President'], [b'is'], [b'the'], [b'highest'], [b'office']]]>

Metin çıkışı text.BertTokenizer bize metin simgeleþtirilmiþ ediliyor nasıl izin verir, fakat modeli tamsayı kimlikleri gerektirir. Biz ayarlayabilir token_out_type için param tf.int64 (kelime içine bir indeksi olan) kimlikleri tamsayıdır elde edildi.

bert_tokenizer = text.BertTokenizer(lookup_table, token_out_type=tf.int64)
segment_a = bert_tokenizer.tokenize(examples["text_a"])
segment_a
<tf.RaggedTensor [[[22, 9], [24], [23, 11, 10], [28], [14], [15, 13, 7]], [[18, 12], [15, 13, 8]]]>
segment_b = bert_tokenizer.tokenize(examples["text_b"])
segment_b
<tf.RaggedTensor [[[16, 5], [19, 6], [28], [30], [21], [0]], [[21], [28], [30], [27], [29]]]>

text.BertTokenizer bir döner RaggedTensor şeklinde [batch, num_tokens, num_wordpieces] . Ekstra gerekmez Çünkü num_tokens mevcut kullanım durumu için boyutları, bir elde etmek son iki boyutu birleştirebilirsiniz RaggedTensor şekli ile [batch, num_wordpieces] :

segment_a = segment_a.merge_dims(-2, -1)
segment_a
<tf.RaggedTensor [[22, 9, 24, 23, 11, 10, 28, 14, 15, 13, 7], [18, 12, 15, 13, 8]]>
segment_b = segment_b.merge_dims(-2, -1)
segment_b
<tf.RaggedTensor [[16, 5, 19, 6, 28, 30, 21, 0], [21, 28, 30, 27, 29]]>

İçerik Kırpma

BERT'nin ana girdisi iki cümlenin birleştirilmesidir. Ancak BERT, girdilerin sabit boyutta ve şekilde olmasını gerektirir ve bütçemizi aşan içeriklere sahip olabiliriz.

Biz kullanarak bu üstesinden gelebilirsiniz text.Trimmer (son eksen boyunca birleştirilmiş bir kez), önceden belirlenmiş bir boyuta içerik aşağı kırpmaya. Farklı vardır text.Trimmer farklı algoritmalar kullanılarak korumak için içerik türlerini seçin. text.RoundRobinTrimmer , örneğin her bir segment için eşit kota tahsis edecek, ancak cümleler uçlarını tıraşlayabilir. text.WaterfallTrimmer son cümlenin sonuna başlayarak Döşeme olacaktır.

Bizim Örneğin, biz kullanacağız RoundRobinTrimmer seçer öğeler soldan sağa bir şekilde her kesimden.

trimmer = text.RoundRobinTrimmer(max_seq_length=[_MAX_SEQ_LEN])
trimmed = trimmer.trim([segment_a, segment_b])
trimmed
[<tf.RaggedTensor [[22, 9, 24, 23], [18, 12, 15, 13]]>,
 <tf.RaggedTensor [[16, 5, 19, 6], [21, 28, 30, 27]]>]

trimmed bir yığın boyunca eleman sayısı 8 eleman (eksen = -1 boyunca birleştirilmiş) olduğu şu anda segmentleri içerir.

Segmentleri birleştirme

Şimdi segmentleri kesilmiş olması, bir tek olsun bir araya getirebilirsiniz RaggedTensor . Bert başlangıcı (belirtmek için özel belirteçleri kullanan [CLS] bir segmentin (arasında) ve son [SEP] ). Biz de bir ihtiyaç RaggedTensor kombine hangi öğeleri gösteren Tensor hangi segmentin aittir. Biz kullanabilirsiniz text.combine_segments() Bunlardan ikisi almak için Tensor sokulan özel fişlerle.

segments_combined, segments_ids = text.combine_segments(
  [segment_a, segment_b],
  start_of_sequence_id=_START_TOKEN, end_of_segment_id=_END_TOKEN)
segments_combined, segments_ids
(<tf.RaggedTensor [[3, 22, 9, 24, 23, 11, 10, 28, 14, 15, 13, 7, 4, 16, 5, 19, 6, 28, 30, 21, 0, 4], [3, 18, 12, 15, 13, 8, 4, 21, 28, 30, 27, 29, 4]]>,
 <tf.RaggedTensor [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1]]>)

Maskeli Dil Modeli Görevi

Şimdi bizim temel girdileri olduğuna göre "Maskeli LM ve Maskeleme Prosedürü" için gerekli girdileri ayıklamak için başlayabilir görev açıklanan bert: Dil Anlayış Derin Çift yönlü Transformers Öncesi eğitim

Maskeli dil modeli görevinin düşünmemiz için iki alt sorunu vardır: (1) maskeleme için hangi öğelerin seçileceği ve (2) bunlara hangi değerler atandığı?

Ürün Seçimi

Rastgele maskeleme için öğeleri seçmek için seçecektir çünkü biz kullanacağız text.RandomItemSelector . RandomItemSelector rastgele verilen kısıtlamaları (bir parti denekte ürün seçer max_selections_per_batch , selection_rate ve unselectable_ids ) ve döner öğeler seçilen hangi belirten bir Boole maskesi.

random_selector = text.RandomItemSelector(
    max_selections_per_batch=_MAX_PREDICTIONS_PER_BATCH,
    selection_rate=0.2,
    unselectable_ids=[_START_TOKEN, _END_TOKEN, _UNK_TOKEN]
)
selected = random_selector.get_selection_mask(
    segments_combined, axis=1)
selected
<tf.RaggedTensor [[False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, True, True, True, False, False], [False, False, False, False, False, True, False, False, False, False, False, True, False]]>

Maskelenmiş Değeri Seçme

Maskeleme değerini seçmek için orijinal BERT belgesini tanımlayan metodoloji aşağıdaki gibidir:

İçin mask_token_rate zaman, öğeyi değiştirmek [MASK] jetonu:

"my dog is hairy" -> "my dog is [MASK]"

İçin random_token_rate zaman, rastgele bir kelime ile öğeyi değiştirin:

"my dog is hairy" -> "my dog is apple"

İçin 1 - mask_token_rate - random_token_rate zaman, değişmeden öğeyi tutmak:

"my dog is hairy" -> "my dog is hairy."

text.MaskedValuesChooser bu mantığını kapsüller ve bizim ön işleme fonksiyonu için kullanılabilir. İşte ne bir örnek MaskValuesChooser döner belirli bir mask_token_rate % 80 ve varsayılan random_token_rate :

input_ids = tf.ragged.constant([[19, 7, 21, 20, 9, 8], [13, 4, 16, 5], [15, 10, 12, 11, 6]])
mask_values_chooser = text.MaskValuesChooser(_VOCAB_SIZE, _MASK_TOKEN, 0.8)
mask_values_chooser.get_mask_values(input_ids)
<tf.RaggedTensor [[1, 1, 1, 1, 1, 1], [1, 1, 1, 1], [1, 10, 1, 1, 6]]>

Bir sağlandığında RaggedTensor girişi text.MaskValuesChooser bir döner RaggedTensor ya ile aynı şekle sahip _MASK_VALUE (0), bir rastgele numarası ya da aynı değişmeden id.

Maskeli Dil Modeli Görevi için Girdiler Oluşturma

Şimdi bir olduğunu RandomItemSelector bize maskeleme ve öğeleri seçmek yardımına text.MaskValuesChooser değerleri atamak için, kullanabileceğimiz text.mask_language_model() bizim Bert modeli için bu görevin tüm girdileri bir araya getirmek.

masked_token_ids, masked_pos, masked_lm_ids = text.mask_language_model(
  segments_combined,
  item_selector=random_selector, mask_values_chooser=mask_values_chooser)
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.

Hadi dalış derin ve çıktılarını incelemek mask_language_model() . Çıkış masked_token_ids olduğu:

masked_token_ids
<tf.RaggedTensor [[3, 22, 1, 24, 23, 1, 10, 28, 1, 15, 1, 7, 4, 16, 5, 19, 6, 28, 30, 21, 0, 4], [3, 18, 12, 15, 13, 1, 4, 21, 28, 30, 27, 1, 4]]>

Girişimizin bir sözlük kullanılarak kodlandığını unutmayın. Biz deşifre olursa masked_token_ids bizim kelime kullanarak elde ederiz:

tf.gather(_VOCAB, masked_token_ids)
<tf.RaggedTensor [[b'[CLS]', b'Sp', b'[MASK]', b'bob', b'Sq', b'[MASK]', b'##pants', b'is', b'[MASK]', b'A', b'[MASK]', b'##ger', b'[SEP]', b'Bar', b'##ack', b'Ob', b'##ama', b'is', b'the', b'President', b'[UNK]', b'[SEP]'], [b'[CLS]', b'Mar', b'##vel', b'A', b'##ven', b'[MASK]', b'[SEP]', b'President', b'is', b'the', b'highest', b'[MASK]', b'[SEP]']]>

Bazı wordpiece belirteçleri ile ya ikame edilmiş olduğuna dikkat edin [MASK] , [RANDOM] ya da farklı bir kimlik değeri. masked_pos çıkış bize değiştirildiği jeton (ilgili toplu) endeksleri verir.

masked_pos
<tf.RaggedTensor [[2, 5, 8, 10], [5, 11]]>

masked_lm_ids bize belirteci özgün değerini verir.

masked_lm_ids
<tf.RaggedTensor [[9, 11, 14, 13], [8, 29]]>

İnsan tarafından okunabilir değerler elde etmek için burada kimliklerin kodunu tekrar çözebiliriz.

tf.gather(_VOCAB, masked_lm_ids)
<tf.RaggedTensor [[b'##onge', b'##uare', b'an', b'##ven'], [b'##gers', b'office']]>

Dolgu Modeli Girişleri

Şimdi bizim model için tüm girdileri sahip olduğunu, bizim ön işleme son adımı sabit 2 boyutlu içine paketlemek için Tensor ler dolgu ile ve ayrıca bir maske oluşturmak Tensor ped değerlerdir değerlerini gösteren. Biz kullanabilirsiniz text.pad_model_inputs() bu görev bize yardımcı olmak için.

# Prepare and pad combined segment inputs
input_word_ids, input_mask = text.pad_model_inputs(
  masked_token_ids, max_seq_length=_MAX_SEQ_LEN)
input_type_ids, _ = text.pad_model_inputs(
  masked_token_ids, max_seq_length=_MAX_SEQ_LEN)

# Prepare and pad masking task inputs
masked_lm_positions, masked_lm_weights = text.pad_model_inputs(
  masked_token_ids, max_seq_length=_MAX_PREDICTIONS_PER_BATCH)
masked_lm_ids, _ = text.pad_model_inputs(
  masked_lm_ids, max_seq_length=_MAX_PREDICTIONS_PER_BATCH)

model_inputs = {
    "input_word_ids": input_word_ids,
    "input_mask": input_mask,
    "input_type_ids": input_type_ids,
    "masked_lm_ids": masked_lm_ids,
    "masked_lm_positions": masked_lm_positions,
    "masked_lm_weights": masked_lm_weights,
}
model_inputs
{'input_word_ids': <tf.Tensor: shape=(2, 8), dtype=int64, numpy=
 array([[ 3, 22,  1, 24, 23,  1, 10, 28],
        [ 3, 18, 12, 15, 13,  1,  4, 21]])>,
 'input_mask': <tf.Tensor: shape=(2, 8), dtype=int64, numpy=
 array([[1, 1, 1, 1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1, 1, 1, 1]])>,
 'input_type_ids': <tf.Tensor: shape=(2, 8), dtype=int64, numpy=
 array([[ 3, 22,  1, 24, 23,  1, 10, 28],
        [ 3, 18, 12, 15, 13,  1,  4, 21]])>,
 'masked_lm_ids': <tf.Tensor: shape=(2, 5), dtype=int64, numpy=
 array([[ 9, 11, 14, 13,  0],
        [ 8, 29,  0,  0,  0]])>,
 'masked_lm_positions': <tf.Tensor: shape=(2, 5), dtype=int64, numpy=
 array([[ 3, 22,  1, 24, 23],
        [ 3, 18, 12, 15, 13]])>,
 'masked_lm_weights': <tf.Tensor: shape=(2, 5), dtype=int64, numpy=
 array([[1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1]])>}

Gözden geçirmek

Şimdiye kadar sahip olduklarımızı gözden geçirelim ve ön işleme fonksiyonumuzu bir araya getirelim. İşte sahip olduklarımız:

def bert_pretrain_preprocess(vocab_table, features):
  # Input is a string Tensor of documents, shape [batch, 1].
  text_a = features["text_a"]
  text_b = features["text_b"]

  # Tokenize segments to shape [num_sentences, (num_words)] each.
  tokenizer = text.BertTokenizer(
      vocab_table,
      token_out_type=tf.int64)
  segments = [tokenizer.tokenize(text).merge_dims(
      1, -1) for text in (text_a, text_b)]

  # Truncate inputs to a maximum length.
  trimmer = text.RoundRobinTrimmer(max_seq_length=6)
  trimmed_segments = trimmer.trim(segments)

  # Combine segments, get segment ids and add special tokens.
  segments_combined, segment_ids = text.combine_segments(
      trimmed_segments,
      start_of_sequence_id=_START_TOKEN,
      end_of_segment_id=_END_TOKEN)

  # Apply dynamic masking task.
  masked_input_ids, masked_lm_positions, masked_lm_ids = (
      text.mask_language_model(
        segments_combined,
        random_selector,
        mask_values_chooser,
      )
  )

  # Prepare and pad combined segment inputs
  input_word_ids, input_mask = text.pad_model_inputs(
    masked_input_ids, max_seq_length=_MAX_SEQ_LEN)
  input_type_ids, _ = text.pad_model_inputs(
    masked_input_ids, max_seq_length=_MAX_SEQ_LEN)

  # Prepare and pad masking task inputs
  masked_lm_positions, masked_lm_weights = text.pad_model_inputs(
    masked_input_ids, max_seq_length=_MAX_PREDICTIONS_PER_BATCH)
  masked_lm_ids, _ = text.pad_model_inputs(
    masked_lm_ids, max_seq_length=_MAX_PREDICTIONS_PER_BATCH)

  model_inputs = {
      "input_word_ids": input_word_ids,
      "input_mask": input_mask,
      "input_type_ids": input_type_ids,
      "masked_lm_ids": masked_lm_ids,
      "masked_lm_positions": masked_lm_positions,
      "masked_lm_weights": masked_lm_weights,
  }
  return model_inputs

Biz daha önce bir inşa tf.data.Dataset ve şimdi bizim monte ön işleme işlevini kullanabilirsiniz bert_pretrain_preprocess() içinde Dataset.map() . Bu, ham dizi verilerimizi tamsayı girdilerine dönüştürmek ve doğrudan modelimize beslemek için bir girdi ardışık düzeni oluşturmamıza olanak tanır.

dataset = tf.data.Dataset.from_tensors(examples)
dataset = dataset.map(functools.partial(
    bert_pretrain_preprocess, lookup_table))

next(iter(dataset))
{'input_word_ids': <tf.Tensor: shape=(2, 8), dtype=int64, numpy=
 array([[ 3, 22,  9,  1,  4, 16,  5, 19],
        [ 3, 18,  1, 15,  4,  1, 28, 30]])>,
 'input_mask': <tf.Tensor: shape=(2, 8), dtype=int64, numpy=
 array([[1, 1, 1, 1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1, 1, 1, 1]])>,
 'input_type_ids': <tf.Tensor: shape=(2, 8), dtype=int64, numpy=
 array([[ 3, 22,  9,  1,  4, 16,  5, 19],
        [ 3, 18,  1, 15,  4,  1, 28, 30]])>,
 'masked_lm_ids': <tf.Tensor: shape=(2, 5), dtype=int64, numpy=
 array([[24, 19,  0,  0,  0],
        [12, 21,  0,  0,  0]])>,
 'masked_lm_positions': <tf.Tensor: shape=(2, 5), dtype=int64, numpy=
 array([[ 3, 22,  9,  1,  4],
        [ 3, 18,  1, 15,  4]])>,
 'masked_lm_weights': <tf.Tensor: shape=(2, 5), dtype=int64, numpy=
 array([[1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1]])>}
  • Bert ile sınıflandırır metin - sınıflandırmak metne pretrained Bert modelini nasıl kullanılacağına dair bir dokuman. BERT modeli tarafından kullanılan girdilerin nasıl önişlemden geçirileceğini bildiğinize göre, bu güzel bir takip.

  • TF Metin ile tokenizing - Öğretici TF.Text var tokenizers farklı detaylandırma.

  • İle Metin İşleme RaggedTensor -, oluşturmak, kullanmak ve işlemek için nasıl Detaylı rehber RaggedTensor s.