大模型笔记5 Extractive QA任务评估

news2024/9/29 17:23:13

目录

Extractive QA任务评估

Extractive QA评测指标

precision, recall, f1

ROUGE

划分训练与评估数据集

token位置评估

单个token位置评估

输入label的token位置

预测token位置

评估

Wandb

共享机器同时登录

样本类别平衡

标记token label时对窗口进行筛选

训练输入json数据格式调整

GPU内存不足

服务器远程连接断开后进程停止运行


Extractive QA任务评估

Extractive QA评测指标

Extractive QA Evaluation Metrics:

参考:

Evaluating Question Answering Evaluation

Evaluating Question Answering Evaluation - ACL Anthology

现有指标(BLEU、ROUGE、METEOR 和 F1)是使用 n-gram 相似性计算的

how-to-evaluate-question-answering代码

How to Evaluate a Question Answering System | deepset

Evaluation of a QA System | Haystack

slides:

https://anthonywchen.github.io/Papers/evaluatingqa/mrqa_slides.pdf

QAEval:

https://direct.mit.edu/tacl/article/doi/10.1162/tacl_a_00397/106792/Towards-Question-Answering-as-an-Automatic-Metric

代码:

https://github.com/CogComp/qaeval-experiments

precision:candidate中匹配reference的内容占candidate比例

recall:candidate中匹配reference的内容占reference比例

Reference: I work on machine learning.

Candidate A: I work.

Candidate B: He works on machine learning.

Precision A>B, recall B>A

F1

import evaluate

metric = evaluate.load("squad")

metric.compute(predictions=predicted_answers, references=theoretical_answers)

{'exact_match': 83.0, 'f1': 88.25}

ROUGE (Recall Oriented Understudy for Gisting Evaluation)

https://aclanthology.org/W04-1013/

分类:ROUGE-N(常用其中的ROUGE-1和ROUGE-2), ROUGE-L,ROUGE-W,ROUGE-S(后两种不常用) 原版论文中ROUGE主要关注recall值,但事实上在用的时候可以用precision、recall和F值。

ROUGE-N:基于n-grams,如ROUGE-1计算基于匹配unigrams的recall,以此类推。 ROUGE-L:基于longest common subsequence (LCS)

BLUE

precision用modified n-gram precision估计,recall用best match length估计。

Modified n-gram precision:

n-gram precision是candidate中与reference匹配的n-grams占candidates的比例

Reference: I work on machine learning.

Candidate 1: He works on machine learning.

Precision=60%(3/5)

best match length

precision, recall, f1

数据集标签labels_texts中一篇文章的数据集描述为一个字符串list,

模型输出prediction_strings中一篇文章的数据集描述为连在一起的字符串.

示例数据:

labels_texts = [["description1 in paper1", "description2 in paper1"], ["description1 in paper2"]]

prediction_strings = ["description1 in paper1. description2 in paper1", "description1 in paper2"]

使用 F1 分数来评估模型的输出

1. 将 labels_texts 转化为 token 级别的标签。

2. 训练模型并生成预测结果 prediction_strings。

3. 比较预测的 token 和参考的 token,并基于它们的交集计算评估指标。

# 评估模型输出

def evaluate(predictions, references):

    y_true = []

    y_pred = []

    for ref, pred in zip(references, predictions):

        ref_tokens = tokenizer.tokenize(" ".join(ref))

        pred_tokens = tokenizer.tokenize(pred)

        common = set(ref_tokens) & set(pred_tokens)

       

        y_true.extend([1] * len(common) + [0] * (len(ref_tokens) - len(common)))

        y_pred.extend([1] * len(common) + [0] * (len(pred_tokens) - len(common)))

   

    precision, recall, f1, _ = precision_recall_fscore_support(y_true, y_pred, average='binary')

    return precision, recall, f1

precision, recall, f1 = evaluate(prediction_strings, labels_texts)

print(f"Precision: {precision:.4f}, Recall: {recall:.4f}, F1 Score: {f1:.4f}")

precision, recall, f1, _ = precision_recall_fscore_support(y_true, y_pred, average='binary')这一句报错ValueError: Found input variables with inconsistent numbers of samples: [40, 42]

这是因为生成的句子比参考的句子更长

常见的处理方法包括

截断生成的句子:将生成的句子截断到与参考句子相同的长度。

填充参考句子:将参考句子填充到与生成句子相同的长度。

对齐比较:在评估时只比较重叠部分,并忽略多出的部分。

截断比较

        # 两个字符串长度不一样, 会报错, 截断比较

        min_len = min(len(ref_tokens), len(pred_tokens))

        ref_tokens = ref_tokens[:min_len]

        pred_tokens = pred_tokens[:min_len]

得到输出

Prediction Strings: ['impossible. In this paper, we aim to solve this problem by introducing FAR-Trans, the first public dataset for FAR, containing pricing in- formation and retail investor transactions acquired from a large European financial institution.']

