Обработка временных рядов в машинном обучении: Практическое руководство

Обработка временных рядов в машинном обучении: Практическое руководство

Картинка к публикации: Обработка временных рядов в машинном обучении: Практическое руководство

Введение

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

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

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

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

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

Получение и подготовка данных

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

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

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

Практический подход к подготовке данных включает в себя следующие шаги:

  • Извлечение данных: Сначала данные загружаются из внешнего источника. В нашем случае, это достигается путем отправки запросов к API и загрузки ZIP-архива с данными.
  • Преобразование данных: Данные распаковываются и преобразуются в формат, с которым удобно работать. В примере используется DataFrame библиотеки pandas, который является стандартом де-факто для анализа данных на Python.
  • Очистка данных: Следующим шагом является очистка данных. Это включает в себя удаление лишних столбцов, обработку пропущенных значений и, при необходимости, изменение типов данных.

Функция получения данных от API Тинькофф Инвестиции:

import os
import zipfile
from io import BytesIO, StringIO

import pandas as pd
import requests
from dotenv import load_dotenv

load_dotenv()

TOKEN = os.getenv('INVEST_TOKEN')


def get_stock_data(figi: str, years: list) -> pd:
    base_url = "https://invest-public-api.tinkoff.ru/history-data"
    headers = {"Authorization": f"Bearer {TOKEN}"}
    result_df = pd.DataFrame()

    for year in years:        
        params = {
            "figi": figi,
            "year": year
        }
        response = requests.get(base_url, params=params, headers=headers)
        if response.status_code == 200:        
            with zipfile.ZipFile(BytesIO(response.content), 'r') as zip_file:
                for file_info in zip_file.filelist:
                    with zip_file.open(file_info.filename) as file:
                        decoded_content = file.read().decode('utf-8')
                        df = pd.read_csv(StringIO(decoded_content), sep=';', header=None)
                        result_df = pd.concat([result_df, df], ignore_index=True)
        else:
            print(f"Ошибка: {response.status_code}")
            
    return result_df
    

result_df = get_stock_data(figi, [2018, 2019, 2020, 2021, 2022, 2023, 2024])

Предварительно необходимо получить figi акции. Это можно сделать воспользовавшись скриптом от Тинькофф Инветиции (ТИ). 

INVEST_TOKEN - это токен который нужно получить в личном кабинете ТИ. На данный момент, это пожалуй лучший способ в России для получения котировок по фондовому рынку.

Напишем функцию для визуализации котировок:

def closing_trend_chart(df: pd.DataFrame, step: int = None) -> None:
    """Создает график цены на закрытие с пересемплированием данных.

    ## Args:
    - df (`pd.DataFrame`): Датафрейм с данными.
    - step (`int`, optional): Опциональный параметр, шаг для пересэмплирования данных в минутах (по умолчанию None).

    ## Returns:
    - None
    """
    data_resampled = df['Close'].resample(f'{step}T').last() if step else df['Close']
    plt.figure(figsize=(20, 8))
    ax0 = plt.subplot2grid((4, 4), (0, 0), rowspan=3, colspan=4)
    data_resampled.plot(ax=ax0)
    plt.title(f'График цены на {TICKER} (1h)')
    plt.show()

Извлечём данные из полученного дата фрэйма:

# получение данных их выгрузки
data = result_df.drop(result_df.columns[[0, 7]], axis='columns')
data.columns = ['Data', 'Open', 'Close', 'High', 'Low', 'Volume']
data['Data'] = pd.to_datetime(data['Data'])
data.set_index('Data', inplace=True)
data.index.name = None

И отобразим их на графике с интервалов в 60 минут:

closing_trend_chart(data, 60)
print('размер минутных DF', data.shape)
data.head()
размер минутных DF (1093147, 5)
							Open	Close	High	Low		Volume
