IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 人工智能 -> 为了小论文之跟着李沐学AI(二十) -> 正文阅读

[人工智能]为了小论文之跟着李沐学AI(二十)

Encoder和Decoder

其实现在发现其实LSTM,GRU就是一个Encoder和Decoder的例子。我们把最后的全链接层想象成解码前,前面的RNN网络想象成编码器。是不是有那味儿了。

class Encoder(nn.Module):
    """编码器-解码器结构的基本编码器接口。"""
    def __init__(self, **kwargs):
        super(Encoder, self).__init__(**kwargs)

    def forward(self, X, *args):
        raise NotImplementedError
    #编码器你看,其实跟之前的网络是相似的,没什么太大的差别,给一个X输出一个东西  

Encoder,其实乍一看,你会发现和我们之前的网络结构没有什么本质上的区别

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

# 解码器就有点不同了,首先他会根据encoder传过来的输入,更新自己的状态
# 其次,他也有自己的输入X,这个就是自己很奇妙的地方,就是他有自己的输入

Decoder也只是略有不同。首先,他需要初始化一个隐藏状态,这个隐藏状态是来自于Encoder的输出的。其次,对于Deocder,他是有一个自己的输入的。

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)

再写一个类包装它的话,就是这样。

现在我们真正来实现一个Seq2Seq的模型

class Seq2SeqEncoder(d2l.Encoder):
    """用于序列到序列学习的循环神经网络编码器。"""
    def __init__(self, vocab_size, embed_size, num_hiddens, num_layers,
                 dropout=0, **kwargs):
        super(Seq2SeqEncoder, self).__init__(**kwargs)
        # 嵌入层
        self.embedding = nn.Embedding(vocab_size, embed_size)
        self.rnn = nn.GRU(embed_size, num_hiddens, num_layers,
                          dropout=dropout)

    def forward(self, X, *args):
        # 输出'X'的形状:(`batch_size`, `num_steps`, `embed_size`)
        X = self.embedding(X)
        # 在循环神经网络模型中,第一个轴对应于时间步
        X = X.permute(1, 0, 2)
        # 如果未提及状态,则默认为0
        output, state = self.rnn(X)
        # `output`的形状: (`num_steps`, `batch_size`, `num_hiddens`)
        # `state[0]`的形状: (`num_layers`, `batch_size`, `num_hiddens`)
        return output, state

在这个Encoder部分。首先我们会用nn.Embedding去嵌入我们的输入
再用一个rnn去获得我们的输出
记得我们的X输入,需要调整它的维度,让时间步在前面

class Seq2SeqDecoder(d2l.Decoder):
    """用于序列到序列学习的循环神经网络解码器。"""
    def __init__(self, vocab_size, embed_size, num_hiddens, num_layers,
                 dropout=0, **kwargs):
        super(Seq2SeqDecoder, self).__init__(**kwargs)
        self.embedding = nn.Embedding(vocab_size, embed_size)
        self.rnn = nn.GRU(embed_size + num_hiddens, num_hiddens, num_layers,
                          dropout=dropout)
        self.dense = nn.Linear(num_hiddens, vocab_size)

    def init_state(self, enc_outputs, *args):
        return enc_outputs[1]

    def forward(self, X, state):
        # 输出'X'的形状:(`batch_size`, `num_steps`, `embed_size`)
        X = self.embedding(X).permute(1, 0, 2)
        # 广播`context`,使其具有与`X`相同的`num_steps`
        context = state[-1].repeat(X.shape[0], 1, 1)
        X_and_context = torch.cat((X, context), 2)
        output, state = self.rnn(X_and_context, state)
        output = self.dense(output).permute(1, 0, 2)
        # `output`的形状: (`batch_size`, `num_steps`, `vocab_size`)
        # `state[0]`的形状: (`num_layers`, `batch_size`, `num_hiddens`)
        return output, state

其实真正有意思的代码都在decoder部分,来看我分析。
首先我们要明确,H是一个声明东西,之前我误解的把他理解为一个 hiddenshiddens的矩阵,不是这样的,它是一个batch_size * hiddens的矩阵。对应到每一个batch(可以理解为每一句话),都是一个向量。这个向量怎么来的。看我分析,首先对于我们的输入
比如 4 * 7,4表示batch_size 7表示表示timestep
首先我们会进行一个embedding ,假设我们的embedding层是一个 vocab_size为10,embed_size为8的一个层。
那么它就会变成4 * 7 8的一个3d矩阵。
如果我们要把这个东西输入到rnn的网络中
我们会先进行维度的置换,因为我们想要的是每一个时间步的迭代更新,而不是,一个batch_size的迭代更新对吗
变成一个7
4
8的矩阵后,在一个rnn模型中(不是GRU或者LSTM)
会有Whh 一个 embedding * hiddens的矩阵(或略Bias) 在这里就是一个816(假设hiddens是16)的。经过点乘变成一个(每一次迭代,只会进去 28) 216这样一个矩阵(用T表示)(这是一个时间步的迭代)
与此同时,会初始化一个H ,这个H的维数是一个 batchsize
hidddens的矩阵,也就是216的矩阵用H表示 H + T就是我们想要新的隐藏层H,(如果根据这个H 216 的H,再加上一个输出层 16*8,这里为什么是8,这个输出层跟着什么东西,全部看你想要获得一个什么东西,比如在这里,我想做一个文本的预测,做个文本的纠错问题,我希望它的输出还是一个词,那这个词只会来自于vocab字典中,所以我们映射成embedding的形状,到最后我们知道它是一个什么词对吗!

分析完了这么多,我们正式来看一下decoder,其实对于前面的理解并不难,难的是GRU的这里变成了embed_size + num_hiddens为什么是这样的,下面来看我分析。
我们定位到forward函数中,之前的循环神经网络,decoder部分我们直接套了一个hiddens * embedding的一个全连接层,但是我们不满足于H带出来的输出,我们希望是H + X进行输出,怎么做,进行维度上的concat,在这里,你可以看我们的X 是一个 4 * 7 8的矩阵 4表示我们的batchsize 7表示我们的timestep 8 表示我们的embeddingsize,我在embeddingsize这个维度concat了,其实是在embedding的维数上进行一个concat,让x的信息,让两个隐藏层的信息进去,这样就相当于带了两个隐藏层的信息和自己的embedding,。然后再进入一个rnn,然后出来的向量是一个batchsziehiddien,在进入一个全连接层,返回自己的vocab

  人工智能 最新文章
2022吴恩达机器学习课程——第二课(神经网
第十五章 规则学习
FixMatch: Simplifying Semi-Supervised Le
数据挖掘Java——Kmeans算法的实现
大脑皮层的分割方法
【翻译】GPT-3是如何工作的
论文笔记:TEACHTEXT: CrossModal Generaliz
python从零学(六)
详解Python 3.x 导入(import)
【答读者问27】backtrader不支持最新版本的
上一篇文章      下一篇文章      查看所有文章
加:2021-11-20 18:23:44  更:2021-11-20 18:26:17 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/27 4:36:35-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码