Precision: 1.0000, Recall: 0.9750, F1 Score: 0.9873

ROUGE

 (Recall Oriented Understudy for Gisting Evaluation)

ROUGE: A Package for Automatic Evaluation of Summaries - ACL Anthology

文本生成评估指标简单介绍BLEU+ROUGE+Perplexity+Meteor 代码实现_meteor指标-CSDN博客

简介:主要用于评估机器翻译文本摘要(或其他自然语言处理任务)的质量,即:衡量目标文本与生成文本之间的匹配程度,此外还考虑生成文本的召回率,BLEU则相对更看重生成文本的准确率,着重于涵盖参考摘要的内容和信息的完整性。

主要有两种形式:

ROUGE-N(N = 1, 2, 3, …)

ROUGE-L

ROUGE-N计算方式为:

ROUGE-N = Candidate ∩ Reference l e n ( Reference ) \text{ROUGE-N} = \frac{\text{Candidate} \cap \text{Reference}}{len(\text{Reference})}

这里的分子交集不像ROUGE-L的最长公共子串一样,这里的交集不考虑顺序。

交集主要考虑n-gram

参考:

https://zhuanlan.zhihu.com/p/647310970

n代表连续的n个词的组合。"n"可以是1、2、3,或者更高。

  • 1-gram:也称为unigram,是指单个的词语。例如,在句子 "我喜欢学习自然语言处理。" 中的1-gram为:["我", "喜欢", "学习", "自然语言处理", "。"]
  • 2-gram:也称为bigram,是指两个连续的词语组合。例如,在句子 "我喜欢学习自然语言处理。" 中的2-gram为:["我喜欢", "喜欢学习", "学习自然语言处理", "自然语言处理。"]

ROUGE-L
考虑最长公共子串(是区分顺序的)

单句ROUGE-L

ROUGE-L = 最长公共子串 ( Candidate , Reference ) l e n ( Reference ) \text{ROUGE-L} = \frac{\text{最长公共子串}(\text{Candidate}, \text{Reference})}{len(\text{Reference})}

Rouge库:

rouge · PyPI

https://www.cnblogs.com/bonelee/p/18152511

发现环境中已经按照了rouge-score

rouge-score · PyPI

from rouge_score import rouge_scorer

scorer = rouge_scorer.RougeScorer(['rouge1','rouge2', 'rougeL'], use_stemmer=True)

scores = scorer.score('The quick brown fox jumps over the lazy dog',

                      'The quick brown dog jumps on the log.')

print(scores["rouge1"])

print(scores["rouge2"])

print(scores["rougeL"])

看看多组不能直接预测, 要拆开每一个样本对比预测.

这样多个样本时候如何计算呢, 查到一个例子, 是把列表中所有字符串拼接在一起

自然语言处理评估指标_自然语言处理结果-CSDN博客

文本摘要教程

https://github.com/hellotransformers/Natural_Language_Processing_with_Transformers/blob/main/chapter6.md

多个样本例子:

https://stackoverflow.com/questions/67390427/rouge-score-append-a-list

#同一个文档拼接到同一个字符串

==================rouge====================

from nltk.translate.bleu_score import sentence_bleu

from nltk.translate.rouge_score import rouge_n, rouge_scorer

def gouge(evaluated_sentences, reference_sentences):

    """

    :param evaluated_sentences: 生成的摘要句子列表

    :param reference_sentences: 参考摘要句子列表

    :return: GOUGE指标

    """

    scorer = rouge_scorer.RougeScorer(['rouge1', 'rouge2', 'rouge    3', 'rouge4'])

    scores = scorer.score(' '.join(evaluated_sentences),

                          ' '.join(reference_sentences))

    rouge_n_scores = [scores[f'rouge{i}'].precision for i in range(1, 5)]

    return np.exp(np.mean(np.log(rouge_n_scores)))

# 不同文档分别计算评估指标

# importing the native rouge library

from rouge_score import rouge_scorer

# a list of the hypothesis documents

hyp = ['This is the first sample', 'This is another example']

# a list of the references documents

ref = ['This is the first sentence', 'It is one more sentence']

# make a RougeScorer object with rouge_types=['rouge1']

scorer = rouge_scorer.RougeScorer(['rouge1'])

# a dictionary that will contain the results

results = {'precision': [], 'recall': [], 'fmeasure': []}

# for each of the hypothesis and reference documents pair

for (h, r) in zip(hyp, ref):

    # computing the ROUGE

    score = scorer.score(h, r)

    # separating the measurements

    precision, recall, fmeasure = score['rouge1']

    # add them to the proper list in the dictionary

    results['precision'].append(precision)

    results['recall'].append(recall)

    results['fmeasure'].append(fmeasure)

print(results)

{'precision': [0.8, 0.2], 'recall': [0.8, 0.25], 'fmeasure': [0.8000000000000002, 0.22222222222222224]}

但是拼接不同样本为同一个字符串再一起计算rouge的方式在含义上不太合适, 所以每个样本分别计算, 然后对所有样本取均值.