2018-03-07 18:33:00+00:00	273.16	273.16	273.16	273.16	50
2018-03-07 18:34:00+00:00	273.10	273.30	273.30	273.09	2070
2018-03-07 18:35:00+00:00	273.18	273.02	273.26	273.02	3380
2018-03-07 18:36:00+00:00	273.00	273.10	273.11	272.80	5049
2018-03-07 18:37:00+00:00	272.83	272.98	273.14	272.83	887

Как видно есть множество неторговых дней, которые будут создавать лишний шум и мешать обучению модели. Уберём их из DF и оставим только часовые данные. Так же уберём цены открытия, макс, мин в каждом периоде (H1). Они нам не понадобятся для обучения в конкретном случае.

hourly_data = data.resample('H').first()
hourly_data.dropna(inplace=True)

del hourly_data['Open']
del hourly_data['High']
del hourly_data['Low']

closing_trend_chart(hourly_data)
print('размер', hourly_data.shape)
hourly_data.head()
размер (18967, 2)
							Close	Volume
2018-03-07 18:00:00+00:00	273.16	50.0
2018-03-07 19:00:00+00:00	272.28	1046.0
2018-03-07 20:00:00+00:00	270.82	15508.0
2018-03-07 21:00:00+00:00	271.66	961.0
2018-03-07 22:00:00+00:00	271.60	1483.0

Анализ временных рядов

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

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

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

  • Определение трендов: Мы можем использовать различные статистические методы и модели для определения и измерения трендов в данных. Один из подходов — это вычисление процентного изменения цены закрытия на протяжении заданного временного интервала, что помогает выявить растущие, падающие или стабильные тренды в временном ряду.
  • Идентификация сезонности: Сезонные колебания можно определить с помощью анализа периодических паттернов в данных. Это может быть сделано путем изучения повторяющихся шаблонов в течение определенных временных промежутков, таких как дни, недели, месяцы или кварталы.

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

def trend_depth_selection(float_data: pd.DataFrame, depth_value: float, step_in_the_last: int) -> pd.DataFrame:
    """Добавляет разметку тренда к датасету с котировками на основе заданных параметров.
    
    0 - флет; 1 - растущий бар; 2 - падающий бар    

    ## Args:
    - float_data (`pd.DataFrame`): Датасет с котировками, содержащий столбец 'Close' с ценой закрытия.
    - depth_value (`float`): Уровень определения тренда. Если расчетное изменение меньше этого значения, то считается флет.
    - step_in_the_last (`int`): По скольки шагам в прошлое определяем тренд.

    ## Returns:
    - pd.DataFrame: Датасет с добавленными столбцами 'Y_1', 'Y_2', и так далее, представляющими разметку тренда.
    
    """
    for i in range(1, step_in_the_last + 1):
      indicator_name = 'Y_%d' % (i)
      float_data[indicator_name] = float_data['Close'].pct_change(i)

    float_data = float_data.dropna()

    for i in range(1, step_in_the_last + 1):
      indicator_name = 'Y_%d' % (i)
      float_data[indicator_name] = float_data[indicator_name].apply(
          lambda x: 2 if x < -depth_value else (1 if x > depth_value else 0))
    return float_data

Выбор параметров step_in_the_last и n_steps в функции trend_depth_selection  является одним из ключевых моментов, поскольку они напрямую влияют на то, как модель будет воспринимать и интерпретировать данные. Выбор этих параметров имеет следующие пояснение:

  1. step_in_the_last = 42: Этот параметр определяет, на сколько шагов в прошлое мы будем смотреть, чтобы определить тренд. Выбор 42 основан на специфическом цикле и на результате предыдущих исследований и анализов, которые показали, что рассмотрение именно такого количества прошлых точек данных является оптимальным для прогнозирования будущих трендов.
  2. n_steps = 9: Этот параметр указывает на то, какой объем данных (серия из скольких баров) будет использоваться для анализа в каждой точке времени. Выбор числа 9 связан с тем, что именно такое количество последовательных точек данных наилучшим образом отражает краткосрочные колебания в данных или характеризует определенные торговые паттерны.

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

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

Итак:

step_in_the_last = 42
n_steps = 9

vector_data = trend_depth_selection(hourly_data, 0.0003, step_in_the_last)

print(vector_data.shape)
vector_data[:5]
(18925, 44)							
							Close	Volume	Y_1	Y_2	Y_3	...	Y_40	Y_41	Y_42
2018-03-14 07:00:00+00:00	273.69	3046.0	2	2	2	...	1		1		1
2018-03-14 08:00:00+00:00	273.83	12.0	1	2	2	...	1		1		1
2018-03-14 09:00:00+00:00	273.59	840.0	2	2	2	...	1		1		1
2018-03-14 13:00:00+00:00	273.00	3890.0	2	2	2	...	1		1		1
2018-03-14 14:00:00+00:00	272.49	22998.0	2	2	2	...	2		1		1

Построение модели

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

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

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

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

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

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

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

indicator_name = 'Y_%d' % (step_in_the_last)
data_Y = vector_data[indicator_name]
print("Классы для one-hot encoding", np.unique(vector_data[indicator_name]))
data_Y[:5]

categorical_labels = to_categorical(data_Y, num_classes=3)
print("Всего записей:", len(categorical_labels))
categorical_labels[:5]
Классы для one-hot encoding [0 1 2]
Всего записей: 18925
array([[0., 1., 0.],
       [0., 1., 0.],
       [0., 1., 0.],
       [0., 1., 0.],
       [0., 1., 0.]], dtype=float32)
# Делим на обучающую и проверочную выборки
vector_data = vector_data.values
print(vector_data.shape, type(vector_data))

# Берем для xTest последние 600 значений
n_train = 600
xTrain = vector_data[:-n_train-n_steps]
xTest = vector_data[-n_train:]
yTrain = categorical_labels[:-n_train-n_steps]
yTest = categorical_labels[-n_train:]

print('xTrain: ', xTrain.shape, '\tyTrain:', yTrain.shape, '\nxTest:  ', xTest.shape, '\tyTest: ', yTest.shape)
xTrain.shape[0]+xTest.shape[0]
(18925, 44) <class 'numpy.ndarray'>
xTrain:  (18316, 44) 	yTrain: (18316, 3) 
xTest:   (600, 44) 	yTest:  (600, 3)
18916
from sklearn.preprocessing import MinMaxScaler

xScaler = MinMaxScaler()
xScaler.fit(xTrain)
xTrain = xScaler.transform(xTrain)
xTest = xScaler.transform(xTest)

print(xTrain.shape, xTest.shape, type(xTrain))
xTest[-1:]
(18316, 44) (600, 44) <class 'numpy.ndarray'>
array([[6.30668458e-01, 2.10429444e-06, 0.00000000e+00, 0.00000000e+00,
        5.00000000e-01, 0.00000000e+00, 5.00000000e-01, 5.00000000e-01,
		...
        5.00000000e-01, 5.00000000e-01, 5.00000000e-01, 5.00000000e-01,
        5.00000000e-01, 5.00000000e-01, 5.00000000e-01, 5.00000000e-01]])
# Создаем генератор для обучения
trainDataGen = TimeseriesGenerator(xTrain, yTrain, length=n_steps, stride=1, sampling_rate=1, batch_size=84)

# Создаем аналогичный генератор для валидации при обучении
testDataGen = TimeseriesGenerator(xTest, yTest, length=n_steps, stride=1, batch_size=84)

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

Обучение модели нейронной сети

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

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

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

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

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

Напишем функцию визуализации процесса обучения:

import matplotlib.pyplot as plt
from typing import Dict, Any, Optional, List, Union, Tuple


def print_graf_result(
    history: Dict[str, Any],
    metrics: str,
    title: str = '',
    colors: Optional[Union[List[str], Tuple[str, str]]] = ('b', 'g')
) -> None:
    """Выводит графики результатов обучения модели.

    ### Args:
    - history (`Dict[str, Any]`): История обучения.
    - metrics (`str`): метрика
    - title (`str`, optional): Заголовок графиков. По умолчанию пустая строка.
    - colors (`Union[List[str], Tuple[str, str]]`, optional): Цвета для графиков обучения и проверки.
        Может быть списком из двух строк для цветов графиков обучения и проверки соответственно
        или кортежем. По умолчанию ('b', 'g').

    ### Example:
        >>> print_graf_result(history, metrics='mae', title='Результаты обучения', colors=('r', 'y'))
    """
    history = history.history
    fig, axes = plt.subplots(1, 2, figsize=(16, 4), dpi=60)

    plot_label = {
        'accuracy': 'Доля верных ответов на обучающем наборе',
        'mae': 'Средняя абсолютная ошибка на обучающем наборе',
    }
    plot_val_label = {
        'accuracy': 'Доля верных ответов на проверочном наборе',
        'mae': 'Средняя абсолютная ошибка на проверочном наборе',
    }

    plot_set_ylabel = {
        'accuracy': 'Доля верных ответов',
        'mae': 'Средняя абсолютная ошибка',
    }

    fig.suptitle(title)

    # График доли верных ответов
    axes[0].plot(history[metrics], label=plot_label[metrics], color=colors[0])
    axes[0].plot(history[f'val_{metrics}'], label=plot_val_label[metrics], color=colors[1])
    axes[0].set_xlabel('Эпоха обучения')
    axes[0].set_ylabel(plot_set_ylabel[metrics])
    axes[0].legend()

    # График ошибки
    axes[1].plot(history['loss'], label='Ошибка на обучающем наборе', color=colors[0])
    axes[1].plot(history['val_loss'], label='Ошибка на проверочном наборе', color=colors[1])
    axes[1].set_xlabel('Эпоха обучения')
    axes[1].set_ylabel('Ошибка')
    axes[1].legend()

    plt.tight_layout()
    plt.show()

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

Аргументы функции:

  • history: Словарь, содержащий историю обучения. Это обычно объект History, который возвращается методом fit() модели в Keras. Он содержит записи о метриках обучения после каждой эпохи.
  • metrics: Строка, определяющая метрику для отображения, например 'accuracy' или 'mae' (средняя абсолютная ошибка).
  • title: Необязательный строковый параметр, который задает заголовок графиков.
  • colors: Необязательный параметр, задающий цвета линий на графиках для обучающего и валидационного наборов.

Подготовка данных:

  • Словарь history извлекается из объекта History, если он еще не был преобразован в словарь.
  • Создаются два графика с помощью subplots библиотеки matplotlib.

Лейблы и названия:

  • В словарях plot_label и plot_val_label определяются названия для легенд графиков в зависимости от выбранной метрики.
  • plot_set_ylabel содержит названия для осей Y графиков.

Отрисовка графиков:

  • На первом графике (axes[0]) отображаются данные об обучающей метрике и валидационной метрике (например, точность модели). Для этого используются данные из history.
  • На втором графике (axes[1]) отображаются данные о потерях (loss) на обучающем и валидационном наборах данных.
  • Для каждого графика устанавливаются подписи осей, заголовки и легенда.

Отображение графиков:

  • plt.tight_layout() применяется для корректировки размеров и расположения элементов графика, чтобы все элементы были четко видны и не перекрывали друг друга.
  • plt.show() вызывается для отображения графиков на экране пользователя.

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

Оптимизация и настройка модели

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

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

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

Ранняя остановка — еще одна техника для предотвращения переобучения модели. Этот метод заключается в остановке обучения, когда метрика на валидационном наборе данных перестает улучшаться.

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

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

Итак что в итоге?

