强化学习控制加热炉的方法

强化学习控制加热炉

题目

本文解决的问题是一个加热炉炉温控制的问题,一般的加热炉无论是工业或是家用,都需要解决一个恒温的问题,设定温度后,系统希望能够一直保持在该温度加热。但是现实往往很不如意,总是有着很多干扰因素对炉温产生影响,而且如何控制加热装置,让它保持恒温也是一个很头疼的问题。

算法应用简介

那么本文使用强化学习的方法来控制这个炉温。
其实对于一个这样的简单系统(理想化情况下),我们只需要使用最简单的q-learning就可以解决该问题。
可能会有这样的疑问,我们在不知道该加热炉具体模型的时候,该如何去控制它,而强化学习的魅力就是在没有模型参数和没有具体输入输出数据时完成,自我生成数据,自我学习的一个方法。
虽然题目之中是有数据的,但是我们其实也不需要。那么废话不多说,开始介绍:

Q-learning

在这里插入图片描述
其实之所以叫做q-learning,就是它所学习的就是更新它的q值,那么什么是q值呢,之后,我会将强化学习的各类算法做个单独的文章栏目详细介绍。这里只需要知道q值为状态动作值函数的值。也就是评估在该状态下,该动作的好坏的一个值。我们通过当前状态选择一个动作,达到下一个状态,而后得到一个奖励reward,再利用这个奖励来更新我们的Q函数值,若是好的,则奖励多,若是不好的,则无奖励,以此迭代,来更新q_table,最后得到一个在任意状态下的一个完整的q_table,用以判断任一状态下的动作,来达到控制的效果。

程序

import numpy as np
import pandas as pd
import time

import os

os.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID"  # 可不写
os.environ["CUDA_VISIBLE_DEVICES"] = "1"  # 0就是指定GPU 0 跑实验,可按需修改成其他GPU

np.random.seed(2)  # reproducible


N_STATES = 7   #世界的长度
ACTIONS = ['down', 'up']     # 动作表
EPSILON = 0.1  # 探索值
ALPHA = 1     # 学习率
GAMMA = 0.9    # 折扣因子
MAX_EPISODES = 100   # 最大迭代数(一episode为达到一次目标)
FRESH_TIME = 0   # 刷新时间


def build_q_table(n_states, actions):
    table = pd.DataFrame(
        np.zeros((n_states, len(actions))),     # q表赋初值0
        columns=actions,    # actions's name
    )
    # print(table)    # 显示q表
    return table


def choose_action(state, q_table):
    # 动作选择
    state_actions = q_table.iloc[state, :]
    if (np.random.uniform() > EPSILON) or ((state_actions == 0).all()):  # 探索时
        action_name = np.random.choice(ACTIONS)
    else:   # 贪婪时,即正常选择时
        action_name = state_actions.idxmax()    # 选择最大的动作值的动作
    return action_name


def get_env_feedback(S, A):
    # 更新环境,即执行动作后进入下一状态的规则
    if A == 'up':    # 炉温上升
        if S == N_STATES - 5:   # 达到期望值
            S_ = 'terminal'
            R = 1
        elif S == 6:
            S_ = S  # 到最高点不能再往上了
            R = 0
        else:
            S_ = S + 1
            R = 0
    else:   # 降温
        if S == N_STATES-3:  #达到期望值
            S_ = 'terminal'
            R = 1
        elif S == 0:
            S_ = S  # 到最低点不能再往下了
            R = 0
        else:
            S_= S - 1
            R = 0
    return S_, R


def update_env(S, episode, step_counter):
    # 可视化训练和动作与状态交互
    env_list = ['-']*int(((N_STATES-1)/2)) + ['T'] +['-']*int(((N_STATES-1)/2))   # 环境建立,本文建立的是---T---环境
    if S == 'terminal':    #达到期望值,输出第几次episode和多少步达到期望值
        interaction = 'Episode %s: total_steps = %s' % (episode+1, step_counter)
        print('\r{}'.format(interaction), end='')
        time.sleep(2)
        print('\r                                ', end='')
    else:
        env_list[S] = 'o'   #移动人物,本文为,可视化移动温度
        interaction = ''.join(env_list)
        print('\r{}'.format(interaction), end='')
        time.sleep(FRESH_TIME)


def rl(chuzhi):
    # RL的训练循环部分
    q_table = build_q_table(N_STATES, ACTIONS)  #获取初始q表
    for episode in range(MAX_EPISODES):    #episode循环
        step_counter = 0   #步数初值设为0
        S = np.random.choice(chuzhi)      #随机选择初始温度
        is_terminated = False   #达到期望值的标志
        update_env(S, episode, step_counter)   #可视化动作环境交互一次
        while not is_terminated:   #当没达到期望值时

            A = choose_action(S, q_table)    #选择动作输入到A中
            S_, R = get_env_feedback(S, A)  # 在S状态下执行A动作,得到下一状态S_和奖励值R
            #print(R)
            q_predict = q_table.loc[S, A]    #在状态S下的A动作输入到q_predict中
            if S_ != 'terminal':   #当下一状态没达到期望值时
                q_target = R + GAMMA * q_table.iloc[S_, :].max()   # 将下一状态的动作q值更新
            else:    #下一状态达到期望值时
                q_target = R     # 将奖励值输入q_target中
                is_terminated = True    #达到期望值标志为真

            q_table.loc[S, A] += ALPHA * (q_target - q_predict)  # 当前状态的该动作值更新
            S = S_  # 进入下一状态

            update_env(S, episode, step_counter+1)  #输出动作环境交互
            step_counter += 1  #加一步数
    return q_table  #训练结束得到q表


if __name__ == "__main__":
    q_table = rl([0,1,2,4,5,6])  #输入S的状态选择表
    print('\r\nQ-table:\n')
    print(q_table)

该程序采用- - - T - - -的环境用o表示目前温度在什么位置,T为期望控制的温度值。随机的给定现在的温度,在T的左边或右边。由于作者电脑的算力不足,所以只能建立一个这样的环境来训练,若是需要实际的系统,可以在T的左边加249个 -,T的右边放250个 -,来模拟这个系统。
训练结束后得到q表如下:
在这里插入图片描述

可以看到当s小于3的状态时,a的动作为up,s状态大于3时,a的动作为down。
用程序测试一下:

import numpy as np
import pandas as pd
import time
N_STATES=7
FRESH_TIME=0.3
def choose_action(state, q_table):
    # This is how to choose an action
    state_actions = q_table.iloc[state, :]
    action_name = state_actions.idxmax()    
    return action_name

def get_env_feedback(S, A):
    if A == 'up':    # move up
        if S == N_STATES - 5:   
            S_ = 'terminal'
            R = 1
        elif S == 6:
            S_ = S 
            R = 0
        else:
            S_ = S + 1
            R = 0
    else:   
        if S == N_STATES-3:
            S_ = 'terminal'
            R = 1
        elif S == 0:
            S_ = S  
            R = 0
        else:
            S_= S - 1
            R = 0
    return S_

def update_env(S):
    env_list = ['-']*int(((N_STATES-1)/2)) + ['T'] +['-']*int(((N_STATES-1)/2))   
    if S != 'terminal':
        env_list[S] = 'o'
    else:
        env_list[3] = 'o'
    interaction = ''.join(env_list)
    print('\r{}'.format(interaction), end='')
    time.sleep(FRESH_TIME)

data=np.load('data.txt.npy')
ACTIONS = ['down', 'up']
table = pd.DataFrame(
    data,  
    columns=ACTIONS,  
)
S=0
is_terminated=False
update_env(S)
while not is_terminated:

    A = choose_action(S, table)
    S_= get_env_feedback(S, A)  
    # print(R)
    if S_ == 'terminal':
        is_terminated = True  
    S = S_  

    update_env(S)

当S=0时,得到环境交互:
1 o- - T - - -
2 - o - T - - -
3 - - o T - - -
4 - - - o - - -
当S=6时,得到环境交互:
1 - - - T - - o
2 - - - T - o -
3 - - - T o - -
4 - - - o - - -
这个效果是非常不错的。
至此,控制效果已经达到了。
推广到整个加热炉的控制问题上,也是一样。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值