专栏首页叫我NLPerRoBERTa多标签分类:你是最胖的!

RoBERTa多标签分类:你是最胖的!

一 :今日吐槽

啥是NSP?

还有你们口中的 MLM,LN,SGNS,都给我解释清楚!

NSP,就是 Next Sentence Prediction,是 BERT 的两大任务之一:输入两段文本,预测第二段是否为第一段的下文。

MLM,就是 Masked Language Model,是 BERT 的两大任务之二: 将输入文本中的最小单元,随机地用 [MASK] 标记进行替换,然后用上下文预测被替换的这个最小单元。

LN,就是 Lay Normanization,是对深度网络中,同层神经元的输入做归一化,使其拥有相同的均值和方差。

SGNS,就是 Skip-Gram with Negative Sampling,是 word2vec 中训练词向量的一种方法。Skip-Gram是指用中间的词,预测前后的词。而Negative Sampling是指负采样。

二:内容预告

本文尝试用 RoBERTa 做文本多标签分类。

RoBERTa 是2019年, Facebook 和华盛顿大学搞出来的一个BERT改进版。

RoBERTa中文名是: 萝卜塔, 英文全称是:A Robustly Optimized BERT Pretraining Approach。

Robust 的意思是:健壮的,粗野的。

所以你能猜到 RoBERATa 干了以下几件事:

更多数据,更大的batch size,更长的序列长度,更长的训练时间。

你以为就这些?

下面就来看看,这个号称打败XLNet、重建人们对MLM信仰的RoBERTa,到底是何方神圣。

本文主要关注以下四方面的内容:

  • RoBERTa有哪些改进的地方?
  • 哪些改进版可以用BERT官方代码加载?
  • 如何接多标签分类的下游任务?

三:RoBERTa的贡献

频率学派和贝叶斯学派的区别

频率学派和贝叶斯学派的区别

频率学BERT派和贝叶斯学派的区别

我们来读论文:

https://arxiv.org/abs/1907.11692

RoBERTa的研究人员发现,谷歌对BERT模型的训练不充分, 如果训练充分,可以超越包括 XLNet 在内的所有后来者。

所以 RoBERTa 还是沿着BERT这一套来搞,也就是MLM,或者说 Auto-Encoder Language Model。

这是对 XLNet 的 Auto-Rgressive Language Model 宣战,要重建对 MLM 的信仰。

RoBEATa的工作,可以总结为以下三个方面:

  • 针对BERT训练不充分的问题,采取了更大数据量、更大batch size,更长训练时间和更长的输入长度的策略。
  • 采用动态MASK(Dynamic Masking),代替静态MASK(Static Masking)。
  • 把NSP任务移除,同时把输入改为从同一篇文档中获取的句子对。

01

Dynamic Masking

谷歌的BERT使用的是静态MASK(Static Masking),也就是说随机MASK的操作,是在数据预处理阶段一次性完成的,在训练过程中,不会再进行MASK操作。

而RoBERTa使用的是动态MASK(Dynamic Masking),也是在训练过程中,做MASK操作。每次把一段文本序列输入到模型中时,都随机进行MASK。

动态MASK,相当于获取了更丰富的训练样本,这在增大训练样本和训练时长的策略下,大有裨益。

02

Remove NSP

谷歌原生BERT的NSP任务中,输入的PAIR,严格来说不是句子对,而是两段文本(Document Segments)。

这两段文本,有50%的概率来自同一篇文档,有50%的概率来自不同的文档。NSP任务,就是要预测这两段文本,是否来自同一篇文档(SEGMENT-PAIR+NSP)。

RoBERTa的研究员对NSP任务的必要性提出了质疑,他们移除了NSP任务,并把输入的PAIR改为来自同一篇文档的句子对(DOC-SENTENCES)。

这两条完整的句子,有50%的概率是前后衔接的句子,有50%的概率不是相邻的。

实验结果表明,这两种改进,有利于提升下游任务的精度。

四:可用BERT代码加载的改进版

频率学派和贝叶斯学派的区别

频率学派和贝叶斯学派的区别

频率学派和贝叶斯学派的区别

谷歌原生的BERT,训练语料为中文维基百科,语料规模偏小,存在训练不充分的问题。此外,模型本身还有很多改进的空间。

所以,这次加载BERT的改进版,来做多标签分类。

那么,哪些改进版可以BERT官方代码来加载呢?

一个是RoBERTa。

徐亮老师的团队,用超大规模的中文语料,预训练了中文的RoBERTa,提供了TensorFlow和PyTorch两种模型。

Github 地址:https://github.com/brightmart/roberta_zh

有6层、12层和24层三种大小的版本。

另一个是中文全词MASK的BERT模型。

谷歌自身对BERT进行了改良,加入了全词MASK(Whole Word Masking,wwm)。

原版BERT中,Tokenize的方式是WordPiece,会把完整的英文单词拆分成类似词根词缀的片段,会把中文词语切分成单字,然后对片段和字随机进行MASK。

而全词MASK则是把完整的英文单词和中文词语,做MASK。

预训练的中文全词MASK模型,可从以下网站下载。

Github地址:https://github.com/ymcui/Chinese-BERT-wwm。

五:多标签分类的数据预处理

频率学派和贝叶斯学派的区别

我们用RoBERTa做多标签分类。

之前写过如何用BERT做多分类,这次多标签分类的代码流程,基本与多分类一致。

如果有疑惑,可以先看:BERT多分类

代码主要参考LJ老师的代码,感谢。

实验环境为:

  • CUDA:10.1
  • CUDA:7.6.4
  • GTX 1080:11177M
  • TensorFlow:1.13.1

01

多标签数据集

这次训练一个多标签文本分类模型,对高中试题的知识点进行自动标注。

样本(item)及标签(label)的情况如下。

样本是高中的试题,标签是试题涉及的知识点。每个题目涉及到多个知识点(包括了高中和学科这两个标签),也就是多标签。

所以训练模型的目的,就是输入一个试题,输出涉及到的知识点。

point_df.head(3)
                            label                                               item
0  高中 生物 分子与细胞 组成细胞的化学元素 组成细胞的化合物        菠菜从土壤中吸收的氮元素可以用来合成()A.淀粉和纤维素B.葡萄糖和DNAC.核酸和蛋白质D...
1  高中 生物 稳态与环境 神经调节和体液调节的比较                 下列有关生物体内信息传递的叙述,正确的是()A下丘脑分泌的促甲状腺激素释放激素,可作用于甲状...
2  高中 生物 生物技术实践 生物工程技术                         从自然菌样筛选较理想生产菌种的一般步骤是:采集菌样→富集培养→纯种分离→性能测定.1.不同微...

02

下载预训练的中文RoBERTa

下载的地址如上。

这次使用的是12层的RoBEARTa:roberta_zh_l12。

RoBERTa 预训练模型的参数配置和谷歌原生BERT一致,不再赘述。

{
  "attention_probs_dropout_prob": 0.1, 
  "directionality": "bidi", 
  "hidden_act": "gelu", 
  "hidden_dropout_prob": 0.1, 
  "hidden_size": 768, 
  "initializer_range": 0.02, 
  "intermediate_size": 3072, 
  "max_position_embeddings": 512, 
  "num_attention_heads": 12, 
  "num_hidden_layers": 12, 
  "pooler_fc_size": 768, 
  "pooler_num_attention_heads": 12, 
  "pooler_num_fc_layers": 3, 
  "pooler_size_per_head": 128, 
  "pooler_type": "first_token_transform", 
  "type_vocab_size": 2, 
  "vocab_size": 21128
} 

本次的代码代码结构如下(不包含数据集):

├── bert                          # 使用到的BERT代码模块
│   ├── __init__.py
│   ├── modeling.py
│   ├── optimization.py
│   ├── run_classifier.py
│   └── tokenization.py
├── config.py                     # 数据和模型的路径信息
├── data_processor.py             # 1:多标签数据集的预处理
├── output
│   └── epochs5
├── pretrained_model             
│   └── roberta_zh_l12            # 预训练的中文RoBERTa
│       ├── bert_config.json
│       ├── bert_model.ckpt.data-00000-of-00001
│       ├── bert_model.ckpt.index
│       ├── bert_model.ckpt.meta
│       ├── checkpoint
│       └── vocab.txt
├── run_classifier.py             # 2:进行训练和预测的模块
├── run.sh                        # 一键执行数据预处理、模型训练和测试
└── run_test.py                   # 3:模型测试

03

数据预处理

首先读取数据,获取所有多标签的类别,以及划分数据集。

用sklearn中的MultiLabelBinarizer这个包,来处理样本的多标签。

不过这次,我们不需要得到多标签的one-hot编码,而是得到所有的类别。

并且,把所有标签保存下来。

mlb = MLB()
mlb.fit(point_df["label"])
all_class = mlb.classes_.tolist()

一共得到95个类别。

['“重农抑商”政策', '不完全显性', '与细胞分裂有关的细胞器', '中央官制——三公九卿制', '中心体的结构和功能', '人体免疫系统在维持稳态中的作用',...]

该部分的完整代码如下。

#coding:utf-8
import sys
sys.path.append("bert")
import pandas as pd
import os
from bert import tokenization
from sklearn.model_selection import train_test_split
from config import Config
from sklearn.preprocessing import MultiLabelBinarizer as MLB

config = Config()

""" 一: 读取数据、获取类别和划分数据集 """
def load_dataset():

    """ 1: 读取数据 """
    print("\n读取数据 ... \n")
    point_df = pd.read_csv(config.point_path, header=None, names=["label", "item"])
    point_df.dropna(inplace=True)
    print(f"\nThe shape of the dataset : {point_df.shape}\n")

    """ 2: 获取所有类别并保存 """
    print("\n获取所有类别 ... \n")
    point_df["label"] = point_df["label"].apply(lambda x:x.split())
    mlb = MLB()
    mlb.fit(point_df["label"])
    all_class = mlb.classes_.tolist()

    with open(config.class_path, "w",encoding='utf-8') as f:
        f.write("\n".join(all_class))

    """ 3: 划分数据集 """ 
    print("\n划分数据集 ... \n")
    df_train, df_test = train_test_split(point_df[:], test_size=0.2, shuffle=True)
    df_valid, df_test = train_test_split(df_test[:], test_size=0.5, shuffle=True)    

    return df_train, df_valid, df_test

然后创建目录,保存划分好的数据集。

""" 二:创建保存训练集、验证集和测试集的目录 """
def create_dir():

    print("\n创建保存训练集、验证集和测试集的目录 ... \n")
    proc_dir = config.proc_dir
    if not os.path.exists(proc_dir):
        os.makedirs(os.path.join(proc_dir, "train"))
        os.makedirs(os.path.join(proc_dir, "valid"))
        os.makedirs(os.path.join(proc_dir, "test")) 

    return proc_dir

最后,用BERT的tokenizer对中文进行单字切分,对英文做WordPiece。

样本处理的结果:

按 照 天 体 系 统 的 层 次 , 图 中 序 号 所 代 表 的 天 体 系 统 , 正 确 的 是 ( ) a ##① 是 河 外 星 系 b ##② 是 太 阳 系 c ##③ 是 银 河 系 d ##④ 是 地 月 系

标签处理的结果:

高中 地理 宇宙中的地球 地球所处的宇宙环境
高中 生物 分子与细胞 蛋白质的合成 组成细胞的化学元素 组成细胞的化合物

这部分的完整代码如下:

""" 三:按字粒度切分样本 """
def prepare_dataset():

    """ 1: 读取数据、贴标签和划分数据集"""
    df_train, df_valid, df_test = load_dataset()

    """ 2: 创建保存训练集、验证集和测试集的目录"""
    proc_dir = create_dir()

    """ 3: 初始化 bert_token 工具"""
    bert_tokenizer = tokenization.FullTokenizer(vocab_file=config.vocab_file, do_lower_case=True) 

    """ 4: 按字进行切分"""
    print("\n按字进行切分 ... \n")

    type_list = ["train", "valid", "test"]
    for set_type, df_data in zip(type_list, [df_train, df_valid, df_test]):
        print(f'\ndatasize: {len(df_data)}\n')

        """ 打开文件 """
        text_f = open(os.path.join(proc_dir, set_type,"text.txt"), "w",encoding='utf-8')
        token_in_f = open(os.path.join(proc_dir, set_type, "token_in.txt"),"w",encoding='utf-8')
        label_f = open(os.path.join(proc_dir, set_type,"label.txt"), "w",encoding='utf-8')

        """ 按字进行切分 """
        text = '\n'.join(df_data.item)
        text_tokened = df_data.item.apply(bert_tokenizer.tokenize)
        text_tokened = '\n'.join([' '.join(row) for row in text_tokened])
        label = '\n'.join([" ".join(row) for row in df_data.label])

        """ 写入文件 """
        text_f.write(text)
        token_in_f.write(text_tokened)
        label_f.write(label)

        text_f.close()
        token_in_f.close()
        label_f.close()

if __name__ == "__main__":

    prepare_dataset()

六:多标签分类的下游任务

频率

01

自定义Processor类

继承DataProcessor基类,然后自定义多标签分类的Processor类,用于加载训练数据和标签。

由于是分类任务,输入的单句而非句子对,所以 text_b=None。

examples.append(InputExample(guid=guid, text_a=text_token, text_b=None, label=label_str))

同时,把95类别的标签数据加载进来。

""" 1: 创建自己的DataProcessor """
class Multi_Label_Processor(DataProcessor):

    def __init__(self):
        self.language = "zh"

    @staticmethod
    def _load_examples(data_dir):
        with open(os.path.join(data_dir, "token_in.txt"), encoding='utf-8') as token_in_f:
            with open(os.path.join(data_dir, "label.txt"), encoding='utf-8') as label_f:
                token_in_list = [seq.replace("\n", '') for seq in token_in_f.readlines()]
                label_list = [label.replace("\n", '') for label in label_f.readlines()]
                assert len(token_in_list) == len(label_list)
                examples = list(zip(token_in_list, label_list))
                return examples

    @staticmethod
    def _create_example(lines, set_type):
        """Creates examples for the training and dev sets."""
        examples = []
        for (i, line) in enumerate(lines):
            guid = "%s-%s" % (set_type, i)
            text_token = line[0]
            label_str = line[1]
            examples.append(InputExample(guid=guid, text_a=text_token, text_b=None, label=label_str))
        return examples    

    def get_train_examples(self, data_dir):
        return self._create_example(self._load_examples(os.path.join(data_dir, "train")), "train")

    def get_dev_examples(self, data_dir):
        return self._create_example(self._load_examples(os.path.join(data_dir, "valid")), "valid")

    def get_test_examples(self, data_dir):
        return self._create_example(self._load_examples(os.path.join(data_dir, "test")), "test")

    def get_labels(self):
        """
        95 labels
        """
        all_labels = open(config.class_path,encoding="utf-8").readlines()
        return [label.strip() for label in all_labels]

02

对标签进行one-hot编码

训练的文本已经进行tokenize了,而多标签还没有处理。

于是对多标签进行one-hot编码。

label_map 为 {"高中":0 ,"生物":1 ,...} 这样的字典,那如果一个样本只有 [高中, 生物] 两个标签,那么one-hot编码为(省略的都为0):

[1, 1, 0, 0, 0, 0,...,0]
""" 2: 标签进行one-hot编码,多分类和多标签都适用。"""
def label_to_id(labels, label_map):
    label_map_length = len(label_map)
    label_ids = [0] * label_map_length
    for label in labels:
        label_ids[label_map[label]] = 1
    return label_ids

03

自定义多标签下游任务

这一步最关键了。

与多分类加dense层,做softmax相比,多标签分类是把dense层的输出,做sigmoid。

然后计算loss。

""" 6: 修改模型,在预训练层外面增加一个dense层,做sigmoid """
def create_model(bert_config, is_training, input_ids, input_mask, segment_ids,
                 labels, num_labels, use_one_hot_embeddings):
    """Creates a classification model."""
    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)

    """ 7: 文本分类,适用对序列做池化后的输出;序列标注,适用序列输出 """
    output_layer = model.get_pooled_output()

    """ 8: 依次添加weights和bias,构成dense层。"""
    hidden_size = output_layer.shape[-1].value

    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_wx = tf.matmul(output_layer, output_weights, transpose_b=True)
        logits = tf.nn.bias_add(logits_wx, output_bias)

        """ 9:多标签,用sigmoid """
        probs = tf.sigmoid(logits)

        """ 10: 与源码相比,已经是one-hot编码了,不用再转换。"""
        label_ids = tf.cast(labels, tf.float32)

        per_example_loss = tf.reduce_mean(
            tf.nn.sigmoid_cross_entropy_with_logits(logits=logits, labels=label_ids), axis=-1)
        loss = tf.reduce_mean(per_example_loss)

        return (loss, per_example_loss, logits, probs)

04

修改验证时的accuracy

BERT源码中accuracy的计算,适用于二分类。这里针对多标签分类,进行了修改。

要注意,将模型输出的概率转化为one-hot,需要按是否大于0.5来进行判断。

""" 11: 修改模型评估函数中的accuracy """
def model_fn_builder(bert_config, num_labels, init_checkpoint, learning_rate,
                     num_train_steps, num_warmup_steps, use_tpu,
                     use_one_hot_embeddings):
    ...

    def model_fn(features, labels, mode, params):  # pylint: disable=unused-argument

        """ 11: 修改的模型,在这里调用了 """
        (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)

        ...

        elif mode == tf.estimator.ModeKeys.EVAL:

            """ 12: 修改评估函数,计算多标签的准确率 """
            def metric_fn(per_example_loss,label_ids, probabilities,is_real_example):

                predict_ids = tf.cast(probabilities > 0.5, tf.int32)
                label_ids = tf.cast(label_ids, tf.int32)

                elements_equal = tf.cast(tf.equal(predict_ids, label_ids), tf.int32)
                row_predict_ids = tf.reduce_sum(elements_equal, -1)
                row_label_ids = tf.reduce_sum(tf.ones_like(label_ids), -1)

                accuracy = tf.metrics.accuracy(labels=row_label_ids, predictions=row_predict_ids)
                loss = tf.metrics.mean(values=per_example_loss, weights=is_real_example) 

                return {"eval_accuracy": accuracy,
                        "eval_loss": loss}            

            eval_metrics = (metric_fn,
                            [per_example_loss,label_ids,probabilities,is_real_example])
    ...

    return model_fn

05

修改预测时的输出为文本

BERT源码中,用训练好的模型做预测时,输出的是每个类别的二分类概率(多标签的95类,相当于训练95个二分类模型)。

在main函数中进行修改,把概率转化为one-hot编码,再映射为文本标签。

def main():
    tf.logging.set_verbosity(tf.logging.INFO)

    processors = {
        "multi_label_95": Multi_Label_Processor,
    }

    ...

    if FLAGS.do_predict:
        predict_examples = processor.get_test_examples(FLAGS.data_dir)
        num_actual_predict_examples = len(predict_examples)

        ...

        """ 16: 相比源码,多传入了一个参数:label_length """
        predict_input_fn = file_based_input_fn_builder(
            input_file=predict_file,
            seq_length=FLAGS.max_seq_length,
            label_length=label_length,
            is_training=False,
            drop_remainder=predict_drop_remainder)

        result = estimator.predict(input_fn=predict_input_fn)

        output_predict_file = os.path.join(FLAGS.output_dir, "predicted_label.txt")
        with tf.gfile.GFile(output_predict_file, "w") as writer:
            num_written_lines = 0
            tf.logging.info("***** Predict results *****")
            for (i, prediction) in enumerate(result):
                probabilities = prediction["probabilities"]
                if i >= num_actual_predict_examples:
                    break

                """ 17: 相比源码输出概率值,这里改为输出文本标签 """
                predicted_labels = []
                for idx,class_prob in enumerate(probabilities):
                    if class_prob > 0.5:
                        predicted_labels.append(label_list[idx])

                output_line_predict = " ".join(predicted_labels) + "\n"
                writer.write(output_line_predict)
                num_written_lines += 1
    assert num_written_lines == num_actual_predict_examples

其他部分,还有些修改的小细节,这里就不介绍了。

写好 data_processor.py 和 run_classifier.py 后,我们就可以训练模型了。

06

多标签的测试集评估

在BERT模型的训练过程中,不方便在测试集上进行评估模型。

所以另外写一个:run_test.py,用于评估模型。

前面说了,预测集上的输出,不是概率值,而是转化为了文本标签。

于是,把测试集的真实标签和预测的标签,读取进来,计算F1值。

同样用sklearn的MultiLabelBinarizer包来进行数值编码。

mlb.fit([[label] for label in all_labels])
y_true = mlb.transform(y_true)
y_pred = mlb.transform(y_pred)

完整代码如下。

#coding:utf-8
from sklearn.metrics import f1_score,accuracy_score
from config import Config
import os
from sklearn.preprocessing import MultiLabelBinarizer

config = Config()

all_labels = open(config.class_path,encoding="utf-8").readlines()
all_labels = [label.strip() for label in all_labels]
mlb = MultiLabelBinarizer()
mlb.fit([[label] for label in all_labels])


true_file = os.path.join(config.proc_dir,"test","label.txt")
predict_file = os.path.join(config.output_dir,"epochs3","predicted_label.txt")

y_true, y_pred = [], []
with open(true_file, encoding='utf8') as f:
    for line in f.readlines():
        y_true.append(line.strip().split())

with open(predict_file, encoding='utf8') as f:
    for i,line in enumerate(f.readlines()): 
        y_pred.append(line.strip().split())

y_true = mlb.transform(y_true)
y_pred = mlb.transform(y_pred)

accuracy = accuracy_score(y_true, y_pred)
f1_macro = f1_score(y_true, y_pred,average='macro')
f1_micro = f1_score(y_true, y_pred,average='micro')

print("1: Accuracy of model is {:.4f}\n".format(accuracy))
print("2: F1-macro of model is {:.4f}\n".format(f1_macro))
print("3: F1-micro of model is {:.4f}\n".format(f1_micro))

七:RoBERTA模型训练

频率学派和贝叶斯学派的区别

写一个shell脚本:run.sh,同时完成数据预处理、训练模型和评估模型的操作。

batch size 设为8,否则可能OOM。

python data_processor.py

python run_classifier.py \
  --task_name multi_label_95 \
  --do_train true \
  --do_eval true \
  --do_predict true \
  --data_dir ../data/bert_multi_label_results/proc/ \
  --vocab_file pretrained_model/roberta_zh_l12/vocab.txt \
  --bert_config_file pretrained_model/roberta_zh_l12/bert_config.json \
  --init_checkpoint pretrained_model/roberta_zh_l12/bert_model.ckpt \
  --max_seq_length 400 \
  --train_batch_size 8 \
  --learning_rate 2e-5 \
  --num_train_epochs 3.0 \
  --output_dir ../data/bert_multi_label_results/epochs3/

# test bert
python run_test.py

执行:sh run.sh。

尝试先跑3个epoch,测试集上的评估结果如下。

效果不敢恭维。

1: Accuracy of model is 0.4553

2: F1-macro of model is 0.6732

3: F1-micro of model is 0.9013

再改为跑5个epoch,结果好了很多。

1: Accuracy of model is 0.5970

2: F1-macro of model is 0.8052

3: F1-micro of model is 0.9269

好了,RoBERTa 多标签分类模型的训练到此结束。

后续,再介绍如何用 Tensorflow Serving,把这个RoBERTa模型包装成服务。

END

本文分享自微信公众号 - 叫我NLPer(gh_39af6a29685b),作者:邓邓

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-03-14

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • BERT部署:TF-Serving+Nvidia-Docker+gRPC

    这次把 TensorFlow-Serving+Nvidia-Docker+gRPC的部署方式跑通了,参考了多篇博文,以及优秀的GITHUB代码。

    邓邓最棒
  • BERT多分类:你还要我怎样?

    接触tensorflow 1.X之前,我听过一个笑话。 面试官:请手写个简单的神经网络。 面试者:import tensorflow as tf。 这个笑话...

    邓邓最棒
  • 双向最大匹配和实体标注:你以为我只能分词?

    举叉烧同学文章里的例子,有一句话:宫保鸡丁和红烧牛肉哪个好吃,我们需要给句子中的两个实体 [宫保鸡丁, 红烧牛肉] 打上 Food 标签,非实体打上 O 标签。

    邓邓最棒
  • 分类问题的label为啥必须是 one hot 形式?

    作者:桔了个仔 链接:https://www.zhihu.com/question/359742335/answer/930586793 来源:知乎

    zenRRan
  • 语义分割--Label Refinement Network for Coarse-to-Fine Semantic Segmentation

    Label Refinement Network for Coarse-to-Fine Semantic Segmentation

    用户1148525
  • 施工专题第11篇:Python 包和模块使用总结

    今天这个专题讨论Python代码工程化、结构化的方法。我们都会遇到这种情景:所有代码都堆积到一个模块里,导致代码越来越长,最后变得难以维护,很明显代码只写到一个...

    double
  • 如何用r语言制作交互可视化报告图表

    拓端
  • 带你玩转系列之Burpsuite

    Burp Suite是无人不晓的web渗透测试必备的工具。从应用程序表面的映射和内部分析,到探测和利用漏洞等过程,所有插件支持整体测试程序而无缝地在一起工作。

    Aran
  • KSCrash源码分析

    用户2297838
  • linux ulimit 调优

    概要: linux系统默认open files数目为1024, 有时应用程序会报Too many open files的错误,是因为open files 数目不...

    sunsky

扫码关注云+社区

领取腾讯云代金券