動態規划中 策略迭代 和 值迭代 的一個小例子


強化學習中動態規划是解決已知狀態轉移概率和獎勵值情況下的解決方法,這種情況下我們一般可以采取動態規划中的 策略迭代和值迭代的方式來進行求解,下面給出一個具體的小例子。

 

動態規划可以看成是構成強化學習問題的一個子問題, 與其說是一個子問題更不如說是一種特殊情況,動態規划中我們是知道 reward 和  state transiton probability , 用強化學習的語言表示就是說在動態規划中我們是已知模型的,就是說 在不同狀態 state 時我們選擇任意行為 action,  所獲得的獎勵reward和跳轉到的新狀態是已知的, 不需要我們抽樣來學習。而在強化學習問題中我們往往是不知道 獎勵值和跳轉到的新狀態的。

 

也就是說,這里面我們要說的 策略迭代  和  值迭代  都是在已知模型的情況下,因為這里我們討論的是動態規划問題,而在強化學習中我們往往不知道模型的情況下我們一般采用  蒙特卡洛  和   時序差分的方法, 其中蒙特卡洛方法需要采樣一次完整的決策過程才可以對過程中的決策動作更新Q值,計算量較大,計算不方便,不能單步的改進動作Q值, 因此我們往往采用時序差分的方法,如  Q-learnging 和 Sarsa 方法。這里我們主要講的是動態規划中的策略迭代和值迭代方法, 也可以看做是強化學習中已知模型的情況下求解最優策略的方法。

 

 

 

 策略迭代  方法的代碼為:

#encoding:UTF-8
#!/usr/bin/env python3

import random

#狀態
states=["1", "2"]

#動作
actions=["a", "b"]

# 獎勵的折扣因子
gama=0.99

""" 狀態值  v_value 
v_value={
"1":0,
"2":0
}"""
v_value={}
for state in states:
    v_value[state]=0


# 動作值 ("1", "a"):0
q_value={}


def p_state_reward(state, action):
    # 輸入當前狀態,及行為
    # return 跳轉概率,下一狀態, 獎勵
    if state=="1":
        if action=="a":
            return ((1.0/3, "1", 0),
                   (2.0/3, "2", 1))
        else:
            return ((2.0/3, "1", 0),
                   (1.0/3, "2", 1))
    if state=="2":
        if action=="a":
            return ((1.0/3, "1", 0),
                   (2.0/3, "2", 1))
        else:
            return ((2.0/3, "1", 0),
                   (1.0/3, "2", 1))

# q_value 初始值
"""q_value={
("1", "a"):(1.0/3*()),
("1", "b"):0,
("2", "a"):0,
("2", "b"):0
}"""
def q_value_fun():
    q_value.clear()
    for state in states:
        for action in actions:
            temp=0
            for t in p_state_reward(state, action):
                temp+=t[0]*(t[2]+gama*v_value[t[1]])
            q_value[(state, action)]=temp

#q_value初始化
q_value_fun()    


#策略 pi 初始化   "1":{"a":0.5, "b":0.5}
pi={}
for state in states:
    temp={}
    for action in actions:
        temp[action]=1.0/len(actions)
    pi[state]=temp

#print(v_value)
#print(pi)
#print(q_value)

#策略評估 得出 v_value 值
def policy_evalue():
    global v_value
    v_value_new={}

    def v_update():
        nonlocal v_value_new
        v_value_new={}
        for state in states:
            temp=0
            for action, p in pi[state].items():
                temp+=p*q_value[(state, action)]
            v_value_new[state]=temp 
        #print("v_value:        "+str(v_value))
        #print("v_value_new:    "+str(v_value_new))

    def stop_judge(): 
        flag=True
        for state, value in v_value.items():
            if abs(v_value_new[state]-value)>0.0001:
                flag=False
        return flag

    # 計算 v_value_new
    v_update()

    while stop_judge()!=True:
        # 更新 v_value
        v_value=v_value_new
        # 更新 q_value
        q_value_fun()
        # 再次迭代 計算v_value_new
        v_update()


#策略改進 max
def policy_improve():
    flag=True
    for state in states: 
        #L=[]
        #for action in actions:
        #    L.append((q_value[state, action], action))
        #action=max(L)[-1]
        action=max((q_value[state, action], action) for action in actions)[-1]

        for k in pi[state]:
            if k==action:
                if pi[state][k]!=1.0:
                    pi[state][k]=1.0
                    flag=False
            else:
                pi[state][k]=0.0
    return flag
 

