深入Bert实战(Pytorch)----fine-Tuning 2

深入Bert实战(Pytorch)----fine-Tuning 2

https://www.bilibili.com/video/BV1K5411t7MD?p=5
https://www.youtube.com/channel/UCoRX98PLOsaN8PtekB9kWrw/videos
深入BERT实战(PyTorch) by ChrisMcCormickAI
这是ChrisMcCormickAI在油管bert,8集系列第三篇fine-Tuning的pytorch的讲解的代码,在油管视频下有cloab地址,如果不能翻墙的可以留下邮箱我全部看完整理后发给你。但是在fine-tuning最好还是在cloab上运行


4. Train Our Classification Model

4.1. BertForSequenceClassification

对于这个任务,我们首先要修改预训练的BERT模型以给出分类输出,然后在自己的数据集上继续训练模型,直到整个模型(端到端的模型)非常适合自己的任务。

值得庆幸的是,huggingface pytorch实现包含一组为各种NLP任务设计的接口。尽管这些接口都建立在训练好的BERT模型之上,但每个接口都有不同的顶层和输出类型,以适应它们特定的NLP任务。

这里是目前提供的fine-tuning列表

  • BertModel
  • BertForPreTraining
  • BertForMaskedLM
  • BertForNextSentencePrediction
  • BertForSequenceClassification - The one we’ll use.
  • BertForTokenClassification
  • BertForQuestionAnswering

这里是transformer的文档here.

我们使用BertForSequenceClassification。这是普通的BERT模型,上面添加了一个用于分类的线性层,我们将使用它作为句子分类器。当我们输入数据时,整个预训练的BERT模型和额外的未训练的分类层是同时在这个任务上进行训练

好的,现在加载BERT!这里有几种不同的预训练模型,"bert-base-uncased"版本,仅有小写字母(“uncased”)相比于是较小的(“base” vs “large”)。

预训练的文档在from_pretrainedhere 定义了其它参数 here

from transformers import BertForSequenceClassification, AdamW, BertConfig

# Load BertForSequenceClassification, the pretrained BERT model with a single 
# linear classification layer on top. 
# 加载BertForSequenceClassification,预训练的模型+顶层单层线性分类层
model = BertForSequenceClassification.from_pretrained(
    "bert-base-uncased", # Use the 12-layer BERT model, with an uncased vocab.
    num_labels = 2, # The number of output labels--2 for binary classification.
                    # You can increase this for multi-class tasks.
    # 2分类问题,可以增加为多分类问题
    output_attentions = False, # Whether the model returns attentions weights.
    output_hidden_states = False, # Whether the model returns all hidden-states.
)

# Tell pytorch to run this model on the GPU.
model.cuda()

出于好奇,我们可以在这里按名称浏览所有的模型参数。
在下面的单元格中,我打印出了以下权重的名称和尺寸:

这里作者打印了所有层,总共有201层,也打印了权重和大小

  1. The embedding layer.
  2. The first of the twelve transformers.
  3. The output layer.
# Get all of the model's parameters as a list of tuples.
params = list(model.named_parameters())

print('The BERT model has {:} different named parameters.\n'.format(len(params)))

print('==== Embedding Layer ====\n')

for p in params[0:5]:
    print("{:<55} {:>12}".format(p[0], str(tuple(p[1].size()))))

print('\n==== First Transformer ====\n')

for p in params[5:21]:
    print("{:<55} {:>12}".format(p[0], str(tuple(p[1].size()))))

print('\n==== Output Layer ====\n')

for p in params[-4:]:
    print("{:<55} {:>12}".format(p[0], str(tuple(p[1].size()))))
The BERT model has 201 different named parameters.

==== Embedding Layer ====

bert.embeddings.word_embeddings.weight                  (30522, 768)
bert.embeddings.position_embeddings.weight                (512, 768)
bert.embeddings.token_type_embeddings.weight                (2, 768)
bert.embeddings.LayerNorm.weight                              (768,)
bert.embeddings.LayerNorm.bias                                (768,)

