【NLP】语言模型和迁移学习

10.13 Update:最近新出了一个state-of-the-art预训练模型,传送门:

李入魔:【NLP】Google BERT详解​zhuanlan.zhihu.com

1. 简介

长期以来,词向量一直是NLP任务中的主要表征技术。随着2017年底以及2018年初的一系列技术突破,研究证实预训练的语言表征经过精调后可以在众多NLP任务中达到更好的表现。目前预训练有两种方法:

  1. Feature-based:将训练出的representation作为feature用于任务,从词向量、句向量、段向量、文本向量都是这样的。新的ELMo也属于这类,但迁移后需要重新计算出输入的表征。
  2. Fine-tuning:这个主要借鉴于CV,就是在预训练好的模型上加些针对任务的层,再对后几层进行精调。新的ULMFit和OpenAI GPT属于这一类。

本文主要对ELMo、ULMFiT以及OpenAI GPT三种预训练语言模型作简要介绍。

2. ELMo

2.1 模型原理与架构

原文链接:Deep contextualized word representations

ELMo是从双向语言模型(BiLM)中提取出的Embedding。训练时使用BiLSTM,给定N个tokens (t1, t2,...,tN), 目标为最大化:

ELMo对于每个token , 通过一个L层的biLM计算出2L+1个表示:

其中 是对token进行直接编码的结果(这里是字符通过CNN编码), 是每个biLSTM层输出的结果。

应用中将ELMo中所有层的输出R压缩为单个向量, , 最简单的压缩方法是取最上层的结果做为token的表示: , 更通用的做法是通过一些参数来联合所有层的信息:

其中 是softmax出来的权重, 是一个任务相关的scale参数,在优化过程中很重要,同时因为每层BiLM的输出分布不同, 可以对层起到normalisation的作用。

论文中使用的预训练BiLM在Jozefowicz et al.中的CNN-BIG-LSTM基础上做了修改,最终模型为2层biLSTM(4096 units, 512 dimension projections),并在第一层和第二层之间增加了残差连接。同时使用CNN和两层Highway对token进行字符级的上下文无关编码。使得模型最终对每个token输出三层向量表示。

2.2 模型训练注意事项

- 正则化

1. Dropout

2. 在loss中添加权重的惩罚项 (实验结果显示ELMo适合较小的 )

- TF版源码解析

1. 模型架构的代码主要在training模块的LanguageModel类中,分为两步:第一步创建word或character的Embedding层(CNN+Highway);第二步创建BiLSTM层。

2. 加载所需的预训练模型为model模块中的BidirectionalLanguageModel类。

2.3 模型的使用

  1. 将ELMo向量 与传统的词向量 拼接成 后,输入到对应具体任务的RNN中。
  2. 将ELMo向量放到模型输出部分,与具体任务RNN输出的 拼接成 。
  3. Keras代码示例
import tensorflow as tf
from keras import backend as K
import keras.layers as layers
from keras.models import Model# Initialize session
sess = tf.Session()
K.set_session(sess)# Instantiate the elmo model
elmo_model = hub.Module("https://tfhub.dev/google/elmo/1", trainable=True)
sess.run(tf.global_variables_initializer())
sess.run(tf.tables_initializer())# We create a function to integrate the tensorflow model with a Keras model
# This requires explicitly casting the tensor to a string, because of a Keras quirk
def ElmoEmbedding(x):return elmo_model(tf.squeeze(tf.cast(x, tf.string)), signature="default", as_dict=True)["default"]input_text = layers.Input(shape=(1,), dtype=tf.string)
embedding = layers.Lambda(ElmoEmbedding, output_shape=(1024,))(input_text)
dense = layers.Dense(256, activation='relu')(embedding)
pred = layers.Dense(1, activation='sigmoid')(dense)model = Model(inputs=[input_text], outputs=pred)model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
model.summary()复制代码

2.4 模型的优缺点

优点

  1. 效果好,在大部分任务上都较传统模型有提升。实验正式ELMo相比于词向量,可以更好地捕捉到语法和语义层面的信息。
  2. 传统的预训练词向量只能提供一层表征,而且词汇量受到限制。ELMo所提供的是character-level的表征,对词汇量没有限制。

缺点

速度较慢,对每个token编码都要通过language model计算得出。

2.5 适用任务

  • Question Answering
  • Textual entailment
  • Semantic role labeling
  • Coreference resolution
  • Named entity extraction
  • Sentiment analysis

3. ULMFiT

3.1 模型原理与架构

原文链接:Universal Language Model Fine-tuning for Text Classification

ULMFiT是一种有效的NLP迁移学习方法,核心思想是通过精调预训练的语言模型完成其他NLP任务。文中所用的语言模型参考了Merity et al. 2017a的AWD-LSTM模型,即没有attention或shortcut的三层LSTM模型。

ULMFiT的过程分为三步:


1. General-domain LM pre-train

  • 在Wikitext-103上进行语言模型的预训练。
  • 预训练的语料要求:large & capture general properties of language
  • 预训练对小数据集十分有效,之后仅有少量样本就可以使模型泛化。

2. Target task LM fine-tuning

文中介绍了两种fine-tuning方法:

  • Discriminative fine-tuning

因为网络中不同层可以捕获不同类型的信息,因此在精调时也应该使用不同的learning rate。作者为每一层赋予一个学习率 ,实验后发现,首先通过精调模型的最后一层L确定学习率 ,再递推地选择上一层学习率进行精调的效果最好,递推公式为:

  • Slanted triangular learning rates (STLR)

为了针对特定任务选择参数,理想情况下需要在训练开始时让参数快速收敛到一个合适的区域,之后进行精调。为了达到这种效果,作者提出STLR方法,即让LR在训练初期短暂递增,在之后下降。如图b的右上角所示。具体的公式为:

    • T: number of training iterations
    • cut_frac: fraction of iterations we increase the LR
    • cut: the iteration when we switch from increasing to decreasing the LR
    • p: the fraction of the number of iterations we have increased or will decrease the LR respectively
    • ratio: specifies how much smaller the lowest LR is from thr max LR
    • : the LR at iteration t

文中作者使用的

3. Target task classifier fine-tuning

为了完成分类任务的精调,作者在最后一层添加了两个线性block,每个都有batch-norm和dropout,使用ReLU作为中间层激活函数,最后经过softmax输出分类的概率分布。最后的精调涉及的环节如下:

  • Concat pooling
    第一个线性层的输入是最后一个隐层状态的池化。因为文本分类的关键信息可能在文本的任何地方,所以只是用最后时间步的输出是不够的。作者将最后时间步 与尽可能多的时间步 池化后拼接起来,以 作为输入。
  • Gradual unfreezing
    由于过度精调会导致模型遗忘之前预训练得到的信息,作者提出逐渐unfreez网络层的方法,从最后一层开始unfreez和精调,由后向前地unfreez并精调所有层。
  • BPTT for Text Classification (BPT3C)
    为了在large documents上进行模型精调,作者将文档分为固定长度为b的batches,并在每个batch训练时记录mean和max池化,梯度会被反向传播到对最终预测有贡献的batches。
  • Bidirectional language model
    在作者的实验中,分别独立地对前向和后向LM做了精调,并将两者的预测结果平均。两者结合后结果有0.5-0.7的提升。

3.2 模型训练注意事项

- PyTorch版源码解析 (FastAI第10课)

# location: fastai/lm_rnn.pydef get_language_model(n_tok, emb_sz, n_hid, n_layers, pad_token,dropout=0.4, dropouth=0.3, dropouti=0.5, dropoute=0.1, wdrop=0.5, tie_weights=True, qrnn=False, bias=False):"""Returns a SequentialRNN model.A RNN_Encoder layer is instantiated using the parameters provided.This is followed by the creation of a LinearDecoder layer.Also by default (i.e. tie_weights = True), the embedding matrix used in the RNN_Encoderis used to  instantiate the weights for the LinearDecoder layer.The SequentialRNN layer is the native torch's Sequential wrapper that puts the RNN_Encoder andLinearDecoder layers sequentially in the model.Args:n_tok (int): number of unique vocabulary words (or tokens) in the source datasetemb_sz (int): the embedding size to use to encode each tokenn_hid (int): number of hidden activation per LSTM layern_layers (int): number of LSTM layers to use in the architecturepad_token (int): the int value used for padding text.dropouth (float): dropout to apply to the activations going from one LSTM layer to anotherdropouti (float): dropout to apply to the input layer.dropoute (float): dropout to apply to the embedding layer.wdrop (float): dropout used for a LSTM's internal (or hidden) recurrent weights.tie_weights (bool): decide if the weights of the embedding matrix in the RNN encoder should be tied to theweights of the LinearDecoder layer.qrnn (bool): decide if the model is composed of LSTMS (False) or QRNNs (True).bias (bool): decide if the decoder should have a bias layer or not.Returns:A SequentialRNN model"""rnn_enc = RNN_Encoder(n_tok, emb_sz, n_hid=n_hid, n_layers=n_layers, pad_token=pad_token,dropouth=dropouth, dropouti=dropouti, dropoute=dropoute, wdrop=wdrop, qrnn=qrnn)enc = rnn_enc.encoder if tie_weights else Nonereturn SequentialRNN(rnn_enc, LinearDecoder(n_tok, emb_sz, dropout, tie_encoder=enc, bias=bias))def get_rnn_classifier(bptt, max_seq, n_class, n_tok, emb_sz, n_hid, n_layers, pad_token, layers, drops, bidir=False,dropouth=0.3, dropouti=0.5, dropoute=0.1, wdrop=0.5, qrnn=False):rnn_enc = MultiBatchRNN(bptt, max_seq, n_tok, emb_sz, n_hid, n_layers, pad_token=pad_token, bidir=bidir,dropouth=dropouth, dropouti=dropouti, dropoute=dropoute, wdrop=wdrop, qrnn=qrnn)return SequentialRNN(rnn_enc, PoolingLinearClassifier(layers, drops))复制代码

3.3 模型的优缺点

优点

对比其他迁移学习方法(ELMo)更适合以下任务:

- 非英语语言,有标签训练数据很少

- 没有state-of-the-art模型的新NLP任务

- 只有部分有标签数据的任务

缺点

对于分类和序列标注任务比较容易迁移,对于复杂任务(问答等)需要新的精调方法。

3.4 适用任务

  • Classification
  • Sequence labeling

4. OpenAI GPT

4.1 模型原理与架构

原文链接:Improving Language Understanding by Generative Pre-Training (未出版)

OpenAI Transformer是一类可迁移到多种NLP任务的,基于Transformer的语言模型。它的基本思想同ULMFiT相同,都是在尽量不改变模型结构的情况下将预训练的语言模型应用到各种任务。不同的是,OpenAI Transformer主张用Transformer结构,而ULMFiT中使用的是基于RNN的语言模型。文中所用的网络结构如下:


模型的训练过程分为两步:

1. Unsupervised pre-training

第一阶段的目标是预训练语言模型,给定tokens的语料 ,目标函数为最大化似然函数:

该模型中应用multi-headed self-attention,并在之后增加position-wise的前向传播层,最后输出一个分布:

2. Supervised fine-tuning

有了预训练的语言模型之后,对于有标签的训练集 ,给定输入序列 和标签 ,可以通过语言模型得到 ,经过输出层后对 进行预测:

则目标函数为:

整个任务的目标函数为:

4.2 模型训练注意事项

- TF版源码解析

# location: finetune-transformer-lm/train.pydef model(X, M, Y, train=False, reuse=False):with tf.variable_scope('model', reuse=reuse):# n_special=3,作者把数据集分为三份# n_ctx 应该是 n_contextwe = tf.get_variable("we", [n_vocab+n_special+n_ctx, n_embd], initializer=tf.random_normal_initializer(stddev=0.02))we = dropout(we, embd_pdrop, train)X = tf.reshape(X, [-1, n_ctx, 2])M = tf.reshape(M, [-1, n_ctx])# 1. Embeddingh = embed(X, we)# 2. transformer blockfor layer in range(n_layer):h = block(h, 'h%d'%layer, train=train, scale=True)# 3. 计算语言模型losslm_h = tf.reshape(h[:, :-1], [-1, n_embd])lm_logits = tf.matmul(lm_h, we, transpose_b=True)lm_losses = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=lm_logits, labels=tf.reshape(X[:, 1:, 0], [-1]))lm_losses = tf.reshape(lm_losses, [shape_list(X)[0], shape_list(X)[1]-1])lm_losses = tf.reduce_sum(lm_losses*M[:, 1:], 1)/tf.reduce_sum(M[:, 1:], 1)# 4. 计算classifier lossclf_h = tf.reshape(h, [-1, n_embd])pool_idx = tf.cast(tf.argmax(tf.cast(tf.equal(X[:, :, 0], clf_token), tf.float32), 1), tf.int32)clf_h = tf.gather(clf_h, tf.range(shape_list(X)[0], dtype=tf.int32)*n_ctx+pool_idx)clf_h = tf.reshape(clf_h, [-1, 2, n_embd])if train and clf_pdrop > 0:shape = shape_list(clf_h)shape[1] = 1clf_h = tf.nn.dropout(clf_h, 1-clf_pdrop, shape)clf_h = tf.reshape(clf_h, [-1, n_embd])clf_logits = clf(clf_h, 1, train=train)clf_logits = tf.reshape(clf_logits, [-1, 2])clf_losses = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=clf_logits, labels=Y)return clf_logits, clf_losses, lm_losses复制代码

4.3 模型的优缺点

优点

  1. 循环神经网络所捕捉到的信息较少,而Transformer可以捕捉到更长范围的信息。
  2. 计算速度比循环神经网络更快,易于并行化
  3. 实验结果显示Transformer的效果比ELMo和LSTM网络更好

缺点

对于某些类型的任务需要对输入数据的结构作调整

4.4 适用任务

  • Natural Language Inference
  • Question Answering and commonsense reasoning
  • Classification
  • Semantic Similarity

5. 总结

从Wrod Embedding到OpenAI Transformer,NLP中的迁移学习从最初使用word2vec、GLoVe进行字词的向量表示,到ELMo可以提供前几层的权重共享,再到ULMFiT和OpenAI Transformer的整个预训练模型的精调,大大提高了NLP基本任务的效果。同时,多项研究也表明,以语言模型作为预训练模型,不仅可以捕捉到文字间的语法信息,更可以捕捉到语义信息,为后续的网络层提供高层次的抽象信息。另外,基于Transformer的模型在一些方面也展现出了优于RNN模型的效果。

最后,关于具体任务还是要进行多种尝试,可以使用以上方法做出模型baseline,再调整网络结构提升效果。

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

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

相关文章

TCPIP传送协议

以下代码实现在客户端查询成绩(数据库在服务器端): 客户端: static void Main(string[] args) { string str null; while (str ! Convert.ToString(0)) { Console.WriteLine("…

sql优化技巧_使用这些查询优化技巧成为SQL向导

sql优化技巧成为SQL向导! (Become an SQL Wizard!) It turns out storing data by rows and columns is convenient in a lot of situations, so relational databases have remained a cornerstone of data management in businesses across the globe. Structured…

Day 4:集合——迭代器与List接口

Collection-迭代方法 1、toArray() 返回Object类型数据,接收也需要Object对象! Object[] toArray(); Collection c new ArrayList(); Object[] arr c.toArray(); 2、iterator() Collection的方法,返回实现Iterator接口的对象,…

oem是代工还是贴牌_代加工和贴牌加工的区别是什么

展开全部代加工就是替别人加工,贴别人的牌子。贴牌加工即商家自己不生产,而是委托其他生产企e68a8462616964757a686964616f31333365663431业生产,而品牌是自己的。拓展资料:OEM(Original Equipment Manufacture)的基本含义是定牌生…

KNN 算法--图像分类算法

KNN 算法–图像分类算法 找到最近的K个邻居,在前k个最近样本中选择最近的占比最高的类别作为预测类别。 给定测试对象,计算它与训练集中每个对象的距离。圈定距离最近的k个训练对象,作为测试对象的邻居。根据这k个紧邻对象所属的类别&#xf…

java核心技术-NIO

1、reactor(反应器)模式 使用单线程模拟多线程,提高资源利用率和程序的效率,增加系统吞吐量。下面例子比较形象的说明了什么是反应器模式: 一个老板经营一个饭店, 传统模式 - 来一个客人安排一个服务员招呼…

物种分布模型_减少物种分布建模中的空间自相关

物种分布模型Species distribution models (SDM; for review and definition see, e.g., Peterson et al., 2011) are a dominant paradigm to quantify the relationship between environmental dynamics and several manifestations of species biogeography. These statisti…

BZOJ1014: [JSOI2008]火星人prefix

BZOJ1014: [JSOI2008]火星人prefix Description 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀。 比方说,有这样一个字符串:madamimadam,我们将这个字符串的各个字符予以标号: 序号: 1 2 3 4 5 6…

redis将散裂中某个值自增_这些Redis命令你都掌握了没?

本章主要内容字符串命令、列表命令和集合命令散列命令和有序集合命令发布命令与订阅命令其他命令本章将介绍一些没有在第1章和第2章出现过的Redis命令,学习这些命令有助于读者在已有示例的基础上构建更为复杂的程序,并学会如何更好地去解决自己遇到的问题…

asp.net的MessageBox

public class MessageBox{ public enum MsgButton { /// <summary> /// 只是OK按钮 /// </summary> OK 1, /// <summary> /// 提示是否确定 /// </summary> OKCancel 2 } publ…

深入理解激活函数

为什么需要非线性激活函数&#xff1f; 说起神经网络肯定会降到神经函数&#xff0c;看了很多资料&#xff0c;也许你对激活函数这个名词会感觉很困惑&#xff0c; 它为什么叫激活函数&#xff1f;它有什么作用呢&#xff1f; 看了很多书籍上的讲解说会让神经网络变成很丰富的…

如何一键部署项目、代码自动更新

为什么80%的码农都做不了架构师&#xff1f;>>> 摘要&#xff1a;my-deploy:由nodejs写的一个自动更新工具,理论支持所有语言(php、java、c#)的项目,支持所有git仓库(bitbucket、github等)。github效果如何?如果你的后端项目放在github、bitbucket等git仓库中管理…

Kettle7.1在window启动报错

实验环境&#xff1a; window10 x64 kettle7.1 pdi-ce-7.1.0.0-12.zip 错误现象&#xff1a; a java exception has occurred 问题解决&#xff1a; 运行调试工具 data-integration\SpoonDebug.bat //调试错误的&#xff0c;根据错误明确知道为何启动不了&#xff0c;Y--Y-…

opa847方波放大电路_电子管放大电路当中阴极电阻的作用和选择

胆机制作知识视频&#xff1a;6P14单端胆机用示波器方波测试输出波形详细步骤演示完整版自制胆机试听视频&#xff1a;胆机播放《猛士的士高》经典舞曲 熟悉的旋律震撼的效果首先看下面这一张300B电子管电路图&#xff1a;300B单端胆机原理图图纸里面画圆圈的电阻就是放大电路当…

键盘钩子

C#键盘钩子//*************************键盘钩子********************** //定义变量 public delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam); static int hKeyboardHook 0; HookProc KeyboardHookProcedure; /************************* * 声明API函数 * ***…

matplotlib基础函数函数 plot, figure

matplotlib.pyplot.plot(*args, scalexTrue, scaleyTrue,dataNone,**kwargs) 用线段和标记去绘制x和y。调用签名&#xff1a; plot([x], y, [fmt], *, dataNone, **kwargs) plot([x], y, [fmt], [x2], y2, [fmt2], ..., **kwargs)点或线的坐标由x, y给出 操作参数 fmt 是为了…

清洁数据ploy n_清洁屋数据

清洁数据ploy nAs a bootcamp project, I was asked to analyze data about the sale prices of houses in King County, Washington, in 2014 and 2015. The dataset is well known to students of data science because it lends itself to linear regression modeling. You …

redis安装redis集群

NoSql数据库之Redis1、什么是nosql&#xff0c;nosql的应用场景2、Nonsql数据库的类型a) Key-valueb) 文档型&#xff08;类似于json&#xff09;c) 列式存储d) 图式3、redis的相关概念kv型的。4、Redis的安装及部署5、Redis的使用方法及数据类型a) Redis启动及关闭b) Redis的数…

联想拯救者y7000p加内存条_内存、硬盘不够用?手把手教你升级联想拯救者Y7000P...

由于这两年内存价格的高企&#xff0c;主流笔记本的内存容量被锁定在 8GB 已经有了相当长的时间。作为近几个月最热门的游戏本产品&#xff0c;联想拯救者 Y7000P 除顶配之外同样使用的是 8GB 内存和 512GB 固态硬盘的配置。所以买到这款机器的玩家多数都会选择进行内存和硬盘的…

机器学习实践一 logistic regression regularize

Logistic regression 数据内容&#xff1a; 两个参数 x1 x2 y值 0 或 1 Potting def read_file(file):data pd.read_csv(file, names[exam1, exam2, admitted])data np.array(data)return datadef plot_data(X, y):plt.figure(figsize(6, 4), dpi150)X1 X[y 1, :]X2 X[…