Мало знаний, большой вызов! Эта статья участвует в " Необходимые знания для программистов
Эта статья также участвует "Проект "Звезда раскопок"" , чтобы выиграть творческие подарочные наборы и бросить вызов творческим поощрениям
Прошло много времени с момента последнего RNN.С одной стороны, я не хочу его писать.С другой стороны, поскольку это связано с другими вещами, я тянул.Я сегодня напишу LSTM, и я надеюсь понять это с точки зрения студента.
1. Что такое лстм
LSTM: Long Short-Term Memory (LSTM, Long Short-Term Memory) — это нейронная сеть с циклическим временем, которая специально разработана для решения проблемы долговременной зависимости общей RNN (рекуррентной нейронной сети).Все RNN имеют цепочечную форму. повторяющихся модулей нейронной сети.
Проблема RNN: существует проблема взрыва и исчезновения градиента, а эффект обучения междугородных предложений не очень хорош.
Градиент исчезает: градиент RNN исчезает, потому что обратная функция функции активации tanh находится в диапазоне от 0 до 1. Когда параметры в предыдущий момент обновляются во время обратного распространения, когда параметр W инициализируется до числа меньше 1, кратное (tanh функций' * W) умножение приведет к чрезвычайно малым частным производным (числа меньше 1 умножаются непрерывно), что приведет к исчезновению градиента.
Взрыв градиента: когда параметры инициализируются достаточно большими, чтобы обратная величина функции тангенса, умноженной на W, была больше 1, частная производная будет чрезвычайно большой (умножение чисел больше 1), что приводит к взрыву градиента.
Короче говоря, когда параметр больше 1, градиент n-й степени 1 будет взрываться, приближаясь к положительной бесконечности.Когда параметр меньше 1, градиент n-й степени 1 исчезнет, приближаясь к 0, и реверс Математическое обоснование распространения будет написано в отдельной статье
2. Сетевая структура lstm
Следующее изображение — самое простое изображение, которое я видел в своем исследовании, Можно сказать, что я понимаю LSTM из-за этого изображения.
Основная идея состоит в том, чтобы хранить информацию в ячейках памяти одну за другой и формировать конвейерную ленту (красная линия на рисунке) за счет небольшого количества линейных взаимодействий между ячейками памяти в разных скрытых слоях для реализации потока информации. При этом вводится структура «ворот» для добавления или удаления информации в ячейках памяти и управления потоком информации.
1. Схема архитектуры
Я ничего не знаю.Посмотрите на архитектурную схему других.
Примечание:
x - это умножение соответствующих элементов в матрице операции, поэтому две матрицы умножения должны быть одного типа.
Знак + означает добавление матрицы.
Ct-1 — это выход текущего нейрона
Ht-1 — параметр скрытого слоя
Из диаграммы архитектуры мы видим, что в основном есть три блока вентилей: вентиль забывания, входной вентиль и выходной вентиль.
Входными данными шлюза забывания и входного шлюза являются вход Xt текущего времени и данные предыдущего скрытого слоя.
Вход в выходной вентиль является текущим выходом
3. Дверь лстм
Вышеизложенное предназначено для понимания структуры LSTM. Ниже будут представлены подробности. Попробуйте использовать простой язык, чтобы помочь вам понять. Также будут прилагаться математические формулы. Если вы можете это понять, вы можете это понять.
Сначала прикрепите классическую LSTM-архитектуру (рисунок действительно не очень, слишком сложный для понимания)
Ворота представляют собой слой нейронной сети. Например, tanh — это не простая функция tanh в обычном смысле, а слой нейронной сети tanh. Обратите внимание, чтобы различать
Хотя конечный эффект тот же, это нейронная сеть, а слои нейронной сети имеют параметры.
3.1 Инструкции по вводу данных
Например:
Здесь мы ориентируемся на данные, введенные в
Например, ввод: я люблю пекинскую площадь Тяньаньмэнь.
Закодируйте ввод [1, 2, 3, 4, 5, 6, 7] (как правило, кодируется не так, обычно кодируется как вектор слов, здесь просто для иллюстрации проблемы)
Введите Xt-1 = 2, затем Xt = 3, все предложение представляет собой последовательность.
3.2 Ядром lstm являются три гейт-функции
Еще одна простая картинка, вы можете увидеть функцию, используемую текущей ячейкой, есть только два слоя нейронной сети sigmod и tanh
Тан слой нейронной сети
Введенное значение будет сохранено в интервале [-1,1],
слой нейронной сети sigmod
Входные данные будут преобразованы в интервал (0,1)
3.3 Забытые ворота
Ворота забывания отвечают за забывание того, сколько памяти в блоке памяти Ht-1 сохранено.
Как показано на рисунке: Ниже приводится подробный анализ математических операций.
Ht-1 = [0.1,0.2,0.3] — матрица с одной строкой и тремя столбцами
Xt = [0.6,0.7,0.8] также является матрицей с одной строкой и тремя столбцами
Тогда [Ht-1,Xt] = [0,1,0,2,0,3,0,6,0,7,0,8], т.е.
6 представляет нейронную единицу, а модель всей функции f = wx +b
Wf — параметр текущего нейронного блока
bf — параметр смещения
Выход всего нейрона — это все значения между (0,1) через сигмовидную функцию, например [0,4,0,8,0,9]
3.4 Входные ворота
Роль входных ворот состоит в том, чтобы добавить что-то новое к информации о состоянии.
Входной вентиль состоит из двух частей и одновременно использует две функции нейрона.
Работа функции It аналогична объяснению вышеприведенного входного вентиля, который используется для управления степенью обновления информации о новом состоянии.
Ct используется для управления входными данными
Конечный результат зависит от результатов двух предыдущих шагов. Я считаю, что вы должны знать, что означает эта математическая формула
Ct - выход в текущий момент
Ct-1 - это выход в предыдущий момент
Это степень обновления входных ворот
C"t - данные управляющего входа
3.5 Выходной шлюз
Нам нужно определить, какое значение выводить. Вывод будет основан на состоянии нашей ячейки, а также на отфильтрованной версии. Во-первых, мы запускаем сигмовидный слой, чтобы определить, какая часть состояния ячейки будет выведена. Затем мы обрабатываем состояние ячейки с помощью tanh (получая значение от 0 до 1) и умножаем его на выход сигмовидного вентиля, и в итоге мы получаем только ту часть, которую мы определили для вывода.
Выходной вентиль — это память выхода, то есть предыдущего накопления
Выходные ворота также представляют собой два нейронных блока.
От - сигмод нейронной единицы
Ht - ячейка tanh с Ct в качестве входных данных
4. параметры модуля pytorch
pytorch обеспечивает реализацию LSTM, поэтому давайте поговорим об объяснении параметров
class torch.nn.LSTM(*args, **kwargs)
参数有:
input_size:x的特征维度
hidden_size:隐藏层的特征维度
num_layers:lstm隐层的层数,默认为1
bias:False则bihbih=0和bhhbhh=0. 默认为True
batch_first:True则输入输出的数据格式为 (batch, seq, feature)
dropout:除最后一层,每一层的输出都进行dropout,默认为: 0
bidirectional:True则为双向lstm默认为False
input(seq_len, batch, input_size)
参数有:
seq_len:序列长度,在NLP中就是句子长度,一般都会用pad_sequence补齐长度
batch:每次喂给网络的数据条数,在NLP中就是一次喂给网络多少个句子
input_size:特征维度,和前面定义网络结构的input_size一致。
output,(ht, ct) = net(input)
output: 最后一个状态的隐藏层的神经元输出
ht:最后一个状态的隐含层的状态值
ct:最后一个状态的隐含层的遗忘门值
5. Пример лстм
Требуемые пакеты: numpy, панды matplotlib, pytorch
Портал установки среды:Слишком поздно, если вы не войдете в яму, не изучите pytorch с нуля и не создадите среду шаг за шагом.
Исходный код:
import torch
import torch.nn as nn
import torch.nn.functional
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
"""
导入数据
"""
# load the dataset
flight_data = pd.read_csv('flights.csv', usecols=[1], engine='python')
dataset = flight_data.values
dataset = dataset.astype('float32')
print(flight_data.head())
print(flight_data.shape)
#绘制每月乘客的出行频率
fig_size = plt.rcParams['figure.figsize']
fig_size[0] = 15
fig_size[1] = 5
plt.rcParams['figure.figsize'] = fig_size
plt.title('Month vs Passenger')
plt.ylabel('Total Passengers')
plt.xlabel('Months')
plt.grid(True)
plt.autoscale(axis='x',tight=True)
plt.plot(flight_data['passengers'])
plt.show()
"""
数据预处理
"""
flight_data.columns#显示数据集中 列的数据类型
all_data = flight_data['passengers'].values.astype(float)#将passengers列的数据类型改为float
#划分测试集和训练集
test_data_size = 12
train_data = all_data[:-test_data_size]#除了最后12个数据,其他全取
test_data = all_data[-test_data_size:]#取最后12个数据
print(len(train_data))
print(len(test_data))
#最大最小缩放器进行归一化,减小误差
from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler(feature_range=(-1, 1))
train_data_normalized = scaler.fit_transform(train_data.reshape(-1, 1))
#查看归一化之后的前5条数据和后5条数据
print(train_data_normalized[:5])
print(train_data_normalized[-5:])
#将数据集转换为tensor,因为PyTorch模型是使用tensor进行训练的,并将训练数据转换为输入序列和相应的标签
train_data_normalized = torch.FloatTensor(train_data_normalized).view(-1)
#view相当于numpy中的resize,参数代表数组不同维的维度;
#参数为-1表示,这个维的维度由机器自行推断,如果没有-1,那么view中的所有参数就要和tensor中的元素总个数一致
#定义create_inout_sequences函数,接收原始输入数据,并返回一个元组列表。
def create_inout_sequences(input_data, tw):
inout_seq = []
L = len(input_data)
for i in range(L-tw):
train_seq = input_data[i:i+tw]
train_label = input_data[i+tw:i+tw+1]#预测time_step之后的第一个数值
inout_seq.append((train_seq, train_label))#inout_seq内的数据不断更新,但是总量只有tw+1个
return inout_seq
train_window = 12#设置训练输入的序列长度为12,类似于time_step = 12
train_inout_seq = create_inout_sequences(train_data_normalized, train_window)
print(train_inout_seq[:5])#产看数据集改造结果
"""
注意:
create_inout_sequences返回的元组列表由一个个序列组成,
每一个序列有13个数据,分别是设置的12个数据(train_window)+ 第13个数据(label)
第一个序列由前12个数据组成,第13个数据是第一个序列的标签。
同样,第二个序列从第二个数据开始,到第13个数据结束,而第14个数据是第二个序列的标签,依此类推。
"""
"""
创建LSTM模型
参数说明:
1、input_size:对应的及特征数量,此案例中为1,即passengers
2、output_size:预测变量的个数,及数据标签的个数
2、hidden_layer_size:隐藏层的特征数,也就是隐藏层的神经元个数
"""
class LSTM(nn.Module):#注意Module首字母需要大写
def __init__(self, input_size=1, hidden_layer_size=100, output_size=1):
super().__init__()
self.hidden_layer_size = hidden_layer_size
# 创建LSTM层和linear层,LSTM层提取特征,linear层用作最后的预测
##LSTM算法接受三个输入:先前的隐藏状态,先前的单元状态和当前输入。
self.lstm = nn.LSTM(input_size, hidden_layer_size)
self.linear = nn.Linear(hidden_layer_size, output_size)
#初始化隐含状态及细胞状态C,hidden_cell变量包含先前的隐藏状态和单元状态
self.hidden_cell = (torch.zeros(1, 1, self.hidden_layer_size),
torch.zeros(1, 1, self.hidden_layer_size))
# 为什么的第二个参数也是1
# 第二个参数代表的应该是batch_size吧
# 是因为之前对数据已经进行过切分了吗?????
def forward(self, input_seq):
lstm_out, self.hidden_cell = self.lstm(input_seq.view(len(input_seq), 1, -1), self.hidden_cell)
#lstm的输出是当前时间步的隐藏状态ht和单元状态ct以及输出lstm_out
#按照lstm的格式修改input_seq的形状,作为linear层的输入
predictions = self.linear(lstm_out.view(len(input_seq), -1))
return predictions[-1]#返回predictions的最后一个元素
"""
forward方法:LSTM层的输入与输出:out, (ht,Ct)=lstm(input,(h0,C0)),其中
一、输入格式:lstm(input,(h0, C0))
1、input为(seq_len,batch,input_size)格式的tensor,seq_len即为time_step
2、h0为(num_layers * num_directions, batch, hidden_size)格式的tensor,隐藏状态的初始状态
3、C0为(seq_len, batch, input_size)格式的tensor,细胞初始状态
二、输出格式:output,(ht,Ct)
1、output为(seq_len, batch, num_directions*hidden_size)格式的tensor,包含输出特征h_t(源于LSTM每个t的最后一层)
2、ht为(num_layers * num_directions, batch, hidden_size)格式的tensor,
3、Ct为(num_layers * num_directions, batch, hidden_size)格式的tensor,
"""
#创建LSTM()类的对象,定义损失函数和优化器
model = LSTM()
loss_function = nn.MSELoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)#建立优化器实例
print(model)
"""
模型训练
batch-size是指1次迭代所使用的样本量;
epoch是指把所有训练数据完整的过一遍;
由于默认情况下权重是在PyTorch神经网络中随机初始化的,因此可能会获得不同的值。
"""
epochs = 300
for i in range(epochs):
for seq, labels in train_inout_seq:
#清除网络先前的梯度值
optimizer.zero_grad()#训练模型时需要使模型处于训练模式,即调用model.train()。缺省情况下梯度是累加的,需要手工把梯度初始化或者清零,调用optimizer.zero_grad()
#初始化隐藏层数据
model.hidden_cell = (torch.zeros(1, 1, model.hidden_layer_size),
torch.zeros(1, 1, model.hidden_layer_size))
#实例化模型
y_pred = model(seq)
#计算损失,反向传播梯度以及更新模型参数
single_loss = loss_function(y_pred, labels)#训练过程中,正向传播生成网络的输出,计算输出和实际值之间的损失值
single_loss.backward()#调用loss.backward()自动生成梯度,
optimizer.step()#使用optimizer.step()执行优化器,把梯度传播回每个网络
# 查看模型训练的结果
if i%25 == 1:
print(f'epoch:{i:3} loss:{single_loss.item():10.8f}')
print(f'epoch:{i:3} loss:{single_loss.item():10.10f}')
"""
预测
注意,test_input中包含12个数据,
在for循环中,12个数据将用于对测试集的第一个数据进行预测,然后将预测值附加到test_inputs列表中。
在第二次迭代中,最后12个数据将再次用作输入,并进行新的预测,然后 将第二次预测的新值再次添加到列表中。
由于测试集中有12个元素,因此该循环将执行12次。
循环结束后,test_inputs列表将包含24个数据,其中,最后12个数据将是测试集的预测值。
"""
fut_pred = 12
test_inputs = train_data_normalized[-train_window:].tolist()#首先打印出数据列表的最后12个值
print(test_inputs)
#更改模型为测试或者验证模式
model.eval()#把training属性设置为false,使模型处于测试或验证状态
for i in range(fut_pred):
seq = torch.FloatTensor(test_inputs[-train_window:])
with torch.no_grad():
model.hidden = (torch.zeros(1, 1, model.hidden_layer_size),
torch.zeros(1, 1, model.hidden_layer_size))
test_inputs.append(model(seq).item())
#打印最后的12个预测值
print(test_inputs[fut_pred:])
#由于对训练集数据进行了标准化,因此预测数据也是标准化了的
#需要将归一化的预测值转换为实际的预测值。通过inverse_transform实现
actual_predictions = scaler.inverse_transform(np.array(test_inputs[train_window:]).reshape(-1, 1))
print(actual_predictions)
"""
根据实际值,绘制预测值
"""
x = np.arange(132, 132+fut_pred, 1)
plt.title('Month vs Passenger with all data')
plt.ylabel('Total Passengers')
plt.xlabel('Months')
plt.grid(True)
plt.autoscale(axis='x', tight=True)
plt.plot(flight_data['passengers'])
plt.plot(x, actual_predictions)
plt.show()
#绘制最近12个月的实际和预测乘客数量,以更大的尺度观测数据
plt.title('Month vs Passenger last pred data')
plt.ylabel('Total Passengers')
plt.xlabel('Months')
plt.grid(True)
plt.autoscale(axis='x', tight=True)
plt.plot(flight_data['passengers'][-train_window:])
plt.plot(x, actual_predictions)
plt.show()
Глядя на результаты моего обучения для 150 и 300 эпох, похоже, что 300 работает хорошо, в основном имитируя тренд.
Исходный код и адрес загрузки данных:скачать.CSDN.net/download/PE…
6. Резюме
Три ворот LSTM являются ключевыми моментами, и их легко понять, но из-за введения большого количества контента количество параметров увеличивается, что также значительно усложняет обучение. Поэтому во многих случаях мы склонны использовать GRU с эффектами, аналогичными LSTM, но с меньшим количеством параметров для построения моделей с большими объемами обучения. В следующем выпуске поговорим о GRU, оптимизированной или урезанной версии LSTM.
Если есть что-то, что вы не понимаете, пожалуйста, оставьте мне сообщение или добавьте меня в друзья