if __name__=="__main__":
    """
    policy_evalue()
    print("*"*30)
    print(v_value) 
    print("*"*30)
    print(q_value) 
    print("*"*30)
    print(pi)
    """
    policy_evalue()
    flag=policy_improve()
    i=1
    while flag!=True:
        i+=1
        policy_evalue()
        flag=policy_improve()

    print("*"*30+"\n")
    print("總共運行次數:"+str(i)+"\n")
    print("狀態值為:")
    print(v_value) 
    print("")
    print("行為值為:")
    print(q_value) 
    print("策略為:")
    print(pi)

 

 

 在折扣因子 gama 設置為0.99的情況下, 狀態“1”的狀態值為66.65674655343062,

 狀態“2”的狀態值為66.65674655343062 。

 

 

 

 值迭代  方法的代碼為:

#encoding:UTF-8
#!/usr/bin/env python3

import random

#狀態
states=["1", "2"]

#動作
actions=["a", "b"]

# 獎勵的折扣因子
gama=0.99

""" 狀態值  v_value 
v_value={
"1":0,
"2":0
}"""
v_value={}
for state in states:
    v_value[state]=0


# 動作值 ("1", "a"):0
q_value={}


def p_state_reward(state, action):
    # 輸入當前狀態,及行為
    # return 跳轉概率,下一狀態, 獎勵
    if state=="1":
        if action=="a":
            return ((1.0/3, "1", 0),
                   (2.0/3, "2", 1))
        else:
            return ((2.0/3, "1", 0),
                   (1.0/3, "2", 1))
    if state=="2":
        if action=="a":
            return ((1.0/3, "1", 0),
                   (2.0/3, "2", 1))
        else:
            return ((2.0/3, "1", 0),
                   (1.0/3, "2", 1))

# q_value 初始值
"""q_value={
("1", "a"):(1.0/3*()),
("1", "b"):0,
("2", "a"):0,
("2", "b"):0
}"""
def q_value_fun():
    q_value.clear()
    for state in states:
        for action in actions:
            temp=0
            for t in p_state_reward(state, action):
                temp+=t[0]*(t[2]+gama*v_value[t[1]])
            q_value[(state, action)]=temp

#q_value初始化
q_value_fun()    


# 值迭代方法
def value_iteration():
    global v_value
    flag=True
    v_value_new={}

    for state in states:
        v_value_new[state]=max(q_value[(state, action)] for action in actions)

        if abs(v_value_new[state]-v_value[state])>0.0001:
            flag=False

    if flag==False: 
        v_value=v_value_new
        q_value_fun()
    return flag


if __name__=="__main__":
    i=1
    flag=value_iteration()
    while flag!=True:
        i+=1
        flag=value_iteration()

 
    #策略 pi 
    pi={}
    for state in states:
        act=max((q_value[(state, action)],action) for action in actions)[-1]
        temp={}
        for action in actions:
            if action==act:
                temp[action]=1.0
            else:
                temp[action]=0.0

        pi[state]=temp 


    print("*"*30+"\n")
    print("總共運行次數:"+str(i)+"\n")
    print("狀態值為:")
    print(v_value) 
    print("")
    print("行為值為:")
    print(q_value) 
    print("策略為:")
    print(pi)

 

 從結果可知:

 在折扣因子 gama 設置為0.99的情況下, 狀態“1”的狀態值為66.65674655343062,

 狀態“2”的狀態值為66.65674655343062 。

 

可以發現 在超參數相同, gama折扣因子都為0.99 ,   兩浮點數相同的判斷規格都為0.0001, 這時候 策略迭代和值迭代都可以得到相同的策略,同時 狀態值v, 和 動作值 q  也都是完全相同的。   在求解上可以視為 策略迭代法和值迭代法是等價的。(允許存在一定誤差)

 

 

 

 

 

如果假設我們是不知道   獎勵值和跳轉狀態的, 那么我們可以把這個動態規划問題或者說是已知模型的強化學習問題看做是未知模型的強化學習問題。

下面給出這個問題的在未知模型下采用強化學習中的時序差分方法如何解決:

Q—Learning  方法:

#encoding:UTF-8
#!/usr/bin/env python3

import random

#動作
actions=["a", "b"]

#狀態
states=["1", "2"]

#構建環境   s, a    r s a
def next_state_reward(state, action):
    alfa=random.random()

    if state=="1":
        if action=="a":
            if alfa<=1.0/3:
                new_state="1"
                reward=0
            else:
                new_state="2"
                reward=1
        else:
            if alfa>1.0/3:
                new_state="1"
                reward=0
            else:
                new_state="2"
                reward=1
    else:
         if action=="a":
            if alfa<=1.0/3:
                new_state="1"
                reward=0
            else:
                new_state="2"
                reward=1
         else:
            if alfa>1.0/3:
                new_state="1"
                reward=0
            else:
                new_state="2"
                reward=1
    return new_state, reward


# q_value    state:{ action:0 }
q_value={}
for state in states:
    temp={}
    for action in actions:
        temp[action]=0.0
    q_value[state]=temp


def action_max(state):
    temp=list(q_value[state].items())
    random.shuffle(temp)
    return max(temp, key=lambda p:p[-1])[0]
    

def action_greedy(state):
    if random.random()<epsilon:
        return random.choice(actions)
    else:
        return action_max(state)


epsilon=0.4
gama=0.99
learning_rate=0.1

def q_learning():
    state=random.choice(states)
    action=action_greedy(state)

    next_state, reward=next_state_reward(state, action)
    next_action=action_max(next_state)

    q_estimate = reward + gama*q_value[next_state][next_action]   

    td_error=q_estimate - q_value[state][action] 
   
    q_value[state][action]+=learning_rate*td_error 


if __name__=="__main__":
    for episode in range(10**6):
        q_learning()

    epsilon=0.01
    for episode in range(10**5):
        q_learning()

    print(q_value)

 

 

 

 Sarsa 方法:

#encoding:UTF-8
#!/usr/bin/env python3

import random

#動作
actions=["a", "b"]

#狀態
states=["1", "2"]

#構建環境   s, a    r s a
def next_state_reward(state, action):
    alfa=random.random()

    if state=="1":
        if action=="a":
            if alfa<=1.0/3:
                new_state="1"
                reward=0
            else:
                new_state="2"
                reward=1
        else:
            if alfa>1.0/3:
                new_state="1"
                reward=0
            else:
                new_state="2"
                reward=1
    else:
         if action=="a":
            if alfa<=1.0/3:
                new_state="1"
                reward=0
            else:
                new_state="2"
                reward=1
         else:
            if alfa>1.0/3:
                new_state="1"
                reward=0
            else:
                new_state="2"
                reward=1
    return new_state, reward


# q_value    state:{ action:0 }
q_value={}
for state in states:
    temp={}
    for action in actions:
        temp[action]=0.0
    q_value[state]=temp


def action_max(state):
    temp=list(q_value[state].items())
    random.shuffle(temp)
    return max(temp, key=lambda p:p[-1])[0]
    

def action_greedy(state):
    if random.random()<epsilon:
        return random.choice(actions)
    else:
        return action_max(state)


epsilon=0.4
gama=0.99
learning_rate=0.1

def sarsa_learning():
    state=random.choice(states)
    action=action_greedy(state)

    next_state, reward=next_state_reward(state, action)
    #next_action=action_max(next_state)
    next_action=action_greedy(next_state)

    q_estimate = reward + gama*q_value[next_state][next_action]   

    td_error=q_estimate - q_value[state][action] 
   
    q_value[state][action]+=learning_rate*td_error 


if __name__=="__main__":
    for episode in range(10**6):
        sarsa_learning()

    #epsilon=0.01
    #for episode in range(10**5):
    #    q_learning()

    #print(q_value)

 

分別運行  Q-Learning 和 Sarsa 方法多次,發現 Q-Learning估計的結果確實普遍比真實值高,但是一個新的發現是Sarsa方法估計的V值普遍比真實值低,至於為什么評估出的結果和真實值有這樣的誤差也是搞不清楚的,不過這個問題是強化學習這幾十年來最火的一個問題,各種說法都有,今年NIPS會議上最佳論文之一也是討論如何解決和解釋這個問題的, Q-Learning和Sarsa 方法很簡單,但是為了說明它居然用了幾十年還沒有解決,這確實要人不好說呀。

 

 

 

 

 ==========================================================================

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM