NbAiLabArchive/test_w5_long_dataset
083
1#!/usr/bin/env python2# coding=utf-83# Copyright 2021 The HuggingFace Team All rights reserved.4#5# Licensed under the Apache License, Version 2.0 (the "License");6# you may not use this file except in compliance with the License.7# You may obtain a copy of the License at8#9# http://www.apache.org/licenses/LICENSE-2.010#11# Unless required by applicable law or agreed to in writing, software12# distributed under the License is distributed on an "AS IS" BASIS,13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.14# See the License for the specific language governing permissions and15# limitations under the License.16"""17Fine-tuning the library models for masked language modeling (BERT, ALBERT, RoBERTa...) with whole word masking on a18text file or a dataset.19 20Here is the full list of checkpoints on the hub that can be fine-tuned by this script:21https://huggingface.co/models?filter=masked-lm22"""23import logging24import os25import sys26import time27from dataclasses import dataclass, field28 29# You can also adapt this script on your own masked language modeling task. Pointers for this are left as comments.30from pathlib import Path31from typing import Dict, List, Optional, Tuple32 33import numpy as np34from datasets import load_dataset35from tqdm import tqdm36 37import flax38import jax39import jax.numpy as jnp40import optax41from flax import jax_utils, traverse_util42from flax.training import train_state43from flax.training.common_utils import get_metrics, onehot, shard44from transformers import (45 CONFIG_MAPPING,46 FLAX_MODEL_FOR_MASKED_LM_MAPPING,47 AutoConfig,48 AutoTokenizer,49 FlaxAutoModelForMaskedLM,50 HfArgumentParser,51 PreTrainedTokenizerBase,52 TensorType,53 TrainingArguments,54 is_tensorboard_available,55 set_seed,56)57 58 59MODEL_CONFIG_CLASSES = list(FLAX_MODEL_FOR_MASKED_LM_MAPPING.keys())60MODEL_TYPES = tuple(conf.model_type for conf in MODEL_CONFIG_CLASSES)61 62 63@dataclass64class ModelArguments:65 """66 Arguments pertaining to which model/config/tokenizer we are going to fine-tune, or train from scratch.67 """68 69 model_name_or_path: Optional[str] = field(70 default=None,71 metadata={72 "help": "The model checkpoint for weights initialization."73 "Don't set if you want to train a model from scratch."74 },75 )76 model_type: Optional[str] = field(77 default=None,78 metadata={"help": "If training from scratch, pass a model type from the list: " + ", ".join(MODEL_TYPES)},79 )80 config_name: Optional[str] = field(81 default=None, metadata={"help": "Pretrained config name or path if not the same as model_name"}82 )83 tokenizer_name: Optional[str] = field(84 default=None, metadata={"help": "Pretrained tokenizer name or path if not the same as model_name"}85 )86 cache_dir: Optional[str] = field(87 default=None, metadata={"help": "Where do you want to store the pretrained models downloaded from s3"}88 )89 use_fast_tokenizer: bool = field(90 default=True,91 metadata={"help": "Whether to use one of the fast tokenizer (backed by the tokenizers library) or not."},92 )93 dtype: Optional[str] = field(94 default="float32",95 metadata={96 "help": "Floating-point format in which the model weights should be initialized and trained. Choose one of `[float32, float16, bfloat16]`."97 },98 )99 100 101@dataclass102class DataTrainingArguments:103 """104 Arguments pertaining to what data we are going to input our model for training and eval.105 """106 107 dataset_name: Optional[str] = field(108 default=None, metadata={"help": "The name of the dataset to use (via the datasets library)."}109 )110 dataset_config_name: Optional[str] = field(111 default=None, metadata={"help": "The configuration name of the dataset to use (via the datasets library)."}112 )113 train_file: Optional[str] = field(default=None, metadata={"help": "The input training data file (a text file)."})114 validation_file: Optional[str] = field(115 default=None,116 metadata={"help": "An optional input evaluation data file to evaluate the perplexity on (a text file)."},117 )118 train_ref_file: Optional[str] = field(119 default=None,120 metadata={"help": "An optional input train ref data file for whole word masking in Chinese."},121 )122 validation_ref_file: Optional[str] = field(123 default=None,124 metadata={"help": "An optional input validation ref data file for whole word masking in Chinese."},125 )126 overwrite_cache: bool = field(127 default=False, metadata={"help": "Overwrite the cached training and evaluation sets"}128 )129 validation_split_percentage: Optional[int] = field(130 default=5,131 metadata={132 "help": "The percentage of the train set used as validation set in case there's no validation split"133 },134 )135 max_seq_length: Optional[int] = field(136 default=None,137 metadata={138 "help": "The maximum total input sequence length after tokenization. Sequences longer "139 "than this will be truncated. Default to the max input length of the model."140 },141 )142 preprocessing_num_workers: Optional[int] = field(143 default=None,144 metadata={"help": "The number of processes to use for the preprocessing."},145 )146 mlm_probability: float = field(147 default=0.15, metadata={"help": "Ratio of tokens to mask for masked language modeling loss"}148 )149 pad_to_max_length: bool = field(150 default=False,151 metadata={152 "help": "Whether to pad all samples to `max_seq_length`. "153 "If False, will pad the samples dynamically when batching to the maximum length in the batch."154 },155 )156 line_by_line: bool = field(157 default=False,158 metadata={"help": "Whether distinct lines of text in the dataset are to be handled as distinct sequences."},159 )160 161 def __post_init__(self):162 if self.dataset_name is None and self.train_file is None and self.validation_file is None:163 raise ValueError("Need either a dataset name or a training/validation file.")164 else:165 if self.train_file is not None:166 extension = self.train_file.split(".")[-1]167 assert extension in ["csv", "json", "txt"], "`train_file` should be a csv, a json or a txt file."168 if self.validation_file is not None:169 extension = self.validation_file.split(".")[-1]170 assert extension in ["csv", "json", "txt"], "`validation_file` should be a csv, a json or a txt file."171 172 173@flax.struct.dataclass174class FlaxDataCollatorForLanguageModeling:175 """176 Data collator used for language modeling. Inputs are dynamically padded to the maximum length of a batch if they177 are not all of the same length.178 179 Args:180 tokenizer (:class:`~transformers.PreTrainedTokenizer` or :class:`~transformers.PreTrainedTokenizerFast`):181 The tokenizer used for encoding the data.182 mlm_probability (:obj:`float`, `optional`, defaults to 0.15):183 The probability with which to (randomly) mask tokens in the input.184 185 .. note::186 187 For best performance, this data collator should be used with a dataset having items that are dictionaries or188 BatchEncoding, with the :obj:`"special_tokens_mask"` key, as returned by a189 :class:`~transformers.PreTrainedTokenizer` or a :class:`~transformers.PreTrainedTokenizerFast` with the190 argument :obj:`return_special_tokens_mask=True`.191 """192 193 tokenizer: PreTrainedTokenizerBase194 mlm_probability: float = 0.15195 196 def __post_init__(self):197 if self.tokenizer.mask_token is None:198 raise ValueError(199 "This tokenizer does not have a mask token which is necessary for masked language modeling. "200 "You should pass `mlm=False` to train on causal language modeling instead."201 )202 203 def __call__(self, examples: List[Dict[str, np.ndarray]], pad_to_multiple_of: int) -> Dict[str, np.ndarray]:204 # Handle dict or lists with proper padding and conversion to tensor.205 batch = self.tokenizer.pad(examples, pad_to_multiple_of=pad_to_multiple_of, return_tensors=TensorType.NUMPY)206 207 # If special token mask has been preprocessed, pop it from the dict.208 special_tokens_mask = batch.pop("special_tokens_mask", None)209 210 batch["input_ids"], batch["labels"] = self.mask_tokens(211 batch["input_ids"], special_tokens_mask=special_tokens_mask212 )213 return batch214 215 def mask_tokens(216 self, inputs: np.ndarray, special_tokens_mask: Optional[np.ndarray]217 ) -> Tuple[jnp.ndarray, jnp.ndarray]:218 """219 Prepare masked tokens inputs/labels for masked language modeling: 80% MASK, 10% random, 10% original.220 """221 labels = inputs.copy()222 # We sample a few tokens in each sequence for MLM training (with probability `self.mlm_probability`)223 probability_matrix = np.full(labels.shape, self.mlm_probability)224 special_tokens_mask = special_tokens_mask.astype("bool")225 226 probability_matrix[special_tokens_mask] = 0.0227 masked_indices = np.random.binomial(1, probability_matrix).astype("bool")228 labels[~masked_indices] = -100 # We only compute loss on masked tokens229 230 # 80% of the time, we replace masked input tokens with tokenizer.mask_token ([MASK])231 indices_replaced = np.random.binomial(1, np.full(labels.shape, 0.8)).astype("bool") & masked_indices232 inputs[indices_replaced] = self.tokenizer.convert_tokens_to_ids(self.tokenizer.mask_token)233 234 # 10% of the time, we replace masked input tokens with random word235 indices_random = np.random.binomial(1, np.full(labels.shape, 0.5)).astype("bool")236 indices_random &= masked_indices & ~indices_replaced237 238 random_words = np.random.randint(self.tokenizer.vocab_size, size=labels.shape, dtype="i4")239 inputs[indices_random] = random_words[indices_random]240 241 # The rest of the time (10% of the time) we keep the masked input tokens unchanged242 return inputs, labels243 244 245def generate_batch_splits(samples_idx: jnp.ndarray, batch_size: int) -> jnp.ndarray:246 num_samples = len(samples_idx)247 samples_to_remove = num_samples % batch_size248 249 if samples_to_remove != 0:250 samples_idx = samples_idx[:-samples_to_remove]251 sections_split = num_samples // batch_size252 batch_idx = np.split(samples_idx, sections_split)253 return batch_idx254 255 256def write_train_metric(summary_writer, train_metrics, train_time, step):257 summary_writer.scalar("train_time", train_time, step)258 259 train_metrics = get_metrics(train_metrics)260 for key, vals in train_metrics.items():261 tag = f"train_{key}"262 for i, val in enumerate(vals):263 summary_writer.scalar(tag, val, step - len(vals) + i + 1)264 265 266def write_eval_metric(summary_writer, eval_metrics, step):267 for metric_name, value in eval_metrics.items():268 summary_writer.scalar(f"eval_{metric_name}", value, step)269 270 271if __name__ == "__main__":272 # See all possible arguments in src/transformers/training_args.py273 # or by passing the --help flag to this script.274 # We now keep distinct sets of args, for a cleaner separation of concerns.275 276 parser = HfArgumentParser((ModelArguments, DataTrainingArguments, TrainingArguments))277 if len(sys.argv) == 2 and sys.argv[1].endswith(".json"):278 # If we pass only one argument to the script and it's the path to a json file,279 # let's parse it to get our arguments.280 model_args, data_args, training_args = parser.parse_json_file(json_file=os.path.abspath(sys.argv[1]))281 else:282 model_args, data_args, training_args = parser.parse_args_into_dataclasses()283 284 if (285 os.path.exists(training_args.output_dir)286 and os.listdir(training_args.output_dir)287 and training_args.do_train288 and not training_args.overwrite_output_dir289 ):290 raise ValueError(291 f"Output directory ({training_args.output_dir}) already exists and is not empty."292 "Use --overwrite_output_dir to overcome."293 )294 295 # Setup logging296 logging.basicConfig(297 format="%(asctime)s - %(levelname)s - %(name)s - %(message)s",298 level="NOTSET",299 datefmt="[%X]",300 )301 302 # Log on each process the small summary:303 logger = logging.getLogger(__name__)304 305 # Set the verbosity to info of the Transformers logger (on main process only):306 logger.info(f"Training/evaluation parameters {training_args}")307 308 # Set seed before initializing model.309 set_seed(training_args.seed)310 311 # Get the datasets: you can either provide your own CSV/JSON/TXT training and evaluation files (see below)312 # or just provide the name of one of the public datasets available on the hub at https://huggingface.co/datasets/313 # (the dataset will be downloaded automatically from the datasets Hub).314 #315 # For CSV/JSON files, this script will use the column called 'text' or the first column if no column called316 # 'text' is found. You can easily tweak this behavior (see below).317 #318 # In distributed training, the load_dataset function guarantees that only one local process can concurrently319 # download the dataset.320 if data_args.dataset_name is not None:321 # Downloading and loading a dataset from the hub.322 datasets = load_dataset(data_args.dataset_name, data_args.dataset_config_name, cache_dir=model_args.cache_dir)323 324 if "validation" not in datasets.keys():325 datasets["validation"] = load_dataset(326 data_args.dataset_name,327 data_args.dataset_config_name,328 split=f"train[:{data_args.validation_split_percentage}%]",329 cache_dir=model_args.cache_dir,330 )331 datasets["train"] = load_dataset(332 data_args.dataset_name,333 data_args.dataset_config_name,334 split=f"train[{data_args.validation_split_percentage}%:]",335 cache_dir=model_args.cache_dir,336 )337 else:338 data_files = {}339 if data_args.train_file is not None:340 data_files["train"] = data_args.train_file341 if data_args.validation_file is not None:342 data_files["validation"] = data_args.validation_file343 extension = data_args.train_file.split(".")[-1]344 if extension == "txt":345 extension = "text"346 datasets = load_dataset(extension, data_files=data_files, cache_dir=model_args.cache_dir)347 # See more about loading any type of standard or custom dataset (from files, python dict, pandas DataFrame, etc) at348 # https://huggingface.co/docs/datasets/loading_datasets.html.349 350 # Load pretrained model and tokenizer351 352 # Distributed training:353 # The .from_pretrained methods guarantee that only one local process can concurrently354 # download model & vocab.355 if model_args.config_name:356 config = AutoConfig.from_pretrained(model_args.config_name, cache_dir=model_args.cache_dir)357 elif model_args.model_name_or_path:358 config = AutoConfig.from_pretrained(model_args.model_name_or_path, cache_dir=model_args.cache_dir)359 else:360 config = CONFIG_MAPPING[model_args.model_type]()361 logger.warning("You are instantiating a new config instance from scratch.")362 363 if model_args.tokenizer_name:364 tokenizer = AutoTokenizer.from_pretrained(365 model_args.tokenizer_name, cache_dir=model_args.cache_dir, use_fast=model_args.use_fast_tokenizer366 )367 elif model_args.model_name_or_path:368 tokenizer = AutoTokenizer.from_pretrained(369 model_args.model_name_or_path, cache_dir=model_args.cache_dir, use_fast=model_args.use_fast_tokenizer370 )371 else:372 raise ValueError(373 "You are instantiating a new tokenizer from scratch. This is not supported by this script."374 "You can do it from another script, save it, and load it from here, using --tokenizer_name."375 )376 377 # Preprocessing the datasets.378 # First we tokenize all the texts.379 if training_args.do_train:380 column_names = datasets["train"].column_names381 else:382 column_names = datasets["validation"].column_names383 text_column_name = "text" if "text" in column_names else column_names[0]384 385 max_seq_length = min(data_args.max_seq_length, tokenizer.model_max_length)386 387 if data_args.line_by_line:388 # When using line_by_line, we just tokenize each nonempty line.389 padding = "max_length" if data_args.pad_to_max_length else False390 391 def tokenize_function(examples):392 # Remove empty lines393 examples = [line for line in examples if len(line) > 0 and not line.isspace()]394 return tokenizer(395 examples,396 return_special_tokens_mask=True,397 padding=padding,398 truncation=True,399 max_length=max_seq_length,400 )401 402 tokenized_datasets = datasets.map(403 tokenize_function,404 input_columns=[text_column_name],405 batched=True,406 num_proc=data_args.preprocessing_num_workers,407 remove_columns=column_names,408 load_from_cache_file=not data_args.overwrite_cache,409 )410 411 else:412 # Otherwise, we tokenize every text, then concatenate them together before splitting them in smaller parts.413 # We use `return_special_tokens_mask=True` because DataCollatorForLanguageModeling (see below) is more414 # efficient when it receives the `special_tokens_mask`.415 def tokenize_function(examples):416 return tokenizer(examples[text_column_name], return_special_tokens_mask=True)417 418 tokenized_datasets = datasets.map(419 tokenize_function,420 batched=True,421 num_proc=data_args.preprocessing_num_workers,422 remove_columns=column_names,423 load_from_cache_file=not data_args.overwrite_cache,424 )425 426 # Main data processing function that will concatenate all texts from our dataset and generate chunks of427 # max_seq_length.428 def group_texts(examples):429 # Concatenate all texts.430 concatenated_examples = {k: sum(examples[k], []) for k in examples.keys()}431 total_length = len(concatenated_examples[list(examples.keys())[0]])432 # We drop the small remainder, we could add padding if the model supported it instead of this drop, you can433 # customize this part to your needs.434 if total_length >= max_seq_length:435 total_length = (total_length // max_seq_length) * max_seq_length436 # Split by chunks of max_len.437 result = {438 k: [t[i : i + max_seq_length] for i in range(0, total_length, max_seq_length)]439 for k, t in concatenated_examples.items()440 }441 return result442 443 # Note that with `batched=True`, this map processes 1,000 texts together, so group_texts throws away a444 # remainder for each of those groups of 1,000 texts. You can adjust that batch_size here but a higher value445 # might be slower to preprocess.446 #447 # To speed up this part, we use multiprocessing. See the documentation of the map method for more information:448 # https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map449 tokenized_datasets = tokenized_datasets.map(450 group_texts,451 batched=True,452 num_proc=data_args.preprocessing_num_workers,453 load_from_cache_file=not data_args.overwrite_cache,454 )455 456 # Enable tensorboard only on the master node457 has_tensorboard = is_tensorboard_available()458 if has_tensorboard and jax.process_index() == 0:459 try:460 from flax.metrics.tensorboard import SummaryWriter461 462 summary_writer = SummaryWriter(log_dir=Path(training_args.output_dir))463 except ImportError as ie:464 has_tensorboard = False465 logger.warning(466 f"Unable to display metrics through TensorBoard because some package are not installed: {ie}"467 )468 else:469 logger.warning(470 "Unable to display metrics through TensorBoard because the package is not installed: "471 "Please run pip install tensorboard to enable."472 )473 474 # Data collator475 # This one will take care of randomly masking the tokens.476 data_collator = FlaxDataCollatorForLanguageModeling(tokenizer=tokenizer, mlm_probability=data_args.mlm_probability)477 478 # Initialize our training479 rng = jax.random.PRNGKey(training_args.seed)480 dropout_rngs = jax.random.split(rng, jax.local_device_count())481 482 if model_args.model_name_or_path:483 model = FlaxAutoModelForMaskedLM.from_pretrained(484 model_args.model_name_or_path, config=config, seed=training_args.seed, dtype=getattr(jnp, model_args.dtype)485 )486 else:487 model = FlaxAutoModelForMaskedLM.from_config(488 config, seed=training_args.seed, dtype=getattr(jnp, model_args.dtype)489 )490 491 # Store some constant492 num_epochs = int(training_args.num_train_epochs)493 train_batch_size = int(training_args.per_device_train_batch_size) * jax.device_count()494 eval_batch_size = int(training_args.per_device_eval_batch_size) * jax.device_count()495 496 num_train_steps = len(tokenized_datasets["train"]) // train_batch_size * num_epochs497 498 # Create learning rate schedule499 warmup_fn = optax.linear_schedule(500 init_value=0.0, end_value=training_args.learning_rate, transition_steps=training_args.warmup_steps501 )502 decay_fn = optax.linear_schedule(503 init_value=training_args.learning_rate,504 end_value=0,505 transition_steps=num_train_steps - training_args.warmup_steps,506 )507 linear_decay_lr_schedule_fn = optax.join_schedules(508 schedules=[warmup_fn, decay_fn], boundaries=[training_args.warmup_steps]509 )510 511 # We use Optax's "masking" functionality to not apply weight decay512 # to bias and LayerNorm scale parameters. decay_mask_fn returns a513 # mask boolean with the same structure as the parameters.514 # The mask is True for parameters that should be decayed.515 # Note that this mask is specifically adapted for FlaxBERT-like models.516 # For other models, one should correct the layer norm parameter naming517 # accordingly.518 def decay_mask_fn(params):519 flat_params = traverse_util.flatten_dict(params)520 flat_mask = {path: (path[-1] != "bias" and path[-2:] != ("LayerNorm", "scale")) for path in flat_params}521 return traverse_util.unflatten_dict(flat_mask)522 523 # create adam optimizer524 if training_args.adafactor:525 # We use the default parameters here to initialize adafactor,526 # For more details about the parameters please check https://github.com/deepmind/optax/blob/ed02befef9bf81cbbf236be3d2b0e032e9ed4a40/optax/_src/alias.py#L74527 optimizer = optax.adafactor(528 learning_rate=linear_decay_lr_schedule_fn,529 )530 else:531 optimizer = optax.adamw(532 learning_rate=linear_decay_lr_schedule_fn,533 b1=training_args.adam_beta1,534 b2=training_args.adam_beta2,535 eps=training_args.adam_epsilon,536 weight_decay=training_args.weight_decay,537 mask=decay_mask_fn,538 )539 540 # Setup train state541 state = train_state.TrainState.create(apply_fn=model.__call__, params=model.params, tx=optimizer)542 543 # Define gradient update step fn544 def train_step(state, batch, dropout_rng):545 dropout_rng, new_dropout_rng = jax.random.split(dropout_rng)546 547 def loss_fn(params):548 labels = batch.pop("labels")549 550 logits = state.apply_fn(**batch, params=params, dropout_rng=dropout_rng, train=True)[0]551 552 # compute loss, ignore padded input tokens553 label_mask = jnp.where(labels > 0, 1.0, 0.0)554 loss = optax.softmax_cross_entropy(logits, onehot(labels, logits.shape[-1])) * label_mask555 556 # take average557 loss = loss.sum() / label_mask.sum()558 559 return loss560 561 grad_fn = jax.value_and_grad(loss_fn)562 loss, grad = grad_fn(state.params)563 grad = jax.lax.pmean(grad, "batch")564 new_state = state.apply_gradients(grads=grad)565 566 metrics = jax.lax.pmean(567 {"loss": loss, "learning_rate": linear_decay_lr_schedule_fn(state.step)}, axis_name="batch"568 )569 570 return new_state, metrics, new_dropout_rng571 572 # Create parallel version of the train step573 p_train_step = jax.pmap(train_step, "batch", donate_argnums=(0,))574 575 # Define eval fn576 def eval_step(params, batch):577 labels = batch.pop("labels")578 579 logits = model(**batch, params=params, train=False)[0]580 581 # compute loss, ignore padded input tokens582 label_mask = jnp.where(labels > 0, 1.0, 0.0)583 loss = optax.softmax_cross_entropy(logits, onehot(labels, logits.shape[-1])) * label_mask584 585 # compute accuracy586 accuracy = jnp.equal(jnp.argmax(logits, axis=-1), labels) * label_mask587 588 # summarize metrics589 metrics = {"loss": loss.sum(), "accuracy": accuracy.sum(), "normalizer": label_mask.sum()}590 metrics = jax.lax.psum(metrics, axis_name="batch")591 592 return metrics593 594 p_eval_step = jax.pmap(eval_step, "batch", donate_argnums=(0,))595 596 # Replicate the train state on each device597 state = jax_utils.replicate(state)598 599 train_time = 0600 epochs = tqdm(range(num_epochs), desc=f"Epoch ... (1/{num_epochs})", position=0)601 for epoch in epochs:602 # ======================== Training ================================603 train_start = time.time()604 train_metrics = []605 606 # Create sampling rng607 rng, input_rng = jax.random.split(rng)608 609 # Generate an epoch by shuffling sampling indices from the train dataset610 num_train_samples = len(tokenized_datasets["train"])611 train_samples_idx = jax.random.permutation(input_rng, jnp.arange(num_train_samples))612 train_batch_idx = generate_batch_splits(train_samples_idx, train_batch_size)613 614 # Gather the indexes for creating the batch and do a training step615 for step, batch_idx in enumerate(tqdm(train_batch_idx, desc="Training...", position=1)):616 samples = [tokenized_datasets["train"][int(idx)] for idx in batch_idx]617 model_inputs = data_collator(samples, pad_to_multiple_of=16)618 619 # Model forward620 model_inputs = shard(model_inputs.data)621 state, train_metric, dropout_rngs = p_train_step(state, model_inputs, dropout_rngs)622 train_metrics.append(train_metric)623 624 cur_step = epoch * (num_train_samples // train_batch_size) + step625 626 if cur_step % training_args.logging_steps == 0 and cur_step > 0:627 # Save metrics628 train_metric = jax_utils.unreplicate(train_metric)629 train_time += time.time() - train_start630 if has_tensorboard and jax.process_index() == 0:631 write_train_metric(summary_writer, train_metrics, train_time, cur_step)632 633 epochs.write(634 f"Step... ({cur_step} | Loss: {train_metric['loss']}, Learning Rate: {train_metric['learning_rate']})"635 )636 637 train_metrics = []638 639 if cur_step % training_args.eval_steps == 0 and cur_step > 0:640 # ======================== Evaluating ==============================641 num_eval_samples = len(tokenized_datasets["validation"])642 eval_samples_idx = jnp.arange(num_eval_samples)643 eval_batch_idx = generate_batch_splits(eval_samples_idx, eval_batch_size)644 645 eval_metrics = []646 for i, batch_idx in enumerate(tqdm(eval_batch_idx, desc="Evaluating ...", position=2)):647 samples = [tokenized_datasets["validation"][int(idx)] for idx in batch_idx]648 model_inputs = data_collator(samples, pad_to_multiple_of=16)649 650 # Model forward651 model_inputs = shard(model_inputs.data)652 metrics = p_eval_step(state.params, model_inputs)653 eval_metrics.append(metrics)654 655 # normalize eval metrics656 eval_metrics = get_metrics(eval_metrics)657 eval_metrics = jax.tree_map(jnp.sum, eval_metrics)658 eval_normalizer = eval_metrics.pop("normalizer")659 eval_metrics = jax.tree_map(lambda x: x / eval_normalizer, eval_metrics)660 661 # Update progress bar662 epochs.desc = f"Step... ({cur_step} | Loss: {eval_metrics['loss']}, Acc: {eval_metrics['accuracy']})"663 664 # Save metrics665 if has_tensorboard and jax.process_index() == 0:666 write_eval_metric(summary_writer, eval_metrics, cur_step)667 668 if cur_step % training_args.save_steps == 0 and cur_step > 0:669 # save checkpoint after each epoch and push checkpoint to the hub670 if jax.process_index() == 0:671 params = jax.device_get(jax.tree_map(lambda x: x[0], state.params))672 model.save_pretrained(673 training_args.output_dir,674 params=params,675 push_to_hub=training_args.push_to_hub,676 commit_message=f"Saving weights and logs of step {cur_step}",677 )678 