# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved. # Copyright 2021 The HuggingFace Inc. team. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import paddle from paddlenlp.data import Dict, Pad class DataCollatorMLM: def __init__(self, tokenizer, batch_pad=None): self.batch_pad = batch_pad self.mask_token_id = tokenizer.mask_token_id self.pad_token_id = tokenizer.pad_token_id self.token_len = tokenizer.vocab_size if batch_pad is None: self.batch_pad = lambda samples, fn=Dict( { "input_ids": Pad(axis=0, pad_val=self.pad_token_id, dtype="int64"), # input # 'token_type_ids': Pad(axis=0, pad_val=0, dtype='int64'), # segment "special_tokens_mask": Pad(axis=0, pad_val=True, dtype="int64"), # segment } ): fn(samples) else: self.batch_pad = batch_pad def __call__(self, examples): examples = self.batch_pad(examples) examples = [paddle.to_tensor(e) for e in examples] examples[0], labels = self._mask_tokens( examples[0], paddle.cast(examples[1], dtype=bool), self.mask_token_id, self.token_len ) examples.append(labels) return examples def _mask_tokens(self, inputs, special_tokens_mask, mask_token_id, token_len, mlm_prob=0.15, ignore_label=-100): """ Prepare masked tokens inputs/labels for masked language modeling: 80% MASK, 10% random, 10% original. """ labels = inputs.clone() probability_matrix = paddle.full(labels.shape, mlm_prob) probability_matrix[special_tokens_mask] = 0 masked_indices = paddle.cast(paddle.bernoulli(probability_matrix), dtype=bool) labels[~masked_indices] = ignore_label # We only compute loss on masked tokens # 80% of the time, we replace masked input tokens with tokenizer.mask_token ([MASK]) indices_replaced = paddle.cast(paddle.bernoulli(paddle.full(labels.shape, 0.8)), dtype=bool) & masked_indices inputs[indices_replaced] = mask_token_id # 10% of the time, we replace masked input tokens with random word indices_random = ( paddle.cast(paddle.bernoulli(paddle.full(labels.shape, 0.5)), dtype=bool) & masked_indices & ~indices_replaced ) random_words = paddle.randint(low=0, high=token_len, shape=labels.shape) inputs[indices_random] = random_words[indices_random] # The rest of the time (10% of the time) we keep the masked input tokens unchanged return inputs, labels