持续创造,加快生长!这是我参加「日新计划 10 月更文应战」的第7天,点击检查活动详情


不论你懂不懂seq2seq都没事,你都能够看这篇文章,只需你懂什么是神经网络你就能够看懂这篇文章。

这个不需要什么太多常识储藏就能看懂。


原理

先看一下神经网络,神经网络是在做什么:输入通过躲藏层核算,得到输出

比如一个痴汉,通过核算发现自己是小丑。

怎么用PyTorch实现一个Encoder-Decoder框架?

实际进程是这样的:

怎么用PyTorch实现一个Encoder-Decoder框架?

假定现在是在一个单躲藏层的神经网络中。

假定我的输入是个长为10的向量(由于有十个字),那现在inpput:[X]101inpput: [X]_{10\times 1}

通过一个躲藏层核算之后,躲藏层长度是12,现在hidden:[H]121hidden: [H]_{12\times 1}

最终得到输出向量长度为7,那便是output:[Y]71output:[Y]_{7\times 1}

核算进程便是:

H=WHXX+bHH = W_{HX}X + b_{H} Y=WYHH+bYY = W_{YH}H + b_{Y}

其间权重WW和偏置bb的维度为别是: [WHX]1210[W_{HX}]_{12\times 10}[bH]121[b_{H}]_{12\times 1}[WYH]712[W_{YH}]_{7\times 12}[bY]71[b_{Y}]_{7\times 1}

普通长度的神经网络确实能够改变向量的长度,可是他能做的工作太有限了,并且跟着数据量的增大以及向量的边长, 核算开支会爆炸增长。这个时候咱们可能就需要用到一些其他东西来进行核算。

比如对于一些不定长序列的转化,例如机器翻译,咱们能够运用一种称为seq2sqe的东西,即一个sequence到另一个sequence,这就要用到一个所谓的encoder-decoder。

从原理上来讲,这两部分首要担任的功用是:

  • encoder:表明输入
  • decoder:得到输出

encoder-decoder便是处理输入并得到对应的输出的一个架构

图呢看起来仍是这个图,可是你能够把前一部分做向量对其的封装起来做encoder,后一部分核算输出的封装起来做decoder。

怎么用PyTorch实现一个Encoder-Decoder框架?

当然了,已然变复杂了,功用也不是彻底一样的,在decoder部分咱们仍是能够接纳额定的输入的。

怎么用PyTorch实现一个Encoder-Decoder框架?

也便是输入在承受编码器产生的成果的一起,还能够接纳新的输入进行相应的核算。

怎么用PyTorch实现一个Encoder-Decoder框架?


代码

from torch import nn

根本操作先导个包。

class Encoder(nn.Module):
    def __init__(self, **kwargs):
        super(Encoder, self).__init__(**kwargs)
    def forward(self, X, *args):
        raise NotImplementedError

encoder部分搞一个类,传入对应的参数,这儿界说一个前向传达进行核算,承受输入X,对其进行核算,得到中心状态。

class Decoder(nn.Module):
    def __init__(self, **kwargs):
        super(Decoder, self).__init__(**kwargs)
    def init_state(self, enc_outputs, *args):
        raise NotImplementedError
    def forward(self, X, state):
        raise NotImplementedError 

decoder部分看一会儿,这儿开始也是进行一些参数的初始化

中心有个init_state是承受encoder传来的核算成果,所以参数列表里有个enc_outputs即encoder的输出作为该部分的输入。

decoder部分也有一个前向传达的核算进程,这个是承受额定输入的,是否运用这一部分取决于你是否要在这一部分增加输入。

class EncoderDecoder(nn.Module):
    def __init__(self, encoder, decoder, **kwargs):
        super(EncoderDecoder, self).__init__(**kwargs)
        self.encoder = encoder
        self.decoder = decoder
    def forward(self, enc_X, dec_X, *args):
        enc_outputs = self.encoder(enc_X, *args)
        dec_state = self.decoder.init_state(enc_outputs, *args)
        return self.decoder(dec_X, dec_state)

最终将二者一个合并,初始化对其运用相应的encoder和decoder。 在核算部分能够看到有两个参数enc_Xdec_X,这两个分别是encoder的输入和decoder的输入。

decoder的状态是运用encoder的初始化函数,对encoder的输出进行核算的。最终的输出是运用decoder的输入和上一步取得的decoder的状态进行核算的。

大致结构是这样的,具体内容要根据实际操作进行填充。