Bert系列:Bert源码分析,MRPC文本分类任务微调

Bert源码工程介绍

工程地址在github仓库位置google-research/bert,该工程包含多个Python脚本,包括

  • modeling.py:定义Bert的网络结构,主要transformer,embedding,pool等网络模块
  • run_classifier.py:基于Bert网络开启一个文本分类任务,如果指定了预训练模型,基于预训练模型的参数再训练做微调
  • run_pretraining.py:Bert的预训练部分,包括NSP任务和MLM任务
  • create_pretraining_data.py:制作预训练数据
  • tokenization.py:一些句子处理工具模块,包括分词,标点处理,格式统一等
  • run_squad.py:配置和启动基于bert在squad数据集上的问答任务
  • extract_features.py:通过Bert计算句子向量
  • optimization.py:定义了模型训练的优化器模块

在上一篇文章介绍完Bert,Transformer,预训练模型,微调的基本概念和关系之后,本篇从Bert的官方源码入手进行源码跟读学习,先从最容易地直接应用Bert预训练模型进行MRPC任务微调入手,以run_classifier.py脚本为入口。


MRPC任务介绍

MPRC的学习目标是给定两个句子,判断这两个句子是否说的是一个意思,相当于输入一对句子做二分类。样例数据如下

Quality #1 ID   #2 ID   #1 String       #2 String
1       702876  702977  Amrozi accused his brother , whom he called " the witness " , of deliberately distorting his evidence . Referring to him as only " the witness " , Amrozi accused his brother of deliberately distorting his evidence .

第一列代表y值,1意思相同,2意思不同,后面分别是句子1的id,句子2的id,句子1的内容,句子2的内容。相当于输入一对句子给模型,而Bert的预训练部分也是输入也是一对句子,两者输入基本相同,预训练基于输入无监督学习语义知识,微调部分基于输入迁移预训练的模型参数去做分类。
从网络上下载预训练模型uncased_L-2_H-128_A-2.zip(2层transformer,128维embedding,BERT-Tiny)和对应的MRPC数据,使用如下脚本即可允许训练和验证过程跑通模型

python run_classifier.py --task_name=MRPC --do_train=true --do_eval=true --data_dir=./bert-master/GLUE_MRPC --vocab_file=./bert-master/bert_base_model/vocab.txt --bert_config_file=./bert-master/bert_base_model/bert_config.json  --max_seq_length=128 --train_batch_size=32  --init_checkpoint=./bert-master/bert_base_model/bert_model.ckpt --learning_rate=2e-5 --num_train_epochs=3 --output_dir=/tmp/mrpc_output

运行结束验证集模型效果如下,验证集准确率达到0.710。

I0814 21:25:02.392750 140513357039424 run_classifier.py:993] ***** Eval results *****
INFO:tensorflow:  eval_accuracy = 0.7107843
INFO:tensorflow:  eval_loss = 0.56687844
INFO:tensorflow:  global_step = 343
INFO:tensorflow:  loss = 0.56687844


输入层,数据格式要求

进入run_classifier.py源码,从main入口开始看,第一步是构造数据,实例化一个MRPC的数据处理类MrpcProcessor,他的目的是读取训练,验证,测试数据,以及将y值,句子1,句子2全部写入Python内存集合中。

# 实例化MrpcProcessor
    processor = processors[task_name]()

然后实例化一个分词工具tokenizer,它的目的是在下面构造样本阶段提供空格分词wordpiece,以及token转idid转token的功能。

# 实例化一个分词信息类
    tokenizer = tokenization.FullTokenizer(
        # True
        vocab_file=FLAGS.vocab_file, do_lower_case=FLAGS.do_lower_case)

然后开始读取样本数据到Python集合,返回一个list of InputExample对象。

train_examples = processor.get_train_examples(FLAGS.data_dir)

每个InputExample包含全局样本id,句子1,句子2,y值。

class InputExample(object):
    def __init__(self, guid, text_a, text_b=None, label=None):
        self.guid = guid
        self.text_a = text_a
        self.text_b = text_b
        self.label = label

下一步将Python内存样本数据转化为tfrecord格式的磁盘数据,当数据量较大时不能一把将所有数据load到内存,此时训练过程中的数据IO会影响训练效率,因此将数据先转化为tfrecord提高效率。

train_file = os.path.join(FLAGS.output_dir, "train.tf_record")
        # 将list InputExample转化为tfrecord,写入/tmp/mrpc_output/train.tf_record
        file_based_convert_examples_to_features(
            train_examples, label_list, FLAGS.max_seq_length, tokenizer, train_file)

对Python集合样本数据逐行遍历,构造成key:value格式

feature = convert_single_example(ex_index, example, label_list,
                                         max_seq_length, tokenizer)
        def create_int_feature(values):
            f = tf.train.Feature(int64_list=tf.train.Int64List(value=list(values)))
            return f

        # 在5个特征5列
        features = collections.OrderedDict()
        features["input_ids"] = create_int_feature(feature.input_ids)
        features["input_mask"] = create_int_feature(feature.input_mask)
        features["segment_ids"] = create_int_feature(feature.segment_ids)
        # 改为list
        features["label_ids"] = create_int_feature([feature.label_id])
        features["is_real_example"] = create_int_feature(
            [int(feature.is_real_example)])

        tf_example = tf.train.Example(features=tf.train.Features(feature=features))
        # 一行一行写入
        writer.write(tf_example.SerializeToString())

将单个InputExample对象转化为tfrecord格式的逻辑如下,首先对句子长度进行截取最大长度128

    if tokens_b:
        # 如果tokens_a,tokens_b太长超过128,进行均匀截取,最大长度max_seq_length - 3,要留三个给[CLS], [SEP], [SEP]
        _truncate_seq_pair(tokens_a, tokens_b, max_seq_length - 3)
    else:
        # Account for [CLS] and [SEP] with "- 2"
        if len(tokens_a) > max_seq_length - 2:
            tokens_a = tokens_a[0:(max_seq_length - 2)]

当Bert的输入是一个句子时有两个特殊符[CLS],[SEP],当输入是一对句子时有三个特殊符[CLS],[SEP],[SEP],因此最大字符串长度要对应减去2或者3。剩下的超长部分字符串从右侧截取,如果是两个句子谁长截取谁。
下面开始构造符合Bert输入的token_id和type_ids,作者的代码备注如下

    # The convention in BERT is:
    # (a) For sequence pairs:
    #  tokens:   [CLS] is this jack ##son ##ville ? [SEP] no it is not . [SEP]
    #  type_ids: 0     0  0    0    0     0       0 0     1  1  1  1   1 1
    # (b) For single sequences:
    #  tokens:   [CLS] the dog is hairy . [SEP]
    #  type_ids: 0     0   0   0  0     0 0

单句子和一对句子已经在上文有介绍,新出现的type_ids代表句子编号,第一句都是0,第二句都是1。
作者将[SEP],[CLS]拼接原始的分词数据里面,然后对所有分词做了数字id转换

input_ids = tokenizer.convert_tokens_to_ids(tokens)

再此基础上构造mask,所有mask都是以0填充

input_mask = [1] * len(input_ids)

    # Zero-pad up to the sequence length.
    # 如果超过128,已经在前面处理成最大128了 while不进入
    while len(input_ids) < max_seq_length:
        # 所有padding全是0 [PAD]
        input_ids.append(0)
        input_mask.append(0)
        segment_ids.append(0)

数据构造完成,在日志里面作者打印出了5条样本,比如其中一条,特征包含tokensinput_idsinput_masksegment_ids

INFO:tensorflow:guid: dev-1
INFO:tensorflow:tokens: [CLS] he said the foods ##er ##vic ##e pie business doesn ' t fit the company ' s long - term growth strategy . [SEP] " the foods ##er ##vic ##e pie business does not fit our long - term growth strategy . [SEP]
INFO:tensorflow:input_ids: 101 2002 2056 1996 9440 2121 7903 2063 11345 2449 2987 1005 1056 4906 1996 2194 1005 1055 2146 1011 2744 3930 5656 1012 102 1000 1996 9440 2121 7903 2063 11345 2449 2515 2025 4906 2256 2146 1011 2744 3930 5656 1012 102 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
INFO:tensorflow:input_mask: 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
INFO:tensorflow:segment_ids: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
INFO:tensorflow:label: 1 (id = 1)


Bert模型层,transformer结构

首先将预训练的Bert模型的可设置的参数读进来是一个字典的形式。

bert_config = modeling.BertConfig.from_json_file(FLAGS.bert_config_file)

{"hidden_size": 128, "hidden_act": "gelu", "initializer_range": 0.02, "vocab_size": 30522, "hidden_dropout_prob": 0.1, "num_attention_heads": 2, "type_vocab_size": 2, "max_position_embeddings": 512, "num_hidden_layers": 2, "intermediate_size": 512, "attention_probs_dropout_prob": 0.1}

主要包括隐藏层大小(词表embedding维度,以及多头self attention之后每个词的embedding维度),隐藏层激活函数,词表大小,dropout比例等。
下一步计算总训练step数,以及需要分配多少step用于warm up学习率

# 计算总共多少step=343
        num_train_steps = int(
            # train_batch_size = 32
            # num_train_epochs = 3
            len(train_examples) / FLAGS.train_batch_size * FLAGS.num_train_epochs)
        # warmup_proportion=0.1,预热学习率,先以一个较小的学习率进行学习,然后再恢复为指定学习率,34
        num_warmup_steps = int(num_train_steps * FLAGS.warmup_proportion)

warmup_proportion=0.1代表前10%的step的学习率先从一个很小的值慢慢变大到设置的真实学习率,目的是为了模型在训练初期小步前进,防止模型的初始化参数和新任务不匹配,学习率太大导致无法收敛。
下一步构建模型输入函数

model_fn = model_fn_builder(
        bert_config=bert_config,
        num_labels=len(label_list),
        init_checkpoint=FLAGS.init_checkpoint,
        learning_rate=FLAGS.learning_rate,
        num_train_steps=num_train_steps,
        num_warmup_steps=num_warmup_steps,
        use_tpu=FLAGS.use_tpu,
        use_one_hot_embeddings=FLAGS.use_tpu)

跟进model_fn,作者在其中创建了Bert模型,并且拿到之前tfrecord制作的特征输入模型,基于一个二分类任务的y值计算了一次正向传播拿到了loss

# TODO 正向传播
        (total_loss, per_example_loss, logits, probabilities) = create_model(
            bert_config, is_training, input_ids, input_mask, segment_ids, label_ids,
            num_labels, use_one_hot_embeddings)

跟进create_model,这个方法定了Bert模型

model = modeling.BertModel(
        config=bert_config,
        is_training=is_training,
        input_ids=input_ids,
        input_mask=input_mask,
        token_type_ids=segment_ids,
        use_one_hot_embeddings=use_one_hot_embeddings)

跟进BertModel,这里有Bert的模型结构,首先作者构建了一个全部词表的embedding映射table,维度128,将input_ids输入进去拿到映射后的稠密向量。

            with tf.variable_scope("embeddings"):
                # Perform embedding lookup on the word ids.
                # 给出输入的embedding映射,以及lookup表
                (self.embedding_output, self.embedding_table) = embedding_lookup(
                    input_ids=input_ids,
                    vocab_size=config.vocab_size,
                    embedding_size=config.hidden_size,
                    initializer_range=config.initializer_range,
                    word_embedding_name="word_embeddings",
                    use_one_hot_embeddings=use_one_hot_embeddings)

然后对输出的embedding进行后处理,包括加入segment_id和pos_id的映射相加的结果,在做layer norm和dropout。

self.embedding_output = embedding_postprocessor(
                    input_tensor=self.embedding_output,
                    use_token_type=True,
                    token_type_ids=token_type_ids,
                    token_type_vocab_size=config.type_vocab_size,
                    token_type_embedding_name="token_type_embeddings",
                    use_position_embeddings=True,
                    position_embedding_name="position_embeddings",
                    initializer_range=config.initializer_range,
                    max_position_embeddings=config.max_position_embeddings,
                    dropout_prob=config.hidden_dropout_prob)

在构造位置编码的时候作者直接向前划去前128个位置的随机初始化向量作为位置编码,因为本例中限制了输入最大长度128

position_embeddings = tf.slice(full_position_embeddings, [0, 0],
                                           [seq_length, -1])

在将三个embedding相加之后所有输入准备完毕,进入encoder阶段,encoder和Transformer模型的内容一致,这里不做展开

self.all_encoder_layers = transformer_model(
                    input_tensor=self.embedding_output,
                    attention_mask=attention_mask,
                    hidden_size=config.hidden_size,  # 128
                    num_hidden_layers=config.num_hidden_layers,  # 2
                    num_attention_heads=config.num_attention_heads,  # 2
                    intermediate_size=config.intermediate_size,  # 512
                    intermediate_act_fn=get_activation(config.hidden_act),  # gelu激活函数
                    hidden_dropout_prob=config.hidden_dropout_prob,  # 0.1
                    attention_probs_dropout_prob=config.attention_probs_dropout_prob,  # 0.1
                    initializer_range=config.initializer_range,  # 0.02
                    do_return_all_layers=True)

输出self.all_encoder_layers是一个列表,记录了每个transformer block的结果,作者拿到最后一个transformer block的结果作为整个encoder层的输出

self.sequence_output = self.all_encoder_layers[-1]

最后作者将第一个位置[CLS]这个词的embedding输出拿到,并且对他额外做了一层全连接

            with tf.variable_scope("pooler"):
                # 0:1第一个词 => [None, 1, 128] => [None, 128]
                first_token_tensor = tf.squeeze(self.sequence_output[:, 0:1, :], axis=1)
                # [None, 128]
                # 取第一个词做全连接
                self.pooled_output = tf.layers.dense(
                    first_token_tensor,
                    config.hidden_size,  # 128
                    activation=tf.tanh,
                    kernel_initializer=create_initializer(config.initializer_range))

最终这个self.pooled_output是一个[None, 128]维度的张量。


下游任务微调网络

下游任务是MRPC的分类任务,判断两个句子是不是一个意思,作者直接拿到Transformer层的输出self.pooled_output,在加一层全连接映射到y值上计算拿到loss

output_layer = model.get_pooled_output()

    hidden_size = output_layer.shape[-1].value

    # 这个output_weights和output_bias是唯一不是ckpt复现出来的
    output_weights = tf.get_variable(
        "output_weights", [num_labels, hidden_size],
        initializer=tf.truncated_normal_initializer(stddev=0.02))

    output_bias = tf.get_variable(
        "output_bias", [num_labels], initializer=tf.zeros_initializer())

    with tf.variable_scope("loss"):
        if is_training:
            # I.e., 0.1 dropout
            output_layer = tf.nn.dropout(output_layer, keep_prob=0.9)

        # 手动实现的对数似然损失
        # 直接输出到目标
        logits = tf.matmul(output_layer, output_weights, transpose_b=True)
        logits = tf.nn.bias_add(logits, output_bias)
        probabilities = tf.nn.softmax(logits, axis=-1)
        log_probs = tf.nn.log_softmax(logits, axis=-1)

        one_hot_labels = tf.one_hot(labels, depth=num_labels, dtype=tf.float32)

        per_example_loss = -tf.reduce_sum(one_hot_labels * log_probs, axis=-1)
        loss = tf.reduce_mean(per_example_loss)

当mode为训练时,作者又手写了训练操作

        if mode == tf.estimator.ModeKeys.TRAIN:

            # 梯度修剪一次
            # TODO 反向传播
            train_op = optimization.create_optimizer(
                total_loss, learning_rate, num_train_steps, num_warmup_steps, use_tpu)

            output_spec = tf.contrib.tpu.TPUEstimatorSpec(
                mode=mode,
                loss=total_loss,
                train_op=train_op,
                scaffold_fn=scaffold_fn)

这个train_op包含一个warm up学习率的逻辑

    if num_warmup_steps:
        global_steps_int = tf.cast(global_step, tf.int32)
        warmup_steps_int = tf.constant(num_warmup_steps, dtype=tf.int32)

        global_steps_float = tf.cast(global_steps_int, tf.float32)
        warmup_steps_float = tf.cast(warmup_steps_int, tf.float32)
        # global_steps_float增大,warmup_learning_rate逐渐增大
        warmup_percent_done = global_steps_float / warmup_steps_float
        warmup_learning_rate = init_lr * warmup_percent_done

        is_warmup = tf.cast(global_steps_int < warmup_steps_int, tf.float32)
        # 要么是learning_rate要么是warmup_learning_rate
        learning_rate = (
                (1.0 - is_warmup) * learning_rate + is_warmup * warmup_learning_rate)

同时自己写了个优化器,包括学习率衰减,参数权重的迭代更新逻辑。

optimizer = AdamWeightDecayOptimizer(
        learning_rate=learning_rate,
        weight_decay_rate=0.01,
        beta_1=0.9,
        beta_2=0.999,
        epsilon=1e-6,
        exclude_from_weight_decay=["LayerNorm", "layer_norm", "bias"])

下面构造estimator,注意如果run_config里面有model_dir则mode为EVAL,直接读取训练好的模型进行评估

estimator = tf.contrib.tpu.TPUEstimator(
        # False
        use_tpu=FLAGS.use_tpu,
        model_fn=model_fn,
        config=run_config,
        train_batch_size=FLAGS.train_batch_size,  # 32
        eval_batch_size=FLAGS.eval_batch_size,  # 8
        predict_batch_size=FLAGS.predict_batch_size)  # 8

最后读取tfrecord磁盘地址文件,构造输入函数,给道estimator进行训练

train_input_fn = file_based_input_fn_builder(
            input_file=train_file,
            seq_length=FLAGS.max_seq_length,
            is_training=True,
            drop_remainder=True)
        estimator.train(input_fn=train_input_fn, max_steps=num_train_steps)


预训练模型参数迁移

作者在构建模型之后,通过tf.train.init_from_checkpoint将预训练模型的参数从ckpt检查点原封不动地迁移到新构建的Bert网络中同名的参数上

        if init_checkpoint:
            (assignment_map, initialized_variable_names
             ) = modeling.get_assignment_map_from_checkpoint(tvars, init_checkpoint)
            if use_tpu:

                def tpu_scaffold():
                    tf.train.init_from_checkpoint(init_checkpoint, assignment_map)
                    return tf.train.Scaffold()

                scaffold_fn = tpu_scaffold
            else:
                # 从ckpt中把同名参数的变量的值恢复到新网络中
                tf.train.init_from_checkpoint(init_checkpoint, assignment_map)

迁移的参数包括

变量名维度是否从ckpt迁移
bert/embeddings/word_embeddings:0,(30522,128),INIT_FROM_CKPT
bert/embeddings/token_type_embeddings:0,(2,128),INIT_FROM_CKPT
bert/embeddings/position_embeddings:0,(512,128),INIT_FROM_CKPT
bert/embeddings/LayerNorm/beta:0,(128),INIT_FROM_CKPT
bert/embeddings/LayerNorm/gamma:0,(128),INIT_FROM_CKPT
bert/encoder/layer_0/attention/self/query/kernel:0,(128,128),INIT_FROM_CKPT
bert/encoder/layer_0/attention/self/query/bias:0,(128),INIT_FROM_CKPT
bert/encoder/layer_0/attention/self/key/kernel:0,(128,128),INIT_FROM_CKPT
bert/encoder/layer_0/attention/self/key/bias:0,(128),INIT_FROM_CKPT
bert/encoder/layer_0/attention/self/value/kernel:0,(128,128),INIT_FROM_CKPT
bert/encoder/layer_0/attention/self/value/bias:0,(128),INIT_FROM_CKPT
bert/encoder/layer_0/attention/output/dense/kernel:0,(128,128),INIT_FROM_CKPT
bert/encoder/layer_0/attention/output/dense/bias:0,(128),INIT_FROM_CKPT
bert/encoder/layer_0/attention/output/LayerNorm/beta:0,(128),INIT_FROM_CKPT
bert/encoder/layer_0/attention/output/LayerNorm/gamma:0,(128),INIT_FROM_CKPT
bert/encoder/layer_0/intermediate/dense/kernel:0,(128,512),INIT_FROM_CKPT
bert/encoder/layer_0/intermediate/dense/bias:0,(512),INIT_FROM_CKPT
bert/encoder/layer_0/output/dense/kernel:0,(512,128),INIT_FROM_CKPT
bert/encoder/layer_0/output/dense/bias:0,(128),INIT_FROM_CKPT
bert/encoder/layer_0/output/LayerNorm/beta:0,(128),INIT_FROM_CKPT
bert/encoder/layer_0/output/LayerNorm/gamma:0,(128),INIT_FROM_CKPT
bert/encoder/layer_1/attention/self/query/kernel:0,(128,128),INIT_FROM_CKPT
bert/encoder/layer_1/attention/self/query/bias:0,(128),INIT_FROM_CKPT
bert/encoder/layer_1/attention/self/key/kernel:0,(128,128),INIT_FROM_CKPT
bert/encoder/layer_1/attention/self/key/bias:0,(128),INIT_FROM_CKPT
bert/encoder/layer_1/attention/self/value/kernel:0,(128,128),INIT_FROM_CKPT
bert/encoder/layer_1/attention/self/value/bias:0,(128),INIT_FROM_CKPT
bert/encoder/layer_1/attention/output/dense/kernel:0,(128,128),INIT_FROM_CKPT
bert/encoder/layer_1/attention/output/dense/bias:0,(128),INIT_FROM_CKPT
bert/encoder/layer_1/attention/output/LayerNorm/beta:0,(128),INIT_FROM_CKPT
bert/encoder/layer_1/attention/output/LayerNorm/gamma:0,(128),INIT_FROM_CKPT
bert/encoder/layer_1/intermediate/dense/kernel:0,(128,512),INIT_FROM_CKPT
bert/encoder/layer_1/intermediate/dense/bias:0,(512),INIT_FROM_CKPT
bert/encoder/layer_1/output/dense/kernel:0,(512,128),INIT_FROM_CKPT
bert/encoder/layer_1/output/dense/bias:0,(128),INIT_FROM_CKPT
bert/encoder/layer_1/output/LayerNorm/beta:0,(128),INIT_FROM_CKPT
bert/encoder/layer_1/output/LayerNorm/gamma:0,(128),INIT_FROM_CKPT
bert/pooler/dense/kernel:0,(128,128),INIT_FROM_CKPT
bert/pooler/dense/bias:0,(128),INIT_FROM_CKPT
output_weights:0,(2, 128)
output_bias:0,(2,)

其中只有微调层的全连接和偏置是新模型自己初始化的,其他参数都是从预训练模型进行迁移,最终将所有参数融合在一起进行训练。预训练模型的参数包括词向量,位置编码,segment编码,每层Transformer的QKV参数,以及全连接层参数。全部参数共计4386178个,440万,其中词向量独占390万,占比89%,由此可见如果预训练部分能训练出很好的词向量,则微调部分就越容易,因为词向量的调整占微调的第一大头。
如果此处init_checkpoint为None,则不使用预训练模型,直接使用新网络随机初始化的embedding进行训练,运行如下

python run_classifier.py --task_name=MRPC --do_train=true --do_eval=true --data_dir=./bert-master/GLUE_MRPC --vocab_file=./bert-master/bert_base_model/vocab.txt --bert_config_file=./bert-master/bert_base_model/bert_config.json  --max_seq_length=128 --train_batch_size=32 --learning_rate=2e-5 --num_train_epochs=3 --output_dir=/tmp/mrpc_output

验证集模型准确率如下,准确率只有0.683

I0814 21:21:21.268342 140291776911168 run_classifier.py:993] ***** Eval results *****
INFO:tensorflow:  eval_accuracy = 0.6838235
INFO:tensorflow:  eval_loss = 0.6237707
INFO:tensorflow:  global_step = 343
INFO:tensorflow:  loss = 0.6237707

相比使用预训练模型的效果0.71下降3个点,由此也体现了在大数据上做预训练+微调,相比于对某个样本直接建模模型效果更好的优势。

最后的最后

感谢你们的阅读和喜欢,我收藏了很多技术干货,可以共享给喜欢我文章的朋友们,如果你肯花时间沉下心去学习,它们一定能帮到你。

因为这个行业不同于其他行业,知识体系实在是过于庞大,知识更新也非常快。作为一个普通人,无法全部学完,所以我们在提升技术的时候,首先需要明确一个目标,然后制定好完整的计划,同时找到好的学习方法,这样才能更快的提升自己。

这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

一、全套AGI大模型学习路线

AI大模型时代的学习之旅:从基础到前沿,掌握人工智能的核心技能!

img

二、640套AI大模型报告合集

这套包含640份报告的合集,涵盖了AI大模型的理论研究、技术实现、行业应用等多个方面。无论您是科研人员、工程师,还是对AI大模型感兴趣的爱好者,这套报告合集都将为您提供宝贵的信息和启示。

img

三、AI大模型经典PDF籍

随着人工智能技术的飞速发展,AI大模型已经成为了当今科技领域的一大热点。这些大型预训练模型,如GPT-3、BERT、XLNet等,以其强大的语言理解和生成能力,正在改变我们对人工智能的认识。 那以下这些PDF籍就是非常不错的学习资源。

img

四、AI大模型商业化落地方案

img
这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

  • 18
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
cola、sst-2和mrpc都是自然语言处理(NLP)中常用的数据集。 cola代表的是Language Understanding Evaluation(LUKE)的共同事业片中的句子相似度任务(STS)。在这个任务中,我们需要判断两个句子之间的相似性。该数据集由句子配对组成,每个句子配对都有一个二进制标签,表示两个句子是否具有相似的语义。我们可以使用这个数据集来开发和评估句子相似度模型。 sst-2代表的是斯坦福树库(Stanford Sentiment Treebank)的二分类情感分类任务。在这个任务中,我们需要将一个句子分类为积极的(positive)还是消极的(negative)。这个数据集包含了大量的电影评论,每个评论都有一个情感标签。sst-2是一个常用的情感分类数据集,适用于训练和评估情感分类模型。 mrpc代表的是微软研究院发布的Microsoft Research Paraphrase Corpus。在这个任务中,我们需要判断两个句子是否是近义词(也称为“改写”或“释义”)。该数据集由句子配对组成,每个配对都有一个二进制标签,表示两个句子是否具有相似的语义。mrpc是一个常用的句子相似度数据集,适用于训练和评估句子相似度模型。 这三个数据集在NLP研究和应用中被广泛使用,可以帮助开发者和研究人员评估各种NLP模型的性能。通过在这些数据集上进行训练和测试,我们可以获得各种任务上的准确性、召回率和F1分数等指标,进而改进和优化NLP模型

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值