Metin Görevleri için Yaygın SavedModel API'leri

Bu sayfada, metinle ilgili görevlere yönelik TF2 SavedModels'in Yeniden Kullanılabilir SavedModel API'sini nasıl uygulaması gerektiği açıklanmaktadır. (Bu, artık kullanımdan kaldırılan TF1 Hub formatına ilişkin Metin için Ortak İmzaların yerine geçer ve kapsamını genişletir.)

Genel Bakış

Metin yerleştirmelerini hesaplamak için çeşitli API'ler vardır (aynı zamanda metnin yoğun temsilleri veya metin özellik vektörleri olarak da bilinir).

  • Metin girişlerinden metin yerleştirmeye yönelik API, bir grup dizeyi bir dizi gömme vektörüne eşleyen bir SavedModel tarafından uygulanır. Bunun kullanımı çok kolaydır ve TF Hub'daki birçok model bunu uygulamıştır. Ancak bu, modelin TPU üzerinde ince ayarlanmasına izin vermiyor.

  • Önceden işlenmiş girişlerle metin yerleştirme API'si aynı görevi çözer ancak iki ayrı SavedModels tarafından uygulanır:

    • tf.data giriş hattı içinde çalışabilen ve dizeleri ve diğer değişken uzunluktaki verileri sayısal Tensörlere dönüştürebilen bir ön işlemci ,
    • Ön işlemcinin sonuçlarını kabul eden ve yerleştirme hesaplamasının eğitilebilir kısmını gerçekleştiren bir kodlayıcı .

    Bu bölünme, girdilerin eğitim döngüsüne beslenmeden önce eşzamansız olarak önceden işlenmesine olanak tanır. Özellikle TPU'da çalıştırılabilen ve ince ayar yapılabilen kodlayıcıların oluşturulmasına olanak tanır.

  • Transformer kodlayıcılarla metin yerleştirmeye yönelik API, metin yerleştirmeye yönelik API'yi önceden işlenmiş girişlerden BERT ve diğer Transformer kodlayıcılara kadar genişletir.

    • Ön işlemci, giriş metninin birden fazla bölümünden kodlayıcı girişleri oluşturacak şekilde genişletilir.
    • Transformer kodlayıcı, bireysel belirteçlerin bağlama duyarlı yerleştirmelerini ortaya çıkarır.

Her durumda, metin girişleri, model belgelerinde aksi belirtilmediği sürece, genellikle düz metinden oluşan UTF-8 kodlu dizelerdir.

API'den bağımsız olarak, farklı modeller, farklı dillerden ve alanlardaki metinler üzerinde ve farklı görevler göz önünde bulundurularak önceden eğitilmiştir. Bu nedenle her metin gömme modeli her soruna uygun değildir.

Metin Girişlerinden Metin Gömme

Metin girişlerinden metin yerleştirmeleri için SavedModel [batch_size] şeklindeki bir Tensör dizesindeki bir grup girişi kabul eder ve bunları, girişlerin yoğun temsillerine (özellik vektörleri) sahip bir float32 şeklinin [batch_size, dim] Tensörüne eşler.

Kullanım özeti

obj = hub.load("path/to/model")
text_input = ["A long sentence.",
              "single-word",
              "http://example.com"]
embeddings = obj(text_input)

Yeniden Kullanılabilir SavedModel API'sinden , modeli eğitim modunda çalıştırmanın (örneğin, bırakma için) obj(..., training=True) anahtar kelime bağımsız değişkenini gerektirebileceğini ve obj uygun olduğu şekilde .variables , .trainable_variables ve .regularization_losses niteliklerini sağladığını hatırlayın. .

Keras'ta tüm bunlar hallediliyor

embeddings = hub.KerasLayer("path/to/model", trainable=...)(text_input)

Dağıtılmış eğitim

Metin yerleştirme, bir dağıtım stratejisiyle eğitilen bir modelin parçası olarak kullanılıyorsa, hub.load("path/to/model") veya hub.KerasLayer("path/to/model", ...) çağrısı yapılır. hub.KerasLayer("path/to/model", ...) , sırasıyla, modelin değişkenlerini dağıtılmış şekilde oluşturmak için DistributionStrategy kapsamı içinde gerçekleşmelidir. Örneğin

  with strategy.scope():
    ...
    model = hub.load("path/to/model")
    ...

Örnekler

Önceden İşlenmiş Girişlerle Metin Gömmeler

