【QMIX】一种基于Value-Based多智能体算法
文章目錄
- 1. QMIX 解決了什么問題(Motivation)
- 2. QMIX 怎樣解決團隊收益最大化問題(Method)
- 2.1 算法大框架 —— 基于 AC 框架的 CTDE(Centralized Training Distributed Execution) 模式
- 2.2 Agent RNN Network
- 2.3 Mixing Network
- 2.4 模型更新流程
- 3. QMIX 效果
QMIX 是一種基于 Value-Based 的多智能體強化學習算法(MARL),其基本思想來源于 Actor-Critic 與 DQN 的結合。使用中心式學習(Centralized Learning)分布式執行(Distributed Execution)的方法,利用中心式 Critic 網絡接受全局狀態用于指導 Actor 進行更新。QMIX 中 Critic 網絡的更新方式和 DQN 相似,使用 TD-Error 進行網絡自更新。除此之外,QMIX 中為 Critic 網絡設立了 evaluate net 和 target net, 這和 DQN 中的設計思想完全相符。
1. QMIX 解決了什么問題(Motivation)
QMIX 是一種解決多智能體強化學習問題的算法,對于大多數多智能體強化學習問題(MARL)都面臨著同樣一個問題:信度分配(也叫回報分配)。
這是指,當多個 Agent 在同時執行任務時,我們應該怎樣合理的去評價每一個 Agent 的行為效用,舉個例子:
假設我們現在正在訓練一個算法模型,使用該算法模型去玩 MOBA 類游戲(DOTA 或者 LOL),算法模型需要同時操控 5 個英雄。在訓練過程中遇到了這樣一個情況:我方 3 個英雄迎面撞上了敵方 1 個英雄。此時,算法模型控制 1 號英雄和 2 號英雄對敵方英雄發起進攻,但卻讓 3 號英雄撤退。那么最終,因為 2 打 1 的局面,我方成功擊敗對方英雄,獲得了 10 分的獎勵分(Reward),那么我們該怎樣為我方的這 3 個英雄進行獎勵分配?
在上面案例中,我們很明顯能看出,在人數占優勢的情況下,算法選擇讓 1 號和 2 號英雄一起發起進攻是一次正確的嘗試,而讓 3 號英雄嘗試撤退顯然就不那么明智了。由于對 1 號和 2 號的正確決策,使得整個指揮策略得到了正向的獎勵分(Positive Reward),但顯然我們不能直接將這個正向獎勵分同時應用到這 3 個英雄上。
我們希望被正確決策的英雄(1 號和 2 號)獲得較高的獎勵分,而被錯誤決策的英雄(3 號)獲得負的懲罰分,即最后的期望得分可能為:1 號(8分),2 號(8分),3 號(-6分)。
三個英雄的得分總和加起來還是 10 分,只是每個英雄能夠按照自己的實際情況獲得對應的合理獎勵分。
這就是 回報分配 的概念。
回報分配通常分為兩種類型: 自下而上類型 和 自上而下類型。
-
自上而下類型:這種類型通常指我們只能拿到一個團隊的最終得分,而無法獲得每一個 Agent 的獨立得分,因此我們需要把團隊回報(Team Reward)合理的分配給每一個獨立的 Agent(Individual Reward),這個過程通常也叫 “獨立回報分配”(Individual Reward Assign)。上述例子就屬于這種類型,典型的代表算法為 COMA算法。
-
自下而上類型:另外一種類型恰恰相反,指當我們只能獲得每個 Agent 的獨立回報(Individual)時,如何使得整個團隊的團隊得分(Team Reward)最大化。
QMIX 算法解決的是上述第二種類型的問題,即,在獲得各 Agent 的獨立回報的情況下,如何使得整個團隊的團隊收益最大化問題。
2. QMIX 怎樣解決團隊收益最大化問題(Method)
2.1 算法大框架 —— 基于 AC 框架的 CTDE(Centralized Training Distributed Execution) 模式
多智能體強化學習(MARL)訓練中面臨的最大問題是:訓練階段和執行階段獲取的信息可能存在不對等問題。即,在訓練的時候我們可以獲得大量的全局信息(事實證明,只有獲取足夠的信息模型才能被有效訓練)。
但在最終應用模型的時候,我們是無法獲取到訓練時那么多的全局信息的,因此,人們提出兩個訓練網絡:一個為中心式訓練網絡(Critic),該網絡只在訓練階段存在,獲取全局信息作為輸入并指導 Agent 行為控制網絡(Actor)進行更新;另一個為行為控制網絡(Actor),該網絡也是最終被應用的網絡,在訓練和應用階段都保持著相同的數據輸入。
AC 算法的應用非常廣泛,QMIX 在設計時同樣借鑒了 AC 的 “中心式網絡” 和 “分布式執行器” 的想法,整個網絡包含了 Mixing Network(類比 Critic 網絡)和 Agent RNN Network(類比 Actor 網絡),整個網絡架構圖如下所示:
下面我們分別來看看 Mixing Network 和 RNN Network 的詳細設計。
2.2 Agent RNN Network
QMIX 中每一個 Agent 都由 RNN 網絡控制,在訓練時你可以為每一個 Agent 個體都訓練一個獨立的 RNN 網絡,同樣也可以所有 Agent 復用同一個 RNN 網絡,這取決于你自己的設計。
RNN 網絡一共包含 3 層,輸入層(MLP)→ 中間層(GRU)→ 輸出層(MLP),實現代碼如下:
class RNN(nn.Module):# 所有 Agent 共享同一網絡, 因此 input_shape = obs_shape + n_actions + n_agents(one_hot_code)def __init__(self, input_shape, args):super().__init__()self.fc1 = nn.Linear(input_shape, args.rnn_hidden_dim)self.rnn = nn.GRUCell(args.rnn_hidden_dim, args.rnn_hidden_dim) # GRUCell(input_size, hidden_size)self.fc2 = nn.Linear(args.rnn_hidden_dim, args.n_actions)def forward(self, obs, hidden_state):x = F.relu(self.fc1(obs))h_in = hidden_state.reshape(-1, self.args.rnn_hidden_dim)h = self.rnn(x, h_in) # GRUCell 的輸入要求(current_input, last_hidden_state)q = self.fc2(h) # h 是這一時刻的隱狀態,用于輸到下一時刻的RNN網絡中去,q 是真實行為Q值輸出return q, h2.3 Mixing Network
Mixing 網絡相當于 Critic 網絡,同時接收 Agent RNN Network 的 Q 值和當前全局狀態 sts_tst? ,輸出在當前狀態下所有 Agent 聯合行為 uuu 的行為效用值 QtotQ_{tot}Qtot?。
Mixing 同樣使用神經網絡結構,不同的是,上圖中藍色部分(中間層神經元)的權重(weights)和偏差(bias)均由右邊紅色的神經網絡產生。即,Mixing 網絡中實際包含兩個神經網絡,紅色參數生成網絡 & 藍色推理網絡。
- 參數生成網絡: 接收全局狀態 sts_tst?,生成藍色網絡中的神經元權重(weights)和偏差(bias)。
- 推理網絡:接收所有 Agent 的行為效用值 QQQ,并將參數生成網絡生成的權重和偏差賦值到網絡自身,從而推理出全局效用 QtotQ_{tot}Qtot?。
下圖是推理網絡示意圖,只含有一個隱層,與隱層相連接的 weights 和 bias 均由參數生成網絡生成,每一層需要的 weights 和 bias 維度如下圖所示:
結合上圖,我們來看看 Mixing 網絡實現代碼:
class QMixNet(nn.Module):def __init__(self, arglist):super().__init__()self.arglist = arglist# 因為生成的 hyper_w1 需要是一個矩陣,而 pytorch 神經網絡只能輸出一個向量,# 所以就先輸出長度為需要的 矩陣行*矩陣列 的向量,然后再轉化成矩陣# hyper_w1 網絡用于輸出推理網絡中的第一層神經元所需的 weights,# 推理網絡第一層需要 qmix_hidden * n_agents 個偏差值,因此 hyper_w1 網絡輸出維度為 qmix_hidden * n_agentsself.hyper_w1 = nn.Sequential(nn.Linear(arglist.state_shape, arglist.hyper_hidden_dim),nn.ReLU(),nn.Linear(arglist.hyper_hidden_dim, arglist.n_agents * arglist.qmix_hidden_dim))# hyper_w2 生成推理網絡需要的從隱層到輸出 Q 值的所有 weights,共 qmix_hidden 個self.hyper_w2 = nn.Sequential(nn.Linear(arglist.state_shape, arglist.hyper_hidden_dim),nn.ReLU(),nn.Linear(arglist.hyper_hidden_dim, arglist.qmix_hidden_dim))# hyper_b1 生成第一層網絡對應維度的偏差 biasself.hyper_b1 = nn.Linear(arglist.state_shape, arglist.qmix_hidden_dim)# hyper_b2 生成對應從隱層到輸出 Q 值層的 biasself.hyper_b2 =nn.Sequential(nn.Linear(arglist.state_shape, arglist.qmix_hidden_dim),nn.ReLU(),nn.Linear(arglist.qmix_hidden_dim, 1))def forward(self, q_values, states): # states的shape為(episode_num, max_episode_len, state_shape)# 傳入的q_values是三維的,shape為(episode_num, max_episode_len, n_agents)episode_num = q_values.size(0)q_values = q_values.view(-1, 1, self.arglist.n_agents) # (episode_num * max_episode_len, 1, n_agents)states = states.reshape(-1, self.arglist.state_shape) # (episode_num * max_episode_len, state_shape)w1 = torch.abs(self.hyper_w1(states))b1 = self.hyper_b1(states)w1 = w1.view(-1, self.arglist.n_agents, self.arglist.qmix_hidden_dim)b1 = b1.view(-1, 1, self.arglist.qmix_hidden_dim)hidden = F.elu(torch.bmm(q_values, w1) + b1) # torch.bmm(a, b) 計算矩陣 a 和矩陣 b 相乘w2 = torch.abs(self.hyper_w2(states))b2 = self.hyper_b2(states)w2 = w2.view(-1, self.arglist.qmix_hidden_dim, 1)b2 = b2.view(-1, 1, 1)q_total = torch.bmm(hidden, w2) + b2q_total = q_total.view(episode_num, -1, 1)return q_total2.4 模型更新流程
至此,我們已經了解了 QMIX 中主要網絡的結構了,現在我們來看看訓練過程中這些神經網絡是如何進行參數更新的吧。
QMIX 的更新方式和 DQN 非常類似,設定 evaluate Net 和 target Net,并利用 TD-Error 完成參數更新:
loss=TDError=Qtot(evalutate)?(r+γQtot(target))loss = TDError = Q_{tot}(evalutate) - (r + \gamma Q_{tot}(target)) loss=TDError=Qtot?(evalutate)?(r+γQtot?(target))
由上述公式可以看出,一共存在兩個 Mixing 網絡(evaluate & target),兩個網絡分別用于產生 Qtot(evaluate)Q_{tot}(evaluate)Qtot?(evaluate) 和 Qtot(target)Q_{tot}(target)Qtot?(target),兩個網絡接收不同的輸入:
- eval 網絡: 接收在狀態 sss 下每個 Agent RNN Network 所選行為的 QQQ 值作為輸入,輸出 Qtot(evaluate)Q_{tot}(evaluate)Qtot?(evaluate)。
- target 網絡:接收在狀態 snexts_{next}snext? 下每個 Agent RNN Network 所有行為中最大的 QQQ 值作為輸入,輸出 Qtot(target)Q_{tot}(target)Qtot?(target)。
實現代碼如下:
def learn(self, batch):episode_num = batch['o'].shape[0]self.init_hidden(episode_num)# 把 batch 里的數據轉化成 tensorfor key in batch.keys():if key == 'u':batch[key] = torch.tensor(batch[key], dtype=torch.long)else:batch[key] = torch.tensor(batch[key], dtype=torch.float32)s, s_next, u, r, avail_u, avail_u_next, terminated = batch['s'], batch['s_next'], batch['u'], \batch['r'], batch['avail_u'], batch['avail_u_next'],\batch['terminated']# 得到每個 agent 對應的 Q 值列表q_evals, q_targets = self.get_q_values(batch)# 取出每個 agent 所選擇動作的對應 Q 值q_evals = torch.gather(q_evals, dim=3, index=u).squeeze(3)# 得到target_q,取所有行為中最大的 Q 值q_targets[avail_u_next == 0.0] = - 9999999 # 如果該行為不可選,則把該行為的Q值設為極小值,保證不會被選到q_targets = q_targets.max(dim=3)[0]# qmix更新過程,evaluate網絡輸入的是每個agent選出來的行為的q值,target網絡輸入的是每個agent最大的q值,和DQN更新方式一樣q_total_eval = self.eval_qmix_net(q_evals, s)q_total_target = self.target_qmix_net(q_targets, s_next)targets = r + self.arglist.gamma * q_total_target * (1 - terminated)td_error = (q_total_eval - targets.detach())# 不能直接用mean,因為還有許多經驗是沒用的,所以要求和再比真實的經驗數,才是真正的均值loss = (masked_td_error ** 2).sum() / mask.sum()self.optimizer.zero_grad()loss.backward()torch.nn.utils.clip_grad_norm_(self.eval_parameters, self.arglist.grad_norm_clip)self.optimizer.step()# 在指定周期更新 target network 的參數if train_step > 0 and train_step % self.arglist.target_update_cycle == 0:self.target_rnn.load_state_dict(self.eval_rnn.state_dict())self.target_qmix_net.load_state_dict(self.eval_qmix_net.state_dict())3. QMIX 效果
下圖是 QMIX 論文中給出的 QMIX 與其他算法之間的效果對比圖:
可以看出,QMIX 相較于 IQL 有明顯大幅度的提升,并且比 VDN 具有更優的效果。QMIX 實質上是 VDN 的一個改進版本,在 VDN 中直接將每個 Agent 的 QQQ 值相加得到 QtotQ_{tot}Qtot?,而在 QMIX 中,利用兩個神經網絡,結合每個 Agent 的 QQQ 值與全局狀態 sts_tst? 共同推理出全局效用 QtotQ_{tot}Qtot?,從結果來看確實比 VDN 在效果上有一定的提升。
QMIX 論文鏈接: https://arxiv.org/pdf/1803.11485.pdf
QMIX 實現代碼:https://github.com/oxwhirl/smac
總結
以上是生活随笔為你收集整理的【QMIX】一种基于Value-Based多智能体算法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MultiProcessing中主进程与
- 下一篇: 【COMA】一种将团队回报拆分为独立回报