文章目录
- 56 Gated Recurrent Unit(GRU)
- 56.1 Motivation: How to focus on a sequence
- 56.2 The concept of doors
- 56.3 Candidate hidden state
- 56.4 hidden state
- 56.5 summarize
- 56.6 QA
- 57 Long short-term memory network
- 57.1 Basic concepts
- 57.2 Long short-term memory network:
- 57.2.1 door:
- 57.2.2 Candidate memory unit
- 57.2.3 Memory unit
- 57.2.4 hidden state
- 57.2.5 summarize
- 57.3 Implement from scratch
- 57.3.1 Initialize model parameters
- 57.3.2 definition model
- 57.3.3 Training and prediction
- 58 Deep Recurrent Neural Network
- 58.1 Deep Recurrent Neural Network
- 58.2 Formula
- 58.3 summarize
- 59 Encoder decoder architecture
- 59.1 Explanation in CNN
- 59.2 Interpretation in RNN
- 59.3 Abstract encoder decoder architecture
- 60 Sequence to sequence learning
- 60.1 Application example: Machine translation
- 60.2 model architecture : Seq2seq
- 60.3 Encoder decoder details
- 60.4 Training and reasoning
- 60.5 Measuring the quality of generated sequences:BLEU
- 60.6 BLUE value definition:
- 60.7 Definitive parsing
- 60.8 QA
56 Gated Recurrent Unit(GRU)
- GRU 是一种循环神经网络(RNN)的变体,旨在解决传统RNN在处理长期依赖关系时遇到的梯度消失和梯度爆炸问题。GRU在结构上比长短期记忆(LSTM)网络简单,但同样能够有效地捕捉序列数据中的长期依赖关系。
以下是GRU的基本结构和原理:
-
重置门(Reset Gate):
- 重置门决定了如何将新的输入与先前的隐藏状态结合。它基于当前输入和上一个隐藏状态来计算一个介于0和1之间的值。
- 如果重置门的值接近0,那么它将忽略先前的隐藏状态,只考虑当前输入。如果值接近1,那么它将把先前的隐藏状态和当前输入一起考虑。
- 公式表示为: r t = σ ( W r ⋅ [ h t − 1 , x t ] + b r r_t = \sigma(W_r \cdot [h_{t-1}, x_t] + b_r rt=σ(Wr⋅[ht−1,xt]+br,其中(\sigma)是sigmoid激活函数,(W_r)和(b_r)是权重和偏置。
-
更新门(Update Gate):
- 更新门决定了从先前的隐藏状态传递到当前隐藏状态的信息量。同样,它也是基于当前输入和上一个隐藏状态来计算一个介于0和1之间的值。
- 如果更新门的值接近0,那么它将忽略先前的隐藏状态,只考虑候选隐藏状态(由当前输入和重置门计算得出)。如果值接近1,那么它将保留先前的隐藏状态的大部分信息。
- 公式表示为: z t = σ ( W z ⋅ [ h t − 1 , x t ] + b z z_t = \sigma(W_z \cdot [h_{t-1}, x_t] + b_z zt=σ(Wz⋅[ht−1,xt]+bz,其中(W_z)和(b_z)是权重和偏置。
-
候选隐藏状态(Candidate Hidden State):
- 候选隐藏状态是基于当前输入和先前的隐藏状态(通过重置门进行调整)来计算的。它类似于传统RNN中的隐藏状态,但没有直接用于输出,而是用于与更新门结合来计算最终的隐藏状态。
- 公式表示为: h ~ t = tanh ( W ⋅ [ r t ⊙ h t − 1 , x t ] + b \tilde{h}_t = \tanh(W \cdot [r_t \odot h_{t-1}, x_t] + b h~t=tanh(W⋅[rt⊙ht−1,xt]+b,其中(\odot)表示逐元素相乘,(W)和(b)是权重和偏置。
-
当前隐藏状态(Current Hidden State):
- 当前的隐藏状态是基于更新门、先前的隐藏状态和候选隐藏状态来计算的。它结合了先前的隐藏状态和新的候选隐藏状态的信息,由更新门来控制这种信息的比例。
- 公式表示为: h t = ( 1 − z t ) ⊙ h t − 1 + z t ⊙ h ~ t h_t = (1 - z_t) \odot h_{t-1} + z_t \odot \tilde{h}_t ht=(1−zt)⊙ht−1+zt⊙h~t。
GRU的结构使其能够更有效地捕捉长期依赖关系,因为它可以通过更新门和重置门来控制信息在隐藏状态中的流动。这使得GRU在处理序列数据时比传统RNN更加有效,并且在许多任务中都取得了很好的性能。
56.1 Motivation: How to focus on a sequence
- 不是每个观察值都是同等重要
比如上图中的序列,若干个猫中出现了一个鼠,那么我们应该重点关注这个鼠,而中间重复出现的猫则减少关注。文本序列同理,通常长文本我们需要关注的是几个关键词,关键句。
- 想只记住相关的观察需要:
- 能关注的机制(更新门):顾名思义,是否需要根据我的输入,更新隐藏状态
- 能遗忘的机制(重置门):更新候选项时,是否要考虑前一隐藏状态。
56.2 The concept of doors
-
更新门Zt,重置门Rt的公式大体相同,唯一不同的是学习到的参数。
-
需要注意的是,计算门的方式和原来RNN的实现中计算新的隐状态相似,只是激活函数改成了sigmoid。
-
门本来是电路中的一个概念,0,1代表不同的电平,可以用于控制电路的通断。此处sigmoid将门的数值归一化到0到1之间,是一种"软更新"方式。而从后面的公式上可以看出,现在采用的是低电平有效(越靠近0,门的作用越明显)的方式控制。
56.3 Candidate hidden state
-
候选隐状态,如果抛开公式中的 R t R_{t} Rt遗忘门来说,这个和之前RNN中计算当前步的隐状态没有差别。
-
但是这里引入了遗忘门,如果 R t R_{t} Rt无限接近于0,那么此时候选隐状态将不再考虑前一隐状态的影响,也就是和MLP没有区别,起到“遗忘”的作用;
-
反之,如果 R t R_{t} Rt无限接近于1,那么与RNN计算隐状态的过程没有差别,不进行遗忘。
-
公式中的⊙表示逐元素乘积。
为什么叫候选隐状态?
在RNN中,这个所谓的候选隐状态就是当前步的隐状态( R t R_{t} Rt无限接近1时)。但是由于引入了更新门,我们需要考虑是直接沿用上一步的隐藏状态,还是像RNN一样使用当前步计算的隐状态。所以这个结合了当前输入计算的隐状态,不能立马变成当前的 H t H_{t} Ht,而是需要用更新门和前一隐状态 H t − 1 H_{t-1} Ht−1做一个加权,所以它是一个候选项。
56.4 hidden state
用更新门对候选隐状态和前一隐状态做加权,得到当前步隐状态的值。
如果 Z t Z_{t} Zt无限接近于0,更新起作用,候选隐状态“转正”,变为当前隐状态。
如果 Z t Z_{t} Zt无限接近于1,更新不起作用,当前隐状态还是沿用前一隐状态。
56.5 summarize
上图四行公式概括了GRU模型。在RNN的基础上,最重要的是引入了更新门和重置门,来决定前一隐状态对当前隐状态的影响。以最开始的猫鼠序列的例子来说,如果我的模型一直看到猫,模型可以学习到隐状态不怎么去更新,于是隐状态一直保留了猫的信息,而看到老鼠,隐状态才进行更新。
- 对于一个更具体的例子而言(语言模型):
“The cat, which already ate ……, __(is/ was) full.”,假设我的句子很长,预测完前面的词后需要预测下一个词is还是was,如果引入这种更新/重置的机制,那我们的模型可以在was这个词之前尽可能去保持隐状态的信息,从而即使阅读了一个很长的定语从句,但我们还是保留了cat这个词的单数信息,从而模型预测下一个词为’was’。
- 一个与RNN的联动在于:
如果更新门完全发挥作用(无限接近于0),重置门不起作用(无限接近于1),此时GRU模型退化为RNN模型。
56.6 QA
问题:GRU为什么需要两个门?
重置门和更新门各司其职。重置门单方面控制自某个节点开始,之前的记忆(隐状态)不在乎了,直接清空影响,同时也需要更新门帮助它实现记忆的更新。更新门更多是用于处理梯度消失问题,可以选择一定程度地保留记忆,防止梯度消失。
重置门影响的是当前步新的候选隐状态的计算,更新门影响的是当前步隐状态的更新程度。
57 Long short-term memory network
57.1 Basic concepts
- LSTM 是一种特殊的循环神经网络(RNN)架构,旨在解决传统RNN在处理长序列时存在的梯度消失和梯度爆炸问题。LSTM通过引入门控机制(Gate Mechanism)来控制信息的流动,从而能够捕捉序列中的长期依赖关系。
LSTM的核心部分包括以下几个组件:
- 输入门(Input Gate):控制新信息流入细胞(Cell)的程度。输入门接收当前时刻的输入 x t x_t xt和上一时刻的隐藏状态 h t − 1 h_{t-1} ht−1,并通过sigmoid函数产生一个0到1之间的值,表示有多少新信息可以被存储到细胞状态中。
- 遗忘门(Forget Gate):控制从细胞状态中丢弃哪些信息。遗忘门同样接收 x t x_t xt和 h t − 1 h_{t-1} ht−1,并通过sigmoid函数产生一个0到1之间的值,表示细胞状态中哪些信息应该被保留或丢弃。
- 细胞状态(Cell State):LSTM的关键部分,用于存储长期信息。新的细胞状态 C t C_t Ct是由旧的细胞状态 C t − 1 C_{t-1} Ct−1、输入门和遗忘门的输出共同决定的。具体地,新的细胞状态 C t C_t Ct是遗忘门与旧细胞状态的逐元素乘积(即选择性遗忘)加上输入门与候选细胞状态的逐元素乘积(即选择性记忆)。
- 输出门(Output Gate):控制从细胞状态中输出哪些信息到隐藏状态 h t h_t ht。输出门接收 x t x_t xt和 h t − 1 h_{t-1} ht−1,并通过sigmoid函数产生一个0到1之间的值。然后,将细胞状态 C t C_t Ct通过tanh函数压缩到-1到1之间,再与输出门的输出进行逐元素乘积,得到最终的隐藏状态 h t h_t ht。
通过这些门控机制,LSTM能够更有效地处理长序列数据,并在自然语言处理、语音识别、时间序列预测等领域取得了显著成果。
57.2 Long short-term memory network:
- 忘记门:将值朝0减少
- 输入门:决定是不是忽略掉输入数据
- 输出门:决定是不是使用隐状态
可以说,长短期记忆网络的设计灵感来自于计算机的逻辑门。 长短期记忆网络引入了记忆元(memory cell),或简称为单元(cell)。 有些文献认为记忆元是隐状态的一种特殊类型, 它们与隐状态具有相同的形状,其设计目的是用于记录附加的信息。 为了控制记忆元,我们需要许多门。 其中一个门用来从单元中输出条目,我们将其称为输出门(output gate)。 另外一个门用来决定何时将数据读入单元,我们将其称为输入门(input gate)。 我们还需要一种机制来重置单元的内容,由遗忘门(forget gate)来管理, 这种设计的动机与门控循环单元相同, 能够通过专用机制决定什么时候记忆或忽略隐状态中的输入。
57.2.1 door:
这三个门的算式和普通RNN计算Ht算式相同。
57.2.2 Candidate memory unit
相当于在ht-1到ht的预测中又加了一层隐藏单元
57.2.3 Memory unit
如果遗忘门始终为(1)且输入门始终为(0), 则过去的记忆元 将随时间被保存并传递到当前时间步。 引入这种设计是为了缓解梯度消失问题, 并更好地捕获序列中的长距离依赖关系。
57.2.4 hidden state
最后,我们需要定义如何计算隐状态, 这就是输出门发挥作用的地方。 在长短期记忆网络中,它仅仅是记忆元的的门控版本。 这就确保了Ht的值始终在区间((-1, 1))内.
只要输出门接近1,我们就能够有效地将所有记忆信息传递给预测部分, 而对于输出门接近(0),我们只保留记忆元内的所有信息,而不需要更新隐状态。
57.2.5 summarize
LSTM的计算流程:
57.3 Implement from scratch
加载时光机器数据集
import torch
from torch import nn
from d2l import torch as d2l
batch_size, num_steps = 32, 35
train_iter, vocab = d2l.load_data_time_machine(batch_size, num_steps)
57.3.1 Initialize model parameters
def get_lstm_params(vocab_size, num_hiddens, device):
num_inputs = num_outputs = vocab_size
def normal(shape):
return torch.randn(size=shape, device=device)*0.01
def three():
return (normal((num_inputs, num_hiddens)),
normal((num_hiddens, num_hiddens)),
torch.zeros(num_hiddens, device=device))
W_xi, W_hi, b_i = three() # 输入门参数
W_xf, W_hf, b_f = three() # 遗忘门参数
W_xo, W_ho, b_o = three() # 输出门参数
W_xc, W_hc, b_c = three() # 候选记忆元参数
# 输出层参数
W_hq = normal((num_hiddens, num_outputs))
b_q = torch.zeros(num_outputs, device=device)
# 附加梯度
params = [W_xi, W_hi, b_i, W_xf, W_hf, b_f, W_xo, W_ho, b_o, W_xc, W_hc,
b_c, W_hq, b_q]
for param in params:
param.requires_grad_(True)
return params
57.3.2 definition model
在初始化函数中, 长短期记忆网络的隐状态需要返回一个额外的记忆元, 单元的值为0,形状为(批量大小,隐藏单元数)。 因此,我们得到以下的状态初始化。
def init_lstm_state(batch_size, num_hiddens, device):
return (torch.zeros((batch_size, num_hiddens), device=device),
torch.zeros((batch_size, num_hiddens), device=device))
实际模型的定义与我们前面讨论的一样: 提供三个门和一个额外的记忆元。 请注意,只有隐状态才会传递到输出层, 而记忆元(\mathbf{C}_t)不直接参与输出计算。
def lstm(inputs, state, params):
[W_xi, W_hi, b_i, W_xf, W_hf, b_f, W_xo, W_ho, b_o, W_xc, W_hc, b_c,
W_hq, b_q] = params
(H, C) = state
outputs = []
for X in inputs:
I = torch.sigmoid((X @ W_xi) + (H @ W_hi) + b_i)
F = torch.sigmoid((X @ W_xf) + (H @ W_hf) + b_f)
O = torch.sigmoid((X @ W_xo) + (H @ W_ho) + b_o)
C_tilda = torch.tanh((X @ W_xc) + (H @ W_hc) + b_c)
C = F * C + I * C_tilda
H = O * torch.tanh(C)
Y = (H @ W_hq) + b_q
outputs.append(Y)
return torch.cat(outputs, dim=0), (H, C)
57.3.3 Training and prediction
vocab_size, num_hiddens, device = len(vocab), 256, d2l.try_gpu()
num_epochs, lr = 500, 1
model = d2l.RNNModelScratch(len(vocab), num_hiddens, device, get_lstm_params,
init_lstm_state, lstm)
d2l.train_ch8(model, train_iter, vocab, lr, num_epochs, device)
58 Deep Recurrent Neural Network
- 深层循环神经网络 ,简称DRNN 是循环神经网络(Recurrent Neural Network,简称RNN)的一种扩展形式,它具有多个隐藏层,可以处理长度不固定的序列数据。以下是关于深层循环神经网络的详细解释:
-
定义与原理:
- 深层循环神经网络通过在RNN的基础上增加多个隐藏层来构建,从而提高了模型的表达能力和对复杂函数的学习能力。
- 每个隐藏层都有自己的权重矩阵,可以对输入和前一个隐藏层的状态进行转换。这使得DRNN能够通过多次非线性变换来学习更高级别的特征。
-
特点:
- 处理序列数据:DRNN可以处理长度不固定的序列数据,如自然语言处理中的文本序列、语音识别中的语音序列等。
- 增强的表达能力:通过增加隐藏层的数量,DRNN能够学习更复杂的函数,并增强模型的表达能力。
- 计算复杂性:由于DRNN的计算涉及到多个时间步和多个隐藏层,因此其计算量相对较大。这可能导致训练过程耗时较长。
- Dropout使用:DRNN一般不在同一层使用dropout,而是在同一时刻不同层之间使用dropout,以防止过拟合。
-
应用领域:
- 自然语言处理:如文本生成、机器翻译、情感分析等。
- 语音识别:将输入的语音信号转化为文本形式,进行语音识别和语音合成。
- 图像处理:虽然DRNN主要被用于处理序列数据,但在某些图像处理任务中,如视频分析、动作识别等,也可以应用DRNN。
-
改进方法:
- 长短时记忆网络(LSTM):为了解决RNN在处理长序列时可能出现的梯度消失和梯度爆炸问题,研究者提出了LSTM。LSTM通过引入门控机制,能够捕捉长期依赖关系。
- 门控循环单元(GRU):GRU是LSTM的简化版本,它通过减少门控单元的数量降低了计算复杂度,同时保持了一定的性能。
-
训练与优化:
- 反向传播时间(BPTT):DRNN的训练通常使用BPTT算法,该算法在序列的每个时间步上进行正向传播,然后通过反向传播计算参数的梯度值并更新参数。
- 优化算法:在训练DRNN时,可以使用各种优化算法来调整神经网络中的参数,如随机梯度下降(SGD)、动量法、Adam等。
58.1 Deep Recurrent Neural Network
- .之前的RNN都只有一个隐藏层(序列变长不算是深度),而一个隐藏层的RNN一旦做的很宽就容易出现过拟合。因此我们考虑将网络做的更深而非更宽,每层都只做一点非线性,靠层数叠加得到更加非线性的模型。
浅RNN:输入-隐层-输出
深RNN:输入-隐层-隐层-…-输出
58.2 Formula
第一层的第t步状态是关于第一层第t-1步状态和第t步输入的函数
第j层的第t步状态是关于当前层上一步步状态和上一层当前步的函数
由最后一个隐藏层得到输出
58.3 summarize
- 深度循环神经网络使用多个隐藏层来获得更多的非线性性
将RNN/GRU/LSTM做深都是一个道理,三者只是使用的函数f不同。
59 Encoder decoder architecture
59.1 Explanation in CNN
考虑一个CNN模型:
整个CNN实际上可以看作一个编码器,解码器两部分。
- 底层的神经网络,也就是编码器将输入编码成能被模型识别的中间表达形式,也就是特征
- 解码器将中间结果解码为输出
59.2 Interpretation in RNN
对于RNN而言,同样有着类似的划分
- 编码器将输入文本表示为向量
- 解码器将向量表示为输出
59.3 Abstract encoder decoder architecture
指一个模型被分为两块:
- 一块是编码器,也叫encoder,用于将输入处理为一个中间状态
- 一块是解码器,也叫decoder,用于将中间状态表示为输出
- 解码器也可以有额外的输入提供信息
60 Sequence to sequence learning
- 序列到序列学习( 简称Seq2Seq)是一种深度学习模型,主要用于将一个序列转化为另一个序列。以下是关于序列到序列学习的详细解释:
1. 定义与原理
- 定义:序列到序列学习是指训练一个模型,使其能够将一个序列(如一个英文句子)转化为另一个序列(如对应的法文句子)。
- 原理:序列到序列模型通常由两个主要部分组成:编码器(Encoder)和解码器(Decoder)。编码器负责将输入序列编码为一个固定长度的向量,而解码器则利用这个向量来生成输出序列。
2. 模型结构
-
编码器:
- 将输入序列(如英文句子)中的每个元素(如单词)通过嵌入层(Embedding Layer)转换为向量表示。
- 使用循环神经网络(RNN)、长短期记忆网络(LSTM)或门控循环单元(GRU)等模型计算整个输入序列的向量表示(通常称为上下文向量或隐藏状态)。
-
解码器:
- 利用编码器的输出(上下文向量)作为初始状态,开始逐步生成输出序列。
- 在每个时间步,解码器都会根据前一个时间步的输出和当前状态来预测下一个输出元素。
- 应用领域
-
机器翻译:将一种语言的句子翻译为另一种语言的句子。
-
文本摘要:将长篇文章或文档总结为简短的摘要。
-
对话系统:根据用户的输入生成相应的回复或响应。
- 关键技术
- 注意力机制(Attention Mechanism):
- 允许解码器在生成输出序列时关注编码器输出的不同部分,从而提高模型的预测能力。
- 注意力权重通常通过softmax函数计算得到,用于对编码器输出进行加权求和。
- 束搜索(Beam Search):
- 一种搜索策略,用于在解码过程中找到最佳输出序列。
- 通过维护一个候选集合,并根据某个评估准则(如概率)来筛选最优输出。
- 改进与优化
- Scheduled Sampling:
- 一种改善序列生成任务中错误累积问题的方法。
- 在训练早期使用目标序列中的真实元素作为解码器输入,随着训练的进行逐渐使用生成的元素作为输入。
- 半监督学习:
- 利用未标注数据进行预训练,然后通过有标注数据进行微调,以提高模型的性能。
60.1 Application example: Machine translation
- 给定一个源语言的句子,自动翻译成目标语言
- 这两个句子可以有不同的长度
60.2 model architecture : Seq2seq
-
序列到序列模型由编码器-解码器构成。
-
编码器RNN可以是双向,由于输入的句子是完整地,可以正着看,也可以反着看;而解码器只能是单向,由于预测时,只能正着去预测。
-
编码器,解码器采用不同的RNN,此RNN也可以是GRU,LSTM等。
60.3 Encoder decoder details
-
编码器的RNN没有连接输出层
-
编码器的最后时间步的隐状态用作解码器的初始隐状态(图中箭头的传递)
60.4 Training and reasoning
- 之前提到编码器没有输出层,只有解码器有,于是损失函数的计算只关注解码器的输出层。
- 训练和预测(推理)有区别的,训练时解码器使用目标句子(真值)作为输入,以指导模型训练;而推理时无法提前得知真值,需要一步一步进行预测。
60.5 Measuring the quality of generated sequences:BLEU
BLUE值,全称Best Linear Unbiased Estimator,即最佳线性无偏估计量。以下是关于BLUE值的详细定义和解释:
-
定义:
- BLUE值是混合线性模型中固定因子的最佳线性无偏估计值。
- 它是在古典假定条件下,对于固定效应参数进行估计时,具有最小方差且无偏的线性估计量。
-
特点:
- 最佳:BLUE值提供了估计误差最小的线性估计。
- 线性:BLUE值的计算基于线性模型,即估计值与观察值之间呈线性关系。
- 无偏:BLUE值的数学期望等于真值,即估计值没有系统偏差。
- 评估当前表现:BLUE值着重于评估品种在当前条件下的表现,而不是预测其未来的表现。
-
应用:
- 在GWAS(全基因组关联研究)或GS(基因组选择)等遗传分析中,BLUE值常被用作表型值进行后续计算。
- 在农业育种中,BLUE值可用于评估作物品种在不同环境条件下的表现,从而选择适应性强、产量高的品种。
-
与BLUP值的区别:
- BLUP值(Best Linear Unbiased Prediction)是混合线性模型中随机因子的最佳线性无偏预测值,它着重于预测品种将来的表现。
- BLUE值和BLUP值在概念上相似,但应用场合和目的不同。BLUE值用于评估当前表现,而BLUP值用于预测未来表现。
-
计算方法:
- BLUE值的计算通常基于线性混合模型,其中需要区分固定因子和随机因子。
- 在实际应用中,可以使用统计软件(如R语言中的lme4包)进行建模和计算。
60.6 BLUE value definition:
宗成庆老师《统计自然语言处理》(第二版)一书中关于BLEU的定义:
同时,吴恩达深度学习课程中也是使用这一方式定义。但观察两种方式,BP惩罚因子的计算是一致的,pn也是使用了几何平均的方式,只是对于wn这一加权值的选择有所不同。
60.7 Definitive parsing
BLEU值衡量的是精确率,而且对不同n-gram进行集成打分。
-
BP惩罚因子:为了惩罚过短的句子,由于过短的句子基数小,精确率容易提升,所以加上一个BP乘子,当预测句子长度<参考句子长度,则BP<1。
-
wn的选择:李沐老师课程中是采用了 1 2 n \frac{1}{2^n} 2n1作为加权因子,n越大,加权因子越小,但由于pn<1,赋予的权重越大,即长匹配具有更高的权重。而宗老师的书中所述:在BLEU的基线系统中取N=4,wn=1/N,也可以参考。
60.8 QA
问题:LSTM、GRU、Seq2Seq的区别是什么?
Seq2Seq是一种由编码器和解码器组成的框架,而LSTM、GRU是组成编码器和解码器的一种单元。
问题:encoder的输出和decoder的输入,拼接和按位相加起来有什么区别么?
不能够按位加,由于encoder的输出最后维度是hidden_size,而decoder的输入最后维度是embedding_size,可能不一样,所以用拼接。
问题:embedding层是做word2vec吗?
这里不是,这里是从头开始训练。现在用的比较多得都是预训练,BERT等。