DL Homework 11

2023-12-17 10:20
文章标签 dl homework

本文主要是介绍DL Homework 11,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

由于好多同学问我要代码,但这两天光顾着考四六级了,所以只能今天熬夜先给赶出来,第一题先搁置,晚点补上,先写第二题

习题6-4  推导LSTM网络中参数的梯度, 并分析其避免梯度消失的效果

习题6-3P  编程实现下图LSTM运行过程

 1. 使用Numpy实现LSTM算子

import numpy as npx = np.array([[1, 0, 0, 1],[3, 1, 0, 1],[2, 0, 0, 1],[4, 1, 0, 1],[2, 0, 0, 1],[1, 0, 1, 1],[3, -1, 0, 1],[6, 1, 0, 1],[1, 0, 1, 1]])
# x = np.array([
#               [3, 1, 0, 1],
#
#               [4, 1, 0, 1],
#               [2, 0, 0, 1],
#               [1, 0, 1, 1],
#               [3, -1, 0, 1]])
inputGate_W = np.array([0, 100, 0, -10])
outputGate_W = np.array([0, 0, 100, -10])
forgetGate_W = np.array([0, 100, 0, 10])
c_W = np.array([1, 0, 0, 0])def sigmoid(x):y = 1 / (1 + np.exp(-x))if y >= 0.5:return 1else:return 0temp = 0
y = []
c = []
for input in x:c.append(temp)temp_c = np.sum(np.multiply(input, c_W))temp_input = sigmoid(np.sum(np.multiply(input, inputGate_W)))temp_forget = sigmoid(np.sum(np.multiply(input, forgetGate_W)))temp_output = sigmoid(np.sum(np.multiply(input, outputGate_W)))temp = temp_c * temp_input + temp_forget * tempy.append(temp_output * temp)
print("memory:",c)
print("y     :",y)

 实验结果如下:

        这么一看答案是不是和要求一样,确实和要求一样,而且仿照李老师给的图写的代码,但是细心的同学就会发现,代码表达的模型和李老师展示的不一致,不能说不一致,而是按照一般的LSTM模型,候选状态需要由tanh函数作为激活函数,而我们看李老师的图,再x_1,x_2,x_3分别为3,0,1的时候计算得到的输入值,这里记作c_t,c_t应该是3,并且通过激活函数后还是3,这里我们直接垮掉了,因此我经历了长达1小时的挣扎,但得到的答案五花八门,不太靠谱,不得已,抱着追求真理的想法,我去再次听了一遍李老师的手撕LSTM,李老师明确指出了,他将tanh激活函数,也叫做针对输入信息和当前隐​​​状态激活函数输出的激活函数修改了.

        老师是这么说的:input activate function是linear的,memory cell的activate function也是linear的,总结一句话,老师将tanh激活函数换为线性激活函数。所以可以通过输入3,输出也是3

并且将sigmoid的值域修改为【0,1】,只有两个值。与一般的LSTM模型有了细微的差距

邱老师的《神经网络与深度学习》

        但是通过搜索了大量资料我发现Pytorch不提供修改LSTMCell和RSTM的内部激活函数的端口,所以为了验证后面两个实验的正确性,我仿照一般的LSTM模型手写了一个检测版本如下:

import numpy as npx = np.array([[1, 0, 0, 1],[3, 1, 0, 1],[2, 0, 0, 1],[4, 1, 0, 1],[2, 0, 0, 1],[1, 0, 1, 1],[3, -1, 0, 1],[6, 1, 0, 1],[1, 0, 1, 1]])inputGate_W = np.array([0, 100, 0, -10])
outputGate_W = np.array([0, 0, 100, -10])
forgetGate_W = np.array([0, 100, 0, 10])
c_W = np.array([1, 0, 0, 0])def sigmoid(x):return 1 / (1 + np.exp(-x))temp = 0
y = []
for input in x:temp_c = np.tanh(np.sum(np.multiply(input, c_W)))temp_input = sigmoid(np.sum(np.multiply(input, inputGate_W)))temp_forget = sigmoid(np.sum(np.multiply(input, forgetGate_W)))temp_output = sigmoid(np.sum(np.multiply(input, outputGate_W)))temp = temp_c * temp_input + temp_forget * tempy.append(temp_output * np.tanh(temp))
# print(y)
outputs_rounded = [round(x) for x in y]
print(outputs_rounded)
# 感觉有点问题没用tanh函数啊

 实验结果如下:

2. 使用nn.LSTMCell实现

        当然看函数的用法肯定是官方文档原汁原味,但是排除像我这种英语不好的一看英语脑袋疼,我也发现了一个特别好的中译版的和官方文档内容完全一样。

PyTorch - torch.nn.LSTMCell (runebook.dev)

LSTMCell — PyTorch 2.1 documentation

Parameters

  • input_size – 输入 x 中预期特征的数量
  • hidden_​​size – 隐藏状态下的特征数量 h
  • 偏差 – 如果 False ,则该层不使用偏差权重 b_ih 和 b_hh 。默认值: True

输入:输入,(h_0, c_0)

  • 形状 (batch, input_size) 的输入:包含输入特征的张量
  • h_0 形状为 (batch, hidden_size) :包含批次中每个元素的初始隐藏状态的张量。
  • c_0 形状为 (batch, hidden_size) :包含批次中每个元素的初始单元状态的张量。

    如果未提供 (h_0, c_0) ,则 h_0 和 c_0 均默认为零。

输出:(h_1,c_1)

  • h_1 形状为 (batch, hidden_size) :包含批次中每个元素的下一个隐藏状态的张量
  • c_1 形状为 (batch, hidden_size) :包含批次中每个元素的下一个单元状态的张量

Variables:

  • ~LSTMCell.weight_ih – 可学习的输入隐藏权重,形状为 (4*hidden_size, input_size)
  • ~LSTMCell.weight_hh – 可学习的隐藏权重,形状为 (4*hidden_size, hidden_size)
  • ~LSTMCell.bias_ih – 可学习的输入隐藏偏差,形状为 (4*hidden_size)
  • ~LSTMCell.bias_hh – 可学习的隐藏-隐藏偏差,形状为 (4*hidden_size)

这里解释一下,对LSTMCell的模型进行变量初始化的时候,为什么大小为第一维度都为4 * hidden

具体来说,lstm_cell.weight_ih 被划分为以下四个部分(按行分割):

  1. Forget Gate 的权重:控制前一个隐藏状态中信息被遗忘的程度。这部分的权重用于计算是否要从前一个隐藏状态中丢弃哪些信息。
  2. Input Gate 的权重:控制新的输入信息对当前隐藏状态的贡献程度。这部分的权重用于计算应该增加哪些新的信息到当前隐藏状态中。
  3. Candidate Value 的权重:用于计算更新的候选值,它包含了可能添加到当前隐藏状态中的新信息。
  4. Output Gate 的权重:控制当前隐藏状态对下一时刻输出的贡献程度。这部分的权重用于计算应该输出哪些信息给下一个时间步。

 总结的说就是将四个门的参数以行为单位同时封装在一个矩阵中了,其他参数的第一维向量也是如次的含义,ih和hh分别代表的输入层和各个门之间的参数,hh代表输出层与各个门之间的参数。

代码如下:

import torch
import torch.nn as nn# 输入数据 x 维度需要变换,因为LSTMcell接收的是(time_steps,batch_size,input_size)
# time_steps = 9, batch_size = 1, input_size = 4
x = torch.tensor([[1, 0, 0, 1],[3, 1, 0, 1],[2, 0, 0, 1],[4, 1, 0, 1],[2, 0, 0, 1],[1, 0, 1, 1],[3, -1, 0, 1],[6, 1, 0, 1],[1, 0, 1, 1]], dtype=torch.float)
x = x.unsqueeze(1)
# LSTM的输入size和隐藏层size
input_size = 4
hidden_size = 1# 定义LSTM单元
lstm_cell = nn.LSTMCell(input_size=input_size, hidden_size=hidden_size, bias=False)lstm_cell.weight_ih.data = torch.tensor([[0, 100, 0, 10],   # forget gate[0, 100, 0, -10],  # input gate[1, 0, 0, 0], # output gate[0, 0, 100, -10]]).float()  # cell gate
lstm_cell.weight_hh.data = torch.zeros([4 * hidden_size, hidden_size])
#https://runebook.dev/zh/docs/pytorch/generated/torch.nn.lstmcellhx = torch.zeros(1, hidden_size)
cx = torch.zeros(1, hidden_size)
outputs = []
for i in range(len(x)):hx, cx = lstm_cell(x[i], (hx, cx))outputs.append(hx.detach().numpy()[0][0])
outputs_rounded = [round(x) for x in outputs]
print(outputs_rounded)

实验结果:

和Numpy流程的结果一致,所以答案正确。 

3. 使用nn.LSTM实现

PyTorch - torch.nn.LSTM (runebook.dev)

LSTM — PyTorch 2.1 documentation

依旧是两个链接,个人建议点一下链接自己去看一下,个人感觉和RNN参数及其相似,RNN参数懂了,我感觉这个就没有难度。

Parameters

  • input_size – 输入 x 中预期特征的数量
  • hidden_​​size – 隐藏状态下的特征数量 h
  • num_layers – 循环层数。例如,设置 num_layers=2 意味着将两个 LSTM 堆叠在一起形成 stacked LSTM ,第二个 LSTM 接收第一个 LSTM 的输出并计算最终结果。默认值:1
  • 偏差 – 如果 False ,则该层不使用偏差权重 b_ih 和 b_hh 。默认值: True
  • batch_first – 如果是 True ,则输入和输出张量提供为(batch、seq、feature)。默认: False
  • dropout – 如果非零,则在除最后一层之外的每个 LSTM 层的输出上引入 Dropout 层,dropout 概率等于 dropout 。默认值:0
  • 双向 – 如果是 True ,则成为双向 LSTM。默认: False
  • proj_size – 如果是 > 0 ,将使用具有相应大小投影的 LSTM。默认值:0

输入:输入,(h_0, c_0)

  • 形状 (seq_len, batch, input_size) 的输入:包含输入序列特征的张量。输入也可以是打包的可变长度序列。有关详细信息,请参阅 torch.nn.utils.rnn.pack_padded_sequence() 或 torch.nn.utils.rnn.pack_sequence() 。
  • h_0 形状为 (num_layers * num_directions, batch, hidden_size) :包含批次中每个元素的初始隐藏状态的张量。如果 LSTM 是双向的,则 num_directions 应为 2,否则应为 1。如果指定了 proj_size > 0 ,则形状必须为 (num_layers * num_directions, batch, proj_size) 。
  • c_0 形状为 (num_layers * num_directions, batch, hidden_size) :包含批次中每个元素的初始单元状态的张量。

    如果未提供 (h_0, c_0) ,则 h_0 和 c_0 均默认为零。

输出:输出,(h_n, c_n)

  • 形状 (seq_len, batch, num_directions * hidden_size) 的输出:对于每个 t ,包含来自 LSTM 最后一层的输出特征 (h_t) 的张量。如果 torch.nn.utils.rnn.PackedSequence 作为输入,输出也将是压缩序列。如果指定 proj_size > 0 ,输出形状将为 (seq_len, batch, num_directions * proj_size) 。

    对于未包装的情况,可以使用 output.view(seq_len, batch, num_directions, hidden_size) 来区分方向,向前和向后分别是方向 0 和 1 。同样,在包装盒中,方向可以分开。

  • h_n 形状为 (num_layers * num_directions, batch, hidden_size) :包含 t = seq_len 隐藏状态的张量。如果指定了 proj_size > 0 ,则 h_n 形状将为 (num_layers * num_directions, batch, proj_size) 。

    与输出一样,可以使用 h_n.view(num_layers, num_directions, batch, hidden_size) 来分离层,对于 c_n 也类似。

  • c_n 形状为 (num_layers * num_directions, batch, hidden_size) :包含 t = seq_len 细胞状态的张量。

代码如下:

import torch
import torch.nn as nn# 输入数据 x 维度需要变换,因为 LSTM 接收的是 (sequence_length, batch_size, input_size)
# sequence_length = 9, batch_size = 1, input_size = 4
x = torch.tensor([[1, 0, 0, 1],[3, 1, 0, 1],[2, 0, 0, 1],[4, 1, 0, 1],[2, 0, 0, 1],[1, 0, 1, 1],[3, -1, 0, 1],[6, 1, 0, 1],[1, 0, 1, 1]], dtype=torch.float)
x = x.unsqueeze(1)# LSTM 的输入 size 和隐藏层 size
input_size = 4
hidden_size = 1# 定义 LSTM 模型
lstm = nn.LSTM(input_size=input_size, hidden_size=hidden_size, bias=False)# 设置 LSTM 的权重矩阵
lstm.weight_ih_l0.data = torch.tensor([[0, 100, 0, 10],   # forget gate[0, 100, 0, -10],  # input gate[1, 0, 0, 0],      # output gate[0, 0, 100, -10]]).float()  # cell gate
lstm.weight_hh_l0.data = torch.zeros([4 * hidden_size, hidden_size])# 初始化隐藏状态和记忆状态
hx = torch.zeros(1, 1, hidden_size)
cx = torch.zeros(1, 1, hidden_size)# 前向传播
outputs, (hx, cx) = lstm(x, (hx, cx))
outputs = outputs.squeeze().tolist()# print(outputs)
outputs_rounded = [round(x) for x in outputs]
print(outputs_rounded)

输出结果如下:

【23-24 秋学期】NNDL 作业11 LSTM-CSDN博客

台大李宏毅机器学习——RNN | 碎碎念 (samaelchen.github.io)

LSTM两个激活函数不能一样_lstm activation-CSDN博客

李宏毅手撕LSTM_哔哩哔哩_bilibili

这篇关于DL Homework 11的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/504035

相关文章

消除安卓SDK更新时的“https://dl-ssl.google.com refused”异常的方法

消除安卓SDK更新时的“https://dl-ssl.google.com refused”异常的方法   消除安卓SDK更新时的“https://dl-ssl.google.com refused”异常的方法 [转载]原地址:http://blog.csdn.net/x605940745/article/details/17911115 消除SDK更新时的“

【DL--05】深度学习基本概念—函数式模型

函数式模型 函数式模型算是本文档比较原创的词汇了,所以这里要说一下 在Keras 0.x中,模型其实有两种,一种叫Sequential,称为序贯模型,也就是单输入单输出,一条路通到底,层与层之间只有相邻关系,跨层连接统统没有。这种模型编译速度快,操作上也比较简单。第二种模型称为Graph,即图模型,这个模型支持多输入多输出,层与层之间想怎么连怎么连,但是编译速度慢。可以看到,Sequentia

【DL--04】深度学习基本概念—data_format

data_format 这是一个无可奈何的问题,在如何表示一组彩色图片的问题上,Theano和TensorFlow发生了分歧,’th’模式,也即Theano模式会把100张RGB三通道的16×32(高为16宽为32)彩色图表示为下面这种形式(100,3,16,32),Caffe采取的也是这种方式。第0个维度是样本维,代表样本的数目,第1个维度是通道维,代表颜色通道数。后面两个就是高和宽了。这种t

【DL--03】深度学习基本概念—张量

张量 TensorFlow中的中心数据单位是张量。张量由一组成形为任意数量的数组的原始值组成。张量的等级是其维数。以下是张量的一些例子: 3 # a rank 0 tensor; this is a scalar with shape [][1. ,2., 3.] # a rank 1 tensor; this is a vector with shape [3][[1., 2., 3.]

【DL--02】深度学习基本概念--符号计算

符号计算 Keras的底层库使用Theano或TensorFlow,这两个库也称为Keras的后端。无论是Theano还是TensorFlow,都是一个“符号式”的库。 因此,这也使得Keras的编程与传统的Python代码有所差别。笼统的说,符号主义的计算首先定义各种变量,然后建立一个“计算图”,计算图规定了各个变量之间的计算关系。建立好的计算图需要编译以确定其内部细节,然而,此时的计算图还

【DL--01】深度学习 揭开DL的神秘面纱

什么是深度学习 深度学习=深度神经网络+机器学习 人工智能 > 机器学习 > 表示学习 > 深度学习 神经元模型 输入信号、加权求和、加偏置、激活函数、输出 全连接层 输入信号、输入层、隐层(多个神经元)、输出层(多个输出,每个对应一个分类)、目标函数(交叉熵) 待求的参数:连接矩阵W、偏置b 训练方法:随机梯度下降,BP算法(后向传播) Python中深度学习实现:Ke

【DL--22】实现神经网络算法NeuralNetwork以及手写数字识别

1.NeuralNetwork.py #coding:utf-8import numpy as np#定义双曲函数和他们的导数def tanh(x):return np.tanh(x)def tanh_deriv(x):return 1.0 - np.tanh(x)**2def logistic(x):return 1/(1 + np.exp(-x))def logistic_derivati

android开发之Android SDK更新出现Connection to http://dl-ssl.google.com refused 的解决办法

文章出处:http://blog.csdn.net/foxeatapple/article/details/8450372 问题描述使用SDK Manager更新时出现问题Failed to fetch URL https://dl-ssl.google.com/android/repository/repository-6.xml, reason: Connection to https

DL/T645-2007_Part2(参变量数据标识编码表)

数据类型分为7类:电能量、最大需量及发生时间、变量、事件记录、参变量、冻结量、负荷记录。 数据标识数据格式 数据 长度  (字节)单位功能数据项名称DI₃DI₂DI₁DI₀读写04 00 01 01020304050607YYMMDDWWhhmm55NNNNXXXXYYNM00hhmmYYNMDDhhmm  4  3  1  2  5  5年月日星期时分秒分分毫秒年月日时分年月日时分日期及星期(其

DL/T645-2007_Part2(变量数据标识编码表)

数据类型分为7类:电能量、最大需量及发生时间、变量、事件记录、参变量、冻结量、负荷记录。 数据标识数据格式数据长度字节单位功能数据项名称 DI₃ DI₂ DI₁DI₀读写 02  01  01 02 03 FF  00 XXX,X2 V十A相电压B相电压C相电压电压数据块 02  02  01 02 03 FF  00 XXX.XXX3 AA相电流B相电流C相电流电流数据块 02  03  00