web-dev-qa-db-ja.com

huggingfaceトークナイザーによるテキストデータのマッピング

次のようなエンコード関数があります。

from transformers import BertTokenizer, BertModel

MODEL = 'bert-base-multilingual-uncased'
tokenizer = BertTokenizer.from_pretrained(MODEL)

def encode(texts, tokenizer=tokenizer, maxlen=10):
#     import pdb; pdb.set_trace()
    inputs = tokenizer.encode_plus(
        texts,
        return_tensors='tf',
        return_attention_masks=True, 
        return_token_type_ids=True,
        pad_to_max_length=True,
        max_length=maxlen
    )

    return inputs['input_ids'], inputs["token_type_ids"], inputs["attention_mask"]

これを実行して、オンザフライでデータをエンコードしたい:

x_train = (tf.data.Dataset.from_tensor_slices(df_train.comment_text.astype(str).values)
           .map(encode))

ただし、これによりエラーが解消されます。

ValueError: Input is not valid. Should be a string, a list/Tuple of strings or a list/Tuple of integers.

encode内にブレークポイントを設定したときの私の理解から、それは非numpy配列を送信していたためでした。入力としてテンソルフロー文字列を使用してhuggingfaceトランスフォーマーでニースを再生するにはどうすればよいですか?

ここにダミーのデータフレームが必要な場合は、次のとおりです。

df_train = pd.DataFrame({'comment_text': ['Today was a good day']*5})

私が試したこと

そこで、from_generatorを使用して、encode_plus関数への文字列を解析できるようにしました。ただし、これはTPUでは機能しません。

AUTO = tf.data.experimental.AUTOTUNE

def get_gen(df):
    def gen():
        for i in range(len(df)):
            yield encode(df.loc[i, 'comment_text']) , df.loc[i, 'toxic']
    return gen

shapes = ((tf.TensorShape([maxlen]), tf.TensorShape([maxlen]), tf.TensorShape([maxlen])), tf.TensorShape([]))

train_dataset = tf.data.Dataset.from_generator(
    get_gen(df_train),
    ((tf.int32, tf.int32, tf.int32), tf.int32),
    shapes
)
train_dataset = train_dataset.batch(BATCH_SIZE).prefetch(AUTO)

バージョン情報:

transformers.__version__, tf.__version__ => ('2.7.0', '2.1.0')

2
sachinruk

bertのトークナイザーは、文字列、文字列のリスト/タプル、または整数のリスト/タプルで機能します。したがって、データが文字列に変換されているかどうかを確認してください。データセット全体にトークナイザーを適用するには、Dataset.mapを使用しましたが、これはグラフモードで実行されます。それで、それをtf.py_functionでラップする必要があります。 tf.py_functionは通常のテンソルを(値とそれにアクセスするための.numpy()メソッドを使用して)ラップしたpython関数に渡します。バイトを文字列に変換するためにtf.compat.as_strを適用しました。

tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
def encode(lang1, lang2):
    lang1 = tokenizer.encode(tf.compat.as_str(lang1.numpy()), add_special_tokens=True)
    lang2 = tokenizer.encode(tf.compat.as_str(lang2.numpy()), add_special_tokens=True)
    return lang1, lang2
def tf_encode(pt, en):
    result_pt, result_en = tf.py_function(func = encode, inp = [pt, en], Tout=[tf.int64, tf.int64])
    result_pt.set_shape([None])
    result_en.set_shape([None])
    return result_pt, result_en
train_dataset = dataset3.map(tf_encode)
BUFFER_SIZE = 200
BATCH_SIZE = 64

train_dataset = train_dataset.shuffle(BUFFER_SIZE).padded_batch(BATCH_SIZE, 
                                                           padded_shapes=(60, 60))
a,p = next(iter(train_dataset))
0