南沙移动网站建设,网站html静态化解决方案,全屏网站宽度,深圳附近推广一 循环神经网络的记忆能力
1.数据集构建
创建了一个DigitSumDataset 类#xff0c;包括初始化函数init、数据生成函数 generate_data、数据加载函数 load_data、__len__ 方法、__getitem__ 方法。
init函数#xff1a;接受的参数是data_path#xff08; 存放数据集的目录…一 循环神经网络的记忆能力
1.数据集构建
创建了一个DigitSumDataset 类包括初始化函数init、数据生成函数 generate_data、数据加载函数 load_data、__len__ 方法、__getitem__ 方法。
init函数接受的参数是data_path 存放数据集的目录用于加载数据、length数据序列的长度、k 数据增强的数量、mode决定生成训练集、验证集还是测试集同时在init函数中初始化这些变量然后是一个选择函数如果传入了data_path就调用load_data从文件中加载数据否则调用generate_data生成数据集。
generate_data通过两层循环生成基础样本然后通过数据增强增加样本多样性
load_data从文件中加载数据
代码
import os
import random
import numpy as np
import torch
from matplotlib import pyplot as plt
from torch import optim
from torch.utils.data import Dataset, DataLoader#数据集构建
# 固定随机种子
random.seed(0)
np.random.seed(0)
class DigitSumDataset(Dataset):def __init__(self, data_pathNone, lengthNone, kNone, modetrain):初始化数据集如果传入了data_path则从文件加载数据如果传入了length和k则生成数据集。参数:data_path: 存放数据集的目录用于加载数据length: 数据序列的长度仅用于生成数据集时k: 数据增强的数量仅用于生成数据集时mode: train/dev/test决定生成训练集、验证集还是测试集仅用于生成数据集时self.data_path data_pathself.length lengthself.k kself.mode modeif data_path: # 从文件加载数据self.examples self.load_data(data_path)else: # 生成数据if length 3 or k 0:raise ValueError(The length of data should be greater than 2 and k should be greater than 0.)self.examples self.generate_data()def generate_data(self):生成数据生成指定长度的数字序列并进行数据增强base_examples []for n1 in range(0, 10):for n2 in range(0, 10):seq [n1, n2] [0] * (self.length - 2)label n1 n2base_examples.append((seq, label))examples []for base_example in base_examples:for _ in range(self.k):idx np.random.randint(2, self.length)val np.random.randint(0, 10)seq base_example[0].copy()label base_example[1]seq[idx] valexamples.append((seq, label))return examplesdef load_data(self, data_path):从文件加载数据def _load_file(file_path):examples []with open(file_path, r, encodingutf-8) as f:for line in f.readlines():items line.strip().split(\t)seq [int(i) for i in items[0].split( )]label int(items[1])examples.append((seq, label))return examples# 加载训练集、验证集、测试集train_examples _load_file(os.path.join(data_path, train.txt))dev_examples _load_file(os.path.join(data_path, dev.txt))test_examples _load_file(os.path.join(data_path, test.txt))return train_examples if self.mode train else dev_examples if self.mode dev else test_examplesdef __len__(self):return len(self.examples)def __getitem__(self, idx):seq, label self.examples[idx]seq_tensor torch.tensor(seq, dtypetorch.long)label_tensor torch.tensor(label, dtypetorch.long)return seq_tensor, label_tensor
2.模型构建
定义了一个嵌入层将输入的数字序列进行向量化即将每个数字映射为向量和SRN层然后定义了定义了一个实现数字预测的模型 Model_RNN4SeqClass里面用到了嵌入层和SRN层。
①Embedding函数会接收两个参数分别是数据数据的总数量和嵌入向量的维度。实现了一个简单的嵌入层用于将输入的数字索引映射为对应的嵌入向量。
②SRN层里面有三个函数分别是init初始化函数init_state初始化隐状态函数forward函数循环执行RNN最终返回一个最后的隐向量。接下来详细解释一下内部实现
init函数接受输入的维度和隐状态的维度并且输入的维度和隐状态的维度这两个维度关乎到模型参数W,U,b的大小。因为输入权重W的大小是input_size*hidden*size,隐层权重U的大小是hidden_size*hidden_size偏置b的大小是1*hidden_size。所以直接定义这样大小的全零矩阵就可以。
init_state函数初始化隐状态向量定义一个batch_size*hidden_size大小的全零矩阵。
forward函数首选利用shape获取输入的形状为batch_size*seq_len*input_size。然后判断一下初始的隐状态是不是没有提供如果没有提供就利用init_state函数初始化一个隐状态。然后就是循环操作循环的是每个序列例如对于长度是5的数据来说seq_len就是5我们要遍历seq_len依次执行各个序列。循环中每个当前时刻的输入step_input数据的形状为batch_size*input*size,利用输入乘以权重W隐层乘以权重U加上偏置b最后把结果利用tanh函数激活得到当前时刻的隐状态。
③Model_RNN4SeqClass包括一个init函数和forward函数
init函数接受的初始参数分别是模型model、词典大小num_digits嵌入函数需要用到、输入维度input_size,隐层维度hidden_size,类别数num_classes。
然后开始定义变量定义模型、词典大小、嵌入向量维度定义embedding层定义线性层输入维度是隐层维度输出维度是分类数输出分类的结果。
forward函数:首先利用嵌入函数将数字序列映射为向量然后调用RNN模型得到最后的隐层状态最后利用linear函数得到在每个类别上的logits
代码
# 嵌入层
class Embedding(nn.Module):def __init__(self, num_embeddings, embedding_dim):super(Embedding, self).__init__()self.W nn.init.xavier_uniform_(torch.empty(num_embeddings, embedding_dim),gain1.0)def forward(self, inputs):# 根据索引获取对应词向量embs self.W[inputs]return embs# 简单循环网络SRN
class SRN(nn.Module):def __init__(self, input_size, hidden_size):super(SRN, self).__init__()# 嵌入向量的维度self.input_size input_size# 隐状态的维度self.hidden_size hidden_size# 定义模型参数W其shape为 input_size x hidden_sizeself.W nn.Parameter(torch.zeros(input_size, hidden_size,dtypetorch.float32))# 定义模型参数U其shape为 hidden_size x hidden_sizeself.U nn.Parameter(torch.zeros(hidden_size, hidden_size,dtypetorch.float32))# 定义模型参数b其shape为 1 x hidden_sizeself.b nn.Parameter(torch.zeros(1, hidden_size,dtypetorch.float32))def init_state(self, batch_size):hidden torch.zeros(batch_size, self.hidden_size,dtypetorch.float32)# 初始化隐状态向量return hiddendef forward(self, inputs, hidden_stateNone):inputs: 输入数据形状为 (batch_size, seq_len, input_size)hidden_state: 初始化隐状态形状为 (batch_size, hidden_size)batch_size, seq_len, input_size inputs.shape# 初始化起始状态的隐向量如果没有提供if hidden_state is None:hidden_state self.init_state(batch_size)# 循环执行RNN计算for step in range(seq_len):# 获取当前时刻的输入数据step_input形状为 (batch_size, input_size)step_input inputs[:, step, :]# 计算当前时刻的隐状态使用tanh激活函数hidden_state torch.tanh(torch.matmul(step_input, self.W) torch.matmul(hidden_state, self.U) self.b)return hidden_state# 基于RNN实现数字预测的模型
class Model_RNN4SeqClass(nn.Module):def __init__(self, model, num_digits, input_size, hidden_size, num_classes):super(Model_RNN4SeqClass, self).__init__()# 传入实例化的RNN层例如SRNself.rnn_model model# 词典大小self.num_digits num_digits# 嵌入向量的维度self.input_size input_size# 定义Embedding层self.embedding Embedding(num_digits, input_size)# 定义线性层self.linear nn.Linear(hidden_size, num_classes)def forward(self, inputs):# 将数字序列映射为相应向量inputs_emb self.embedding(inputs)# 调用RNN模型hidden_state self.rnn_model(inputs_emb)# 使用最后一个时刻的状态进行数字预测logits self.linear(hidden_state)return logits
3.模型训练
首先创建runner类然后遍历不同的序列长度生成数据集定义模型、损失函数、优化器、实例化runner类调用train函数开始训练观察模型在训练集和验证集上面的损失变化。
Runner类还是使用之前的runner类里面包括train函数负责遍历训练集得到损失并反向优化参数evaluate函数用于计算模型在验证集上的损失并根据在验证集上的损失保存最优模型不需要优化参数test函数用于计算测试集在最优模型上的准确率。
定义lengths [5, 10, 15, 20, 25, 30, 35]遍历这个序列对于每个length
利用DigitSumDataset函数分别生成训练集、验证集、测试集然后定义实例化模型需要用到的输入维度、隐层维度、输入数字的类别数和预测数字的类别数。实例化SRN模型得到base_model,然后实例化模型Model_RNN4SeqClass定义损失函数为交叉熵损失、优化器为Adam然后实例化runner类调用train函数开始训练。
代码
#模型训练
class Runner:def __init__(self, model, train_loader, val_loader, test_loader, criterion, optimizer):self.model modelself.train_loader train_loaderself.val_loader val_loaderself.test_loader test_loaderself.criterion criterionself.optimizer optimizerself.best_model Noneself.best_val_loss float(inf)self.train_losses [] # 存储训练损失self.val_losses [] # 存储验证损失def train(self, epochs):for epoch in range(epochs):self.model.train()running_loss 0.0for inputs, labels in self.train_loader:self.optimizer.zero_grad()outputs self.model(inputs)loss self.criterion(outputs, labels)loss.backward()self.optimizer.step()running_loss loss.item()# 计算平均训练损失train_loss running_loss / len(self.train_loader)self.train_losses.append(train_loss)# 计算验证集上的损失val_loss self.evaluate()self.val_losses.append(val_loss)print(fEpoch [{epoch 1}/{epochs}], Train Loss: {train_loss:.4f}, Val Loss: {val_loss:.4f})# 如果验证集上的损失最小保存模型if val_loss self.best_val_loss:self.best_val_loss val_lossself.best_model self.model.state_dict()plt.figure(figsize(10, 6))plt.plot(self.train_losses, labelTrain Loss)plt.plot(self.val_losses, labelValidation Loss)plt.xlabel(Epoch)plt.ylabel(Loss)plt.title(Loss Curve)plt.legend()plt.grid()plt.show()def evaluate(self):self.model.eval()val_loss 0.0with torch.no_grad():for inputs, labels in self.val_loader:outputs self.model(inputs)loss self.criterion(outputs, labels)val_loss loss.item()return val_loss / len(self.val_loader)def test(self):self.model.load_state_dict(self.best_model)self.model.eval()correct 0total 0with torch.no_grad():for inputs, labels in self.test_loader:outputs self.model(inputs)_, predicted torch.max(outputs, 1)total labels.size(0)correct (predicted labels).sum().item()test_accuracy correct / totalprint(fTest Accuracy: {test_accuracy:.4f})def predict(self, image):self.model.eval()with torch.no_grad():output self.model(image)_, predicted torch.max(output, 1)return predicted.item()lengths [5, 10, 15, 20, 25, 30, 35]
# lengths [5]
k_train 3 # 训练集数据增强的数量
k_test_val 1 # 验证集和测试集数据增强的数量# 循环不同长度的序列
for length in lengths:# 生成训练集train_dataset DigitSumDataset(lengthlength, kk_train, modetrain)train_loader DataLoader(train_dataset, batch_size64, shuffleTrue)# 生成验证集dev_dataset DigitSumDataset(lengthlength, kk_test_val, modedev)dev_loader DataLoader(dev_dataset, batch_size64, shuffleFalse)# 生成测试集test_dataset DigitSumDataset(lengthlength, kk_test_val, modetest)test_loader DataLoader(test_dataset, batch_size64, shuffleFalse)# 输入数字的类别数num_digits 10# 将数字映射为向量的维度input_size 32# 隐状态向量的维度shidden_size 32# 预测数字的类别数num_classes 19base_model SRN(input_size, hidden_size)model Model_RNN4SeqClass(base_model, num_digits, input_size, hidden_size, num_classes)# 定义损失函数和优化器criterion nn.CrossEntropyLoss()optimizer optim.Adam(model.parameters(), lr0.001)# 创建Runner实例并进行训练runner Runner(model, train_loader, dev_loader, test_loader, criterion, optimizer)print(fTraining model for sequence length {length}...)# 训练并测试模型runner.train(epochs600) # 训练模型
4.模型评价
调用test函数进行模型测试
代码
runner.test() # 测试模型
5实验结果
1.序列长度分别是5、10、15 时的loss变化和准确率 从输出结果看随着数据序列长度的增加虽然训练集损失逐渐逼近于0但是验证集损失整体趋向越来越大这表明当序列变长时SRN模型保持序列长期依赖能力在逐渐变弱越来越无法学习到有用的知识.并且随着序列长度的增加测试集的准确度整体趋势是降低的这同样说明SRN模型保持长期依赖的能力在不断降低.
二 梯度爆炸实验
1.梯度打印函数
定义梯度打印函数custom_print_log接受的参数是runner。
分别初始化W、U、b的梯度L2范数 W_grad_l2、U_grad_l2 和 b_grad_l2 为 0。使用 model.named_parameters() 遍历模型的所有参数它会返回每个参数的名字name和对应的张量param。如果变量的名称为rnn_model.W就获取这个参数的L2范数赋值给W_grad_l2。在函数体外创建了三个列表W_list []、U_list []、b_list []把每个epoch得到的梯度分别存储到列表中训练结束后可视化梯度变化。
代码
W_list []
U_list []
b_list []# 计算梯度范数
def custom_print_log(runner):model runner.modelW_grad_l2, U_grad_l2, b_grad_l2 0, 0, 0# 遍历模型的所有参数for name, param in model.named_parameters():if name rnn_model.W: # 针对W参数计算L2范数W_grad_l2 torch.norm(param.grad, p2).item() # 获取L2范数elif name rnn_model.U: # 针对U参数计算L2范数U_grad_l2 torch.norm(param.grad, p2).item() # 获取L2范数elif name rnn_model.b: # 针对b参数计算L2范数b_grad_l2 torch.norm(param.grad, p2).item() # 获取L2范数# 打印梯度L2范数print(f[Training] W_grad_l2: {W_grad_l2:.5f}, U_grad_l2: {U_grad_l2:.5f}, b_grad_l2: {b_grad_l2:.5f})# 保存每个步骤的梯度范数W_list.append(W_grad_l2)U_list.append(U_grad_l2)b_list.append(b_grad_l2)
2.复现梯度爆炸现象
把优化器改为SGD设置学习率为0.2调用train函数训练观察W、U、b梯度变化。
代码
from random import randomimport numpy as np
import torch
from matplotlib import pyplot as plt
from torch import nn, optim
from torch.utils.data import DataLoader
import os
import random
import numpy as np
import torch
from matplotlib import pyplot as plt
from torch import optim
from torch.utils.data import Dataset, DataLoader#数据集构建
# 固定随机种子
random.seed(0)
np.random.seed(0)
class DigitSumDataset(Dataset):def __init__(self, data_pathNone, lengthNone, kNone, modetrain):初始化数据集如果传入了data_path则从文件加载数据如果传入了length和k则生成数据集。参数:data_path: 存放数据集的目录用于加载数据length: 数据序列的长度仅用于生成数据集时k: 数据增强的数量仅用于生成数据集时mode: train/dev/test决定生成训练集、验证集还是测试集仅用于生成数据集时self.data_path data_pathself.length lengthself.k kself.mode modeif data_path: # 从文件加载数据self.examples self.load_data(data_path)else: # 生成数据if length 3 or k 0:raise ValueError(The length of data should be greater than 2 and k should be greater than 0.)self.examples self.generate_data()def generate_data(self):生成数据生成指定长度的数字序列并进行数据增强base_examples []for n1 in range(0, 10):for n2 in range(0, 10):seq [n1, n2] [0] * (self.length - 2)label n1 n2base_examples.append((seq, label))examples []for base_example in base_examples:for _ in range(self.k):idx np.random.randint(2, self.length)val np.random.randint(0, 10)seq base_example[0].copy()label base_example[1]seq[idx] valexamples.append((seq, label))return examplesdef load_data(self, data_path):从文件加载数据def _load_file(file_path):examples []with open(file_path, r, encodingutf-8) as f:for line in f.readlines():items line.strip().split(\t)seq [int(i) for i in items[0].split( )]label int(items[1])examples.append((seq, label))return examples# 加载训练集、验证集、测试集train_examples _load_file(os.path.join(data_path, train.txt))dev_examples _load_file(os.path.join(data_path, dev.txt))test_examples _load_file(os.path.join(data_path, test.txt))return train_examples if self.mode train else dev_examples if self.mode dev else test_examplesdef __len__(self):return len(self.examples)def __getitem__(self, idx):seq, label self.examples[idx]seq_tensor torch.tensor(seq, dtypetorch.long)label_tensor torch.tensor(label, dtypetorch.long)return seq_tensor, label_tensor# 设定数据集的路径和生成参数
# lengths [5, 10, 15, 20, 25, 30, 35]
lengths [5]
k_train 3 # 训练集数据增强的数量
k_test_val 1 # 验证集和测试集数据增强的数量#总的模型
import torch
import torch.nn as nn
import torch.nn.functional as F# 嵌入层
class Embedding(nn.Module):def __init__(self, num_embeddings, embedding_dim):super(Embedding, self).__init__()# 定义嵌入层self.embedding nn.Embedding(num_embeddings, embedding_dim)def forward(self, inputs):# 根据索引获取对应的嵌入向量return self.embedding(inputs)# 简单循环网络SRN
class SRN(nn.Module):def __init__(self, input_size, hidden_size):super(SRN, self).__init__()# 嵌入向量的维度self.input_size input_size# 隐状态的维度self.hidden_size hidden_size# 定义模型参数W其shape为 input_size x hidden_sizeself.W nn.Parameter(torch.randn(input_size, hidden_size))# 定义模型参数U其shape为 hidden_size x hidden_sizeself.U nn.Parameter(torch.randn(hidden_size, hidden_size))# 定义模型参数b其shape为 1 x hidden_sizeself.b nn.Parameter(torch.randn(1, hidden_size))def init_state(self, batch_size):# 初始化隐状态向量return torch.zeros(batch_size, self.hidden_size)def forward(self, inputs, hidden_stateNone):inputs: 输入数据形状为 (batch_size, seq_len, input_size)hidden_state: 初始化隐状态形状为 (batch_size, hidden_size)batch_size, seq_len, input_size inputs.shape# 初始化起始状态的隐向量如果没有提供if hidden_state is None:hidden_state self.init_state(batch_size)# 循环执行RNN计算for step in range(seq_len):# 获取当前时刻的输入数据step_input形状为 (batch_size, input_size)step_input inputs[:, step, :]# 计算当前时刻的隐状态使用tanh激活函数hidden_state torch.tanh(torch.matmul(step_input, self.W) torch.matmul(hidden_state, self.U) self.b)return hidden_state# 基于RNN实现数字预测的模型
class Model_RNN4SeqClass(nn.Module):def __init__(self, model, num_digits, input_size, hidden_size, num_classes):super(Model_RNN4SeqClass, self).__init__()# 传入实例化的RNN层例如SRNself.rnn_model model# 词典大小self.num_digits num_digits# 嵌入向量的维度self.input_size input_size# 定义Embedding层self.embedding Embedding(num_digits, input_size)# 定义线性层self.linear nn.Linear(hidden_size, num_classes)def forward(self, inputs):# 将数字序列映射为相应向量inputs_emb self.embedding(inputs)# 调用RNN模型hidden_state self.rnn_model(inputs_emb)# 使用最后一个时刻的状态进行数字预测logits self.linear(hidden_state)return logitsW_list []
U_list []
b_list []# 计算梯度范数
def custom_print_log(runner):model runner.modelW_grad_l2, U_grad_l2, b_grad_l2 0, 0, 0# 遍历模型的所有参数for name, param in model.named_parameters():if name rnn_model.W: # 针对W参数计算L2范数W_grad_l2 torch.norm(param.grad, p2).item() # 获取L2范数elif name rnn_model.U: # 针对U参数计算L2范数U_grad_l2 torch.norm(param.grad, p2).item() # 获取L2范数elif name rnn_model.b: # 针对b参数计算L2范数b_grad_l2 torch.norm(param.grad, p2).item() # 获取L2范数# 打印梯度L2范数print(f[Training] W_grad_l2: {W_grad_l2:.5f}, U_grad_l2: {U_grad_l2:.5f}, b_grad_l2: {b_grad_l2:.5f})# 保存每个步骤的梯度范数W_list.append(W_grad_l2)U_list.append(U_grad_l2)b_list.append(b_grad_l2)
#模型训练
class Runner:def __init__(self, model, train_loader, val_loader, test_loader, criterion, optimizer):self.model modelself.train_loader train_loaderself.val_loader val_loaderself.test_loader test_loaderself.criterion criterionself.optimizer optimizerself.best_model Noneself.best_val_loss float(inf)self.train_losses [] # 存储训练损失self.val_losses [] # 存储验证损失def train(self, epochs):for epoch in range(epochs):self.model.train()running_loss 0.0for inputs, labels in self.train_loader:self.optimizer.zero_grad()outputs self.model(inputs)loss self.criterion(outputs, labels)loss.backward()self.optimizer.step()running_loss loss.item()# 计算平均训练损失train_loss running_loss / len(self.train_loader)self.train_losses.append(train_loss)# 计算验证集上的损失val_loss self.evaluate()self.val_losses.append(val_loss)print(fEpoch [{epoch 1}/{epochs}], Train Loss: {train_loss:.4f}, Val Loss: {val_loss:.4f})# 调用自定义函数来打印和记录梯度范数custom_print_log(self)# 如果验证集上的损失最小保存模型if val_loss self.best_val_loss:self.best_val_loss val_lossself.best_model self.model.state_dict()plt.figure(figsize(10, 6))plt.plot(self.train_losses, labelTrain Loss)plt.plot(self.val_losses, labelValidation Loss)plt.xlabel(Epoch)plt.ylabel(Loss)plt.title(Loss Curve)plt.legend()plt.grid()plt.show()# 可视化梯度L2范数plt.figure(figsize(10, 6))plt.plot(W_list, labelW Gradient L2 Norm)plt.plot(U_list, labelU Gradient L2 Norm)plt.plot(b_list, labelb Gradient L2 Norm)plt.xlabel(Epoch)plt.ylabel(L2 Norm)plt.title(Gradient L2 Norms Across Epochs)plt.legend()plt.grid()plt.show()def evaluate(self):self.model.eval()val_loss 0.0with torch.no_grad():for inputs, labels in self.val_loader:outputs self.model(inputs)loss self.criterion(outputs, labels)val_loss loss.item()return val_loss / len(self.val_loader)def test(self):self.model.load_state_dict(self.best_model)self.model.eval()correct 0total 0with torch.no_grad():for inputs, labels in self.test_loader:outputs self.model(inputs)_, predicted torch.max(outputs, 1)total labels.size(0)correct (predicted labels).sum().item()test_accuracy correct / totalprint(fTest Accuracy: {test_accuracy:.4f})def predict(self, image):self.model.eval()with torch.no_grad():output self.model(image)_, predicted torch.max(output, 1)return predicted.item()length5
# 生成训练集
train_dataset DigitSumDataset(lengthlength, kk_train, modetrain)
train_loader DataLoader(train_dataset, batch_size8, shuffleTrue)
# 生成验证集
dev_dataset DigitSumDataset(lengthlength, kk_test_val, modedev)
dev_loader DataLoader(dev_dataset, batch_size8, shuffleFalse)
# 生成测试集
test_dataset DigitSumDataset(lengthlength, kk_test_val, modetest)
test_loader DataLoader(test_dataset, batch_size8, shuffleFalse)
# 输入数字的类别数
num_digits 10
# 将数字映射为向量的维度
input_size 32
# 隐状态向量的维度s
hidden_size 32
# 预测数字的类别数
num_classes 19
base_model SRN(input_size, hidden_size)
model Model_RNN4SeqClass(base_model, num_digits, input_size, hidden_size, num_classes)
# 定义损失函数和优化器
criterion nn.CrossEntropyLoss()
optimizer optim.SGD(model.parameters(), lr0.2, momentum0.9)
# 创建Runner实例并进行训练
runner Runner(model, train_loader, dev_loader, test_loader, criterion, optimizer)
print(fTraining model for sequence length {length}...)# 训练并测试模型
runner.train(epochs600) # 训练模型
runner.test() # 测试模型print(fFinished training for length {length}.\n)
3.使用梯度截断解决梯度爆炸问题
在参数更新前面加上一行代码nn.utils.clip_grad_norm_(parametersself.model.parameters(),max_norm5, norm_type1)用于控制梯度范数防止梯度爆炸。
4.实验结果
1.梯度爆炸现象 通过观察发现梯度范数急剧变大而后梯度范数几乎为0. 这是因为Tanh为Sigmoid型函数其饱和区的导数接近于0由于梯度的急剧变化参数数值变的较大或较小容易落入梯度饱和区导致梯度为0模型很难继续训练. 在最优模型上计算准确率发现只有0.01
2.使用梯度截断法解决梯度爆炸 引入按模截断的策略之后模型训练时参数梯度的变化情况。可以看到随着迭代步骤的进行梯度始终保持在一个有值的状态表明按模截断能够很好地解决梯度爆炸的问题. 由于为复现梯度爆炸现象改变了学习率优化器等因此准确率相对比较低。但由于采用梯度截断策略后在后续训练过程中模型参数能够被更新优化因此准确率有一定的提升。
三总结和心得体会
解释词向量、词嵌入
词向量是用固定维度的 实数向量 来表示一个词语。它通过对语言中词语之间的语义相似度进行建模来生成这些向量。词向量通常是一个低维稠密的向量相较于传统的稀疏表示如独热编码它能更有效地捕捉词语的语义信息。例如假设有一个词语“dog”其对应的词向量可能是[0.12, -0.34, 0.65, -0.22, ...]。词向量的生成方式通常是基于上下文信息例如通过共现统计词与词之间的共现频率或者神经网络模型如Word2Vec, GloVe等来训练这些词向量。
词向量的特点
①低维稠密表示相比传统的稀疏表示如独热编码词向量可以有效地表示词语之间的相似性。
②向量之间的运算词向量可以进行加法、减法等数学操作这种方式使得词向量能够在向量空间中进行运算。例如“king” - “man” “woman” ≈ “queen”。
词嵌入是通过 神经网络模型如 Word2Vec、GloVe、FastText 等将词语映射到一个 连续的向量空间 中。这些词嵌入不仅可以通过共现频率学习也能在不同的上下文中不断更新学习到更多语义信息。换句话说词嵌入是通过一种方法或算法将词语映射到一个低维的稠密向量空间这些词嵌入的向量不仅包含了每个词的单一表示还能捕捉到词与词之间的关系。
常见的词嵌入方法有
①Word2Vec通过 Skip-gram 或 CBOW 模型训练词向量能够通过上下文信息捕捉词语之间的关系。
②GloVeGlobal Vectors for Word Representation基于词语共现矩阵的全局统计信息使用矩阵分解技术来训练词向量。
③FastText比 Word2Vec 更进一步能够处理词内子词信息尤其适用于处理罕见词。
在RNN的记忆能力的实验中新东西就是创建基于RNN实现数字预测的模型在这个模型中先把输入进行嵌入然后调用srn模型得到最后一个状态的隐向量最后利用linear函数将其映射为在每个类别上的数值。通过在不同长度的序列上观察模型的准确率发现序列越长准确率越低就相当于隔得时间越长人的记忆就会越来越模糊。
在梯度爆炸实验中学习率设置一个比较大的数使用SGD优化器SGD是一种非常基础的优化算法它的更新步骤没有任何的约束或调整机制。在每次更新时学习率是固定的且没有任何机制来控制梯度的大小。如果学习率过大SGD很容易因为参数更新过大而导致梯度爆炸。编写了一个记录每个epoch上W、U、b梯度的函数在每个epoch中收集参数的梯度发现训练了几次参数的梯度都变成了0发生了梯度爆炸现象。