实习笔记5-transformer的language modeling解析-3(run_clm结束)

目的是在标记化的过程中监控可能的问题,特别是针对输入文本长度的问题。通过记录警告,可以更好地了解标记化过程中可能发生的问题,并在必要时采取适当的措施,例如将长输入文本分块。

    """
    目的是在标记化的过程中监控可能的问题,特别是针对输入文本长度的问题。通过记录警告,可以更好地了解标记化过程中可能发生的问题,并在必要时采取适当的措施,例如将长输入文本分块。
    """
    def tokenize_function(examples):
        """
        使用 CaptureLogger(tok_logger) 上下文管理器捕获 tok_logger 中的日志输出。
如果捕获到了特定的警告消息:"Token indices sequence length is longer than the",则说明输入文本的标记序列长度超过了某个限制。
        """
        with CaptureLogger(tok_logger) as cl:
            #使用 tokenizer 进行标记化:
            # output = tokenizer(examples[text_column_name]) 使用给定的 tokenizer 对输入文本进行标记化,结果存储在 output 中。
            output = tokenizer(examples[text_column_name])
        # clm input could be much much longer than block_size

        """
        记录警告:
如果存在上述警告,通过 tok_logger.warning 记录一条新的警告消息,说明输入文本的长度较长,将在传递给模型之前被分块成较小的部分
"""
        """
        返回标记化的输出:

返回标记化后的输出 output。
"""
        if "Token indices sequence length is longer than the" in cl.out:
            tok_logger.warning(
                "^^^^^^^^^^^^^^^^ Please ignore the warning above - this long input will be chunked into smaller bits"
                " before being passed to the model."
            )
        return output

通常用于在训练之前对数据集进行标记化处理。
使用多进程可以加速处理过程,特别是对于大规模的数据集。流式处理则适用于无法将整个数据集一次性加载到内存中的情况

 """
    通常用于在训练之前对数据集进行标记化处理。
    使用多进程可以加速处理过程,特别是对于大规模的数据集。流式处理则适用于无法将整个数据集一次性加载到内存中的情况。
    """

    """
    with training_args.main_process_first(desc="dataset map tokenization")::
使用 main_process_first 上下文管理器,确保在主进程中执行以下代码块。
desc="dataset map tokenization" 提供了一个描述,用于在进度条中显示。
    """
    with training_args.main_process_first(desc="dataset map tokenization"):
        # 如果不是流式处理(not data_args.streaming),执行以下操作:
        if not data_args.streaming:
            # 使用 raw_datasets.map 函数对原始数据集进行标记化处理
            # batched=True 表示对数据集进行批处理。
            # num_proc=data_args.preprocessing_num_workers 表示使用多进程进行处理,可以提高效率。
            tokenized_datasets = raw_datasets.map(
                tokenize_function,
                batched=True,
                num_proc=data_args.preprocessing_num_workers,
                # remove_columns=column_names 表示移除不再需要的列,即之前确定的 column_names
                remove_columns=column_names,
                # load_from_cache_file=not data_args.overwrite_cache
                # 表示尝试从缓存文件加载数据,如果缓存文件不存在或用户选择覆盖缓存,则重新生成。
                load_from_cache_file=not data_args.overwrite_cache,
                # desc="Running tokenizer on dataset" 提供了一个进度描述。
                desc="Running tokenizer on dataset",
            )
        else:
            tokenized_datasets = raw_datasets.map(
                tokenize_function,
                batched=True,
                remove_columns=column_names,
            )

这段代码的目的是在模型配置中查找 max_position_embeddings 属性,并将其值存储在变量 max_pos_embeddings 中。这个属性通常表示模型支持的最大位置嵌入数,即模型能够处理的最大序列长度。如果模型配置中未定义该属性,则使用默认值 1024

   # 这段代码的目的是在模型配置中查找 max_position_embeddings 属性,并将其值存储在变量 max_pos_embeddings 中。
# 这个属性通常表示模型支持的最大位置嵌入数,即模型能够处理的最大序列长度。如果模型配置中未定义该属性,则使用默认值 1024
    # 使用 hasattr(config, "max_position_embeddings") 检查模型配置 config 是否具有名为 max_position_embeddings 的属性。
    if hasattr(config, "max_position_embeddings"):
        max_pos_embeddings = config.max_position_embeddings
    else:
        # Define a default value if the attribute is missing in the config.
        max_pos_embeddings = 1024

代码确保了 block_size 的合理设置,以适应模型的最大长度,并在用户指定块大小时进行相应的处理和警告。这对于确保输入数据的长度适应模型输入的限制是很重要的。

