我想說:
其實(shí)很多事情找對(duì)方法很重要,可以事半功倍展氓,就好比學(xué)習(xí)穆趴;
原本打算將機(jī)器學(xué)習(xí)基礎(chǔ)寫完以后再寫深度學(xué)習(xí)、強(qiáng)化學(xué)習(xí)遇汞、遷移學(xué)習(xí)的內(nèi)容,但是現(xiàn)在看還是中間穿插一點(diǎn)比較好簿废。
看一下強(qiáng)化學(xué)習(xí)入門的一點(diǎn)東西空入,從概念說起吧:下面基本是在挖坑,后面會(huì)慢慢填起來族檬。
其實(shí)機(jī)器學(xué)習(xí)可以大致分為三類:監(jiān)督學(xué)習(xí)歪赢、非監(jiān)督學(xué)習(xí)、強(qiáng)化學(xué)習(xí)单料;
強(qiáng)化學(xué)習(xí)是一個(gè)很重要的分支埋凯,目前來說比較火;
1. 什么是強(qiáng)化學(xué)習(xí):
強(qiáng)化學(xué)習(xí):它關(guān)注的是智能如何在環(huán)境中采取一系列行為扫尖,從而獲得最大的累計(jì)回報(bào)白对,通過比較來更深刻的理解一下:
增強(qiáng)學(xué)習(xí)和監(jiān)督學(xué)習(xí)的主要區(qū)別:
增強(qiáng)學(xué)習(xí)是試錯(cuò)學(xué)習(xí),由于沒有直接的指導(dǎo)信息换怖,智能體要以不斷與環(huán)境進(jìn)行交互甩恼,通過試錯(cuò)的方式來獲得最佳的策略;
延遲回報(bào)沉颂, 增強(qiáng)學(xué)習(xí)的指導(dǎo)信息很多条摸, 而且往往是在事后(最后一個(gè)狀態(tài))才給出的,這就導(dǎo)致了一個(gè)問題铸屉,就是獲得正報(bào)或者負(fù)報(bào)以后钉蒲,如何將回報(bào)分配給前面的狀態(tài)。
不明白不要緊彻坛,慢慢來顷啼,看個(gè)例子:
假設(shè)我們要構(gòu)建一個(gè)下國際象棋的機(jī)器帆赢,這種情況不能使用監(jiān)督學(xué)習(xí),首先线梗,我們本身不是優(yōu)秀的棋手椰于,而請(qǐng)象棋老師來遍歷每個(gè)狀態(tài)下的最佳棋步則代價(jià)過于昂貴。其次仪搔,每個(gè)棋步好壞判斷不是孤立的瘾婿,要依賴于對(duì)手的選擇和局勢(shì)的變化。是一系列的棋步組成的策略決定了是否能贏得比賽烤咧。下棋過程的唯一的反饋(在強(qiáng)化學(xué)習(xí)中這個(gè)反饋就是得到的獎(jiǎng)勵(lì)或者懲罰偏陪,也就是說延遲回報(bào),并不是實(shí)時(shí)的煮嫌,也可以理解為不以一時(shí)成敗論英雄笛谦,只看最后,當(dāng)然高手們對(duì)決幾步就可能看出最終的勝負(fù)昌阿,你這么想問題又來了饥脑,你的AI思維哪去了?并不要想當(dāng)然)是在最后贏得或是輸?shù)羝寰謺r(shí)才產(chǎn)生的懦冰。這種情況我們可以采用增強(qiáng)學(xué)習(xí)算法灶轰,通過不斷的探索和試錯(cuò)學(xué)習(xí),增強(qiáng)學(xué)習(xí)可以獲得某種下棋的策略刷钢,并在每個(gè)狀態(tài)下都選擇最有可能獲勝的棋步笋颤。目前這種算法已經(jīng)在棋類游戲中得到了廣泛應(yīng)用。
2. 馬爾可夫決策過程(MDP)
學(xué)習(xí)強(qiáng)化學(xué)習(xí)不得不知的馬爾科夫決策過程:
一個(gè)馬爾可夫決策過程由一個(gè)四元組構(gòu)成M = (S, A, Psa, ?)
S: 表示狀態(tài)集(states)内地,有s∈S伴澄,si表示第i步的狀態(tài)。
A:表示一組動(dòng)作(actions)阱缓,有a∈A非凌,ai表示第i步的動(dòng)作。
?sa: 表示狀態(tài)轉(zhuǎn)移概率茬祷。?s? 表示的是在當(dāng)前s ∈ S狀態(tài)下清焕,經(jīng)過a動(dòng)作 ∈ A作用后,會(huì)轉(zhuǎn)移到的其他狀態(tài)的概率分布情況祭犯。比如秸妥,在狀態(tài)s下執(zhí)行動(dòng)作a,轉(zhuǎn)移到s'的概率可以表示為p(s'|s,a)沃粗。
R: S×A?? 粥惧,R是回報(bào)函數(shù)(reward function)。有些回報(bào)函數(shù)狀態(tài)S的函數(shù)最盅,可以簡(jiǎn)化為R: S??突雪。如果一組(s,a)轉(zhuǎn)移到了下個(gè)狀態(tài)s'起惕,那么回報(bào)函數(shù)可記為r(s'|s, a)。如果(s,a)對(duì)應(yīng)的下個(gè)狀態(tài)s'是唯一的咏删,那么回報(bào)函數(shù)也可以記為r(s,a)惹想。
上面的組成有了,那么我們讓這些組合在一起想去做一件什么事情呢督函?其實(shí)最終的目的就是嘀粱,知道現(xiàn)在的位置如何最快的到達(dá)目的地(達(dá)到目標(biāo)),這個(gè)最快我們?cè)谶@里使用回報(bào)來衡量的辰狡,也可以描述為獲得的回報(bào)最大锋叨。這個(gè)是我們最終想要學(xué)習(xí)的東西,中間的過程是怎么做的宛篇? 了解過強(qiáng)化學(xué)習(xí)的應(yīng)該知道算法:Sarsa和Q-learning:(跳躍有點(diǎn)快娃磺?有坑不要緊:學(xué)習(xí)就是挖坑和填坑的過程,這和強(qiáng)化學(xué)習(xí)的思想差不多叫倍,我也沒必要萬事俱備了再去做一些事情偷卧,可以不斷的探索和試錯(cuò)學(xué)習(xí),已經(jīng)挖了很多坑段标,后面慢慢填起來)
再看一下圖涯冠,可以得到大致流程:開始agent(Q表)隨機(jī)一個(gè)state和action,給env逼庞,env給予反饋,得到下一個(gè)狀態(tài)和獎(jiǎng)勵(lì)瞻赶,更新agent赛糟,之后agent在根據(jù)這個(gè)狀態(tài)和獎(jiǎng)勵(lì)作出下一步行動(dòng),再給env砸逊,一次迭代進(jìn)化璧南。
Sarsa:
Q-learning:
上代碼:先帶帶感覺:
Sarsa:
import numpy as np
import pandas as pd
import time
np.random.seed(2) # reproducible
# 定義6種狀態(tài)
N_STATES = 6
# 在線性狀態(tài)下只能采取往左或者往右
ACTIONS = ['left', 'right']
EPSILON = 0.9 # greedy police
# 學(xué)習(xí)率
ALPHA = 0.1
# 隨機(jī)因素, 我們有10%的可能隨便選取行動(dòng)
GAMMA = 0.9
# 我們的智能體师逸, 進(jìn)化次數(shù)
MAX_EPISODES = 13
# 為了防止太快司倚,方便觀看,sleep一下
FRESH_TIME = 0.3
# Q表用來記錄每種狀態(tài)采取的行動(dòng)回報(bào)值篓像。
# 下面是進(jìn)行初始化动知;
def build_q_table(n_states, actions):
table = pd.DataFrame(
np.zeros((n_states, len(actions))), # 初始化獎(jiǎng)勵(lì)值
columns=actions, # 采取的行動(dòng)
)
# print(table)
return table
# 根據(jù)Q表,獲取目前狀態(tài)下采取的行動(dòng)员辩, 注意有10%的隨機(jī)性
def choose_action(state, q_table):
# 獲得在某狀態(tài)下的獎(jiǎng)勵(lì)盒粮, 但是如何行動(dòng)的話,怎么選擇奠滑?
# 兩種方式:(1)10%的隨機(jī)丹皱;(2)選取回報(bào)最大的作為下一步的行動(dòng)妒穴;
state_actions = q_table.iloc[state, :]
if (np.random.uniform() > EPSILON) or ((state_actions == 0).all()):
action_name = np.random.choice(ACTIONS)
else: # act greedy
action_name = state_actions.idxmax()
return action_name
# 根據(jù)行動(dòng)后,所在的狀態(tài)給予獎(jiǎng)勵(lì)摊崭;
def get_env_feedback(S, A):
# 這里智能體就會(huì)得到反饋讼油;
# 往右移動(dòng)
if A == 'right':
# 這就是延時(shí)回報(bào)的原因,開始進(jìn)化時(shí)只有到了最后我們才知道是否應(yīng)該給予獎(jiǎng)勵(lì)
if S == N_STATES - 2:
S_ = 'terminal'
R = 1
# 下面雖然沒有給予獎(jiǎng)勵(lì)呢簸,但是狀態(tài)加一矮台,也就是說目的地更近了一步,也算是一種獎(jiǎng)勵(lì)
else:
S_ = S + 1
R = 0
# 那么如果你往左阔墩,下面都是懲罰
else:
R = 0
if S == 0:
S_ = S
else:
S_ = S - 1
return S_, R
# 用來更新目前的結(jié)果 和 現(xiàn)實(shí)
def update_env(S, episode, step_counter):
env_list = ['>>>']*(N_STATES-1) + ['OK']
if S == 'terminal':
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] = 'ooo'
interaction = ''.join(env_list)
print('\r{}'.format(interaction), end='')
time.sleep(FRESH_TIME)
# 下面就是智能體核心進(jìn)化流程嘿架, 也就是一個(gè)算法的優(yōu)化流程;
def rl():
# 初始化Q表
q_table = build_q_table(N_STATES, ACTIONS)
# 智能體進(jìn)化次數(shù)
for episode in range(MAX_EPISODES):
step_counter = 0
# 狀態(tài)從0開始啸箫;
S = 0
# 行動(dòng)往左開始耸彪;
A = 'left'
# 一個(gè)標(biāo)示, 表示是否到達(dá)終點(diǎn)忘苛。
is_terminated = False
# 更新顯示
update_env(S, episode, step_counter)
# 如果智能體沒有到達(dá)目的地蝉娜, 不停的迭代
while not is_terminated:
# 根據(jù)此時(shí)狀態(tài)和采取的行動(dòng), 得到下一個(gè)所在的狀態(tài)和應(yīng)得獎(jiǎng)勵(lì)
S_, R = get_env_feedback(S, A)
# 判斷上面采取行動(dòng)A后是否到達(dá)目的地扎唾; 如果沒有召川,此時(shí)再此狀態(tài)從Q表獲得下一步的行動(dòng);
if S_ != 'terminal':
A_ = choose_action(S_, q_table)
# 獲得S狀態(tài)A行動(dòng)下的回報(bào)值胸遇,這里是后面此時(shí)Q表的更新荧呐;
q_predict = q_table.loc[S, A]
# Sarsa算法的精髓
if S_ != 'terminal':
q_target = R + GAMMA * q_table.loc[S_, A_] #.max() # next state is not terminal
# 達(dá)到目的地獲得獎(jiǎng)勵(lì), 回報(bào)給上一個(gè)狀態(tài)動(dòng)作哦纸镊, 就是這樣回傳的倍阐。
else:
q_target = R
is_terminated = True
# 更新
q_table.loc[S, A] += ALPHA * (q_target - q_predict)
S = S_
A = A_
print (S, A)
update_env(S, episode, step_counter+1)
step_counter += 1
print (q_table)
return q_table
if __name__ == "__main__":
q_table = rl()
print('\r\nQ-table:\n')
print(q_table)
Q-learning:
將rl()換成這個(gè):
def rl():
# main part of RL loop
q_table = build_q_table(N_STATES, ACTIONS)
for episode in range(MAX_EPISODES):
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) # take action & get next state and reward
q_predict = q_table.loc[S, A]
if S_ != 'terminal':
q_target = R + GAMMA * q_table.iloc[S_, :].max() # next state is not terminal
else:
q_target = R # next state is terminal
is_terminated = True # terminate this episode
q_table.loc[S, A] += ALPHA * (q_target - q_predict) # update
S = S_ # move to next state
update_env(S, episode, step_counter+1)
step_counter += 1
return q_table
推薦閱讀: