Создайте свой собственный набор данных, используйте TensorFlow для прогнозирования акций

TensorFlow глубокое обучение Нейронные сети Архитектура

из среды

Сборник "Сердце машины"

Участвуют: Цзян Сыюань, Ли Ячжоу, Лю Сяокунь

Команда STATWORX недавно выбрала данные S&P 500 из Google Finance API, которые содержат индекс S&P 500 и информацию о ценах на акции. Вооружившись этими данными, они надеются предсказать S&P 500, используя модель глубокого обучения и цены 500 составляющих акций. Набор данных команды STATWORX очень новый, но для предсказания он использует только полностью подключенную сеть с четырьмя скрытыми слоями Читатели также могут загрузить эти данные, чтобы попробовать лучшую рекуррентную нейронную сеть.

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

Адрес набора данных: http://files.statworx.com/sp500.zip

Импорт и предварительная обработка данных

Команда STATWORX собирает данные о запасах с сервера и сохраняет их в виде CSV-файлов. Набор данных содержит n=41266 минут записей за период с апреля по август 2017 года для 500 акций и S&P 500 с широким распределением акций и фондовых индексов.

  1. # Import data

  2. data = pd.read_csv('data_stocks.csv')

  3. # Dimensions of dataset

  4. n = data.shape[0]

  5. p = data.shape[1]

скопировать код

Набор данных был очищен и предварительно обработан, т. е. как отсутствующие акции, так и фондовые индексы подвергаются LOCF (следующее наблюдение повторяет предыдущее), поэтому в наборе данных нет пропущенных значений.

Мы можем построить данные временного ряда S&P, используя оператор pyplot.plot('SP500').

График временных рядов фондового индекса S&P 500

Подготовка данных для обучения и тестирования

Набор данных необходимо разделить на данные обучения и тестирования, данные обучения содержат 80% записей всего набора данных. Набор данных не нужно возмущать, а просто последовательно нарезать. Обучающие данные можно выбрать с апреля 2017 г. до конца июля 2017 г., а тестовые данные — с остальных до августа 2017 г.

  1. # Training and test data

  2. train_start = 0

  3. train_end = int(np.floor(0.8*n))

  4. test_start = train_end + 1

  5. test_end = n

  6. data_train = data[np.arange(train_start, train_end), :]

  7. data_test = data[np.arange(test_start, test_end), :]

скопировать код

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

нормализация данных

Большинству архитектур нейронных сетей требуются нормализованные данные, поскольку функции активации большинства нейронов, таких как tanh и сигмоид, определяются в интервале [-1, 1] или [0, 1]. В настоящее время наиболее часто используется функция активации ReLU блока линейной коррекции, но диапазон ее значений имеет нижнюю границу и не имеет верхней границы. Однако мы все равно должны масштабировать диапазон входных и целевых значений, что также полезно, когда мы используем алгоритмы градиентного спуска. Масштабирование значений можно легко реализовать с помощью MinMaxScaler от sklearn.

  1. # Scale data

  2. from sklearn.preprocessing import MinMaxScaler

  3. scaler = MinMaxScaler()

  4. scaler.fit(data_train)

  5. scaler.transform(data_train)

  6. scaler.transform(data_test)

  7. # Build X and y

  8. X_train = data_train[:, 1:]

  9. y_train = data_train[:, 0]

  10. X_test = data_test[:, 1:]

  11. y_test = data_test[:, 0]pycharm

скопировать код

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

Введение в TensorFlow

TensorFlow — отличный фреймворк, и в настоящее время он наиболее часто используется для глубокого обучения и нейронных сетей. Он основан на базовом бэкэнде C++, но обычно управляется через Python. TensorFlow использует мощные статические графы для представления алгоритмов и операций, которые нам необходимо разработать. Этот подход позволяет пользователям указывать операции как узлы в графе и передавать данные в виде тензоров для эффективного построения алгоритма. Поскольку нейронные сети на самом деле представляют собой вычислительные графы данных и математических операций, TensorFlow хорошо поддерживает нейронные сети и глубокое обучение.

В общем, TensorFlow — это программная библиотека с открытым исходным кодом для численных вычислений с использованием графов потоков данных. Среди них Tensor представляет, что передаваемые данные представляют собой тензор (многомерный массив), а Flow представляет операцию с использованием вычислительного графа. Графы потоков данных описывают математические операции как ориентированные графы «узлов» и «ребер». «Узел» обычно используется для обозначения прикладной математической операции, но он также может обозначать начальную точку ввода данных и конечную точку вывода или конечную точку чтения/записи постоянных переменных. Ребра представляют отношения ввода/вывода между узлами. Эти ребра данных могут передавать многомерные массивы данных, размеры которых можно динамически регулировать, то есть тензоры.

Простой вычислительный граф для выполнения сложения

На приведенной выше диаграмме задача сложения будет выполняться над двумя нульмерными тензорами (скалярами), которые хранятся в двух переменных a и b. Два значения, протекающие по графу, складываются, когда достигают квадратного узла, а результат сложения сохраняется в переменной c. На самом деле a, b и c можно рассматривать как заполнители, и любое значение, введенное в a и b, будет добавлено к c. Это основной принцип TensorFlow. Пользователи могут определить абстрактное представление модели с помощью заполнителей и переменных, а затем заполнить заполнители фактическими данными для создания фактической операции. Следующий код реализует простой вычислительный граф, показанный выше:

  1. # Import TensorFlow

  2. import tensorflow as tf

  3. # Define a and b as placeholders

  4. a = tf.placeholder(dtype=tf.int8)

  5. b = tf.placeholder(dtype=tf.int8)

  6. # Define the addition

  7. c = tf.add(a, b)

  8. # Initialize the graph

  9. graph = tf.Session()

  10. # Run the graph

  11. graph.run(c, feed_dict{a: 5, b: 4})

скопировать код

После импорта библиотеки TensorFlow, как указано выше, используйте tf.placeholder(), чтобы определить два заполнителя для предварительного сохранения тензоров a и b. После того, как операция определена, граф операции может быть выполнен для получения результата.

Заполнитель

Как упоминалось ранее, нейронные сети изначально создаются из заполнителей. Итак, теперь мы должны определить два заполнителя, чтобы соответствовать модели, X содержит входные данные нейронной сети (все цены акций S&P 500 в момент времени T = t), а Y содержит выходные данные нейронной сети (S&P 500 в момент времени T = t). +1 за показатель степени).

Следовательно, размерность заполнителя входных данных может быть определена как [None, n_stocks], а размерность выходного заполнителя — [None], которые представляют двумерный тензор и одномерный тензор соответственно. Понимание размерностей входных и выходных тензоров важно для построения всей нейронной сети.

  1. # Placeholder

  2. X = tf.placeholder(dtype=tf.float32, shape=[None, n_stocks])

  3. Y = tf.placeholder(dtype=tf.float32, shape=[None])

скопировать код

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

Переменная

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