Önceden işlenmiş girişlere sahip bir metin yerleştirme, iki ayrı SavedModels tarafından uygulanır:

  • [batch_size] şeklindeki bir Tensör dizesini sayısal Tensörlerin bir diktesine eşleyen bir ön işlemci ,
  • Ön işlemci tarafından döndürülen Tensörlerin bir diktesini kabul eden, yerleştirme hesaplamasının eğitilebilir kısmını gerçekleştiren ve bir çıktı diktesi döndüren bir kodlayıcı . "default" anahtarının altındaki çıktı [batch_size, dim] şeklinde bir float32 Tensörüdür.

Bu, ön işlemcinin bir giriş hattında çalıştırılmasına ancak daha büyük bir modelin parçası olarak kodlayıcı tarafından hesaplanan yerleştirmelerde ince ayar yapılmasına olanak tanır. Özellikle TPU üzerinde çalıştırılabilen ve ince ayarı yapılabilen kodlayıcılar oluşturmaya olanak tanır.

Önişlemcinin çıktısında hangi Tensörlerin yer aldığı ve (varsa) kodlayıcının çıktısında "default" dışında hangi ek Tensörlerin bulunduğu bir uygulama detayıdır.

Kodlayıcının dokümantasyonu, kodlayıcıyla birlikte hangi ön işlemcinin kullanılacağını belirtmelidir. Tipik olarak tam olarak tek bir doğru seçim vardır.

Kullanım özeti

text_input = tf.constant(["A long sentence.",
                          "single-word",
                          "http://example.com"])
preprocessor = hub.load("path/to/preprocessor")  # Must match `encoder`.
encoder_inputs = preprocessor(text_input)

encoder = hub.load("path/to/encoder")
encoder_outputs = encoder(encoder_inputs)
embeddings = encoder_outputs["default"]

Yeniden Kullanılabilir SavedModel API'sinden , kodlayıcıyı eğitim modunda çalıştırmanın (örneğin, bırakma için) bir anahtar kelime bağımsız değişkeni encoder(..., training=True) gerektirebileceğini ve encoder uygun olduğu şekilde .variables , .trainable_variables ve .regularization_losses niteliklerini sağladığını hatırlayın. .

preprocessor modeli .variables sahip olabilir ancak daha fazla eğitilmeye yönelik değildir. Ön işleme moda bağlı değildir: eğer preprocessor() bir training=... argümanı varsa, bunun hiçbir etkisi yoktur.

Keras'ta tüm bunlar hallediliyor

encoder_inputs = hub.KerasLayer("path/to/preprocessor")(text_input)
encoder_outputs = hub.KerasLayer("path/to/encoder", trainable=True)(encoder_inputs)
embeddings = encoder_outputs["default"]

Dağıtılmış eğitim

Kodlayıcı, bir dağıtım stratejisiyle eğitilen bir modelin parçası olarak kullanılıyorsa, hub.load("path/to/encoder") veya hub.KerasLayer("path/to/encoder", ...) çağrısı yani içeride gerçekleşmesi gerekir

  with strategy.scope():
    ...

Kodlayıcı değişkenlerini dağıtılmış şekilde yeniden oluşturmak için.

Benzer şekilde, eğer önişlemci eğitilmiş modelin bir parçasıysa (yukarıdaki basit örnekte olduğu gibi), dağıtım stratejisi kapsamı altında da yüklenmesi gerekir. Bununla birlikte, ön işlemci bir giriş hattında kullanılıyorsa (örneğin, tf.data.Dataset.map() öğesine iletilen bir çağrılabilirde), değişkenlerini (varsa) yerleştirmek için yüklemesinin dağıtım stratejisi kapsamı dışında gerçekleşmesi gerekir. ) ana bilgisayar CPU'sunda.

Örnekler

Transformer Encoder'larla metin yerleştirmeleri

Metin için dönüştürücü kodlayıcılar, n üzerinde bazı modele özgü sınırlar dahilinde, her bir dizi n ≥ 1 simgeleştirilmiş metin segmenti içeren bir girdi dizileri kümesi üzerinde çalışır. BERT ve birçok uzantısı için bu sınır 2'dir, dolayısıyla tekli segmentleri ve segment çiftlerini kabul ederler.

Transformer kodlayıcılarla metin yerleştirmeye yönelik API, önceden işlenmiş girişlerle metin yerleştirmeye yönelik API'yi bu ayara kadar genişletir.

Önişlemci