==== First Transformer ====

bert.encoder.layer.0.attention.self.query.weight          (768, 768)
bert.encoder.layer.0.attention.self.query.bias                (768,)
bert.encoder.layer.0.attention.self.key.weight            (768, 768)
bert.encoder.layer.0.attention.self.key.bias                  (768,)
bert.encoder.layer.0.attention.self.value.weight          (768, 768)
bert.encoder.layer.0.attention.self.value.bias                (768,)
bert.encoder.layer.0.attention.output.dense.weight        (768, 768)
bert.encoder.layer.0.attention.output.dense.bias              (768,)
bert.encoder.layer.0.attention.output.LayerNorm.weight        (768,)
bert.encoder.layer.0.attention.output.LayerNorm.bias          (768,)
bert.encoder.layer.0.intermediate.dense.weight           (3072, 768)
bert.encoder.layer.0.intermediate.dense.bias                 (3072,)
bert.encoder.layer.0.output.dense.weight                 (768, 3072)
bert.encoder.layer.0.output.dense.bias                        (768,)
bert.encoder.layer.0.output.LayerNorm.weight                  (768,)
bert.encoder.layer.0.output.LayerNorm.bias                    (768,)

==== Output Layer ====

bert.pooler.dense.weight                                  (768, 768)
bert.pooler.dense.bias                                        (768,)
classifier.weight                                           (2, 768)
classifier.bias                                                 (2,)

4.2. Optimizer & Learning Rate Scheduler

现在我们已经加载了模型,我们需要从存储的模型中获取训练超参数。

为了进行微调,作者建议从以下值中进行选择。(从论文的注释 BERT paper):

  • Batch size: 16, 32
  • Learning rate (Adam): 5e-5, 3e-5, 2e-5
  • Number of epochs: 2, 3, 4

作者选择的参数是:

  • Batch size: 32 (set when creating our DataLoaders)
  • Learning rate: 2e-5
  • Epochs: 4 (we’ll see that this is probably too many…)

参数eps = 1e-8 是"a very small number to prevent any division by zero in the implementation"(from here)

您可以在run_glue.py中找到创建AdamW优化器的方法here.

# Note: AdamW is a class from the huggingface library (as opposed to pytorch) 
# AdamW是huggingface实现的类
# I believe the 'W' stands for 'Weight Decay fix"
optimizer = AdamW(model.parameters(),
                  lr = 2e-5, # args.learning_rate - default is 5e-5, our notebook had 2e-5
                  eps = 1e-8 # args.adam_epsilon  - default is 1e-8.
                )
from transformers import get_linear_schedule_with_warmup

# Number of training epochs. The BERT authors recommend between 2 and 4. 
# We chose to run for 4, but we'll see later that this may be over-fitting the
# training data.
epochs = 4

# Total number of training steps is [number of batches] x [number of epochs]. 
# (Note that this is not the same as the number of training samples).
total_steps = len(train_dataloader) * epochs    # 总共4 * 241批

# Create the learning rate scheduler.
scheduler = get_linear_schedule_with_warmup(optimizer, 
                                            num_warmup_steps = 0, # Default value in run_glue.py
                                            num_training_steps = total_steps)

4.3. 循环训练

下面是我们的训练循环。有很多事情要做,但从根本上来说,对于循环中的每一个过程,我们都有一个training阶段和一个validation阶段。

Thank you to Stas Bekman for contributing the insights and code for using validation loss to detect over-fitting!

Training:

  • 打开我们的数据 inputs 和 labels
  • 加载数据到GPU上
  • 清除之前计算的梯度。
    • 在pytorch中,除非显式清除梯度,否则梯度默认累积(对于rnn之类的东西很有用)。
  • Forward pass(通过网络输入数据)
  • Backward pass 反向传播
  • 告诉网络使用optimizer.step()更新参数
  • 监控进度,跟踪变量

Evalution:

  • 同训练过程一样,打开inputs 和 labels
  • 加载数据到GPU上
  • Forward pass(通过网络输入数据)
  • 计算我们验证数据的损失,监控进度,跟踪变量

Pytorch向我们隐藏了所有详细的计算,但是我们已经对代码进行了注释,指出了每一行上发生的上述步骤。

定义一个计算精度的辅助函数。

import numpy as np

# Function to calculate the accuracy of our predictions vs labels
# 这个函数来计算预测值和labels的准确度
def flat_accuracy(preds, labels):
    pred_flat = np.argmax(preds, axis=1).flatten()    # 取出最大值对应的索引
    labels_flat = labels.flatten()
    return np.sum(pred_flat == labels_flat) / len(labels_flat)

格式化函数时间

import time
import datetime

def format_time(elapsed):
    '''
    Takes a time in seconds and returns a string hh:mm:ss
    '''
    # Round to the nearest second.    四舍五入
    elapsed_rounded = int(round((elapsed)))
    
    # Format as hh:mm:ss
    return str(datetime.timedelta(seconds=elapsed_rounded))

现在开始训练,这里要修改一部分代码,作者给的代码有个地方要做修改,参考run_glue.py

import random
import numpy as np

# This training code is based on the `run_glue.py` script here:
# https://github.com/huggingface/transformers/blob/5bfcd0485ece086ebcbed2d008813037968a9e58/examples/run_glue.py#L128

# Set the seed value all over the place to make this reproducible. 保证可重复性
seed_val = 42

random.seed(seed_val)
np.random.seed(seed_val)
torch.manual_seed(seed_val)
torch.cuda.manual_seed_all(seed_val)

# We'll store a number of quantities(保存如) such as training and validation loss, 
# validation accuracy, and timings.(训练loss, 验证loss, 验证准确率,训练时间)
training_stats = []

# Measure the total training time for the whole run. 总训练时间
total_t0 = time.time()