Модель состоит из четырех скрытых слоев, первый слой содержит 1024 нейрона, а затем следующие три слоя последовательно уменьшаются кратно 2, т.е. 512, 256 и 128 нейронов. Последовательное сокращение нейронов в последующих слоях сжимает признаки, извлеченные в предыдущих слоях. Конечно, мы можем использовать другие архитектуры нейронных сетей и конфигурации нейронов для лучшей обработки данных, например, архитектуры сверточных нейронных сетей для данных изображений, рекуррентные нейронные сети для данных временных рядов, но эта статья является лишь кратким введением для начинающих. полностью подключенная сеть для обработки данных временных рядов, поэтому эти сложные архитектуры не будут обсуждаться в этой статье.

  1. # Model architecture parameters

  2. n_stocks = 500

  3. n_neurons_1 = 1024

  4. n_neurons_2 = 512

  5. n_neurons_3 = 256

  6. n_neurons_4 = 128

  7. n_target = 1

  8. # Layer 1: Variables for hidden weights and biases

  9. W_hidden_1 = tf.Variable(weight_initializer([n_stocks, n_neurons_1]))

  10. bias_hidden_1 = tf.Variable(bias_initializer([n_neurons_1]))

  11. # Layer 2: Variables for hidden weights and biases

  12. W_hidden_2 = tf.Variable(weight_initializer([n_neurons_1, n_neurons_2]))

  13. bias_hidden_2 = tf.Variable(bias_initializer([n_neurons_2]))

  14. # Layer 3: Variables for hidden weights and biases

  15. W_hidden_3 = tf.Variable(weight_initializer([n_neurons_2, n_neurons_3]))

  16. bias_hidden_3 = tf.Variable(bias_initializer([n_neurons_3]))

  17. # Layer 4: Variables for hidden weights and biases

  18. W_hidden_4 = tf.Variable(weight_initializer([n_neurons_3, n_neurons_4]))

  19. bias_hidden_4 = tf.Variable(bias_initializer([n_neurons_4]))

  20. # Output layer: Variables for output weights and biases

  21. W_out = tf.Variable(weight_initializer([n_neurons_4, n_target]))

  22. bias_out = tf.Variable(bias_initializer([n_target]))

скопировать код

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

Спроектировать архитектуру нейронной сети

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

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

  1. # Hidden layer

  2. hidden_1 = tf.nn.relu(tf.add(tf.matmul(X, W_hidden_1), bias_hidden_1))

  3. hidden_2 = tf.nn.relu(tf.add(tf.matmul(hidden_1, W_hidden_2), bias_hidden_2))

  4. hidden_3 = tf.nn.relu(tf.add(tf.matmul(hidden_2, W_hidden_3), bias_hidden_3))

  5. hidden_4 = tf.nn.relu(tf.add(tf.matmul(hidden_3, W_hidden_4), bias_hidden_4))

  6. # Output layer (must be transposed)

  7. out = tf.transpose(tf.add(tf.matmul(hidden_4, W_out), bias_out))

скопировать код

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

Базовая архитектура сети прямой связи

функция потерь

Функция потерь сети в основном используется для генерации значения отклонения между предсказанием сети и фактически наблюдаемой целью обучения. Для задач регрессии чаще всего используется функция среднеквадратичной ошибки (MSE). MSE вычисляет среднеквадратичную ошибку между прогнозируемым значением и целевым значением.

  1. # Cost function

  2. mse = tf.reduce_mean(tf.squared_difference(out, Y))

скопировать код

Однако свойства MSE выгодны для общих задач оптимизации.

оптимизатор

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

  1. # Optimizer

  2. opt = tf.train.AdamOptimizer().minimize(mse)

скопировать код

Выше приведен пример использования оптимизатора Adam, который в настоящее время является оптимизатором по умолчанию в глубоком обучении. Adam означает Adaptive Moment Estimation, и его можно рассматривать как комбинацию двух оптимизаторов, AdaGrad и RMSProp.

инициализатор

Инициализаторы используются для инициализации переменных сети перед обучением. Поскольку нейронные сети обучаются с использованием численных методов оптимизации, отправной точкой для задачи оптимизации является поиск хорошего решения. В TensorFlow есть разные инициализаторы, каждый из которых имеет свой метод инициализации. В этой статье я использую tf.variance_scaling_initializer(), которая является стратегией инициализации по умолчанию.

  1. # Initializers

  2. sigma =

  3. weight_initializer = tf.variance_scaling_initializer(mode="fan_avg", distribution="uniform", scale=sigma)

  4. bias_initializer = tf.zeros_initializer()

скопировать код

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

Подходящая нейронная сеть