class CustomLearningRateScheduler(Callback):
    def __init__(self, factor=0.2, patience=3, min_lr=1e-9, verbose=1):
        """Класс предназначенным для адаптивного управления скоростью обучения в процессе тренировки нейронной сети.

        ## Args:
        - factor (`float`, optional): Коэффициент уменьшения скорости обучения. Когда срабатывает колбэк, текущая скорость обучения умножается на этот коэффициент.
        - patience (`int`, optional): Количество эпох, в течение которых должно произойти ухудшение значения val_loss, прежде чем скорость обучения будет снижена.
        - min_lr (`float`, optional): Минимально допустимая скорость обучения. Скорость обучения не будет снижена ниже этого значения.
        - verbose (`int`, optional): Флаг для управления печатью сообщений о снижении скорости обучения.
        - wait: Счетчик эпох, используемый для отслеживания количества эпох с момента последнего улучшения val_loss.
        - best: Лучшее значение val_loss, достигнутое на данный момент.
        """
        super(CustomLearningRateScheduler, self).__init__()
        self.factor = factor
        self.patience = patience
        self.min_lr = min_lr
        self.verbose = verbose
        self.wait = 0
        self.best = float('inf')

    def on_epoch_end(self, epoch, logs=None):
        current_val_loss = logs.get('val_loss')
        current_lr = self.model.optimizer.lr.read_value()
        if current_val_loss < self.best:
            self.best = current_val_loss
            self.wait = 0
        else:
            self.wait += 1
            if self.wait >= self.patience:
                decay = 0.1
                dynamic_factor = 1 / (1 + decay * epoch)
                new_lr = max(current_lr * dynamic_factor, self.min_lr)
                self.model.optimizer.lr.assign(new_lr)
                if self.verbose > 0:
                    print(
                        f"\nEpoch {epoch+1}: ReduceLROnPlateau reducing learning rate to {new_lr}.")
                self.wait = 0

Наша модель:

drop = 0.5
input = Input(shape=(n_steps, step_in_the_last + 2))
x = Flatten()(input)
x = RepeatVector(3)(x)
x = Conv1D(n_steps*3, 9, padding='same')(x)
x = BatchNormalization()(x)
x = Activation('relu')(x)
x = MaxPooling1D(pool_size=2)(x)
x = Dropout(drop)(x)
x = Flatten()(x)
x = RepeatVector(3)(x)
x = Conv1D(n_steps, 3, padding='same')(x)
x = BatchNormalization()(x)
x = Activation('relu')(x)
x = MaxPooling1D(pool_size=2)(x)
x = Dropout(drop)(x)
x = Flatten()(x)
x = Dense(n_steps*200, activation='relu', kernel_regularizer=l2(0.0005))(x)
x = Dropout(drop)(x)
x = Dense(n_steps*200, activation='relu', kernel_regularizer=l2(0.0005))(x)
x = Dropout(drop)(x)
x = Dense(3, activation='softmax', kernel_regularizer=l1_l2(l1=0.0005, l2=0.0005))(x)
model = Model(input, x)

Компиляция и визуализации процесса обучения:

model.compile(optimizer=Adam(learning_rate=5e-05), loss='categorical_crossentropy', metrics=['accuracy'])

early_stopping = EarlyStopping(monitor='val_loss', patience=7, restore_best_weights=True)

history = model.fit(trainDataGen, epochs=80, verbose=1, validation_data=testDataGen, callbacks=[early_stopping, CustomLearningRateScheduler()])

print_graf_result(history, 'accuracy', 'ОБУЧЕНИЕ')
...
Epoch 69/80
213/218 [============================>.] - ETA: 0s - loss: 0.2737 - accuracy: 0.9254
Epoch 69: ReduceLROnPlateau reducing learning rate to 1.2569131513373577e-07.
218/218 [==============================] - 1s 5ms/step - loss: 0.2740 - accuracy: 0.9249 - val_loss: 0.3287 - val_accuracy: 0.9222

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

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

Но ведь это просто пример... )

Выводы и рекомендации

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

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

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

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

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


Читайте также:

ChatGPT
Eva
💫 Eva assistant