强化学习Q-learnin学习笔记

2 篇文章 0 订阅
1 篇文章 0 订阅
本文介绍了Q-learning的基本原理,通过孩子学习的例子阐述了如何构建Q表并迭代优化。通过Python和C++代码展示了如何让字符'o'通过学习移动到'T'。重点在于Q-learning算法的公式、代码实现及其在环境中的应用。
摘要由CSDN通过智能技术生成

强化学习Q-learnin学习笔记

前言

本文是学习【莫烦python】的课程笔记没找到本子就记在这里了,课程网址如下:https://www.bilibili.com/video/BV13W411Y75P?p=1

一、Q-learning简介

1.情景叙述

机器学习就是一个不断试错,不断学习的过程,为了简化问题,下图中的例子只考虑a1,a2两种情况,s1表示状态1,a1表示动作看电视,a2表示动作写作业。
在这里插入图片描述
孩子做a1,a2的不同抉择,会影响之后的状态,如果孩子在每一个状态s中都一直重复看电视的a1动作,最后就会挨打。Q学习的目的就是从结果中汲取教训反复训练,以至于最后达到理想的结果。
在这里插入图片描述

2.Q表的引入

为了更好的模拟孩子的行为,我们将上文孩在不同状态s下的不同动作a进行抽象,得到了如图的Q表(左下角)。
(s1,a2)表示孩子在s1状态下,选择a2动作(即学习),而(s1,a2)的值表示该状态下执行该动作的价值。
在这里插入图片描述
训练成功的机器人,就可以分析孩子所在的状态s,然后查阅Q表比较s下不同的动作的价值,“高概率”地选择价值更高的动作,以此类推,再到下一个动作,然后选择经过训练学习后最具价值的那个动作。

简而言之,Q表的样子,决定了机器决定了孩子接下来会做什么动作,所以机器学习中Q-learning算法的训练过程,其实就是一个将Q表从一个空表,不断完善成具有参考价值的Q表的过程。

二、Q-learning公式

Q表的迭代过程的核心公式及步骤如下:
在这里插入图片描述
1.将当前状态的s1的值作为估计值,得出下一步机器想要在s2状态执行a2动作。
2.比较得出下一个状态下s2中最具价值的动作,即maxQ(s2),将此值乘y(这里的y一般取0.8),然后加上从s1到s2状态下的奖惩值R(可以取正也可以取负)
(这里在s1状态就利用了Q表中s2的过程,其实就是一个对未来的估计过程)
3.求出二者的差值
4.更新(s1,a2)处的值
5.重复迭代

算法的伪代码如下:
这里的ε表示执行Q-learning算法的概率,如果不执行,则随机选择动作。(为了达到全局最优而设置的)
在这里插入图片描述
这里多提一嘴,为什么要在当前状态s1下考虑s2的值呢?究其原因,就是要让机器学习能够简单的“预测”(或者“学习”)将来的结果,如果将来的结果是错误的,那么在不断的学习迭代的过程中,这种错误的结果会一步步的返回到之前的一步步动作决策中去。
例如我在s3状态下做了关键性决策a2,最后导致在s20状态下陷入失败,那么Q表在不断的更新后就会对a2的值进行不断的削减,以至于最后在Q表中,s3状态下的a1比a2的价值更高。

三、Q-learning代码

我们搭建了一个简单的机器学习环境,让字符‘o’通过自主学习右移到字符’T’中,如下:
      o----T      直到       ----oT
【莫烦python】课中给了python代码,我自己敲了一遍,然后又自己用C++强化了练习了一下,二者代码如下:

1.python代码

import numpy as np
import pandas as pd
import time

np.random.seed(2)

N_SATAES = 6
ACTIONS = ['left','right']
EPSILON = 0.9     #greedy police百分比选择最优动作率
ALPHA=0.1         #learning rate
LAMBDA = 0.9      #discount factor衰减度
MAX_EPSDDES = 50  #maximum dpisodes
FRESH_TIME = 0.01  #fresh time for one move


def buil_q_table(n_states,actions):
    table = pd.DataFrame(np.zeros((n_states,len(actions))),#q_table inital values
    columns=actions,#action's name
     )
    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 == 'right':    #move right
        if S == N_SATAES-2: #terminate
            S_ = 'terminal'
            R = 1       #代表成功时给予的奖励
        else:
            S_ = S+1
            R = 0
    else:
        R = 0
        if S ==0:
            S_ = S #reach the wall
        else:
            S_ = S - 1
    return S_,R


def update_env(S,episode,stpe_counter):
    #环境,可以不看
    env_list = ['-']*(N_SATAES-1) + ['T']
    if S == 'terminal':
        interaction = 'Episode %s:total_steps = %s'%(episode+1,stpe_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():
    q_table = buil_q_table(N_SATAES,ACTIONS)
    for episode in range(MAX_EPSDDES):
        step_counter = 0
        S= 0
        is_terminated = False
        update_env(S,episode,step_counter)
        while not is_terminated:
            A = choose_action(S,q_table)
            S_,R = get_env_feedback(S,A)
            q_predict = q_table.loc[S,A]
            if S_ != 'terminal':
                q_target = R + LAMBDA * q_table.iloc[S_,:].max()
            else:
                q_target = R
                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_table = rl()
print('\r\nQ-table:\n')
print(q_table)

2.C++代码

#include<iostream>
#include<time.h>
#include<vector>
#include<string.h>
#include<stdio.h>
#include<windows.h>
using namespace std;


#define N_SATAES  6
#define EPSILON 0.9  
#define ALPHA  0.1        
#define LAMBDA  0.9 
#define MAX_EPSDDES  20
#define FRESH_TIME  0.1



void get_env_feedback(int S, int A,int &S_,int &R) {
    //这是代理如何对环境进行交流
    if (A == 1)    //move right
    {
        if (S == N_SATAES - 2) //terminate
        {
            S_ = -1;
            R = 1;      //代表成功时给予的奖励
        }
        else
        {
            S_ = S + 1;
            R = 0;
        }
    }
    else
    {
        R = 0;
        if (S == 0)
            S_ = S;//reach the wall
        else
            S_ = S - 1;
    }
}


int choose_action(int state, vector<pair<float, float>> q_table) {
    //这是如何选择动作,action_name=0表示左移,1表示右翼
    int action_name =9999;
    float ra = ((rand() % 100) / 100.0);
    if (( ra> EPSILON) || ((q_table[state].first == 0) && (q_table[state].second == 0)))
    {
        action_name = rand() % 2;
    }
    else//选择比较价值大的数
    {
        if (q_table[state].first > q_table[state].second)
            action_name = 0;
        else
            action_name = 1;
    }
        
    return action_name;
}

void update_env(int S,int episode,int stpe_counter) {
    //环境,可以不看
    string interaction;
    char env_list[] = "-----T";
    if (S == -1)
     {
        printf("\rEpisode %d:total_steps = %d", episode + 1, stpe_counter);
        Sleep(2*1000);
        printf("\r                             ");
     }
    else
    {
        env_list[S] = 'o';
        printf("\r %s",env_list);
        Sleep(FRESH_TIME*1000);
    }
}

int q_learning {
    //新建空的Q表
    vector<pair<float, float>> q_table;
    pair<float, float> q_one = make_pair(0, 0);
    for (int i = 0;i < N_SATAES;i++) {
        q_table.push_back(q_one);
    }

    srand(2);

    //***********主循环*********
    for (int i = 0;i < MAX_EPSDDES;i++)
    {
        int step_counter = 0;
        int S = 0;
        int A, S_, R = 999;
        float q_predict, q_target;
        bool is_terminated = false;
        update_env(S, i, step_counter);
        while (!is_terminated)
        {
            A = choose_action(S, q_table);
            get_env_feedback(S, A, S_, R);
            if (A == 0)
                q_predict = q_table[S].first;
            else
                q_predict = q_table[S].second;
            if (S_ != -1)
            {
                if (q_table[S].first > q_table[S].second)
                    q_target = R + LAMBDA * q_table[S_].first;
                else
                    q_target = R + LAMBDA * q_table[S_].second;
            }
            else
            {
                q_target = R;
                is_terminated = true;
            }
            if (A == 0)
                q_table[S].first += ALPHA * (q_target - q_predict);
            else
                q_table[S].second += ALPHA * (q_target - q_predict);
            S = S_;

            update_env(S, i, step_counter + 1);
            step_counter += 1;
        }
    }
    printf("\r\nQ-table:\n");
    printf("    right  left\n");
    for(int i = 0;i<6;i++)
        printf("%d   %f    %f\n",i,q_table[i].first, q_table[i].second);

    system("pause");
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值