Рекуррентная нейронная сеть LSTM RNN-регрессия: прогнозирование кривой Sin

искусственный интеллект Нейронные сети задняя часть

Аннотация: в этой статье рассказывается, как рекуррентная нейронная сеть LSTM RNN реализует регрессионное прогнозирование.

Эта статья опубликована в сообществе Huawei Cloud Community "[Искусственный интеллект Python] 14. Прогнозирование Sin Curve рекуррентной нейронной сети LSTM RNN Regression Case 丨 [Variety AI Show]", по Истмаунт.

1. Обзор RNN и LSTM

1.RNN

(1) принцип RNN

Рекуррентная нейронная сеть на английском языке — это рекуррентные нейронные сети, называемые RNN. Предположим, есть набор данных data0, data1, data2, data3, используйте одну и ту же нейронную сеть для их предсказания и получите соответствующие результаты. Если существует связь между данными, такими как шаги до и после приготовления и нарезки, и порядком английских слов, как нейронная сеть может изучить связь между данными? Вот где используется RNN.

Предполагая, что существует число ABCD, необходимо предсказать следующее число E, и предсказание будет сделано в соответствии с предыдущим порядком ABCD, который называется памятью. Прежде чем делать прогнозы, необходимо просмотреть предыдущие воспоминания, а также новые точки памяти на этом этапе и, наконец, вывести результат.Рекуррентная нейронная сеть (RNN) использует этот принцип.

Во-первых, давайте подумаем о том, как люди анализируют отношения или порядок вещей. Люди обычно помнят, что произошло раньше, чтобы помочь нам сделать выводы о последующем поведении, поэтому могут ли компьютеры также помнить, что произошло раньше?

При анализе data0 мы сохраняем результаты анализа в памяти, а затем при анализе data1 нейронная сеть (НС) будет генерировать новые воспоминания, но в это время новая память не связана со старой памятью, как показано на рисунке выше. В RNN мы просто будем вызывать старую память для анализа новой памяти.Если мы продолжим анализировать больше данных, NN соберет всю предыдущую память.

Структура RNN показана на рисунке ниже.В соответствии с моментами времени t-1, t и t+1 каждый раз имеет разный x. Каждый расчет будет учитывать состояние предыдущего шага и x(t) этот шаг, а затем выведите значение y. В этой математической форме s (t) генерируется после каждого запуска RNN.Когда RNN хочет проанализировать x (t + 1), y (t + 1) в этот момент определяется s (t) и s (t + 1) Совместно созданный s(t) можно рассматривать как воспоминание о предыдущем шаге. Накопление нескольких нейронных сетей NN преобразуется в рекуррентную нейронную сеть, упрощенная схема которой показана в левой части следующего рисунка.

Таким образом, вы можете использовать RNN, если ваши данные упорядочены, например, порядок человеческой речи, порядок телефонных номеров, порядок пикселей изображения, порядок букв ABC и т. д. При объяснении принципа CNN ранее его можно рассматривать как фильтр, скользящий для сканирования всего изображения, а понимание изображения нейронной сетью углубляется за счет свертки.

RNN также имеет тот же эффект сканирования, но с добавлением функций временной последовательности и памяти. RNN фиксирует динамическую информацию в сериализованных данных, периодически подключая скрытые слои для улучшения результатов прогнозирования.

(2) Приложение РНН

RNN часто используется в обработке естественного языка, машинном переводе, распознавании речи, распознавании изображений и др. Структура, соответствующая приложениям, связанным с RNN, кратко описана ниже.

  • Анализ настроений RNN: при анализе того, являются ли эмоции человека положительными или отрицательными, используйте структуру RNN, показанную на рисунке ниже, которая имеет N входов, 1 выход, а значение Y в последний момент времени представляет окончательный выходной результат.

  • Распознавание изображений RNN: В это время есть вход изображения X и соответствующие выходы N.

  • машинный перевод РНН: Есть два входа и выхода, соответствующие китайскому и английскому языку, как показано на следующем рисунке.

2.LSTM

Далее мы рассмотрим более мощную структуру под названием LSTM.

(1) Зачем внедрять LSTM?

RNN учится на упорядоченных данных, RNN помнит предыдущие данные, как человек, но иногда забывает то, что сказал ранее, как дедушка. Для решения этого недостатка RNN предлагается технология LTSM, полное английское название Long Short-term memory, которая также является одной из самых популярных RNN.

Предположим, что сейчас есть предложение, как показано на рисунке ниже, RNN считает, что это предложение — тушеные свиные ребрышки, которые нужно выучить в это время, а «тушеные свиные ребрышки» стоит в начале предложения.

Слово «тушеные свиные ребрышки» проходит долгий путь, чтобы прийти, через серию ошибок получения, а затем через обратный проход, который на каждом шаге умножается на параметр веса w. Если умноженный вес представляет собой число меньше 1, например 0,9, то 0,9 будет постоянно умножать ошибку, и, наконец, когда это значение передается начальному значению, ошибка исчезает, что называется исчезновением градиента или дисперсией градиента.

И наоборот, если ошибка представляет собой большое число, например 1,1, значение, полученное этим RNN, будет большим, что называется взрывом градиента.