После определения заполнителей, переменных, инициализаторов, стоимостных функций и оптимизаторов для сети можно обучить модель, обычно используя метод мини-пакетного обучения. Во время мини-обучения несколько выборок данных n=batch_size случайным образом выбираются из обучающих данных и передаются в сеть. Набор обучающих данных будет загружаться в сеть последовательно пакетами n/batch_size. На этом этапе в игру вступают заполнители X и Y, они содержат входные данные и целевые данные и представлены в сети как входные и целевые данные соответственно.

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

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

  1. # Run initializer

  2. net.run(tf.global_variables_initializer())

  3. # Setup interactive plot

  4. plt.ion()

  5. fig = plt.figure()

  6. ax1 = fig.add_subplot(111)

  7. line1, = ax1.plot(y_test)

  8. line2, = ax1.plot(y_test*0.5)

  9. plt.show()

  10. # Number of epochs and batch size

  11. epochs = 10

  12. batch_size = 256for e in range(epochs):

  13. # Shuffle training data

  14. shuffle_indices = np.random.permutation(np.arange(len(y_train)))

  15. X_train = X_train[shuffle_indices]

  16. y_train = y_train[shuffle_indices]

  17. # Minibatch training

  18. for i in range(0, len(y_train) // batch_size):

  19. start = i * batch_size

  20. batch_x = X_train[start:start + batch_size]

  21. batch_y = y_train[start:start + batch_size]

  22. # Run optimizer with batch

  23. net.run(opt, feed_dict={X: batch_x, Y: batch_y})

  24. # Show progress

  25. if np.mod(i, 5) == 0:

  26. # Prediction

  27. pred = net.run(out, feed_dict={X: X_test})

  28. line2.set_ydata(pred)

  29. plt.title('Epoch ' + str(e) + ', Batch ' + str(i))

  30. file_name = 'img/epoch_' + str(e) + '_batch_' + str(i) + '.jpg'

  31. plt.savefig(file_name)

  32. plt.pause(0.01)

скопировать код

Во время обучения мы оценивали прогностическую способность сети на тестовом наборе (данные, не изученные сетью), выполняли каждые 5 обучающих пакетов и представляли результаты. Кроме того, эти изображения будут экспортированы на диск и объединены в видео-анимацию тренировочного процесса. Модель быстро запоминает расположение и форму временных рядов в тестовых данных и выдает точные прогнозы после обучения для нескольких эпох. чудесный!

Как видите, сеть быстро адаптируется к базовой форме временного ряда и продолжает изучать более тонкие закономерности в данных. Это происходит благодаря схеме обучения Адама, которая снижает скорость обучения во время обучения модели, чтобы избежать пропуска минимумов. После 10 эпох мы идеально подходим к тестовым данным! СКО последнего теста равняется 0,00078, что очень мало, поскольку цель масштабируется. Средний процент ошибок прогнозов на тестовом наборе равен 5,31%, что является хорошим результатом.

График разброса прогнозируемых и фактических цен S&P (в масштабе)

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

Заключение и перспективы

Выпуск TensorFlow является важной вехой в исследованиях глубокого обучения, поскольку его высокая степень гибкости и высокая производительность позволяют исследователям разрабатывать все виды сложных архитектур нейронных сетей и других алгоритмов машинного обучения. Однако гибкость достигается за счет увеличения времени моделирования по сравнению с использованием высокоуровневых API, таких как Keras или MxNet. Тем не менее, я считаю, что TensorFlow продолжит развиваться и станет стандартом де-факто для исследований и практических приложений нейронных сетей и разработки глубокого обучения. Многие из наших клиентов уже используют TensorFlow или разрабатывают проекты, в которых применяются модели TensorFlow. Наши консультанты по науке о данных STATWORX (https://www.statworx.com/de/data-science/) в основном используют Исследовательский класс TensorFlow разрабатывает глубокое обучение и нейронные сети.

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

Исходная ссылка: https://medium.com/mlreview/a-simple-deep-learning-model-for-stock-price-prediction-using-tensorflow-30505541d877

Нажмите [прочитать исходный текст], чтобы зарегистрироваться для участия в конкурсе. Для регистрации в зоне соревнований в США, пожалуйста, нажмите US на главной странице конкурса, чтобы войти в канал регистрации в зоне соревнований в США.