# For each epoch...
for epoch_i in range(0, epochs):
    
    # ========================================
    #               Training
    # ========================================
    # 对训练集进行一次完整的测试。
    print("")
    print('======== Epoch {:} / {:} ========'.format(epoch_i + 1, epochs))
    print('Training...')

    # Measure how long the training epoch takes.
    t0 = time.time()

    # Reset the total loss for this epoch.
    total_train_loss = 0

    # Put the model into training mode. Don't be mislead--the call to 
    # `train` just changes the *mode*, it doesn't *perform* the training.
    # 这里并不是执行的训练,而是,实例化启用 BatchNormalization 和 Dropout
    # `dropout` and `batchnorm` layers behave differently during training
    # vs. test (source: https://stackoverflow.com/questions/51433378/what-does-model-train-do-in-pytorch)
    model.train()

    # For each batch of training data...
    for step, batch in enumerate(train_dataloader):    # 共241个batches

        # Progress update every 40 batches.    40步打印一次
        if step % 40 == 0 and not step == 0:
            # Calculate elapsed time in minutes.
            elapsed = format_time(time.time() - t0)
            
            # Report progress.
            print('  Batch {:>5,}  of  {:>5,}.    Elapsed: {:}.'.format(step, len(train_dataloader), elapsed))
            # 例: Batch    40  of    241.    Elapsed: 0:00:08.

        # `batch` contains three pytorch tensors:
        #   [0]: input ids 
        #   [1]: attention masks
        #   [2]: labels 
        # 第一步的打开数据, 第二步 将数据放到GPU `to`方法
        b_input_ids = batch[0].to(device)
        b_input_mask = batch[1].to(device)
        b_labels = batch[2].to(device)

        # 在执行 backward pass 之前,始终清除任何先前计算的梯度。
        # PyTorch不会自动这样做,因为累积梯度“在训练rnn时很方便”。
        # (source: https://stackoverflow.com/questions/48001598/why-do-we-need-to-call-zero-grad-in-pytorch)
        model.zero_grad()    # 第三步,梯度清零      

        # 执行 forward pass (在此训练批次上对模型进行评估).
        # The documentation for this `model` function is here: 
        # https://huggingface.co/transformers/v2.2.0/model_doc/bert.html#transformers.BertForSequenceClassification
        # 它根据给定的参数和设置的标志返回不同数量的形参。
        # it returns the loss (because we provided labels) and the "logits"--the model outputs prior to activation.
        # 返回loss和"logits"--激活之前的模型输出。  model = BertForSequenceClassification
        output = model(b_input_ids, 
                             token_type_ids=None, 
                             attention_mask=b_input_mask, 
                             labels=b_labels)

        # 将所有批次的训练损失累积起来,这样我们就可以在最后计算平均损失。 
        # `loss` 是一个单个值的tensor; the `.item()` 函数将它转为一个python number
        loss, logits = output[:2]
        total_train_loss += loss.item()

        # 执行反向传播计算精度.
        loss.backward()

        # Clip the norm of the gradients to 1.0.
        # 梯度裁剪,防止梯度爆炸
        torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)

        # Update parameters and take a step using the computed gradient.
        # 更新参数,计算梯度
        # 优化器规定“update rule”——参数如何根据梯度、学习速率等进行修改。
        optimizer.step()

        # 更新学习率
        scheduler.step()

    # 计算平均loss
    avg_train_loss = total_train_loss / len(train_dataloader)            
    
    # 训练时间
    training_time = format_time(time.time() - t0)
    
    # 打印结果
    print("")
    print("  Average training loss: {0:.2f}".format(avg_train_loss))
    print("  Training epcoh took: {:}".format(training_time))
        
    # ========================================
    #               Validation
    # ========================================
    # 在验证集查看

    print("")
    print("Running Validation...")

    t0 = time.time()

    # 将模型置于评估模式 不使用BatchNormalization()和Dropout()
    model.eval()

    # 跟踪变量
    total_eval_accuracy = 0
    total_eval_loss = 0
    nb_eval_steps = 0

    # 在每个epoch上评估
    for batch in validation_dataloader:
        
        # `batch` contains three pytorch tensors:
        #   [0]: input ids 
        #   [1]: attention masks
        #   [2]: labels 
        b_input_ids = batch[0].to(device)
        b_input_mask = batch[1].to(device)
        b_labels = batch[2].to(device)
        
        # Tell pytorch not to bother with constructing the compute graph during
        # the forward pass, since this is only needed for backprop (training).
        with torch.no_grad():        

            # Forward pass, calculate logit predictions.
            # token_type_ids is the same as the "segment ids", which 
            # differentiates sentence 1 and 2 in 2-sentence tasks.
            # The documentation for this `model` function is here: 
            # https://huggingface.co/transformers/v2.2.0/model_doc/bert.html#transformers.BertForSequenceClassification
            # Get the "logits" output by the model. The "logits" are the output
            # values prior to applying an activation function like the softmax.
            (loss, logits) = model(b_input_ids, 
                                   token_type_ids=None, 
                                   attention_mask=b_input_mask,
                                   labels=b_labels)
            
        # 计算验证损失
        loss, logits = output[:2]
        total_eval_loss += loss.item()

        # Move logits and labels to CPU
        logits = logits.detach().cpu().numpy()
        label_ids = b_labels.to('cpu').numpy()

        # Calculate the accuracy for this batch of test sentences, and
        # accumulate it over all batches.
        total_eval_accuracy += flat_accuracy(logits, label_ids)
        

    # 返回验证结果
    avg_val_accuracy = total_eval_accuracy / len(validation_dataloader)
    print("  Accuracy: {0:.2f}".format(avg_val_accuracy))

    # 计算平均复杂度
    avg_val_loss = total_eval_loss / len(validation_dataloader)
    
    # 时间
    validation_time = format_time(time.time() - t0)
    
    print("  Validation Loss: {0:.2f}".format(avg_val_loss))
    print("  Validation took: {:}".format(validation_time))

    # 记录这个epoch的所有统计数据。 方便后面可视化
    training_stats.append(
        {
            'epoch': epoch_i + 1,
            'Training Loss': avg_train_loss,
            'Valid. Loss': avg_val_loss,
            'Valid. Accur.': avg_val_accuracy,
            'Training Time': training_time,
            'Validation Time': validation_time
        }
    )