Исчезающий градиент или взрывной градиент: в RNN, если ваше состояние представляет собой очень длинную последовательность, при условии, что значение ошибки обратного прохода меньше 1, каждый обратный проход будет умножаться на это число, 0,9 n раз. Направление стремится к 0, а n-я степень 1,1 стремится к бесконечности, что приведет к исчезновению или взрыву градиента.

Это также причина, по которой RNN не восстанавливает память.Чтобы решить проблему исчезновения градиента или взрыва градиента, возникающую при градиентном спуске RNN, вводится LSTM.

(2) LSTM

LSTM внесла некоторые улучшения в обычную RNN.LSTM RNN имеет еще три контроллера, а именно контроллер ввода, вывода и забывания. Слева больше основных линий, таких как основной сюжет фильма, а исходная система RNN стала подсюжетом, а все три контроллера находятся на подстроке.

  • Контроллер ввода (запись ворота): Установите ворота при вводе ввода. Функция ворот состоит в том, чтобы решить, следует ли записывать этот ввод в нашу память. Он эквивалентен параметру и также может быть обучен. Этот параметр используется для управления тем, запоминать ли эту точку в настоящее время.
  • Выходной контроллер (считывающий вентиль): В воротах выходной позиции решите, следует ли читать текущую память.
  • Забудьте контроллер (забудьте ворота): Обработайте забытый контроллер местоположения и решите, следует ли забыть предыдущую память.

Принцип работы LSTM таков: если подсюжет очень важен для конечного результата, контроллер ввода запишет подсюжет в основной сюжет в соответствии с его важностью, а затем проанализирует его; если подсюжет изменит наши предыдущие мысли, то забудьте управление Контроллер забудет некоторые основные графики, а затем пропорционально заменит новые графики, поэтому обновление основного графика зависит от ввода и управления забыванием; окончательный вывод будет основан на основном графике и ветвях.

Наша RNN хорошо контролируется этими тремя воротами, и на основе этих механизмов управления LSTM является хорошим лекарством от задержки памяти, что приводит к лучшим результатам.

2. Описание случая регрессии LSTM RNN

Ранее мы объяснили проблему классификации RNN и CNN, В этой статье будет рассмотрена проблема регрессии. В случае регрессии LSTM RNN мы хотим предсказать красную сплошную линию с синей пунктирной линией, поскольку кривая sin представляет собой волнистый цикл, RNN будет использовать одну последовательность для предсказания другой последовательности.

Базовая структура кода включает в себя:

  • (1) Функция get_batch(), генерирующая данные

  • (2) Основной LSTM RNN

  • (3) Трехслойная нейронная сеть, включая входной_слой, ячейку и выходной_слой, имеет ту же структуру, что и предыдущая классификационная RNN.

    def add_input_layer(self,): pass def add_cell(self): pass
    def add_output_layer(self): pass

  • (4) Рассчитайте функцию ошибок computer_cost

  • (5) Веса ошибок и смещения

  • (6) Основная функция устанавливает модель LSTM RNN.

  • (7) TensorBoard визуализирует модели нейронных сетей, matplotlib визуализирует подходящие кривые,

Наконец, добавьте BPTT и начните писать код.

(1) Обычный РНН

Предположим, мы обучаем последовательность, содержащую данные 1 000 000. Если все обучение будет выполнено, вся последовательность будет передана в RNN, что легко вызовет проблему исчезновения или взрыва градиента. Таким образом, решение состоит в усечении обратного распространения (Truncated Backpropagation, BPTT), мы усекаем последовательность для обучения (num_steps).

Общее усеченное обратное распространение: в текущий момент времени t выполнить обратное распространение на num_steps шагов вперед. Как показано на рисунке ниже, для последовательности длиной 6 количество шагов усечения равно 3, а начальное состояние и конечное состояние передаются в ячейке RNN.

(2) BPTT версии TensorFlow

Но реализация в Tensorflow не такая, она делит последовательность длины 6 на две части, каждая часть имеет длину 3, и конечное состояние, вычисленное в предыдущей части, используется для начального состояния, вычисленного в следующей части. Как показано на рисунке ниже, каждый пакет выполняет отдельное усеченное обратное распространение. Пакет в это время сохранит конечное состояние и будет использовать его в качестве состояния инициализации следующего пакета.

Ссылаться на:Глубокое обучение (07) RNN-рекуррентная нейронная сеть-02- реализация в Tensorflow

3. Реализация кода

Первый шаг — открыть Anaconda, затем выбрать созданную среду «tensorflow» и запустить Spyder.

Второй шаг — импорт пакета расширения.

import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt

Третий шаг — написать функцию get_batch(), которая генерирует данные, которые генерируют последовательность синусоидальных кривых.

# 获取批量数据
def get_batch():
    global BATCH_START, TIME_STEPS
    # xs shape (50batch, 20steps)
    xs = np.arange(BATCH_START, BATCH_START+TIME_STEPS*BATCH_SIZE).reshape((BATCH_SIZE, TIME_STEPS)) / (10*np.pi)
    seq = np.sin(xs)
    res = np.cos(xs)
    BATCH_START += TIME_STEPS    
    # 显示原始曲线
    plt.plot(xs[0, :], res[0, :], 'r', xs[0, :], seq[0, :], 'b--')
    plt.show()
    # 返回序列seq 结果res 输入xs
    return [seq[:, :, np.newaxis], res[:, :, np.newaxis], xs]

Результат в это время показан на рисунке ниже, обратите внимание, что это только ожидаемая кривая моделирования, а не структура, изученная нашей нейронной сетью.

Четвертый шаг: напишите класс LSTMRNN, который используется для определения структуры нашей рекуррентной нейронной сети, операций инициализации и необходимых переменных.

Параметры функции инициализации init() включают в себя:

  • n_steps представляет шаги в пакете, всего 3 шага.
  • input_size указывает длину каждого ввода при передаче пакетных данных. В этом примере и input_size, и output_size равны 1. Как показано на рисунке ниже, предполагая, что длина нашего пакета составляет один цикл (0-6), каждый ввод представляет собой значение x строки, а размер ввода указывает, сколько значений имеется в каждый момент времени. только один балл, так что это 1.
  • output_size представляет значение вывода, вывод соответствует значению y входной строки, а его значение размера равно 1.
  • cell_size указывает количество ячеек RNN, и его значение равно 10.
  • batch_size указывает количество пакетов, переданных в нейронную сеть за один раз, равное 50.

Эта часть кода выглядит следующим образом, обратите внимание на форму xs и ys. В то же время нам нужно использовать Tensorboard для визуализации структуры RNN, поэтому вызовите tf.name_scope(), чтобы установить имя пространства имен каждого нейронного слоя и переменной, см. подробностипятая статья.

#----------------------------------定义参数----------------------------------
BATCH_START = 0
TIME_STEPS = 20
BATCH_SIZE = 50          # BATCH数量
INPUT_SIZE = 1           # 输入一个值
OUTPUT_SIZE = 1          # 输出一个值
CELL_SIZE = 10           # Cell数量
LR = 0.006
BATCH_START_TEST = 0

#----------------------------------LSTM RNN----------------------------------
class LSTMRNN(object):
    # 初始化操作
    def __init__(self, n_steps, input_size, output_size, cell_size, batch_size):
        self.n_steps = n_steps
        self.input_size = input_size
        self.output_size = output_size
        self.cell_size = cell_size
        self.batch_size = batch_size
 
        # TensorBoard可视化操作使用name_scope
        with tf.name_scope('inputs'):         #输出变量
            self.xs = tf.placeholder(tf.float32, [None, n_steps, input_size], name='xs')
            self.ys = tf.placeholder(tf.float32, [None, n_steps, output_size], name='ys')
        with tf.variable_scope('in_hidden'):  #输入层
            self.add_input_layer()
        with tf.variable_scope('LSTM_cell'):  #处理层
            self.add_cell()
        with tf.variable_scope('out_hidden'): #输出层
            self.add_output_layer()
        with tf.name_scope('cost'):           #误差
            self.compute_cost()
        with tf.name_scope('train'):          #训练
            self.train_op = tf.train.AdamOptimizer(LR).minimize(self.cost)

Пятый шаг, затем начали писать три функции (трехслойная нейронная сеть), которая является основной структурой RNN.

# 输入层
def add_input_layer(self,):
    pass
# cell层
def add_cell(self):
    pass
# 输出层
def add_output_layer(self):
    pass

Эти три функции также добавлены в класс LSTMRNN.Основной код и подробные комментарии выглядят следующим образом:

#--------------------------------定义核心三层结构-----------------------------
# 输入层
def add_input_layer(self,):
    # 定义输入层xs变量 将xs三维数据转换成二维
    # [None, n_steps, input_size] => (batch*n_step, in_size)
    l_in_x = tf.reshape(self.xs, [-1, self.input_size], name='2_2D')
    # 定义输入权重 (in_size, cell_size)
    Ws_in = self._weight_variable([self.input_size, self.cell_size])
    # 定义输入偏置 (cell_size, )
    bs_in = self._bias_variable([self.cell_size,])
    # 定义输出y变量 二维形状 (batch * n_steps, cell_size)
    with tf.name_scope('Wx_plus_b'):
        l_in_y = tf.matmul(l_in_x, Ws_in) + bs_in
    # 返回结果形状转变为三维
    # l_in_y ==> (batch, n_steps, cell_size)
    self.l_in_y = tf.reshape(l_in_y, [-1, self.n_steps, self.cell_size], name='2_3D')
 
# cell层
def add_cell(self):
    # 选择BasicLSTMCell模型
    # forget初始偏置为1.0(初始时不希望forget) 随着训练深入LSTM会选择性忘记
    lstm_cell = tf.nn.rnn_cell.BasicLSTMCell(self.cell_size, forget_bias=1.0, state_is_tuple=True)
    # 设置initial_state全为0 可视化操作用name_scope
    with tf.name_scope('initial_state'):
        self.cell_init_state = lstm_cell.zero_state(self.batch_size, dtype=tf.float32)
    # RNN循环 每一步的输出都存储在cell_outputs序列中 cell_final_state为最终State并传入下一个batch中
    # 常规RNN只有m_state LSTM包括c_state和m_state
    self.cell_outputs, self.cell_final_state = tf.nn.dynamic_rnn(
        lstm_cell, self.l_in_y, initial_state=self.cell_init_state, time_major=False)
 
# 输出层 (类似输入层)
def add_output_layer(self):
    # 转换成二维 方能使用W*X+B
    # shape => (batch * steps, cell_size) 
    l_out_x = tf.reshape(self.cell_outputs, [-1, self.cell_size], name='2_2D')
    Ws_out = self._weight_variable([self.cell_size, self.output_size])
    bs_out = self._bias_variable([self.output_size, ])
    # 返回预测结果
    # shape => (batch * steps, output_size)
    with tf.name_scope('Wx_plus_b'):
        self.pred = tf.matmul(l_out_x, Ws_out) + bs_out

Обратите внимание, что reshape() вызывается выше для обновления формы Почему вы хотите изменить трехмерную переменную на двумерную? Потому что W*X+B можно вычислить только после того, как он станет двумерной переменной.

Шестой шаг заключается в определении функции ошибки вычислений.

Примечание: мы использовали функцию seq2seq. Найденная потеря — это потеря каждого шага всего пакета, затем сумма потерь каждого шага становится потерей всего TensorFlow, затем она делится на средний размер пакета и, наконец, получается общая стоимость пакета. пакет, который является скалярным числом.

# 定义误差计算函数      
def compute_cost(self):
    # 使用seq2seq序列到序列模型
    # tf.nn.seq2seq.sequence_loss_by_example()
    losses = tf.contrib.legacy_seq2seq.sequence_loss_by_example(
        [tf.reshape(self.pred, [-1], name='reshape_pred')],
        [tf.reshape(self.ys, [-1], name='reshape_target')],
        [tf.ones([self.batch_size * self.n_steps], dtype=tf.float32)],
        average_across_timesteps=True,
        softmax_loss_function=self.msr_error,
        name='losses'
    )
    # 最终得到batch的总cost 它是一个数字
    with tf.name_scope('average_cost'):
        # 整个TensorFlow的loss求和 再除以batch size
        self.cost = tf.div(
            tf.reduce_sum(losses, name='losses_sum'),
            self.batch_size,
            name='average_cost')
        tf.summary.scalar('cost', self.cost)

В следующих статьях мы напишем подробную статью о машинном переводе и будем использовать модель seq2seq.

Модель Seq2Seq — это модель, используемая, когда длина вывода неопределенна.Такая ситуация обычно возникает в задаче машинного перевода.При переводе предложения с китайского на английский длина английского предложения может быть короче, чем у китайского, или он может быть длиннее, чем у китайского.Китайский длинный, поэтому длина вывода неопределенна. Как показано на рисунке ниже, входная длина на китайском языке равна 4, а выходная длина на английском языке равна 2.

В сетевой структуре вводится китайская последовательность, а затем выводится соответствующий китайский перевод.Результат выходной части предсказывается позже, согласно приведенному выше примеру, то есть сначала выводится «машина», а «машина» используется как следующий ввод, затем вывод «обучения», который может выводить последовательности произвольной длины.

Машинный перевод, человеко-машинный диалог, чат-боты и т. д. — все это приложения современного общества, которые более или менее применяют то, что мы здесь называем Seq2Seq.

Седьмой шаг заключается в определении функции вычисления msr_error, функции вычисления ошибки и функции вычисления смещения.

# 该函数用于计算
# 相当于msr_error(self, y_pre, y_target) return tf.square(tf.sub(y_pre, y_target))
def msr_error(self, logits, labels):
    return tf.square(tf.subtract(logits, labels))
# 误差计算
def _weight_variable(self, shape, name='weights'):
    initializer = tf.random_normal_initializer(mean=0., stddev=1.,)
    return tf.get_variable(shape=shape, initializer=initializer, name=name)
# 偏置计算
def _bias_variable(self, shape, name='biases'):
    initializer = tf.constant_initializer(0.1)
    return tf.get_variable(name=name, shape=shape, initializer=initializer)

На данный момент весь класс определен.

Восьмой шаг — определить основную функцию, выполнить операции обучения и прогнозирования и сначала попробовать визуализацию TensorBoard.

#----------------------------------主函数 训练和预测----------------------------------     
if __name__ == '__main__':
    # 定义模型并初始化
    model = LSTMRNN(TIME_STEPS, INPUT_SIZE, OUTPUT_SIZE, CELL_SIZE, BATCH_SIZE)
    sess = tf.Session()
    merged = tf.summary.merge_all()
    writer = tf.summary.FileWriter("logs", sess.graph)
    sess.run(tf.initialize_all_variables())

4. Полный код и визуальное отображение

Полный код этого этапа выглядит следующим образом, давайте сначала попробуем запустить следующий код:

# -*- coding: utf-8 -*-
"""
Created on Thu Jan  9 20:44:56 2020
@author: xiuzhang Eastmount CSDN
"""
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt

#----------------------------------定义参数----------------------------------
BATCH_START = 0
TIME_STEPS = 20
BATCH_SIZE = 50          # BATCH数量
INPUT_SIZE = 1           # 输入一个值
OUTPUT_SIZE = 1          # 输出一个值
CELL_SIZE = 10           # Cell数量
LR = 0.006
BATCH_START_TEST = 0

# 获取批量数据
def get_batch():
    global BATCH_START, TIME_STEPS
    # xs shape (50batch, 20steps)
    xs = np.arange(BATCH_START, BATCH_START+TIME_STEPS*BATCH_SIZE).reshape((BATCH_SIZE, TIME_STEPS)) / (10*np.pi)
    seq = np.sin(xs)
    res = np.cos(xs)
    BATCH_START += TIME_STEPS    
    # 返回序列seq 结果res 输入xs
    return [seq[:, :, np.newaxis], res[:, :, np.newaxis], xs]