"""
代码确保了 block_size 的合理设置,以适应模型的最大长度,并在用户指定块大小时进行相应的处理和警告。这对于确保输入数据的长度适应模型输入的限制是很重要的。
"""
"""
检查 data_args.block_size 是否为 None:
如果 data_args.block_size 为 None,表示用户没有指定块大小,执行以下操作:
将 block_size 设置为 tokenizer.model_max_length,即 tokenizer 所使用的模型的最大长度。
如果 block_size 大于 max_pos_embeddings(模型的最大位置嵌入数),则发出警告,并将 block_size 重新设置为 min(1024, max_pos_embeddings)。
如果 max_pos_embeddings 大于 0,则将 block_size 重新设置为 min(1024, max_pos_embeddings),否则将 block_size 设置为 1024"""
    if data_args.block_size is None:# 检查 data_args.block_size 是否为 None:
        block_size = tokenizer.model_max_length # 最大长度
        if block_size > max_pos_embeddings:
            logger.warning(
                f"The tokenizer picked seems to have a very large `model_max_length` ({tokenizer.model_max_length}). "
                f"Using block_size={min(1024, max_pos_embeddings)} instead. You can change that default value by passing --block_size xxx."
            )
            if max_pos_embeddings > 0:
                block_size = min(1024, max_pos_embeddings)
            else:
                block_size = 1024
    else:
        if data_args.block_size > tokenizer.model_max_length:
            logger.warning(
                f"The block_size passed ({data_args.block_size}) is larger than the maximum length for the model "
                f"({tokenizer.model_max_length}). Using block_size={tokenizer.model_max_length}."
            )
        block_size = min(data_args.block_size, tokenizer.model_max_length)