Transformer kodlayıcılarla metin yerleştirmeler için bir ön işlemci SavedModel, önceden işlenmiş girişlerle (yukarıya bakın) metin yerleştirmeler için bir ön işlemci SavedModel'in API'sini uygular; bu, tek bölümlü metin girişlerini doğrudan kodlayıcı girişleriyle eşlemenin bir yolunu sağlar.

Buna ek olarak, ön işlemci SavedModel, tokenleştirme için çağrılabilir alt nesneler tokenize (segment başına ayrı ayrı) ve n tokenleştirilmiş segmenti kodlayıcı için tek bir giriş dizisine paketlemek için bert_pack_inputs sağlar. Her alt nesne, Yeniden Kullanılabilir SavedModel API'sini takip eder.

Kullanım özeti

Metnin iki bölümü için somut bir örnek olarak, bir öncülün (ilk bölüm) bir hipotezi (ikinci bölüm) ima edip etmediğini soran bir cümle bütünleme görevine bakalım.

preprocessor = hub.load("path/to/preprocessor")

# Tokenize batches of both text inputs.
text_premises = tf.constant(["The quick brown fox jumped over the lazy dog.",
                             "Good day."])
tokenized_premises = preprocessor.tokenize(text_premises)
text_hypotheses = tf.constant(["The dog was lazy.",  # Implied.
                               "Axe handle!"])       # Not implied.
tokenized_hypotheses = preprocessor.tokenize(text_hypotheses)

# Pack input sequences for the Transformer encoder.
seq_length = 128
encoder_inputs = preprocessor.bert_pack_inputs(
    [tokenized_premises, tokenized_hypotheses],
    seq_length=seq_length)  # Optional argument.

Keras'ta bu hesaplama şu şekilde ifade edilebilir:

tokenize = hub.KerasLayer(preprocessor.tokenize)
tokenized_hypotheses = tokenize(text_hypotheses)
tokenized_premises = tokenize(text_premises)

bert_pack_inputs = hub.KerasLayer(
    preprocessor.bert_pack_inputs,
    arguments=dict(seq_length=seq_length))  # Optional argument.
encoder_inputs = bert_pack_inputs([tokenized_premises, tokenized_hypotheses])

tokenize ayrıntıları

preprocessor.tokenize() çağrısı [batch_size] şeklinde bir Tensör dizesini kabul eder ve değerleri giriş dizelerini temsil eden int32 belirteç kimlikleri olan [batch_size, ...] şeklinde bir RaggedTensor döndürür. batch_size sonra r ≥ 1 düzensiz boyut olabilir ancak başka tek biçimli boyut olamaz.

  • r =1 ise, şekil [batch_size, (tokens)] olur ve her giriş basitçe düz bir jeton dizisi halinde jetonlaştırılır.
  • Eğer r >1 ise, r -1 ek gruplama seviyesi vardır. Örneğin, tensorflow_text.BertTokenizer, belirteçleri sözcüklere göre gruplandırmak için r =2'yi kullanır ve şekil [batch_size, (words), (tokens_per_word)] sonucunu verir. Bu ekstra düzey(ler)den kaçının mevcut olduğu ve bunların hangi gruplandırmaları temsil ettiği, eldeki modele bağlıdır.

Kullanıcı, örneğin kodlayıcı girişlerinin paketlenmesinde uygulanacak seq_length sınırına uyum sağlamak için tokenleştirilmiş girişleri değiştirebilir (ancak buna gerek yoktur). Belirteçleyici çıktısındaki ekstra boyutlar burada yardımcı olabilir (örneğin sözcük sınırlarına saygı göstermek) ancak bir sonraki adımda anlamsız hale gelebilir.

Yeniden Kullanılabilir SavedModel API açısından, preprocessor.tokenize nesnesi .variables sahip olabilir ancak daha fazla eğitilmesi amaçlanmamıştır. Tokenizasyon moda bağlı değildir: eğer preprocessor.tokenize() bir training=... argümanı varsa, hiçbir etkisi olmaz.

bert_pack_inputs ayrıntıları

preprocessor.bert_pack_inputs() çağrısı, simgeleştirilmiş girişlerin Python listesini kabul eder (her giriş bölümü için ayrı ayrı gruplandırılmıştır) ve Transformer kodlayıcı modeli için sabit uzunluklu giriş dizilerinin bir grubunu temsil eden Tensörlerin bir diktesini döndürür.

Her simgeleştirilmiş giriş [batch_size, ...] şeklinde bir int32 RaggedTensor'dur; burada, toplu_size'den sonraki düzensiz boyutların sayısı r ya 1'dir ya da preprocessor.tokenize(). (İkincisi yalnızca kolaylık sağlamak içindir; ekstra boyutlar paketlemeden önce düzleştirilir.)