#----------------------------------LSTM RNN----------------------------------
class LSTMRNN(object):
    # 初始化操作
    def __init__(self, n_steps, input_size, output_size, cell_size, batch_size):
        self.n_steps = n_steps
        self.input_size = input_size
        self.output_size = output_size
        self.cell_size = cell_size
        self.batch_size = batch_size
 
        # TensorBoard可视化操作使用name_scope
        with tf.name_scope('inputs'):         #输出变量
            self.xs = tf.placeholder(tf.float32, [None, n_steps, input_size], name='xs')
            self.ys = tf.placeholder(tf.float32, [None, n_steps, output_size], name='ys')
        with tf.variable_scope('in_hidden'):  #输入层
            self.add_input_layer()
        with tf.variable_scope('LSTM_cell'):  #处理层
            self.add_cell()
        with tf.variable_scope('out_hidden'): #输出层
            self.add_output_layer()
        with tf.name_scope('cost'):           #误差
            self.compute_cost()
        with tf.name_scope('train'):          #训练
            self.train_op = tf.train.AdamOptimizer(LR).minimize(self.cost)
 
    #--------------------------------定义核心三层结构-----------------------------
    # 输入层
    def add_input_layer(self,):
        # 定义输入层xs变量 将xs三维数据转换成二维
        # [None, n_steps, input_size] => (batch*n_step, in_size)
        l_in_x = tf.reshape(self.xs, [-1, self.input_size], name='2_2D')
        # 定义输入权重 (in_size, cell_size)
        Ws_in = self._weight_variable([self.input_size, self.cell_size])
        # 定义输入偏置 (cell_size, )
        bs_in = self._bias_variable([self.cell_size,])
        # 定义输出y变量 二维形状 (batch * n_steps, cell_size)
        with tf.name_scope('Wx_plus_b'):
            l_in_y = tf.matmul(l_in_x, Ws_in) + bs_in
        # 返回结果形状转变为三维
        # l_in_y ==> (batch, n_steps, cell_size)
        self.l_in_y = tf.reshape(l_in_y, [-1, self.n_steps, self.cell_size], name='2_3D')
 
    # cell层
    def add_cell(self):
        # 选择BasicLSTMCell模型
        # forget初始偏置为1.0(初始时不希望forget) 随着训练深入LSTM会选择性忘记
        lstm_cell = tf.nn.rnn_cell.BasicLSTMCell(self.cell_size, forget_bias=1.0, state_is_tuple=True)
        # 设置initial_state全为0 可视化操作用name_scope
        with tf.name_scope('initial_state'):
            self.cell_init_state = lstm_cell.zero_state(self.batch_size, dtype=tf.float32)
        # RNN循环 每一步的输出都存储在cell_outputs序列中 cell_final_state为最终State并传入下一个batch中
        # 常规RNN只有m_state LSTM包括c_state和m_state
        self.cell_outputs, self.cell_final_state = tf.nn.dynamic_rnn(
            lstm_cell, self.l_in_y, initial_state=self.cell_init_state, time_major=False)
 
    # 输出层 (类似输入层)
    def add_output_layer(self):
        # 转换成二维 方能使用W*X+B
        # shape => (batch * steps, cell_size) 
        l_out_x = tf.reshape(self.cell_outputs, [-1, self.cell_size], name='2_2D')
        Ws_out = self._weight_variable([self.cell_size, self.output_size])
        bs_out = self._bias_variable([self.output_size, ])
        # 返回预测结果
        # shape => (batch * steps, output_size)
        with tf.name_scope('Wx_plus_b'):
            self.pred = tf.matmul(l_out_x, Ws_out) + bs_out
 
    #--------------------------------定义误差计算函数-----------------------------     
    def compute_cost(self):
        # 使用seq2seq序列到序列模型
        # tf.nn.seq2seq.sequence_loss_by_example()
        losses = tf.contrib.legacy_seq2seq.sequence_loss_by_example(
            [tf.reshape(self.pred, [-1], name='reshape_pred')],
            [tf.reshape(self.ys, [-1], name='reshape_target')],
            [tf.ones([self.batch_size * self.n_steps], dtype=tf.float32)],
            average_across_timesteps=True,
            softmax_loss_function=self.msr_error,
            name='losses'
        )
        # 最终得到batch的总cost 它是一个数字
        with tf.name_scope('average_cost'):
            # 整个TensorFlow的loss求和 再除以batch size
            self.cost = tf.div(
                tf.reduce_sum(losses, name='losses_sum'),
                self.batch_size,
                name='average_cost')
            tf.summary.scalar('cost', self.cost)
 
    # 该函数用于计算
    # 相当于msr_error(self, y_pre, y_target) return tf.square(tf.sub(y_pre, y_target))
    def msr_error(self, logits, labels):
        return tf.square(tf.subtract(logits, labels))
    # 误差计算
    def _weight_variable(self, shape, name='weights'):
        initializer = tf.random_normal_initializer(mean=0., stddev=1.,)
        return tf.get_variable(shape=shape, initializer=initializer, name=name)
    # 偏置计算
    def _bias_variable(self, shape, name='biases'):
        initializer = tf.constant_initializer(0.1)
        return tf.get_variable(name=name, shape=shape, initializer=initializer)
 
#----------------------------------主函数 训练和预测----------------------------------     
if __name__ == '__main__':
    # 定义模型并初始化
    model = LSTMRNN(TIME_STEPS, INPUT_SIZE, OUTPUT_SIZE, CELL_SIZE, BATCH_SIZE)
    sess = tf.Session()
    merged = tf.summary.merge_all()
    writer = tf.summary.FileWriter("logs", sess.graph)
    sess.run(tf.initialize_all_variables())

На этом этапе в каталоге файлов Python будут созданы папка «logs» и файл событий, как показано на следующем рисунке.

Далее попробуй открыть. Сначала вызовите Anaconda Prompt, активируйте TensorFlow, затем перейдите в каталог файла событий и вызовите команду «tensorboard --logdir=logs для запуска», как показано на рисунке ниже. Обратите внимание, что вам нужно указать только папку здесь, и он автоматически проиндексирует ваш файл.

activate tensorflow
cd\
cd C:\Users\xiuzhang\Desktop\TensorFlow\blog
tensorboard --logdir=logs

Посетите URL-адрес в это время"http://localhost:6006/», выбираем «Графики», после запуска, как показано на рисунке ниже, появляется наша нейросеть.

Структура нейронной сети показана на рисунке ниже, включая входной слой, слой LSTM, выходной слой, расчет ошибки стоимости, обучение поезда и т. д.

Подробная структура показана на следующем рисунке:

Обычно мы откладываем часть поезда в сторону, выбираем «поезд» и щелкаем правой кнопкой мыши «Удалить из основного графика». Основная структура выглядит следующим образом: in_hidden — это первый уровень, который принимает ввод, за ним следует LSTM_cell и, наконец, выходной уровень out_hidden.

  • in_hidden: Включая веса Веса и смещения, формула расчета Wx_plus_b. В то же время он включает операции изменения формы, 2_2D и 2_3D.

  • out_hidden: включает веса, смещения, формулу расчета Wx_plus_b, двумерные данные 2_2D, а выходным результатом является стоимость.

  • cost: Ошибка расчета.

  • Посередине LSTM_cell: Включая рекуррентную нейронную сеть RNN, инициализирующую initial_state, а затем заменяющую обновлением состояния.

Обратите внимание на проблему с версией: читатели могут внести соответствующие изменения и запустить в сочетании со своей собственной версией TensorFlow. Информация о версии версии автора: Python3.6, Anaconda3, Win10, Tensorflow1.15.0.

Если вы получаете сообщение об ошибке AttributeError: модуль «tensorflow._api.v1.nn» не имеет атрибута «seq2seq», это обновление версии TensorFlow, и вызов метода изменился. Решение:

Если вы сообщаете TypeError: msr_error() получила неожиданный аргумент ключевого слова «метки», функция msr_error() получила неожиданный аргумент ключевого слова «метки». Решение: при определении функции msr_error() используйте метки, логиты для указания и установите

def msr_error(self, y_pre, y_target):
    return tf.square(tf.subtract(y_pre, y_target))

Измените его на:

def msr_error(self, logits, labels):
    return tf.square(tf.subtract(logits, labels))

Если вы получаете сообщение об ошибке ValueError: Variable in_hidden/weights уже существует, запрещена. Вы имели в виду установить reuse=True или reuse=tf.AUTO_REUSE в VarScope? , перезапустите ядро ​​для запуска.

5. Прогнозирование и подбор кривой

Наконец, мы кодируем обучение и прогнозирование RNN в основной функции.

Сначала мы проверяем результат обучения стоимости. Код выглядит следующим образом, если cell_init_state является ранее инициализированным состоянием в решении if, а затем состояние обновляется (model.cell_init_state: state), что фактически заменяет конечное состояние исходным состоянием следующего пакета, чтобы соответствовать структуре, которую мы определили.

#----------------------------------主函数 训练和预测----------------------------------     
if __name__ == '__main__':
    # 定义模型并初始化
    model = LSTMRNN(TIME_STEPS, INPUT_SIZE, OUTPUT_SIZE, CELL_SIZE, BATCH_SIZE)
    sess = tf.Session()
    merged = tf.summary.merge_all()
    writer = tf.summary.FileWriter("logs", sess.graph)
    sess.run(tf.initialize_all_variables())
    # Tensorboard可视化展现神经网络结果
 
    #------------------------------RNN学习-------------------------------------    
    # 训练模型 
    for i in range(200):
        # 用seq预测res (序列-seq 结果-res 输入-xs)
        seq, res, xs = get_batch()
        # 第一步赋值 之后会更新cell_init_state
        if i == 0:
            feed_dict = {
                model.xs: seq,
                model.ys: res,
                # create initial state (前面cell_init_state已初始化state)
            }
        else:
            feed_dict = {
                model.xs: seq,
                model.ys: res,
                model.cell_init_state: state    
                # use last state as the initial state for this run
            }
 
        # state为final_state 
        _, cost, state, pred = sess.run(
                [model.train_op, model.cost, model.cell_final_state, model.pred], 
                feed_dict=feed_dict)
 
        # 每隔20步输出结果
        if i % 20 == 0:
            print('cost: ', round(cost, 4))

Результаты выводятся каждые 20 шагов, как показано ниже, ошибка от начальных 33 до конечных 0,335, нейронная сеть постоянно обучается, и ошибка постоянно уменьшается.

cost:  33.1673
cost:  9.1332
cost:  3.8899
cost:  1.3271
cost:  0.2682
cost:  0.4912
cost:  1.0692
cost:  0.3812
cost:  0.63
cost:  0.335

Затем добавьте процесс динамической подгонки кривой sin, визуализированный matplotlib.Окончательный полный код выглядит следующим образом:

# -*- coding: utf-8 -*-
"""
Created on Thu Jan  9 20:44:56 2020
@author: xiuzhang Eastmount CSDN
"""
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt

#----------------------------------定义参数----------------------------------
BATCH_START = 0
TIME_STEPS = 20
BATCH_SIZE = 50          # BATCH数量
INPUT_SIZE = 1           # 输入一个值
OUTPUT_SIZE = 1          # 输出一个值
CELL_SIZE = 10           # Cell数量
LR = 0.006
BATCH_START_TEST = 0

# 获取批量数据
def get_batch():
    global BATCH_START, TIME_STEPS
    # xs shape (50batch, 20steps)
    xs = np.arange(BATCH_START, BATCH_START+TIME_STEPS*BATCH_SIZE).reshape((BATCH_SIZE, TIME_STEPS)) / (10*np.pi)
    seq = np.sin(xs)
    res = np.cos(xs)
    BATCH_START += TIME_STEPS    
 
    # 显示原始曲线
    # plt.plot(xs[0, :], res[0, :], 'r', xs[0, :], seq[0, :], 'b--')
    # plt.show()
 
    # 返回序列seq 结果res 输入xs
    return [seq[:, :, np.newaxis], res[:, :, np.newaxis], xs]

#----------------------------------LSTM RNN----------------------------------
class LSTMRNN(object):
    # 初始化操作
    def __init__(self, n_steps, input_size, output_size, cell_size, batch_size):
        self.n_steps = n_steps
        self.input_size = input_size
        self.output_size = output_size
        self.cell_size = cell_size
        self.batch_size = batch_size
 
        # TensorBoard可视化操作使用name_scope
        with tf.name_scope('inputs'):         #输出变量
            self.xs = tf.placeholder(tf.float32, [None, n_steps, input_size], name='xs')
            self.ys = tf.placeholder(tf.float32, [None, n_steps, output_size], name='ys')
        with tf.variable_scope('in_hidden'):  #输入层
            self.add_input_layer()
        with tf.variable_scope('LSTM_cell'):  #处理层
            self.add_cell()
        with tf.variable_scope('out_hidden'): #输出层
            self.add_output_layer()
        with tf.name_scope('cost'):           #误差
            self.compute_cost()
        with tf.name_scope('train'):          #训练
            self.train_op = tf.train.AdamOptimizer(LR).minimize(self.cost)
 
    #--------------------------------定义核心三层结构-----------------------------
    # 输入层
    def add_input_layer(self,):
        # 定义输入层xs变量 将xs三维数据转换成二维
        # [None, n_steps, input_size] => (batch*n_step, in_size)
        l_in_x = tf.reshape(self.xs, [-1, self.input_size], name='2_2D')
        # 定义输入权重 (in_size, cell_size)
        Ws_in = self._weight_variable([self.input_size, self.cell_size])
        # 定义输入偏置 (cell_size, )
        bs_in = self._bias_variable([self.cell_size,])
        # 定义输出y变量 二维形状 (batch * n_steps, cell_size)
        with tf.name_scope('Wx_plus_b'):
            l_in_y = tf.matmul(l_in_x, Ws_in) + bs_in
        # 返回结果形状转变为三维
        # l_in_y ==> (batch, n_steps, cell_size)
        self.l_in_y = tf.reshape(l_in_y, [-1, self.n_steps, self.cell_size], name='2_3D')
 
    # cell层
    def add_cell(self):
        # 选择BasicLSTMCell模型
        # forget初始偏置为1.0(初始时不希望forget) 随着训练深入LSTM会选择性忘记
        lstm_cell = tf.nn.rnn_cell.BasicLSTMCell(self.cell_size, forget_bias=1.0, state_is_tuple=True)
        # 设置initial_state全为0 可视化操作用name_scope
        with tf.name_scope('initial_state'):
            self.cell_init_state = lstm_cell.zero_state(self.batch_size, dtype=tf.float32)
        # RNN循环 每一步的输出都存储在cell_outputs序列中 cell_final_state为最终State并传入下一个batch中
        # 常规RNN只有m_state LSTM包括c_state和m_state
        self.cell_outputs, self.cell_final_state = tf.nn.dynamic_rnn(
            lstm_cell, self.l_in_y, initial_state=self.cell_init_state, time_major=False)
 
    # 输出层 (类似输入层)
    def add_output_layer(self):
        # 转换成二维 方能使用W*X+B
        # shape => (batch * steps, cell_size) 
        l_out_x = tf.reshape(self.cell_outputs, [-1, self.cell_size], name='2_2D')
        Ws_out = self._weight_variable([self.cell_size, self.output_size])
        bs_out = self._bias_variable([self.output_size, ])
        # 返回预测结果
        # shape => (batch * steps, output_size)
        with tf.name_scope('Wx_plus_b'):
            self.pred = tf.matmul(l_out_x, Ws_out) + bs_out
 
    #--------------------------------定义误差计算函数-----------------------------     
    def compute_cost(self):
        # 使用seq2seq序列到序列模型
        # tf.nn.seq2seq.sequence_loss_by_example()
        losses = tf.contrib.legacy_seq2seq.sequence_loss_by_example(
            [tf.reshape(self.pred, [-1], name='reshape_pred')],
            [tf.reshape(self.ys, [-1], name='reshape_target')],
            [tf.ones([self.batch_size * self.n_steps], dtype=tf.float32)],
            average_across_timesteps=True,
            softmax_loss_function=self.msr_error,
            name='losses'
        )
        # 最终得到batch的总cost 它是一个数字
        with tf.name_scope('average_cost'):
            # 整个TensorFlow的loss求和 再除以batch size
            self.cost = tf.div(
                tf.reduce_sum(losses, name='losses_sum'),
                self.batch_size,
                name='average_cost')
            tf.summary.scalar('cost', self.cost)
 
    # 该函数用于计算
    # 相当于msr_error(self, y_pre, y_target) return tf.square(tf.sub(y_pre, y_target))
    def msr_error(self, logits, labels):
        return tf.square(tf.subtract(logits, labels))
    # 误差计算
    def _weight_variable(self, shape, name='weights'):
        initializer = tf.random_normal_initializer(mean=0., stddev=1.,)
        return tf.get_variable(shape=shape, initializer=initializer, name=name)
    # 偏置计算
    def _bias_variable(self, shape, name='biases'):
        initializer = tf.constant_initializer(0.1)
        return tf.get_variable(name=name, shape=shape, initializer=initializer)
 
#----------------------------------主函数 训练和预测----------------------------------     
if __name__ == '__main__':
    # 定义模型并初始化
    model = LSTMRNN(TIME_STEPS, INPUT_SIZE, OUTPUT_SIZE, CELL_SIZE, BATCH_SIZE)
    sess = tf.Session()
    merged = tf.summary.merge_all()
    writer = tf.summary.FileWriter("logs", sess.graph)
    sess.run(tf.initialize_all_variables())
    # Tensorboard可视化展现神经网络结果
 
    #------------------------------RNN学习-------------------------------------     
    # 交互模式启动
    plt.ion()
    plt.show()
 
    # 训练模型 
    for i in range(200):
        # 用seq预测res (序列-seq 结果-res 输入-xs)
        seq, res, xs = get_batch()
        # 第一步赋值 之后会更新cell_init_state
        if i == 0:
            feed_dict = {
                model.xs: seq,
                model.ys: res,
                # create initial state (前面cell_init_state已初始化state)
            }
        else:
            feed_dict = {
                model.xs: seq,
                model.ys: res,
                model.cell_init_state: state    
                # use last state as the initial state for this run
            }
 
        # state为final_state 
        _, cost, state, pred = sess.run(
                [model.train_op, model.cost, model.cell_final_state, model.pred], 
                feed_dict=feed_dict)

        # plotting
        # 获取第一批数据xs[0,:] 获取0到20区间的预测数据pred.flatten()[:TIME_STEPS]
        plt.plot(xs[0, :], res[0].flatten(), 'r', xs[0, :], pred.flatten()[:TIME_STEPS], 'b--')
        plt.ylim((-1.2, 1.2))
        plt.draw()
        plt.pause(0.3)
 
        # 每隔20步输出结果
        if i % 20 == 0:
            print('cost: ', round(cost, 4))
            # result = sess.run(merged, feed_dict)
            # writer.add_summary(result, i)

Пишите сюда, эта статья наконец закончена. Статья очень длинная, но надеюсь поможет. LSTM RNN предсказывают другой набор данных из одного набора данных. Эффект предсказания показан на рисунке ниже.Красная сплошная линия представляет собой линию, которую необходимо предсказать, а синяя пунктирная линия представляет собой линию, изученную RNN.Они постоянно приближаются.Синяя линия усвоила закон красного линия, и, наконец, синяя линия в основном соответствует красной линии.

6. Резюме

После введения в эту статью будет продолжать публиковаться больше статей о глубоком обучении TensorFlow.Далее мы поделимся контролируемым обучением, GAN, машинным переводом, распознаванием текста, распознаванием изображений, распознаванием речи и т. д. Если у читателей есть что-то, чему они хотят научиться, они также могут пообщаться со мной в частном порядке, и я узнаю и применю их в вашей области.

Наконец, я надеюсь, что эта базовая статья будет вам полезна.Если в статье есть ошибки или недостатки, пожалуйста, также спросите у Haihan~ Как новичок в области искусственного интеллекта, я надеюсь, что смогу продолжать улучшать и углублять, а затем применять его к распознавание изображений, сетевая безопасность, враждебные образцы и другие области, помогите всем написать простые академические статьи, давай вместе!

Адрес загрузки кода (прошу обратить внимание и поставить лайк):

Нажмите «Подписаться», чтобы впервые узнать о новых технологиях HUAWEI CLOUD~