print("")
print("Training complete!")

print("Total training took {:} (h:mm:ss)".format(format_time(time.time()-total_t0)))

让我们来看看训练过程的总结。

import pandas as pd

# 显示浮点数小数点后两位。
pd.set_option('precision', 2)

# 从训练统计数据里,创建一个 DataFrame
df_stats = pd.DataFrame(data=training_stats)

# 用'epoch'行坐标
df_stats = df_stats.set_index('epoch')

# A hack to force the column headers to wrap.
#df = df.style.set_table_styles([dict(selector="th",props=[('max-width', '70px')])])

# Display the table.
df_stats
Training LossValid. LossValid. Accur.Training TimeValidation Time epoch
10.500.450.800:00:51
20.320.460.810:00:51
30.220.490.820:00:51
40.160.550.820:00:51

这里我跑这代码train loss没有下降,反而上升了,有了解这个问题的大大,麻烦请留言指教下

请注意,当训练损失随着时间的推移而下降时,验证损失却在增加!这表明我们训练模型的时间太长了,它对训练数据过于拟合。

(作为参考,我们使用了7,695个训练样本和856个验证样本)。

验证损失是比精度更精确的度量,因为有了精度,我们不关心确切的输出值,而只关心它落在阈值的哪一边。

如果我们预测的是正确的答案,但缺乏信心,那么验证损失将捕捉到这一点,而准确性则不会。

import matplotlib.pyplot as plt
% matplotlib inline

import seaborn as sns

# Use plot styling from seaborn.
sns.set(style='darkgrid')

# Increase the plot size and font size.
sns.set(font_scale=1.5)
plt.rcParams["figure.figsize"] = (12,6)

# 绘制学习曲线
plt.plot(df_stats['Training Loss'], 'b-o', label="Training")
plt.plot(df_stats['Valid. Loss'], 'g-o', label="Validation")

# Label the plot.
plt.title("Training & Validation Loss")
plt.xlabel("Epoch")
plt.ylabel("Loss")
plt.legend()
plt.xticks([1, 2, 3, 4])

plt.show()

在这里插入图片描述

5. 在测试集上的表现

现在,我们将加载holdout数据集并准备输入,就像我们对训练集所做的那样。然后,我们将使用Matthew’s correlation coefficient评估预测,因为这是更广泛的NLP社区用于评估CoLA性能的指标。在这个指标下,+1是最好的分数,-1是最差的分数。通过这种方式,我们可以看到针对这个特定任务的先进模型的性能如何。

5.1. 数据准备

我们需要应用与训练数据相同的所有步骤来准备测试数据集。

import pandas as pd

# 加载数据
df = pd.read_csv("./cola_public/raw/out_of_domain_dev.tsv", delimiter='\t', header=None, names=['sentence_source', 'label', 'label_notes', 'sentence'])

# 显示句子数量
print('Number of test sentences: {:,}\n'.format(df.shape[0]))

# 创建句子和标签列表
sentences = df.sentence.values
labels = df.label.values

# Tokenize 
input_ids = []
attention_masks = []