Paketleme, kodlayıcının beklediği gibi giriş bölümlerinin etrafına özel belirteçler ekler. bert_pack_inputs() çağrısı, orijinal BERT modelleri ve bunların birçok uzantısı tarafından kullanılan paketleme şemasını tam olarak uygular: paketlenmiş dizi, bir dizi başlangıcı belirteci ile başlar, ardından her biri bir bölüm sonu ile sonlandırılan simgeleştirilmiş bölümler gelir. belirteç. Varsa seq_length'e kadar kalan pozisyonlar dolgu jetonlarıyla doldurulur.

Paketlenmiş bir dizi sıra_uzunluğunu aşarsa, bert_pack_inputs() paketli dizinin tam olarak sıra_uzunluğuna uyması için parçalarını yaklaşık olarak eşit boyutlardaki öneklere kısaltır.

Paketleme moda bağlı değildir: eğer preprocessor.bert_pack_inputs() un bir training=... argümanı varsa, hiçbir etkisi yoktur. Ayrıca preprocessor.bert_pack_inputs değişkenlere sahip olması veya ince ayarı desteklemesi beklenmemektedir.

Kodlayıcı

Kodlayıcı, Reusable SavedModel API'sindeki hükümler de dahil olmak üzere, önceden işlenmiş girişlerle (yukarıya bakın) metin yerleştirmeler için API'de olduğu gibi, encoder_inputs diktesiyle çağrılır.

Kullanım özeti

encoder = hub.load("path/to/encoder")
encoder_outputs = encoder(encoder_inputs)

veya eşdeğer olarak Keras'ta:

encoder = hub.KerasLayer("path/to/encoder", trainable=True)
encoder_outputs = encoder(encoder_inputs)

Detaylar

encoder_outputs aşağıdaki tuşlara sahip Tensörlerin bir diktesidir.

  • "sequence_output" : paketlenmiş her giriş dizisinin her bir jetonunun bağlama duyarlı yerleştirilmesiyle [batch_size, seq_length, dim] şeklinde bir float32 Tensörü.
  • "pooled_output" : eğitilebilir bir şekilde dizi_çıkışından türetilen, her giriş dizisinin bir bütün olarak gömüldüğü [batch_size, dim] şeklindeki bir float32 Tensörü.
  • "default" , API'nin önceden işlenmiş girişlerle metin yerleştirmeleri için gerektirdiği şekilde: her giriş sırasının gömülmesiyle birlikte [batch_size, dim] şeklinde bir float32 Tensörü. (Bu yalnızcapooled_output'un takma adı olabilir.)

encoder_inputs içeriği bu API tanımı tarafından kesinlikle gerekli değildir. Bununla birlikte, BERT tarzı girişler kullanan kodlayıcılar için, kodlayıcıların değiştirilmesinde ve ön işlemci modellerinin yeniden kullanılmasında sürtünmeyi en aza indirmek amacıyla aşağıdaki adların ( TensorFlow Model Garden'ın NLP Modelleme Araç Takımından ) kullanılması önerilir:

  • "input_word_ids" : paketlenmiş giriş dizisinin belirteç kimliklerine sahip (yani, bir dizi başlangıcı belirteci, bölüm sonu belirteçleri ve dolgu dahil) [batch_size, seq_length] şeklinde bir int32 Tensörü.
  • "input_mask" : doldurmadan önce mevcut tüm giriş belirteçlerinin konumunda 1 değeri ve doldurma belirteçleri için 0 değeri olan [batch_size, seq_length] şeklinde bir int32 Tensörü.
  • "input_type_ids" : ilgili konumda giriş jetonunun oluşmasına neden olan giriş segmentinin indeksini içeren [batch_size, seq_length] şeklindeki bir int32 Tensörü. İlk girdi segmenti (indeks 0), dizi başlangıcı jetonunu ve segment sonu jetonunu içerir. İkinci ve daha sonraki bölümler (varsa), ilgili bölüm sonu belirtecini içerir. Dolgu jetonları tekrar 0 indeksini alır.

Dağıtılmış eğitim

Ön işlemci ve kodlayıcı nesnelerini bir dağıtım stratejisi kapsamının içine veya dışına yüklemek için, önceden işlenmiş girişlerle metin yerleştirmeler için API'dekiyle aynı kurallar geçerlidir (yukarıya bakın).

Örnekler