这段代码定义了一个名为 group_texts 的函数,该函数的主要目的是将文本数据组合成固定长度的块(chunks)。函数的解释如下:

    # 这段代码定义了一个名为 group_texts 的函数,该函数的主要目的是将文本数据组合成固定长度的块(chunks)。函数的解释如下:

    # Main data processing function that will concatenate all texts from our dataset and generate chunks of block_size.
    def group_texts(examples):
        # Concatenate all texts.
        # 拼接所有的文本
        # 将输入的 examples 中的文本进行拼接。这是通过将每个键(例如,"input_ids")对应的文本列表展平成一个长列表来完成的。
        concatenated_examples = {k: list(chain(*examples[k])) for k in examples.keys()}
        #  计算拼接后文本的总长度。
        # 接着,将 total_length 除以 block_size 并取整,以确保整个文本序列被均匀地划分成大小为 block_size 的块。
        total_length = len(concatenated_examples[list(examples.keys())[0]])
        # We drop the small remainder, and if the total_length < block_size  we exclude this batch and return an empty dict.
        # We could add padding if the model supported it instead of this drop, you can customize this part to your needs.
        total_length = (total_length // block_size) * block_size

        # result 是一个字典,其中包含了将文本拆分成块的结果。
        # 对于每个键 k,通过列表推导式将拼接的文本按 block_size 大小切割成块,存储在 result[k] 中。
        # 最终的 result["labels"] 被设置为 result["input_ids"] 的副本。

        # Split by chunks of max_len.
        result = {
            k: [t[i : i + block_size] for i in range(0, total_length, block_size)]
            for k, t in concatenated_examples.items()
        }

        #返回一个包含拆分后文本的字典。 
        result["labels"] = result["input_ids"].copy()
        return result

这段代码使用 group_texts 函数将标记化后的数据集 tokenized_datasets 组织成适应模型输入的块,并生成一个新的数据集 lm_datasets。
这样的处理过程通常用于准备数据集以用于训练语言模型。通过将文本按块组合,确保输入的序列长度符合模型的要求,并且在处理大规模数据集时能够高效地进行。

    # 这段代码定义了一个名为 group_texts 的函数,该函数的主要目的是将文本数据组合成固定长度的块(chunks)。函数的解释如下:

    # Main data processing function that will concatenate all texts from our dataset and generate chunks of block_size.
    def group_texts(examples):
        # Concatenate all texts.
        # 拼接所有的文本
        # 将输入的 examples 中的文本进行拼接。这是通过将每个键(例如,"input_ids")对应的文本列表展平成一个长列表来完成的。
        concatenated_examples = {k: list(chain(*examples[k])) for k in examples.keys()}
        #  计算拼接后文本的总长度。
        # 接着,将 total_length 除以 block_size 并取整,以确保整个文本序列被均匀地划分成大小为 block_size 的块。
        total_length = len(concatenated_examples[list(examples.keys())[0]])
        # We drop the small remainder, and if the total_length < block_size  we exclude this batch and return an empty dict.
        # We could add padding if the model supported it instead of this drop, you can customize this part to your needs.
        total_length = (total_length // block_size) * block_size

        # result 是一个字典,其中包含了将文本拆分成块的结果。
        # 对于每个键 k,通过列表推导式将拼接的文本按 block_size 大小切割成块,存储在 result[k] 中。
        # 最终的 result["labels"] 被设置为 result["input_ids"] 的副本。

        # Split by chunks of max_len.
        result = {
            k: [t[i : i + block_size] for i in range(0, total_length, block_size)]
            for k, t in concatenated_examples.items()
        }

        #返回一个包含拆分后文本的字典。
        result["labels"] = result["input_ids"].copy()
        return result

数用于预处理模型输出的logits以便进行度量评估

    if training_args.do_eval:
        if "validation" not in tokenized_datasets:
            raise ValueError("--do_eval requires a validation dataset")
        eval_dataset = lm_datasets["validation"]
        if data_args.max_eval_samples is not None:
            max_eval_samples = min(len(eval_dataset), data_args.max_eval_samples)
            eval_dataset = eval_dataset.select(range(max_eval_samples))

        # 模型输出的 logits,这里假设是一个张量(tensor)
        # 标签,用于计算评估指标。
        def preprocess_logits_for_metrics(logits, labels):
            # 如果 logits 是一个元组(tuple),则说明模型输出的 logits 包含了额外的张量
            # ,例如 past_key_values,但是我们只关心 logits 本身,因此取元组中的第一个元素:logits = logits[0]。
            if isinstance(logits, tuple):
                # Depending on the model and config, logits may contain extra tensors,
                # like past_key_values, but logits always come first
                logits = logits[0]
            # 返回预处理后的 logits,通过 logits.argmax(dim=-1) 取得在最后一个维度上的最大值的索引,即模型预测的标签。
            return logits.argmax(dim=-1)
        """
        evaluate.load("accuracy"):
evaluate.load 是 Transformers 库中用于加载评估指标的函数。
通过传递字符串参数 "accuracy",该函数加载了一个计算准确度的评估指标。
metric = evaluate.load("accuracy"):
将加载的 "accuracy" 评估指标存储在变量 metric 中,以便后续使用。
        """

        metric = evaluate.load("accuracy")

        # 函数的目的是计算在评估阶段使用的指标,通常用于评估模型在测试集上的性能。
        # 在计算指标时,需要将模型的预测与真实标签进行比较,并将结果传递给特定的评估指标计算函数(例如,准确度、精确度、召回率等)。
        def compute_metrics(eval_preds):
            # 调用预先加载的评估指标 (metric) 的 compute 方法,传递模型的预测 (predictions) 和真实标签 (references)。
            # 返回计算得到的指标值。
            preds, labels = eval_preds
            # preds have the same shape as the labels, after the argmax(-1) has been calculated
            # by preprocess_logits_for_metrics but we need to shift the labels
            labels = labels[:, 1:].reshape(-1)
            preds = preds[:, :-1].reshape(-1)
            return metric.compute(predictions=preds, references=labels)
    """
    检查是否执行评估 (training_args.do_eval):如果 training_args.do_eval 为 True,表示要执行评估,执行以下操作。
打印评估信息 (logger.info("*** Evaluate ***")):
使用 logger 打印评估的信息。执行评估 (trainer.evaluate):
调用 trainer.evaluate 方法对验证集进行评估,获取评估指标。
获取评估结果的指标 (metrics):
将评估结果中的指标存储在变量 metrics 中。
限制最大评估样本数 (max_eval_samples):
如果用户指定了 data_args.max_eval_samples,则将最大评估样本数设置为该值。
否则,将最大评估样本数设置为验证集的长度。
计算困惑度 (perplexity)
通过将指数函数应用于评估损失 (metrics["eval_loss"]) 计算困惑度。困惑度是语言模型性能的一种度量,它衡量模型对给定数据的预测的不确定性。
记录评估指标 (trainer.log_metrics):

调用 trainer.log_metrics 方法记录评估指标,包括损失、困惑度等。
保存评估指标 (trainer.save_metrics):

调用 trainer.save_metrics 方法将评估指标保存到磁盘。
    """

    # Evaluation
    # 检查是否执行评估
    if training_args.do_eval:
        # 打印评估信息
        logger.info("*** Evaluate ***")
        # 获取评估结果的指标:执行评估
        metrics = trainer.evaluate()
        # 限制最大评估样本数
        # 如果用户指定了data_args.max_eval_samples,则将最大评估样本数设置为该值
        # 否则,将最大评估样本数设置为验证机的长度
        max_eval_samples = data_args.max_eval_samples if data_args.max_eval_samples is not None else len(eval_dataset)
        # 计算困惑度
        metrics["eval_samples"] = min(max_eval_samples, len(eval_dataset))
        try:
            perplexity = math.exp(metrics["eval_loss"])
        except OverflowError:
            perplexity = float("inf")
        metrics["perplexity"] = perplexity

        # 记录评估指标
        trainer.log_metrics("eval", metrics)
        # 保存评估指标
        trainer.save_metrics("eval", metrics)

  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

向上Claire

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值