# For every sentence...
for sent in sentences:
    # `encode_plus` will:
    #   (1) Tokenize the sentence.
    #   (2) 添加 `[CLS]` token 到开始
    #   (3) 添加 `[SEP]` token 到结束
    #   (4) 映射tokens 到 IDs.
    #   (5) 填充或截断句子到`max_length`
    #   (6) Create attention masks for [PAD] tokens.
    encoded_dict = tokenizer.encode_plus(
                        sent,                      # 对句子做encode.
                        add_special_tokens = True, # Add '[CLS]' and '[SEP]'
                        max_length = 64,           # Pad & truncate all sentences.
                        pad_to_max_length = True,
                        return_attention_mask = True,   # Construct attn. masks.
                        return_tensors = 'pt',     # Return pytorch tensors.
                   )
    
    # 将已编码的句子添加到列表中。  
    input_ids.append(encoded_dict['input_ids'])
    
    # 以及它的注意力掩码(简单地区分填充和非填充)。
    attention_masks.append(encoded_dict['attention_mask'])

# Convert the lists into tensors.
input_ids = torch.cat(input_ids, dim=0)
attention_masks = torch.cat(attention_masks, dim=0)
labels = torch.tensor(labels)

# Set the batch size.  
batch_size = 32  

# Create the DataLoader.
prediction_data = TensorDataset(input_ids, attention_masks, labels)
prediction_sampler = SequentialSampler(prediction_data)
prediction_dataloader = DataLoader(prediction_data, sampler=prediction_sampler, batch_size=batch_size)

Number of test sentences: 516

5.2. 在测试集上评估

准备好测试集之后,我们可以应用我们的微调模型来生成测试集的预测。

# Prediction on test set

print('Predicting labels for {:,} test sentences...'.format(len(input_ids)))

# 在测试模型
model.eval()

# 跟踪变量 
predictions , true_labels = [], []

# Predict 
for batch in prediction_dataloader:
  # Add batch to GPU
  batch = tuple(t.to(device) for t in batch)
  
  # Unpack the inputs from our dataloader
  b_input_ids, b_input_mask, b_labels = batch
  
  # 不让模型计算或存储梯度,节省内存和加速预测
  with torch.no_grad():
      # Forward pass, calculate logit predictions
      outputs = model(b_input_ids, token_type_ids=None, 
                      attention_mask=b_input_mask)

  logits = outputs[0]

  # Move logits and labels to CPU
  logits = logits.detach().cpu().numpy()
  label_ids = b_labels.to('cpu').numpy()
  
  # Store predictions and true labels
  predictions.append(logits)
  true_labels.append(label_ids)

print('    DONE.')

CoLA基准的精度是用“Matthews correlation coefficient”来测量的。(MCC)。

我们在这里使用MCC是因为类是不平衡的:

print('Positive samples: %d of %d (%.2f%%)' % (df.label.sum(), len(df.label), (df.label.sum() / len(df.label) * 100.0)))

Positive samples: 354 of 516 (68.60%)

# 计算相关系数
from sklearn.metrics import matthews_corrcoef

matthews_set = []

# 使用Matthew相关系数对每个测试批进行评估
print('Calculating Matthews Corr. Coef. for each batch...')

# For each input batch...
for i in range(len(true_labels)):
  
  # 这个批处理的预测是一个2列的ndarray(一个列是“0”,一个列是“1”)。 
  # 选择值最高的label,并将其转换为0和1的列表。
  pred_labels_i = np.argmax(predictions[i], axis=1).flatten()
  
  # Calculate and store the coef for this batch.  
  matthews = matthews_corrcoef(true_labels[i], pred_labels_i)                
  matthews_set.append(matthews)

最终的分数将基于整个测试集,但是让我们看一下单个批次的分数,以了解批次之间度量的可变性。

每批有32个句子,除了最后一批只有(516% 32)= 4个测试句子。

创建一个柱状图,显示每批测试样品的MCC分数。

ax = sns.barplot(x=list(range(len(matthews_set))), y=matthews_set, ci=None)

plt.title('MCC Score per Batch')
plt.ylabel('MCC Score (-1 to +1)')
plt.xlabel('Batch #')

plt.show()

在这里插入图片描述
现在我们将合并所有批次的结果并计算我们最终的MCC分数。

# 合并所有批次的结果。
flat_predictions = np.concatenate(predictions, axis=0)

# 对于每个样本,选择得分较高的标签(0或1)。
flat_predictions = np.argmax(flat_predictions, axis=1).flatten()

# 将每个批次的正确标签组合成一个单独的列表。
flat_true_labels = np.concatenate(true_labels, axis=0)

# Calculate the MCC
mcc = matthews_corrcoef(flat_true_labels, flat_predictions)

print('Total MCC: %.3f' % mcc)

在大约半个小时的时间里,我们没有做任何超参数的调整(learning rate, epochs, batch size, ADAM properties属性等),我们就获得了一个很好的分数。

为了使分数最大化,我们应该删除“验证集”(我们用来帮助确定要训练多少个纪元),并在整个训练集上训练。

库将基准测试此处的预期精度文档为“49.23”。

官方排行 here.

请注意(由于数据集的大小较小?)在不同的运行中,精度可能会有很大的变化。

总结

这篇文章演示了使用预先训练好的BERT模型,不管你感兴趣的是什么特定的NLP任务,你都可以使用pytorch接口,用最少的努力和训练时间,快速有效地创建一个高质量的模型。

附录

A1. Saving & Loading Fine-Tuned Model

(取自’ run_glue。py 'here)将模型和标记器写入磁盘。

import os

# 保存best-practices:如果您使用模型的默认名称,您可以使用from_pretraining()重新加载它
# Saving best-practices: if you use defaults names for the model, you can reload it using from_pretrained()

output_dir = './model_save/'

# 如果需要,创建输出目录
if not os.path.exists(output_dir):
    os.makedirs(output_dir)

print("Saving model to %s" % output_dir)

# 使用`save_pretrained()`保存训练过的模型、配置和标记器。
# 用`from_pretrained()`重新加载模型。
model_to_save = model.module if hasattr(model, 'module') else model  # 注意distributed/parallel training
model_to_save.save_pretrained(output_dir)
tokenizer.save_pretrained(output_dir)

# Good practice: 保存训练好的模型于模型参数
# torch.save(args, os.path.join(output_dir, 'training_args.bin'))

Revision History

Version 3 - Mar 18th, 2020 - (current)

  • Simplified the tokenization and input formatting (for both training and test) by leveraging the tokenizer.encode_plus function.
    encode_plus handles padding and creates the attention masks for us.
  • Improved explanation of attention masks.
  • Switched to using torch.utils.data.random_split for creating the training-validation split.
  • Added a summary table of the training statistics (validation loss, time per epoch, etc.).
  • Added validation loss to the learning curve plot, so we can see if we’re overfitting.
  • Displayed the per-batch MCC as a bar plot.

Version 2 - Dec 20th, 2019 - link

  • huggingface renamed their library to transformers.
  • Updated the notebook to use the transformers library.

Version 1 - July 22nd, 2019

  • Initial version.
  • 2
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
### 回答1: PyTorch-BERT可以用于多标签任务。多标签任务是指一个样本可以同时被分配多个标签,而不是只有一个唯一的标签。PyTorch-BERT可以通过微调(fine-tuning)来处理多标签任务,具体步骤如下: 1. 数据预处理:首先将原始数据转换为特定的输入格式,即将每个样本编码为输入序列。对于文本分类任务,可以使用tokenizer将输入文本转换为BERT模型对应的输入格式。同时,每个样本的标签也需要进行处理,通常使用独热编码或多标签编码的方式表示多个标签。 2. 模型微调:使用经过预训练的BERT模型,将其权重加载到PyTorch模型中。然后将加载的模型与多标签分类器(如全连接层)结合,以适应多标签任务的需求。微调的目标是让BERT模型能够更好地适应特定的多标签任务。 3. 训练与评估:使用经过微调的模型对训练数据进行训练,并在验证集上进行评估。在训练过程中,通常使用交叉熵损失函数来计算模型的损失,并使用优化算法(如Adam)来更新模型的参数。 4. 预测:在模型训练完成后,可以使用经过微调的模型对新的未标记样本进行预测。模型将输出一个概率分布,表示每个标签是否存在的可能性。可以根据设定的阈值,将概率高于阈值的标签作为模型的预测结果。 总而言之,PyTorch-BERT可以通过微调的方式来处理多标签任务。在微调过程中,需要将BERT模型与多标签分类器结合,并进行相应的训练和评估。通过这种方式,PyTorch-BERT可以应用于各种多标签分类任务,如文本分类、图像标注等。 ### 回答2: PyTorch是一个开源的机器学习框架,它提供了一种强大的编程环境,可以用于构建和训练各种深度学习模型。BERT(Bidirectional Encoder Representations from Transformers)是一种预训练的自然语言处理模型,它能够有效地处理各种自然语言任务。 在PyTorch中使用BERT进行多标签分类任务,需要进行以下几个步骤: 1. 数据预处理:将文本数据转换为适合BERT模型输入的格式。首先,需要将文本分词并添加特殊标记(如"[CLS]"和"[SEP]")来标记句子的开头和结束。然后,将分词后的文本转换为词向量,可以使用BERT的预训练模型来获取词向量。 2. 构建模型:使用PyTorch构建多标签分类模型。可以使用BERT作为基本模型,然后添加适当的全连接层来实现多标签分类。这些全连接层可以将BERT模型的输出映射到具体的标签。在模型的训练过程中,可以使用交叉熵损失函数和梯度下降方法来优化模型的参数。 3. 模型训练:使用标注好的数据集对构建的模型进行训练。可以使用PyTorch提供的优化器(如AdamOptimizer)和内置的训练循环来简化训练过程。 4. 模型评估:使用测试集评估训练得到的模型的性能。可以使用各种指标(如准确率、精确率、召回率和F1分数)来评估模型的多标签分类性能。 总结起来,使用PyTorchBERT进行多标签分类任务,需要进行数据预处理、模型构建、模型训练和模型评估等步骤。通过合理设计模型结构和使用适当的优化算法,可以实现高效准确的多标签分类。 ### 回答3: PyTorch是一个很流行的深度学习框架,而BERT是一个非常强大的预训练模型,可以用于自然语言处理任务。当我们要处理多标签分类问题时,可以使用PyTorchBERT的组合来解决。 多标签分类是指一个样本可以被分配到多个类别中,而不仅仅是一个类别。在使用PyTorchBERT进行多标签分类时,我们首先需要对文本数据进行处理。我们可以使用BERT模型的tokenizer将文本转换为对应的token,然后将其转化为PyTorch的张量。 接下来,我们可以使用BERT模型进行特征提取。BERT模型可以将输入的token序列编码成固定长度的向量表示,这样可以保留输入句子的语义信息。通过BERT模型的输出,我们可以获取每个token的向量表示。 对于多标签分类问题,我们可以使用全连接层或者其他一些分类器来预测每个类别的概率。我们可以将BERT模型的输出连接到一个全连接层中,然后使用激活函数(如sigmoid函数)将输出的概率限制在0和1之间。 接着,我们可以使用交叉熵损失函数来计算模型的损失,并使用反向传播算法来更新模型的参数。在训练过程中,我们可以使用一些评估指标(如精确率、召回率、F1分数等)来评估模型在多标签分类任务上的性能。 为了优化模型的训练,我们可以使用一些技巧,如学习率调整、正则化、批量归一化等。此外,还可以使用数据增强技术来增加训练数据的多样性,从而提升模型的泛化能力。 总结来说,通过使用PyTorchBERT的组合,我们可以很方便地解决多标签分类问题。PyTorch提供了灵活的深度学习框架,而BERT则是一个强大的预训练模型,它们的结合可以帮助我们构建准确度高且性能优良的多标签分类模型。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值