Управление лабораторией контроля температуры с помощью LSTM

Добро пожаловать в часть 3 этого проекта! К настоящему времени ваш работодатель смотрит на ваши результаты и говорит: «Ну и что?» Вы проделали большую работу, чтобы все заработало, но пока что на компьютере все выглядит хорошо. Ну, вот часть «ну и что». Вот где мы, наконец, можем реализовать эту нейронную сеть LSTM для эмуляции поведения ПИД-регулятора. В качестве краткого обзора, вот где мы были и куда мы идем:

  1. Использование лаборатории контроля температуры для создания данных пропорционально-интегрально-дифференциального регулятора
  2. Обучение нейронной сети с долгой кратковременной памятью в Keras для эмуляции ПИД-регулятора
  3. Управление лабораторией контроля температуры с помощью LSTM (эта статья)
  4. Практические приложения управления температурой с использованием LSTM-регулятора вместо ПИД-регулятора

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

Последняя проверка

Хотя в прошлый раз мы проверили вывод контроллера LSTM, мы все же хотим сначала попрактиковаться в безопасности. Мы не хотим отлаживать наш контур управления, работая с чем-то столь чувствительным, как температура реактора. Итак, для начала мы сохраним наш ПИД-регулятор, но также вычислим выходной сигнал контроллера LSTM. Это позволяет нам увидеть, что делает запрограммированный нами LSTM-контроллер по сравнению с PID-контроллером, а также отладить его.

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

#### Set up run ####
# Import model and model parameters
model = load_model('pid_emulate.h5')
model_params = pickle.load(open('model_params.pkl', 'rb'))
s_x = model_params['Xscale']
s_y = model_params['yscale']
window = model_params['window']
# Run time in minutes
run_time = 30.0
# Number of cycles
loops = int(60.0*run_time)
# arrays for storing data
T1 = np.zeros(loops) # measured T (degC)
Qpid = np.zeros(loops) # Heater values for PID controller
Qlstm = np.zeros(loops) # Heater values for LSTM controller
tm = np.zeros(loops) # Time
# Temperature set point (degC)
with tclab.TCLab() as lab:
    Tsp = np.ones(loops) * lab.T1
# vary temperature setpoint
# leave 1st window + 15 seconds of temp set point as room temp
end = window + 15 
while end <= loops: 
    start = end
    # keep new temp set point value for anywhere from 4 to 10 min
    end += random.randint(240,600) 
    Tsp[start:end] = random.randint(30,70)
# leave last 120 seconds as room temp
Tsp[-120:] = Tsp[0]

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

Контур управления, который мы запрограммируем, будет таким же, как и для ПИД-регулятора (см. Часть 1 для освежения знаний, если необходимо), только теперь мы также хотим увидеть, что будет выводить контроллер LSTM. Я уже поместил это в функцию lstm(T1_m,Tsp_m), но я предлагаю сначала поместить это прямо в код для отладки. T1_m — это температура датчика 1 для модели LSTM, которую мы будем считывать в каждый момент времени, а Tsp_m — заданная температура для модели LSTM. Давайте посмотрим, что мы с ним делаем.

Во-первых, рассчитайте ошибку, убедившись, что она такая же, как мы рассчитали ее при обучении LSTM в Часть 2.

# Calculate error (necessary feature for LSTM input)
err = Tsp_m - T1_m

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

# Format data for LSTM input
X = np.vstack((Tsp_m,err)).T
Xs = s_x.transform(X)
Xs = np.reshape(Xs, (1, Xs.shape[0], Xs.shape[1]))

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

# Predict Q for controller and unscale
Q1c_s = model.predict(Xs)
Q1c = s_y.inverse_transform(Q1c_s)[0][0]

И, наконец, как мы заметили в части 2 во время обучения, иногда LSTM будет предсказывать значение за пределами допустимого диапазона [0,100], поэтому мы просто ограничим возможные выходные значения.

# Ensure Q1c is between 0 and 100
Q1c = np.clip(Q1c,0.0,100.0)

Я надеюсь, вы понимаете, почему я решил проверить это и отладить, прежде чем внедрять!

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

# Run LSTM model to get Q1 value for control
if i >= window:
   # Load data for model
   T1_m = T1[i-window:i]
   Tsp_m = Tsp[i-window:i]
   # Predict and store LSTM value for comparison
   Qlstm[i] = lstm(T1_m,Tsp_m)

Я также сохранил несколько снимков поведения контроллера по ходу дела и вставил их в видео. Посмотрим, как это сработало.

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

Управление с помощью LSTM

И вот, чего мы ждали! Переключим контроллер на LSTM. На самом деле здесь нет ничего нового, но для завершения, вот как выглядит мой код для использования LSTM для управления выходом нагревателя, эмулируя поведение ПИД-регулятора.

# Run test
with tclab.TCLab() as lab:
    # Find current T1, T2
    print('Temperature 1: {0:0.2f} °C'.format(lab.T1))
    print('Temperature 2: {0:0.2f} °C'.format(lab.T2))
    start_time = time.time()
    for i in tqdm(range(loops)):
        # Delay 1 second
        if time.time() > prev_time + 1.0:
            print('Exceeded cycle time: ',time.time()-prev_time-1.0)
        else:
            while time.time() < prev_time + 1.0:
                pass
        # Record time
        t = time.time()
        tm[i] = t - start_time
        # Read temperature (C)
        T1[i] = lab.T1
        # Run LSTM model to get Q1 value for control
        if i >= window:
            # Load data for model
            T1_m = T1[i-window:i]
            Tsp_m = Tsp[i-window:i]
            # Predict and store LSTM value for comparison
            Qlstm[i] = lstm(T1_m,Tsp_m)
        # Write heater output (0-100)
        lab.Q1(Qlstm[i])

Итак, как мы поступили?

Ух ты. Не знаю, как у вас, а здесь это захватывающие вещи. Мы успешно воспроизвели поведение ПИД-регулятора с помощью нейронной сети LSTM и смогли использовать его на совершенно новых данных в режиме реального времени для управления температурой. Вот почему машинное обучение так интересно!

Последние мысли

Конечно, вы, вероятно, заметили несколько областей для улучшения. Контроллеру было тяжело в середине цикла, когда температура достигала 70°C. Мы всегда можем настроить гиперпараметры в модели LSTM, и никогда не помешает иметь больше данных для обучения (какие другие идеи могут улучшить точность контроллера LSTM для контроллера PID?). Но даже несмотря на то, что LSTM-контроллер не полностью соответствовал ПИД-регулятору, он все же достиг цели по эмуляции поведения, и это само по себе захватывающе!

В этот момент ваш босс все еще задается вопросом: Ну и что? Какой в ​​этом смысл, если ПИД-регулятор уже делает именно то, что мы хотим? Это то, что у нас впереди, так что оставайтесь с нами для более захватывающих исследований! Как всегда, не стесняйтесь следовать коду здесь, надеюсь, на своем собственном TCLab, который вы можете запустить на своем рабочем столе!