pip安装rouge_score

计算评估指标

def rouge_evaluate(predictions, refs):

    scorer = rouge_scorer.RougeScorer(['rouge1', 'rouge2', 'rougeL'], use_stemmer=True)

    rouge_scores = {'rouge1': [], 'rouge2': [], 'rougeL': []}

   

    for ref, pred in zip(refs, predictions):

        score = scorer.score(" ".join(ref), pred)

        for key in rouge_scores:

            rouge_scores[key].append(score[key].fmeasure)

   

    avg_rouge_scores = {key: sum(scores) / len(scores) for key, scores in rouge_scores.items()}

    #指标直接储存在文件中

    with open('output/evaluation_rouge.txt', 'w') as eval_file:

        # eval_file.write(f"rouge1: {precision:.4f}\n")

        # eval_file.write(f"rouge2: {recall:.4f}\n")

        # eval_file.write(f"rougeL: {f1:.4f}\n")

        eval_file.write(f"ROUGE Scores:\n")

        for key, score in avg_rouge_scores.items():

            eval_file.write(f"{key}: {score:.4f}\n")

    return avg_rouge_scores

rouge_results = rouge_evaluate(dataset_descriptions, labels_texts)

此处只计算f值的均值, 若有需要, 后续再补充其它值.

划分训练与评估数据集

from sklearn.model_selection import train_test_split

在分割完token label后

# Split the dataset into training and evaluation sets

train_size = 0.8

train_indices, val_indices = train_test_split(list(range(len(inputs["input_ids"]))), train_size=train_size, random_state=42)

train_inputs = {key: val[train_indices] for key, val in inputs.items()}

val_inputs = {key: val[val_indices] for key, val in inputs.items()}

train_dataset = TensorDataset(train_inputs["input_ids"], train_inputs["attention_mask"], train_inputs["labels"])

val_dataset = TensorDataset(val_inputs["input_ids"], val_inputs["attention_mask"], val_inputs["labels"])

train_dataloader = DataLoader(train_dataset, batch_size=2, shuffle=True)

val_dataloader = DataLoader(val_dataset, batch_size=2, shuffle=False)

#训练时

for batch in train_dataloader:

avg_epoch_loss = epoch_loss / len(train_dataloader)

#评估时

# Evaluate on the validation set

val_predictions, val_labels = evaluate(model, val_dataloader, tokenizer)

precision, recall, f1, rouge_scores = calculate_metrics(val_predictions, val_labels, tokenizer)

检查batch中是否有paper_idx

注意DataLoader中的key和修改后的输入的key对齐

 ["input_ids"]["attention_mask"]["labels"]["paper_idx"]

val_dataset = TensorDataset(val_inputs["input_ids"], val_inputs["attention_mask"], val_inputs["labels"], val_inputs["paper_idx"])

还有一个问题, 抽样的时候把不同样本的滑窗分开了怎么办

为了确保从同一样本生成的滑动窗口保持在一起,我们需要修改数据拆分过程。我们不会在标记化后拆分数据集,而是拆分原始数据,然后分别对每个子集进行标记。这样,滑动窗口将保留在相同的训练或验证拆分中。

Tokenize前拆分

# Split the original data into training and evaluation subsets

train_sentences, val_sentences, train_labels_texts, val_labels_texts, train_titles, val_titles = train_test_split(

    sentences, labels_texts, titles, train_size=0.8, random_state=42

)

分别tokenize, 创建dataloder

# Tokenize the training and validation data separately

train_inputs = tokenize_and_align_labels(train_sentences, train_labels_texts, train_titles, tokenizer)

val_inputs = tokenize_and_align_labels(val_sentences, val_labels_texts, val_titles, tokenizer)

model.to(device)

train_inputs = {key: val.to(device) for key, val in train_inputs.items()}

val_inputs = {key: val.to(device) for key, val in val_inputs.items()}

train_dataset = TensorDataset(train_inputs["input_ids"], train_inputs["attention_mask"], train_inputs["labels"])

val_dataset = TensorDataset(val_inputs["input_ids"], val_inputs["attention_mask"], val_inputs["labels"])

train_dataloader = DataLoader(train_dataset, batch_size=2, shuffle=True)

val_dataloader = DataLoader(val_dataset, batch_size=2, shuffle=False)#防止生成的同一篇文章断开

评估时的label也更换

precision, recall, f1 = token_evaluate(dataset_descriptions, val_labels_texts)

rouge_results = rouge_evaluate(dataset_descriptions, val_labels_texts)

输出时

dataset_descriptions = get_extracted_description(val_predictions, val_inputs["input_ids"], val_inputs["paper_idx"])

token位置评估

常见方法:

  1. 准确率 (Accuracy):衡量模型预测的答案是否完全正确,适用于答案只有一个标准的情况。
  2. 精确率 (Precision), 召回率 (Recall) 和 F1 分数:这些指标常用于衡量模型在预测多个可能答案时的表现。精确率衡量正确预测的答案在所有预测答案中的比例,召回率衡量正确预测的答案在所有正确答案中的比例,F1 分数是精确率和召回率的调和平均数。
  3. EM (Exact Match):衡量模型预测的答案与参考答案完全匹配的比例。
  4. ROUGE (Recall-Oriented Understudy for Gisting Evaluation):衡量模型生成的答案与参考答案之间的重叠情况,常用于评估生成任务。ROUGE-1 和 ROUGE-L 常用于评估答案的词汇和序列匹配度。
  5. BLEU (Bilingual Evaluation Understudy):衡量模型生成答案与参考答案之间的 n-gram 重叠情况,常用于机器翻译任务,但在 QA 任务中也可作为辅助指标。

使用输出 token 的位置作为评估指标是合适的,特别是在以下情况中:

  • 开始和结束位置的准确性:对于 Extractive QA 任务,模型通常预测答案在文本中的开始和结束位置。这可以直接用于评估模型是否准确地定位了答案的位置。
  • 重叠率:评估预测答案的起止位置与真实答案的起止位置之间的重叠情况,可以使用 Intersection over Union (IoU) 或者其他重叠率指标。

单个token位置评估

此处模型输出不是单个连续序列, 因此使用label中每个token的位置与预测token位置对比进行评估

输入label的token位置

1.利用label_text构建token_label时同时保存token位置(匹配成功的每一个token在该滑窗中的下标), 保存在tokenized_inputs中

添加了一个名为 token_positions 的键,用于保存每个匹配成功的 token 在滑窗中的下标。

    tokenized_inputs = {"input_ids": [], "attention_mask": [], "labels": [], "paper_idx": [], "token_positions": []}

token_positions 列表只包含与 token_label 值为 1 的部分对应的下标

同一篇文章中的每一个滑窗, 其中每一个滑窗是一个数组, 有的label在这个滑窗中, 有的不在, 所以会出现部分滑窗token位置中为空的情况

for j in range(len(input_ids)):#同一篇文章中的每一个滑窗

            tokenized_sentence = tokenizer.convert_ids_to_tokens(input_ids[j])

            token_label = [0] * len(tokenized_sentence)

            main_body_start=find_main_body(tokenized_sentence)

            token_positions = []

            for label_text in labels_text:

                # print("label_text:",label_text)

                tokenized_label = tokenizer.tokenize(label_text)

                # print("label_text:",label_text)

                tokenized_label = [token for token in tokenized_label if token != '<pad>']#删除pad

                label_length = len(tokenized_label)

                # print("tokenized_label:",tokenized_label)

                # 处理label跨滑窗

                for k in range(main_body_start,len(tokenized_sentence)-1):#从正文部分开始匹配

                    # print("tokenized_sentence:",tokenized_sentence[k:k + label_length])

                    end_position=min(len(tokenized_sentence)-1, k + label_length)

                    if tokenized_sentence[k:end_position] == tokenized_label[0:end_position]:#后半部分没有的情况

                        print("matched tokenized_label:", tokenized_sentence[k:end_position])

                        # print("matched tokenized_label:",tokenized_label,"\n",tokenized_sentence[k:end_position])

                        token_label[k:end_position] = [1] * (end_position-k)

                        # print("matched clsfy_label:",token_label[k:len(tokenized_sentence)-1])

                        for pos in range(k, end_position):

                            token_positions.append(pos)

                for label_start in range(label_length-1):#前半部分没有的情况

                    # print("tokenized_sentence:",tokenized_sentence[k:k + label_length])

                    if tokenized_sentence[main_body_start:label_length-label_start] == tokenized_label[label_start:]:#后半部分没有的情况

                        print("matched tokenized_label:",tokenized_sentence[main_body_start:label_length-label_start])

                        # print("matched tokenized_label:",tokenized_sentence[main_body_start:label_length-label_start],"\n",tokenized_label[label_start:])

                        token_label[main_body_start:label_length-label_start] = [1] * (label_length-label_start)

                        # print("matched clsfy_label:",token_label[k:len(tokenized_sentence)-1])

                        for pos in range(main_body_start, label_length - label_start):

                            token_positions.append(pos)

            tokenized_inputs["token_positions"].append(token_positions)

因为tokenized_inputs["token_positions"]中的数组不等长, 无法转换成tensor使用torch.stack(), 无法和其它key一起转到gpu中, 所以, 转到gpu的操作只在分批之后的其它key上进行

预测token位置

2.输出token分类转换成句子时候, 同时输出token预测位置

将get_prediction_string中predicted_tokens_classes的类别预测为'Dataset description'的token位置也记录下来并一起返回

新增一个pre_token_positions列表用于记录预测类别为 'Dataset description' 的 token 的位置。函数最后返回 dataset_description_string 和pre_token_positions

pre_token_positions = []

    for idx, (token, pred_class) in enumerate(zip(tokenized_sub_sentence, predicted_tokens_classes)):

        is_descrp=(pred_class == 'Dataset description')

        if(is_descrp):

            pre_token_positions.append(idx)

    return dataset_description_string, pre_token_positions

        dataset_description, pre_token_positions=get_prediction_string(prediction_class, predicted_input_id, is_same_paper)

不同窗口的token位置分别评测, 避免不同窗口的token位置计算混乱

Token位置不需要拼接吧, 毕竟不是输出包含句意的内容, 放在一个大列表中分开不同窗口评测更好, 拼接之后不同窗口的位置反而容易串了

每一个pre_token_positions列表作为一个元素存入papers_pre_token_positions中

    papers_pre_token_positions=[]

        dataset_description, pre_token_positions=get_prediction_string(prediction_class, predicted_input_id, is_same_paper)

        papers_pre_token_positions.append(pre_token_positions)

    return dataset_descriptions, papers_pre_token_positions

dataset_descriptions,papers_pre_token_positions = get_extracted_description(val_predictions, val_inputs["input_ids"], val_inputs["paper_idx"])

评估

评估时的label与预测中token数量可能不同

其中label, 预测分别为papers_pre_token_positions, val_inputs["token_positions"]

准确率(Precision):P=TP/(TP+FP)。通俗地讲,就是预测正确的正例数据占预测为正例数据的比例。

召回率(Recall):R=TP/(TP+FN)。通俗地讲,就是预测为正例的数据占实际为正例数据的比

F1=(2*P*R)/(P+R)

true_positive 表示预测正确的 token 位置的数量,false_positive 表示错误预测的 token 位置的数量,false_negative 表示遗漏的实际 token 位置的数量。通过遍历每个滑窗的预测位置和实际位置,计算这些指标并最终得到 precision, recall 和 F1-score

def token_evaluate(pre_token_positions, label_token_positions):

    true_positive = 0

    false_positive = 0

    false_negative = 0

   

    for pred_positions, label_positions in zip(pre_token_positions, label_token_positions):

        pred_positions_set = set(pred_positions)

        label_positions_set = set(label_positions)

       

        true_positive += len(pred_positions_set & label_positions_set)

        false_positive += len(pred_positions_set - label_positions_set)

        false_negative += len(label_positions_set - pred_positions_set)

   

    precision = true_positive / (true_positive + false_positive) if (true_positive + false_positive) > 0 else 0

    recall = true_positive / (true_positive + false_negative) if (true_positive + false_negative) > 0 else 0

    f1 = 2 * (precision * recall) / (precision + recall) if (precision + recall) > 0 else 0

   

    return precision, recall, f1

# 例子

pre_token_positions = [[], [2], []]

label_token_positions = [[1], [2], [3]]

precision, recall, f1 = token_evaluate(pre_token_positions, label_token_positions)

print(f"Precision: {precision}")

print(f"Recall: {recall}")

print(f"F1-score: {f1}")

Wandb

Wandb是一个模型训练日志自动记录工具, 配置好后可以比较方便地在wandb.ai的网页查看每一次训练记录的plot和每条曲线的中的值

使用Wandb记录训练日志

安装wandb

pip install wandb

在命令行登录

wandb login

输入注册后生成的key, 登录成功

运行测试样例

import wandb

import random

# start a new wandb run to track this script

wandb.init(

    # set the wandb project where this run will be logged

    project="my-awesome-project",

    # track hyperparameters and run metadata

    config={

    "learning_rate": 0.02,

    "architecture": "CNN",

    "dataset": "CIFAR-100",

    "epochs": 10,

    }

)

# simulate training

epochs = 10

offset = random.random() / 5

for epoch in range(2, epochs):

    acc = 1 - 2 ** -epoch - random.random() / epoch - offset

    loss = 2 ** -epoch + random.random() / epoch + offset

    # log metrics to wandb

    wandb.log({"acc": acc, "loss": loss})

# [optional] finish the wandb run, necessary in notebooks

wandb.finish()

获得提示

wandb: Run data is saved locally in D:\Projects\longformer\wandb\run-20240805_204153-4hznct2i

wandb: Run `wandb offline` to turn off syncing.

wandb: Syncing run hearty-eon-1

wandb:  View project at https://wandb.ai/lalagoon-north-china-electric-power-university/test-project

wandb:  View run at https://wandb.ai/lalagoon-north-china-electric-power-university/test-project/runs/4hznct2i

打开网址可以看到生成的图像, 说明成功了

在自己的项目中加入

import wandb

# start a new wandb run to track this script

wandb.init(

    # set the wandb project where this run will be logged

    project="extract-dataset-description-project",

    # track hyperparameters and run metadata

    config={

    "learning_rate": 5e-5,

    "architecture": "Longformer",

    "dataset": "Description-500",

    "epochs": 100,

    }

)

运行过程中的epoch进行记录

# 记录损失到 wandb

wandb.log({"loss": avg_epoch_loss})

完事关掉

wandb.finish()

得到loss图在

https://wandb.ai/lalagoon-north-china-electric-power-university/extract-dataset-description-project

共享机器同时登录

服务器上有另一个wandb账号已经登录了, 则在命令行用这个代替login

export WANDB_API_KEY='xxxx'

样本类别平衡

标记token label时对窗口进行筛选

如果窗口中没有正例则不输入进行训练

在标记label时, 传入一个flag判断是否标记的是训练集, 训练集中判断token_positions, 如果是空数组, 则不在tokenized_inputs加入这个滑窗.

如果要过滤且没有label在滑窗, 则打断这个滑窗的循环, 不把值加入inputs

            if(filter_empty_window and len(token_positions)==0):

                continue

在训练集中开启

train_inputs = tokenize_and_align_labels(train_papers, tokenizer,filter_empty_window=True)

训练输入json数据格式调整

将输入格式由字符串数组调整为json数组, 同一篇文章的不同信息放在一起方便对比

从json数组中读取

descri_file_path='input/papers_and_datasets.json'

def read_json(file_path):

    with open(file_path, 'r', encoding='utf-8') as file:

        data = json.load(file)

    return data

papers_info = read_json(descri_file_path)

之后所有的循环改成从papers_info中读取

sentences = data['paper_texts']

labels_texts = data['dataset_descriptions']

titles= data['titles']

训练集测试集划分, 改为划分paper_info

train_papers, val_papers = train_test_split(

    papers_info, train_size=0.8, random_state=42

)

输入tokenize_and_align_labels匹配token label时使用paper_info,

train_inputs = tokenize_and_align_labels(train_papers, tokenizer)

val_inputs = tokenize_and_align_labels(val_papers, tokenizer)

def tokenize_and_align_labels(papers, tokenizer, max_length=4096, stride=256):

使用tokenizer时循环paper_info, 并取出其中各项.

    for i, paper in enumerate(papers_info):

        sentence=paper.get("paper_text")

        labels_text = paper.get("dataset_descriptions")

        title = paper.get("title")

在评估时候也循环取出

1.token评估

def token_evaluate(predictions, val_papers, tokenizer):

    for paper, pred in zip(val_papers, predictions):#ref_tokens中是一篇文章的label, y_true.extend后是所有样本的输出

        ref=paper.get("dataset_descriptions")

precision, recall, f1 = token_evaluate(dataset_descriptions, val_papers, tokenizer)

2.rouge

def rouge_evaluate(predictions, val_papers):

    for paper, pred in zip(val_papers, predictions):

        ref=paper.get("dataset_descriptions")

rouge_results = rouge_evaluate(dataset_descriptions, val_papers)

同时, 为方便不同设备路径修改, 将使用到的路径统一汇总到开头

descri_file_path='input/papers_and_datasets.json'

loss_log_path='output/training_loss.txt'

loss_fig_path='output/training_loss.png'

model_save_path="output/trained_model"

eval_token_path='output/evaluation_token.txt'

eval_rouge_path='output/evaluation_rouge.txt'

GPU内存不足

Colab上分批训练时将输入转移到GPU

input_ids, attention_mask, labels = input_ids.to(device), attention_mask.to(device), labels.to(device)

报错

        # OutOfMemoryError: CUDA out of memory. Tried to allocate 24.00 MiB. GPU

注释了移GPU的, RAM又不够, 换了个号一样说不够用, 之后完善一下代码放华为卡上试试吧

华为卡跑多了也报错:

RuntimeError: NPU out of memory. Tried to allocate 578.00 MiB (NPU 0; 60.97 GiB total capacity; 8.23 GiB already allocated; 8.23 GiB current active; 362.04 MiB free; 8.95 GiB reserved in total by PyTorch) If reserved memory is >> allocated memory try setting max_split_size_mb to avoid fragmentation.

清除缓存和减少batch size, 参考

python - How to avoid "CUDA out of memory" in PyTorch - Stack Overflow

import torch

torch.cuda.empty_cache()

torch_npu.npu.empty_cache()

设置max_split_size_mb, 参考:

环境变量方法:

export 'PYTORCH_NPU_ALLOC_CONF=max_split_size_mb:512'

代码方法:

torch._C._debug_set_max_split_size_mb(512)

torch_npu._C._debug_set_max_split_size_mb(512)

华为卡查看剩余NPU资源

npu-smi info

可以看到有人在跑

+---------------------------+---------------+----------------------------------------------------+

| NPU     Chip              | Process id    | Process name             | Process memory(MB)      |

+===========================+===============+====================================================+

| 0       0                 | 1349884       | python                   | 30216                   |

+===========================+===============+====================================================+

指定一块GPU运行python程序, 参考:

https://www.cnblogs.com/tyty-Somnuspoppy/p/10071716.html

os.environ["NPU_VISIBLE_DEVICES"] = "1,2,3"

device = torch.device("npu:1" if torch.npu.is_available() else "npu:2")

检查每个设备的可用内存是否足够:

def select_available_npu(required_memory_mb):

    if torch.npu.is_available():

        for i in range(1, 8):

            props = torch.npu.get_device_properties(f"npu:{i}")

            if props.total_memory - props.reserved_memory >= required_memory_mb * 1024 * 1024:

                return torch.device(f"npu:{i}")

    return torch.device("cpu")

查看总内存

torch_npu.npu.get_device_properties("npu:1").total_memory

设置特定npu, 注意这里查询要用torch_npu.npu, 不然取不到

device = torch.device("npu:1" if torch_npu.npu.is_available() else "npu:2")

longformer的输入序列长, 4096也很大

不像现在的infini transformer这种先分割在分块处理

Longformer不支持多卡训练, 只能把batchsize设置小一点,显存会下降一点

batch_size=8

能跑起来了

----+

| NPU     Chip              | Process id    | Process name             | Process memory(MB)      |

+===========================+===============+====================================================+

| 0       0                 | 47784         | python                   | 52657                   |

+===========================+===============+================================================

服务器远程连接断开后进程停止运行

Nohup参考:

在Linux系统的ECS实例内,当断开SSH客户端后,如何保持进程继续运行的解决方案_云服务器 ECS(ECS)-阿里云帮助中心

Linux服务器SSH客户端断开后保持程序继续运行的方法_ssh退出后如何保持程序继续运行-CSDN博客

SSH 断开后使进程仍在后台运行 — Linux latest 文档

nohup ping www.baidu.com &

ls

cat nohup.out

ps -ef | grep ping

kill [$PID]

[$PID]为之前nohup命令输出的值

[1] 1255914

nohup: ignoring input and appending output to 'nohup.out'

用于执行程序

nohup python tkn_clsfy.py &

ps -ef | grep python

得到输出

[1] 27308

root       27308   27285 99 13:19 pts/14   00:01:49 python tkn_clsfy.py

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1991785.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

亚马逊日本站认证 硅藻土商品

商品说明和商品照片 硅藻土商品&#xff0c;是指以硅藻土为主要原料而制作的商品。其中&#xff0c;针对浴室脚垫和杯垫等呈板状的商品&#xff0c;因需确认其石棉含有率符合相关安全基准规定&#xff0c;请您提交相关证明资料。 防止石棉损害健康条例以及相关法令 可证明该产…

[算法题]课程表/课程表 II

题目链接: 课程表 课程表 II 通过拓扑排序求解, 首先认识有向无环图: 入度表示有多少点指向自己, 出度表示自己指向多少点, 拓扑排序的思想则为选出入度为 0 的点排, 然后将被选出的点指向的点的入度减 1, 当入度被减到 0 时表示该点可以被选出, 一直循环直到全部点被选出或…

书生大模型实战营-基础关卡-2-8G 显存玩转书生大模型 Demo

Cli Demo 部署 InternLM2-Chat-1.8B 模型 先简单试试 InternLM2-Chat-1.8B 模型的能力 生成 300 字的小故事 我的prompt&#xff1a;写一个300字以内的小故事,故事符合中国特色. 模型输出&#xff1a;故事整体性还是很好的。 在一个小镇上&#xff0c;住着一只名叫小明的猫咪…

基于Dijkstra的校园导游系统

目录 一. 设计目的 二. 设计背景 三. 系统功能 四. 系统算法实现 五. 系统调试与结果分析 六. 完整源代码 一. 设计目的 通过设计并实现校园导游系统&#xff0c;使学生对数据结构有更深入的了解。该系统综合性非常广&#xff0c;能够极大提高学生的设计&#xff0c;编程及…

数据库中的约束,聚合函数以及联合查询

目录 数据库中的约束 not null unique default primary key foreign key 表的设计 聚合函数&#xff08;查询&#xff09; 分组 联表查询&#xff08;多表查询&#xff09; 内连接 外连接 左外连接 右外连接 自连接 子查询 合并查询 数据库中的约束 为了保证…

用python获取系统的硬件信息(python实例二十九)

目录 1.认识Python 2.环境与工具 2.1 python环境 2.2 Visual Studio Code编译 3.获取系统信息 3.1 代码构思 3.2 代码示例 3.3 运行部分结果 4.总结 1.认识Python Python 是一个高层次的结合了解释性、编译性、互动性和面向对象的脚本语言。 Python 的设计具有很强的…

计算机组成原理面试-核心概念-问题理解

目录 1.怎么理解计算机组成原理中存储器、控制器、运算器、输入输出设备之间的协作关系和工作流程 2.比、比特等类似几种表示信息存储的单位具体换算 3.介绍计算机的五大功能-数据传送功能、数据存储功能、数据处理功能、操作控制功能、操作判断功能 4.计算机的工作过程/指令…

【Linux基础】Linux基本指令(一)

目录 前言1&#xff0c; ls指令2&#xff0c;pwd指令三&#xff0c;cd指令3.1 当前目录与上级目录3.2 绝对路径和相对路径3.3 tree指令 四&#xff0c;创建一个普通文件或目录4.1 touch指令4.2 mkdir指令 五&#xff0c;删除目录或文件5.1 rmdir指令5.2 rm 指令 六&#xff0c;…

华大基因阿尔茨海默病风险基因检测,助力阿尔茨海默病早预防

中国正面临日益加剧的老龄化挑战。据统计&#xff0c;2020年我国60岁以上的老年人口已达2.6亿&#xff0c;其中轻度认知障碍患者超过3800万&#xff0c;而阿尔茨海默病患者近千万。随着这一趋势的延续&#xff0c;如何早期发现和预防阿尔茨海默病已成为公共卫生领域的重要议题。…

为什么建议从二维向三维GIS开发方向拓展?

GIS开发是地理信息系统领域中一个薪资待遇较高的职业方向&#xff0c;吸引了众多来自测绘、遥感和城市规划等相关专业的学生转型投身于WebGIS开发工作。 那么&#xff0c;今天从技术角度出发&#xff0c;探讨为何鼓励大家超越WebGIS的范畴&#xff0c;继续深入学习三维GIS开发…

el-date-picker 限制开始时间和结束时间

el-date-picker 限制开始时间和结束时间 需求&#xff1a;el-date-picker 月份限制开始时间和结束时间 开始时间&#xff1a;202307 结束时间&#xff1a;202407 代码实现 vue 页面 <el-form-item label"月份" prop"monthList"><el-date-picker …

零基础5分钟上手亚马逊云科技AWS核心云开发/云架构 - 创建高可用数据库集群

简介&#xff1a; 欢迎来到小李哥全新亚马逊云科技AWS云计算知识学习系列&#xff0c;适用于任何无云计算或者亚马逊云科技技术背景的开发者&#xff0c;让大家零基础5分钟通过这篇文章就能完全学会亚马逊云科技一个经典的服务开发架构方案。 我将每天介绍一个基于亚马逊云科…

测试概论之系统测试

系统测试 文章目录 系统测试一、系统测试定义二、系统测试的对象三、系统测试类型1、功能测试2、性能测试3、压力测试4、容量测试5、GUI 测试6、可以性测试7、安装性测试8、配置测试9、异常测试10、备份测试11、健壮性测试12、文档测试13、在线帮助测试14、网络测试 四、系统测…

为什么奥运会采用通义而不是 OpenAI,现在中国的 AI 技术是世界领先了吗?

奥运会作为全球最盛大的体育赛事之一&#xff0c;一直在不断地引入和利用最新的科技来提升赛事的组织效率、观众体验以及运动员的表现。在2024年巴黎奥运会上&#xff0c;人工智能&#xff08;AI&#xff09;技术的应用尤为引人注目。 首先&#xff0c;关于奥运会采用的技术选…

数字噪音计(声级计)【AR814数字噪音计】

系统介绍 声级计&#xff0c;又叫噪音计&#xff0c;是噪声测量中最基本的仪器。声级计一般由电容式传声器、前置放大器、衰减器、放大器、频率计权网络以及有效值指示表头等组成。 声级计的工作原理是&#xff1a;由传声器将声音转换成电信号&#xff0c;再由前置放大器放大…

【json解析】控制台打印json字符串格式正确,但json.loads()解析失败问题解决

问题为控制台打印json字符串格式正确&#xff0c;但json.loads()解析失败。看似简单的问题&#xff0c;却又折腾了好一会&#xff0c;因此记录一下解决方法&#xff01; 出现这个问题的原因&#xff1a;眼见不一定为实&#xff0c;控制台打印的json字符串并不一定是实际的json字…

Typora v1.9.5解锁版下载、安装教程 (轻便简洁的Markdown编辑器)

前言 Typora是一款轻便简洁的Markdown编辑器&#xff0c;支持即时渲染技术&#xff0c;这也是与其他Markdown编辑器最显著的区别。即时渲染使得你写Markdown就想是写Word文档一样流畅自如&#xff0c;不像其他编辑器的有编辑栏和显示栏。 一、下载地址 下载链接&#xff1a;…

软件测试---Fiddler抓包

一、初识Fiddler ①BS架构简介和请求过程理解 ②Fiddler原理 Fiddler是一个代理服务器。代理地址:127.0.0.1&#xff0c;端口:8888。浏览器可以通过设置查看代理服务器&#xff1a;设置->高级->打开您计算机的代理设置->连接->局域网设置->代理服务器->在高级…

Vulnhub靶场-FRISTILEAKS: 1.3

1.环境准备 下载地址&#xff1a;https://www.vulnhub.com/entry/fristileaks-13,133/ 攻击机&#xff1a;kali&#xff08;192.168.26.128&#xff09; 靶机&#xff1a;FRISTILEAKS: 1.3 将靶机和kali的网络连接模式设置为同一种模式&#xff08;Nat模式&#xff09; 注…

【linux】linux中特殊权限管理--FACL详细用法教程与应用实战

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全…