1. 概述
細(xì)節(jié):動(dòng)力不足的汽車必須爬上一維小山才能到達(dá)目標(biāo)。 與MountainCar-v0不同丧失,動(dòng)作(應(yīng)用的引擎力)允許是連續(xù)值豺妓。
目標(biāo)位于汽車右側(cè)的山頂上。 如果汽車到達(dá)或超出布讹,則劇集終止琳拭。
在左側(cè),還有另一座山描验。 攀登這座山丘可以用來獲得潛在的能量白嘁,并朝著目標(biāo)加速。 在這第二座山頂上挠乳,汽車不能超過等于-1的位置权薯,好像有一堵墻。 達(dá)到此限制不會(huì)產(chǎn)生懲罰(可能在更具挑戰(zhàn)性的版本中)[1].
類型:連續(xù)控制
2. 環(huán)境
2.1 Observation & state
請(qǐng)注意睡扬,速度受到限制以便于探索盟蚣,但在更具挑戰(zhàn)性的版本中可能會(huì)放寬此約束。
注意:Observation是 state的函數(shù)卖怜,二者有時(shí)相同屎开,有時(shí)不同,在此例中马靠,二者是一樣的奄抽,在 Pendulum-v0中,Observation是state的函數(shù)甩鳄。
2.2 Actions
2.3 Reward
獎(jiǎng)勵(lì)為到達(dá)右側(cè)山丘目標(biāo)的100逞度,減去從開始到目標(biāo)的動(dòng)作平方總和。這個(gè)獎(jiǎng)勵(lì)函數(shù)提出了一個(gè)探索挑戰(zhàn)妙啃,因?yàn)槿绻砣藳]有盡快到達(dá)目標(biāo)档泽,它將會(huì)發(fā)現(xiàn)最好不要移動(dòng),并且不再找到目標(biāo)揖赴。
請(qǐng)注意馆匿,對(duì)于大多數(shù)已發(fā)表的作品而言,這種獎(jiǎng)勵(lì)是不尋常的燥滑,其目標(biāo)是盡可能快地達(dá)到目標(biāo)渐北,因此有利于爆炸戰(zhàn)略。
更多的獎(jiǎng)勵(lì)函數(shù)形式查看這個(gè)Leaderboard
2.4 初始狀態(tài)
位于-0.6和-0.4之間铭拧,無速度赃蛛。
2.5 終止?fàn)顟B(tài)- Episode Termination
位置等于0.5(此值可能被調(diào)整)恃锉。 可以在更具挑戰(zhàn)性的版本中添加對(duì)速度的約束。
添加最大步數(shù)可能是個(gè)好主意呕臂。
2.6 Solved Requirements
獲得超過90的獎(jiǎng)勵(lì)淡喜。此值可能會(huì)被調(diào)整。
3. 代碼
3.1 導(dǎo)入lib
import math
import gym
from gym import spaces
from gym.utils import seeding
import numpy as np
3.2 定義Continuous_MountainCarEnv
類
class Continuous_MountainCarEnv(gym.Env):
metadata = {
'render.modes': ['human', 'rgb_array'],
'video.frames_per_second': 30
}
3.2.1 定義__init__(self)
函數(shù)
def __init__(self):
self.min_action = -1.0 # 最小動(dòng)作值
self.max_action = 1.0 # 最大動(dòng)作值
self.min_position = -1.2 # 最低位置
self.max_position = 0.6 # 最高位置
self.max_speed = 0.07 # 最大速度
self.goal_position = 0.45 # was 0.5 in gym, 0.45 in Arnaud de Broissia's version
self.power = 0.0015
self.low_state = np.array([self.min_position, -self.max_speed]) # [-1.2, -0.07]
self.high_state = np.array([self.max_position, self.max_speed]) # [0.6, 0.07]
self.viewer = None
# 聲明observation space和action space的上下限
self.action_space = spaces.Box(low=self.min_action, high=self.max_action, shape=(1,))
# (low = 1.0, high = 1.0)
self.observation_space = spaces.Box(low=self.low_state, high=self.high_state)
# (low = -1.2, high = 0.6 )
self.seed()
self.reset()
3.2.2 定義隨機(jī)種子函數(shù)seed(self, seed=None)
def seed(self, seed=None):
self.np_random, seed = seeding.np_random(seed)
return [seed]
3.2.3 定義step(self, action)
函數(shù)
step()
函數(shù)
該函數(shù)在仿真器中扮演物理引擎的角色诵闭。其輸入是動(dòng)作action
, 輸出是:下一步狀態(tài)澎嚣,立即回報(bào)疏尿,是否終止,調(diào)試項(xiàng)。該函數(shù)描述了 智能體與環(huán)境交互的所有信息易桃,是環(huán)境文件中最重要的函數(shù)褥琐。在該函數(shù)中, 一般利用智能體的運(yùn)動(dòng)學(xué)模型和動(dòng)力學(xué)模型計(jì)算下一步的狀態(tài)和立即回報(bào)晤郑,并判斷是否達(dá)到終止?fàn)顟B(tài)
def step(self, action):
1. position = self.state[0]
2. velocity = self.state[1]
# position, velocity = self.state
3. force = min(max(action[0], -1.0), 1.0)
4. velocity += force*self.power - 0.0025 * math.cos(3*position)
5. if (velocity > self.max_speed): velocity = self.max_speed
6. if (velocity < -self.max_speed): velocity = -self.max_speed
7. position += velocity
8. if (position > self.max_position): position = self.max_position
9. if (position < self.min_position): position = self.min_position
10. if (position==self.min_position and velocity<0): velocity = 0
11. done = bool(position >= self.goal_position)
12. reward = 0
13. if done:
14. reward = 100.0
15. reward-= math.pow(action[0],2)*0.1
16. self.state = np.array([position, velocity])
17. return self.state, reward, done, {}
- 初始化位置狀態(tài)
- 初始化速度狀態(tài)
- 引擎力:內(nèi)層的
max(action[0], -1.0)
確保動(dòng)作值不低于下界敌呈,即 - 1.0,
外層的min(max(action[0], -1.0), 1.0)
確保動(dòng)作值不高于上界造寝,即 1.0 - 計(jì)算速度:注意是速度累加的磕洪,這是微分的概念,把連續(xù)過程離散成很小的片段以進(jìn)行近似
- 判斷當(dāng)前速度是否大于最大速度:如果是诫龙,將當(dāng)前速度設(shè)定為最大速度
- 判斷當(dāng)前速度是否小于最小速度:如果是析显,將當(dāng)前速度設(shè)定為最小速度
- 計(jì)算位置:
- 判斷當(dāng)前位置是否高于最高位置:如果是,將當(dāng)前位置設(shè)定為最高位置
- 判斷當(dāng)前位置是否低于最低位置:如果是签赃,將當(dāng)前位置設(shè)定為最低位置
- 如果當(dāng)前位置是最低位置且速度小于 0 :將速度設(shè)為0
- 判斷布爾類型的谷异,返回True或者False
- 初始化 reward = 0
- 如果當(dāng)前位置高于目標(biāo)位置,
- 給予 agent 值為100的reward
- 這是執(zhí)行動(dòng)作之后得到的新的狀態(tài)
-
step()
函數(shù)返回下一時(shí)刻的觀測(cè)锦聊,回報(bào)歹嘹,是否終止,調(diào)試項(xiàng)
11-15 這幾行代碼的意思是:每執(zhí)行一個(gè)step,就會(huì)檢查看自己是否越過了右邊的山峰孔庭,據(jù)此來給done賦值尺上,如果小車沒有越過右邊的山峰,即 done=False史飞,則在這一個(gè)step, reward將會(huì)記為尖昏,也就是這一個(gè)時(shí)間步我們耗費(fèi)了多少能量,我們當(dāng)然不希望耗油太多构资。如果小車越過右邊的山峰抽诉,即 done=True,這一個(gè)step就會(huì)馬上得到 的獎(jiǎng)勵(lì)吐绵。
3.2.4 定義reset()
函數(shù):
在強(qiáng)化學(xué)習(xí)算法中迹淌,智能體需要一次次地嘗試河绽,累積經(jīng)驗(yàn),然后從經(jīng)驗(yàn)中學(xué)到好的動(dòng)作唉窃。一次嘗試我們稱之為一條軌跡或一個(gè)episode. 每次嘗試都要到達(dá)終止?fàn)顟B(tài). 一次嘗試結(jié)束后耙饰,智能體需要從頭開始,這就需要智能體具有重新初始化的功能纹份。函數(shù)
reset()
就是這個(gè)作用, agent與環(huán)境交互前調(diào)用該函數(shù)苟跪,確定agent的初始狀態(tài)以及其他可能的一些初始化設(shè)置。此例中在每個(gè)episode開始時(shí)蔓涧,position初始化為[-0.6,-0.4]之間的一個(gè)任意狀態(tài)件已,速度初始化為0.
def reset(self):
self.state = np.array([self.np_random.uniform(low=-0.6, high=-0.4), 0])
return np.array(self.state)
3.2.5 定義_height(self, xs)
函數(shù):
此函數(shù)用于下面的render()
函數(shù)用來構(gòu)建圖像引擎
def _height(self, xs):
return np.sin(3 * xs)*.45+.55
3.2.6 定義render(self, mode='human')
函數(shù)
render()
函數(shù)是圖像引擎,就是人機(jī)交互界面,進(jìn)行動(dòng)畫演示元暴,一個(gè)仿真環(huán)境必不可少的兩部分 是物理引擎和圖像引擎篷扩。物理引擎模擬環(huán)境中物體的運(yùn)動(dòng)規(guī)律;圖像引擎用來顯示環(huán)境中的物體圖像茉盏。
def render(self, mode='human'):
screen_width = 600
screen_height = 400
world_width = self.max_position - self.min_position
scale = screen_width/world_width
carwidth=40
carheight=20
if self.viewer is None:
from gym.envs.classic_control import rendering
self.viewer = rendering.Viewer(screen_width, screen_height)
xs = np.linspace(self.min_position, self.max_position, 100)
ys = self._height(xs)
xys = list(zip((xs-self.min_position)*scale, ys*scale))
self.track = rendering.make_polyline(xys)
self.track.set_linewidth(4)
self.viewer.add_geom(self.track)
clearance = 10
l,r,t,b = -carwidth/2, carwidth/2, carheight, 0
car = rendering.FilledPolygon([(l,b), (l,t), (r,t), (r,b)])
car.add_attr(rendering.Transform(translation=(0, clearance)))
self.cartrans = rendering.Transform()
car.add_attr(self.cartrans)
self.viewer.add_geom(car)
frontwheel = rendering.make_circle(carheight/2.5)
frontwheel.set_color(.5, .5, .5)
frontwheel.add_attr(rendering.Transform(translation=(carwidth/4,clearance)))
frontwheel.add_attr(self.cartrans)
self.viewer.add_geom(frontwheel)
backwheel = rendering.make_circle(carheight/2.5)
backwheel.add_attr(rendering.Transform(translation=(-carwidth/4,clearance)))
backwheel.add_attr(self.cartrans)
backwheel.set_color(.5, .5, .5)
self.viewer.add_geom(backwheel)
flagx = (self.goal_position-self.min_position)*scale
flagy1 = self._height(self.goal_position)*scale
flagy2 = flagy1 + 50
flagpole = rendering.Line((flagx, flagy1), (flagx, flagy2))
self.viewer.add_geom(flagpole)
flag = rendering.FilledPolygon([(flagx, flagy2), (flagx, flagy2-10),
(flagx+25, flagy2-5)])
flag.set_color(.8,.8,0)
self.viewer.add_geom(flag)
pos = self.state[0]
self.cartrans.set_translation((pos-self.min_position)*scale, self._height(pos)*scale)
self.cartrans.set_rotation(math.cos(3 * pos))
return self.viewer.render(return_rgb_array = mode=='rgb_array')
強(qiáng)化學(xué)習(xí)算法可以不用圖像引擎鉴未,這里我們不做解釋了。
3.2.7 定義close(self)
函數(shù)
def close(self):
if self.viewer:
self.viewer.close()
self.viewer = None
參考: