由於強化學習領域目前還有很多的問題,如數據利用率,收斂,調參玄學等,對於單個Agent的訓練就已經很難了。但是在實際生活中單一代理所能做的事情還是太少了,而且按照羣體的智慧,不考慮訓練硬件和時長問題,使用多個agent同時進行學習,會不會有奇招呢?另外如果在需要multi-agent的場景下,如想要完成多人遊戲的話,也必須要考慮到多代理的問題。
博弈論(game theory)
在單個agent中只需要考慮到自己,把自己優化的最好就可以了,但是涉及到Multi-Agent,研究多個代理之間的關係以提升整體效果或者完成多agent的目標任務時,首當其衝需要參考博弈論的成果。
博弈論是數學的一個分支,也是運籌學的一個重要學科。博弈論主要研究公式化了的激勵結構間的相互作用,研究具有鬥爭或競爭性質現象的數學理論和方法,考慮遊戲中的個體的預測行爲和實際行爲,並研究它們的優化策略。不僅在多代理強化學習中,在深度學習,生成對抗都有應用,主要是用來模擬在有預定規則和結果的情況下不同參與者(agent)的策略互動。
一般根據遊戲類型主要可以分爲:
- 合作vs非合作:即人多力量大,合作狀態下嘗試建立一個聯盟共同贏得遊戲。
- 對稱vs非對稱:對稱遊戲所有人的目標相同。
- 完美信息vs非完美信息:能看到所有人的舉動(象棋vs德州撲克)
- 同時vs順序:同時行動還是順序的比如棋盤遊戲
- 零和vs非零和:零和中一個玩家的獲利一定意味着其他玩家的損失。
納什均衡(Nash Equilibrium)
即在一策略組合中,所有的參與者面臨這樣一種情況,當其他人不改變策略時,他此時的策略是最好的。此時的狀況既不是基於個人的利益,也不是基於整體的效果,但是在概率上是最容易產生的結果,所以在多代理的環境下,是很容易收斂到納什均衡狀態的。比如博弈論中經典的囚徒困境(prisoner’s dilemma):
- 假設有兩個小偷A和B聯合犯事、私入民宅被警察抓住。警方將兩人分別置於不同的兩個房間內進行審訊,對每一個犯罪嫌疑人,警方給出的政策是:如果兩個犯罪嫌疑人都坦白了罪行,交出了贓物,於是證據確鑿,兩人都被判有罪,各被判刑8年;如果只有一個犯罪嫌疑人坦白,另一個人沒有坦白而是抵賴,則以妨礙公務罪(因已有證據表明其有罪)再加刑2年,而坦白者有功被減刑8年,立即釋放。如果兩人都抵賴,則警方因證據不足不能判兩人的偷竊罪,但可以私入民宅的罪名將兩人各判入獄1年。
坦白 | 抵賴 | |
---|---|---|
坦白 | 8,8 | 0,10 |
抵賴 | 10,0 | 1,1 |
雖然看起來如果兩個合作的話(即兩個人抵賴)是最好的結果,但是實際上對某一個人A來說,儘管他不知道B作何選擇,但他知道無論B選擇什麼,他選擇"坦白"總是最優的。顯然,根據對稱性,B也會選擇"坦白",結果是兩人都被判刑8年。所以此時如果直接兩個採用普通的RL的做法,它們都最大化自己的累積收益,最終應該收斂到 坦白-坦白,即納什均衡,但此時對自身與整體的來說都不是一個很好的結果。這種情況在這種“對稱遊戲”中更容易達到。
MARL(Multi-Agent Reinforcement Learning)
這就使得在multi-agent下,探索的隨機性以外,還存在這樣的困惑,即不知道對方的選擇,以及兩者的選擇是否能夠得到最佳的效果。爲了解決這樣的困惑:
- 以促進agent間合作的解決MARL的問題分爲兩條路:
-
- modelling other agents in system。單代理的擴展,嘗試用多個agent去共同決策其他agent的action;
-
- communication for coordination。既然不確定其他代理的選擇,那麼就通過信息交換,去促進agent間的合作。
- 以相互競爭爲綱,最終完成共同進步的思路:類似GAN,這些算法往往會使用minimax的思想,比如minimax Q-learning。
- 另外還有納什均衡也不錯的思路,畢竟類似囚徒困境的博弈太少了,網絡收斂到納什均衡的結果也能接受,代表算法就是Nash-Q。
MADDPG(Multi-Agent Deep Deterministic Policy Gradient)
MADDPG屬於合作類別的思路,實現是流行的MARL以集中式訓練,分佈式執行的思想。
- 集中式訓練:每個agent不僅僅根據自身的情況,還根據其他智能體的行爲來評估當前動作的價值
- 分佈式執行:當agent都訓練完成後,每個agent就可以自己根據狀態採取合適的動作,此時不需要其他agent的參與
大致的訓練上與DDPG很相似,只是在輸入Critic時不僅僅是自己的[s,a]了,還有其他agent的信息,進行共同更新訓練。
#會輸入所有agent的action信息
def critic_network(name, action_input, reuse=False):
with tf.variable_scope(name) as scope:
if reuse:
scope.reuse_variables()
x = state_input
x = tf.layers.dense(x, 64)
if self.layer_norm:
x = tc.layers.layer_norm(x, center=True, scale=True)
x = tf.nn.relu(x)
x = tf.concat([x, action_input], axis=-1)
x = tf.layers.dense(x, 64)
if self.layer_norm:
x = tc.layers.layer_norm(x, center=True, scale=True)
x = tf.nn.relu(x)
x = tf.layers.dense(x, 1, kernel_initializer=tf.random_uniform_initializer(minval=-3e-3, maxval=3e-3))
return x
詳細細節可以參拜原文paper:https://arxiv.org/pdf/1706.02275.pdf
目前communication工作開始聚焦於limited communication,或者decentralized training。
Minimax-Q
主要應用於兩個玩家的零和隨機博弈中,需要優化的對象就是
–是代表競爭對手,是聯合動作值函數。即在當前agent在狀態s時,執行動作a到下一個狀態s‘,在更新Q時,會觀察對手在同樣的狀態s下的動作,再借鑑Q-Learning中的TD方法來更新。
def getReward(self, initialState, finalState, actions, reward, restrictActions=None):
if not self.learning:
return
actionA, actionB = actions
self.Q[initialState, actionA, actionB] = (1 - self.alpha) * self.Q[initialState, actionA, actionB] + \
self.alpha * (reward + self.gamma * self.V[finalState])
# EQUIVALENT TO : min(np.sum(self.Q[initialState].T * self.pi[initialState], axis=1))
self.V[initialState] = self.updatePolicy(initialState)
self.alpha *= self.decay
def updatePolicy(self, state, retry=False):
#建立table
c = np.zeros(self.numActionsA + 1)
c[0] = -1
A_ub = np.ones((self.numActionsB, self.numActionsA + 1))
A_ub[:, 1:] = -self.Q[state].T
b_ub = np.zeros(self.numActionsB)
A_eq = np.ones((1, self.numActionsA + 1))
A_eq[0, 0] = 0
b_eq = [1]
bounds = ((None, None),) + ((0, 1),) * self.numActionsA
#納什均衡問題使用線性規劃求解
res = linprog(c, A_ub=A_ub, b_ub=b_ub, A_eq=A_eq, b_eq=b_eq, bounds=bounds)
if res.success:
self.pi[state] = res.x[1:]
elif not retry:
return self.updatePolicy(state, retry=True)
else:
print("Alert : %s" % res.message)
return self.V[state]
return res.x[0]
Nash Q-Learning
目標是能收斂到納什均衡點,即在每一個狀態s的階段博弈中,都能夠找到一個全局最優點或者鞍點。納什均衡一般使用線性規劃求解,即對於
可以得到其中某一個agent的線性規劃:
其中p表示選擇動作的概率。整個線性規劃看起來就是在類似囚徒困境的表中,對每個agent嘗試找到最好的策略。
#利用對手的action計算Q
def compute_q(self, state, reward, opponent_action, q):
if (self.previous_action, opponent_action) not in q[state].keys():
q[state][(self.previous_action, opponent_action)] = 0.0
q_old = q[state][(self.previous_action, opponent_action)]
#更新Q值
updated_q = q_old + (self.alpha * (reward+ self.gamma*self.nashq[state]- q_old))
def compute_nashq(self, state):
nashq = 0
#遍歷nash表
for action1 in self.actions:
for action2 in self.actions:
nashq += self.pi[state][action1]*self.pi_o[state][action2] * self.q[state][(action1, action2)]