化學(xué)習(xí)模型實(shí)戰(zhàn):從環(huán)境建模到獎(jiǎng)勵(lì)函數(shù)與訓(xùn)練調(diào)優(yōu))
簡(jiǎn)介斗地主強(qiáng)化學(xué)習(xí)模型技術(shù)資料以PDF文檔形式提供面向人工智能、游戲AI方向的開(kāi)發(fā)者和研究者適合希望理解強(qiáng)化學(xué)習(xí)在非完美信息博弈中應(yīng)用的讀者。內(nèi)容從斗地主決策難點(diǎn)切入系統(tǒng)梳理行動(dòng)空間龐大、動(dòng)作價(jià)值估計(jì)、不完全信息博弈、身份與階段差異、人格揣測(cè)、試驗(yàn)環(huán)境與數(shù)據(jù)等問(wèn)題并給出寬度優(yōu)先搜索、時(shí)序差分學(xué)習(xí)、重要性采樣等解決思路。模型架構(gòu)部分重點(diǎn)介紹叫地主模型、斗地主模型、評(píng)估器模型三大組件詳細(xì)說(shuō)明一手牌強(qiáng)度等于所有牌組集合強(qiáng)度加權(quán)、可執(zhí)行牌組執(zhí)行概率按集合采用概率加權(quán)求和等核心假設(shè)并涉及深度優(yōu)先搜索、動(dòng)態(tài)向量表、堆疊注意力機(jī)制、跨通道信息融合等實(shí)現(xiàn)技術(shù)。資料記錄了實(shí)驗(yàn)環(huán)境無(wú)GPU、自對(duì)抗訓(xùn)練、訓(xùn)練一周、實(shí)驗(yàn)方案與后續(xù)優(yōu)化方向含猜牌、行為探索、擴(kuò)大采樣范圍等。資源共包含一個(gè)PDF文件壓縮包大小約為1.12MB已有二百二十二人學(xué)習(xí)下載適合需要快速搭建斗地主人工智能框架并優(yōu)化訓(xùn)練效果的讀者。1. 斗地主RL模型從“能出牌”到“會(huì)贏牌”到底差在哪里很多入門團(tuán)隊(duì)做斗地主RL模型第一版跑通后拿出來(lái)的勝率往往漂亮得嚇人——但在換對(duì)手、換開(kāi)局之后立刻被打回原形。這不奇怪因?yàn)槎返刂鞅举|(zhì)上是“三人博弈、不完全信息、組合動(dòng)作空間”三件事疊在一起的問(wèn)題RL模型真正要解決的并不是“能不能打出一手合法牌”而是“在看不到另外兩家手牌的前提下做出期望收益最高的決策”。這篇文章會(huì)把一個(gè)可用于實(shí)際訓(xùn)練的斗地主RL模型按環(huán)境搭建、特征編碼、訓(xùn)練循環(huán)、參數(shù)調(diào)優(yōu)、常見(jiàn)翻車場(chǎng)景拆開(kāi)講一遍適合正在從單機(jī)規(guī)則AI轉(zhuǎn)向強(qiáng)化學(xué)習(xí)方案的開(kāi)發(fā)者和算法工程師作為落地參考。這里說(shuō)的RL模型指的并不是某個(gè)現(xiàn)成權(quán)重文件而是一整套從牌型識(shí)別到自我博弈的訓(xùn)練方案。2. 先解決“游戲怎么進(jìn)模型”環(huán)境抽象與動(dòng)作空間建模2.1 斗地主的博弈結(jié)構(gòu)為什么它不能當(dāng)普通回合制游戲處理斗地主的一局由叫牌、搶地主、出牌三個(gè)階段組成出牌階段又是典型的輪流出牌機(jī)制。多數(shù)RL建模方案把“叫牌”和“出牌”拆成兩個(gè)獨(dú)立決策模塊這樣做的原因很明顯叫牌階段只需要依據(jù)手牌質(zhì)量估算贏面而出牌階段則要面對(duì)不斷變化的牌權(quán)與剩余牌數(shù)。如果把它們糅合進(jìn)一個(gè)單一動(dòng)作空間動(dòng)作數(shù)量會(huì)變得極大而且大部分動(dòng)作在絕大多數(shù)狀態(tài)下是非法動(dòng)作這會(huì)讓探索效率急劇下降。另一個(gè)關(guān)鍵點(diǎn)是信息結(jié)構(gòu)。每個(gè)玩家只能看到自己的手牌和已經(jīng)打出的牌另外兩家的手牌是不可觀測(cè)的。所以模型輸入不能只拼接自己的手牌編碼還要把“已出牌張數(shù)”“當(dāng)前剩余牌堆分布推測(cè)”等信息放進(jìn)去。我一般會(huì)把每手牌的狀態(tài)組織成四段特征手牌本身、當(dāng)前輪次已出的牌、我方與對(duì)手剩余手牌數(shù)量、歷史出牌統(tǒng)計(jì)序列。這種設(shè)計(jì)比單純的手牌向量要好訓(xùn)練得多因?yàn)樵谌瞬┺睦飳?duì)手的剩余張數(shù)直接決定你是否要主動(dòng)拆牌、是否要保留炸彈。2.2 動(dòng)作空間劃分單張、對(duì)子、三帶、順子與炸彈的合法性檢查出牌動(dòng)作不是“選幾張牌”這么簡(jiǎn)單。一個(gè)動(dòng)作必須是完整牌型比如單張、對(duì)子、三張、三帶一、三帶二、順子、連對(duì)、飛機(jī)、炸彈、火箭。動(dòng)作空間可以超過(guò)一萬(wàn)種但實(shí)際合法的動(dòng)作卻很少通常一次出牌只有幾十到幾百個(gè)合法選擇。常見(jiàn)的做法是建立一張“牌型表”把每種牌型定義成結(jié)構(gòu)體再判斷當(dāng)前手牌是否包含某種牌型。我通常用一個(gè)parse_hand_to_types函數(shù)把17張手牌拆成可出牌型列表再用掩碼過(guò)濾動(dòng)作。下面是核心實(shí)現(xiàn)片段from itertools import combinations from collections import Counter def split_hand_by_rank(hand): rank_count Counter(hand) return rank_count def gen_legal_actions(hand): rc split_hand_by_rank(hand) actions [] # 單張與對(duì)子 for rank, cnt in rc.items(): actions.append((single, rank)) if cnt 2: actions.append((pair, rank)) if cnt 3: actions.append((triple, rank)) if cnt 4: actions.append((bomb, rank)) # 三帶一與三帶二 for rank, cnt in rc.items(): if cnt 3: for kicker, kcnt in rc.items(): if kicker rank: continue if kcnt 1: actions.append((triple_one, rank, kicker)) if kcnt 2: actions.append((triple_two, rank, kicker)) # 順子從A到2不連續(xù)單順至少5張 ranks sorted([r for r in rc.keys() if r 15], reverseTrue) for start in range(len(ranks)): for length in range(5, 13): window ranks[start:startlength] if len(window) length: break if all(window[i] - window[i1] 1 for i in range(length-1)): actions.append((straight, window)) # 火箭 if 14 in rc and 15 in rc: # 大小王約定為14、15 actions.append((rocket,)) return actions這段代碼的關(guān)鍵在于它把牌型生成與合法性檢查合成一步避免在訓(xùn)練循環(huán)內(nèi)部反復(fù)遍歷全量動(dòng)作空間。參數(shù)設(shè)定上需要注意一個(gè)坑大小王的編號(hào)必須單獨(dú)規(guī)劃不能跟普通牌混在順子判斷里。這里采用14和15表示王普通順子判斷時(shí)用rank 15直接排除掉王同時(shí)因?yàn)槎返刂鳑](méi)有2和王的順子還需要再把2也排除掉通常編號(hào)時(shí)把2編碼為13來(lái)規(guī)避排序干擾。2.3 從手牌到狀態(tài)張量一次性完成全部張數(shù)的特征映射環(huán)境返回給模型的不能是字符串手牌而是一個(gè)定長(zhǎng)張量。這里建議采用“牌面計(jì)數(shù)向量”加“全局上下文向量”拼接的形式而不是逐牌one-hot。逐牌one-hot的問(wèn)題在于無(wú)法把“還剩幾張”直接暴露給模型而且手牌順序會(huì)對(duì)網(wǎng)絡(luò)產(chǎn)生干擾。計(jì)數(shù)向量的做法是把每個(gè)合法牌面的剩余張數(shù)作為一維標(biāo)量例如普通牌3到2對(duì)應(yīng)12個(gè)特征位小王、大王各占一位合計(jì)14維。再疊加當(dāng)前輪到誰(shuí)出牌、上家出的牌型編碼、我方可出的最小壓牌代價(jià)等8到10維最終輸入維度通??刂圃?2以內(nèi)。def hand_to_vector(hand, max_rank15): vec [0] * max_rank for card in hand: vec[card] 1 return vec def state_vector(my_hand, last_action_vec, my_remain, opp_remain): hand_vec hand_to_vector(my_hand) context [ last_action_vec[0], # 上家出的牌型種類 last_action_vec[1], # 張數(shù) my_remain, opp_remain[0], opp_remain[1], ] return hand_vec context這里有一個(gè)特別容易忽視的細(xì)節(jié)last_action_vec需要對(duì)“不出”也做編碼否則模型面對(duì)首輪出牌或?qū)也灰獣r(shí)特征缺失。實(shí)際訓(xùn)練時(shí)如果發(fā)現(xiàn)模型經(jīng)常在自己擁有牌權(quán)時(shí)亂出先檢查這個(gè)字段是否為全零。狀態(tài)維度過(guò)低會(huì)讓模型學(xué)不到對(duì)手的剩余結(jié)構(gòu)過(guò)高又會(huì)拖慢訓(xùn)練速度32維以內(nèi)是我自己多次實(shí)驗(yàn)下來(lái)性價(jià)比最高的區(qū)間。2.4 獎(jiǎng)勵(lì)函數(shù)怎么設(shè)稀疏勝負(fù)獎(jiǎng)勵(lì)與階段性獎(jiǎng)勵(lì)的取舍斗地主每局時(shí)間長(zhǎng)短差異很大短則十幾手長(zhǎng)則上百手如果只在終局給獎(jiǎng)勵(lì)模型面對(duì)的信用分配問(wèn)題會(huì)非常嚴(yán)重。推薦采用混合獎(jiǎng)勵(lì)每手牌結(jié)束給一個(gè)小的中間獎(jiǎng)勵(lì)比如“獲得了牌權(quán)”加0.05“送走了下家一手牌但被對(duì)家接住”給負(fù)0.02最終局再根據(jù)輸贏與倍數(shù)給出大獎(jiǎng)勵(lì)。地主和農(nóng)民的目標(biāo)并不完全一致農(nóng)民講究配合地主講究壓制。所以獎(jiǎng)勵(lì)函數(shù)需要區(qū)分兩家陣營(yíng)不能共用一套。def reward_step(winner, is_landlord, player_id, score, hand_change): reward 0.0 if hand_change take_lead: reward 0.05 elif hand_change give_lead: reward - 0.02 if winner player_id: reward score * 0.1 elif winner -1: reward 0.0 else: reward - score * 0.1 return reward這里score要乘上炸彈倍數(shù)和春天倍數(shù)避免模型在炸彈決策上變得畏首畏尾。還有一個(gè)經(jīng)驗(yàn)是不要讓模型為了追求中間獎(jiǎng)勵(lì)而拆掉關(guān)鍵大牌所以中間獎(jiǎng)勵(lì)絕對(duì)值要小勝負(fù)獎(jiǎng)勵(lì)要夠大一般比例在1比20以上。3. 手牌編碼與牌型識(shí)別的工程化處理3.1 為什么不能用“排序后的手牌字符串”直接喂給網(wǎng)絡(luò)有些快速原型直接把手牌轉(zhuǎn)成字符串再做embedding這樣在單機(jī)測(cè)試?yán)镆材苁諗康珦Q到真實(shí)對(duì)局環(huán)境后就出現(xiàn)“過(guò)擬合到固定牌序”的問(wèn)題。原因是同一手牌可以有多種排序方式模型會(huì)學(xué)到排序位置與出牌策略的虛假關(guān)聯(lián)。正確做法是構(gòu)建牌面計(jì)數(shù)向量因?yàn)槎返刂鞯囊?guī)則只關(guān)心牌面組合不關(guān)心物理順序。計(jì)數(shù)向量天然具有置換不變性。這里需要同時(shí)做歸一化。計(jì)數(shù)向量各維度的取值范圍是0到4而剩余手牌數(shù)最大是20直接concat會(huì)導(dǎo)致網(wǎng)絡(luò)對(duì)后者的敏感度遠(yuǎn)高于前者。常見(jiàn)做法是把所有連續(xù)特征減去均值再除以標(biāo)準(zhǔn)差或者直接縮放到0-1范圍。我見(jiàn)過(guò)一個(gè)訓(xùn)練到一半loss不穩(wěn)的例子排查到最后就是my_remain這個(gè)值量級(jí)太大把它除以20后訓(xùn)練曲線立刻恢復(fù)了平穩(wěn)。3.2 出牌動(dòng)作掩碼的實(shí)現(xiàn)把非法動(dòng)作直接“凍結(jié)”住動(dòng)作掩碼是斗地主RL模型最容易出問(wèn)題的地方。模型輸出的動(dòng)作是一個(gè)索引但這個(gè)索引必須落在合法牌型集合上否則訓(xùn)練環(huán)境會(huì)直接報(bào)錯(cuò)或者默默跳過(guò)該輪次。更糟的是如果環(huán)境對(duì)非法動(dòng)作的懲罰是“重新采樣”模型會(huì)學(xué)會(huì)利用這種隨機(jī)性拖延時(shí)間最終產(chǎn)出一個(gè)根本不出牌的廢智能體。def mask_illegal_actions(logits, legal_actions): masked [float(-inf)] * len(logits) for idx in legal_actions: masked[idx] logits[idx] return masked實(shí)際操作中我通常會(huì)在動(dòng)作索引構(gòu)造階段給每個(gè)合法牌型分配一個(gè)穩(wěn)定ID而不是每次重新枚舉。這樣掩碼的計(jì)算量很小而且可以緩存。訓(xùn)練時(shí)如果發(fā)現(xiàn)智能體在某個(gè)狀態(tài)下反復(fù)選擇同一動(dòng)作先看是不是合法動(dòng)作列表長(zhǎng)度為空——這種情況在“自己擁有牌權(quán)且上一手無(wú)人出牌”時(shí)特別容易發(fā)生需要引擎提前把最小的單張加入合法列表。3.3 公共信息與私有信息的特征拼接順序模型輸出的策略必須區(qū)分公共特征和私有特征。公共特征包括當(dāng)前輪次、地主身份、剩余牌張數(shù)、已經(jīng)出過(guò)的牌型統(tǒng)計(jì)。私有特征就是自己的手牌向量和上一輪自己是否出過(guò)牌。拼接時(shí)建議先放公共特征再放私有特征因?yàn)榫W(wǎng)絡(luò)前幾層會(huì)優(yōu)先處理位置靠前的輸入公共特征需要被更早地編碼進(jìn)隱藏狀態(tài)。這不是數(shù)學(xué)上的強(qiáng)制要求只是訓(xùn)練穩(wěn)定性的經(jīng)驗(yàn)之談。關(guān)于特征順序還有一個(gè)細(xì)節(jié)已經(jīng)出過(guò)的牌要按“最近一輪優(yōu)先”排列而不是按全局時(shí)間排序。否則網(wǎng)絡(luò)很難學(xué)到“上家剛出過(guò)什么、我能不能壓住”這類短期上下文。最近一輪的action history一般保留三輪就夠包含當(dāng)前輪之前的三輪出牌記錄。4. 訓(xùn)練主循環(huán)與關(guān)鍵參數(shù)調(diào)優(yōu)4.1 選DQN還是PPO斗地主場(chǎng)景下的對(duì)比取舍在斗地主這個(gè)場(chǎng)景里兩種算法都能跑但使用體驗(yàn)差異很大。DQN適合動(dòng)作空間偏小、獎(jiǎng)勵(lì)相對(duì)穩(wěn)定的場(chǎng)景斗地主的合法動(dòng)作經(jīng)常只有幾十個(gè)而且規(guī)則對(duì)抗的結(jié)果相對(duì)確定所以DQN訓(xùn)練速度較快。但DQN對(duì)目標(biāo)網(wǎng)絡(luò)更新頻率非常敏感更新太快會(huì)導(dǎo)致震蕩更新太慢又會(huì)讓模型對(duì)新策略反應(yīng)遲鈍。PPO在斗地主上的優(yōu)勢(shì)是穩(wěn)定性和可調(diào)的探索范圍缺點(diǎn)是需要更多的環(huán)境交互收斂也更慢。我的建議是如果你只有單機(jī)訓(xùn)練環(huán)境先上DQN變體Double DQN加Dueling結(jié)構(gòu)因?yàn)樗臉颖拘矢呷绻麍F(tuán)隊(duì)有分布式采樣條件考慮PPO配合多個(gè)并行自對(duì)弈環(huán)境能更好地避免策略崩潰。這里面沒(méi)有絕對(duì)的銀彈我見(jiàn)過(guò)用PPO在斗地主上訓(xùn)練一周后效果還不如DQN訓(xùn)三天的。4.2 DQN訓(xùn)練主循環(huán)經(jīng)驗(yàn)池、目標(biāo)網(wǎng)絡(luò)與探索率的設(shè)定主循環(huán)的核心是四件事采樣、存經(jīng)驗(yàn)、更新網(wǎng)絡(luò)、周期同步目標(biāo)網(wǎng)絡(luò)。寫一個(gè)帶優(yōu)先級(jí)經(jīng)驗(yàn)回放的簡(jiǎn)化版訓(xùn)練循環(huán)def train_dqn(env, agent, buffer, batch_size256, target_sync2000, learn_steps1): state, legal_actions env.reset() for step in range(1000000): action agent.act(state, legal_actions, epsilon0.1) next_state, reward, done, next_legal env.step(action) buffer.push(state, action, reward, next_state, done, legal_actions, next_legal) if len(buffer) batch_size and step % learn_steps 0: batch buffer.sample(batch_size) agent.update(batch) if step % target_sync 0: agent.sync_target() if done: state, legal_actions env.reset() else: state, legal_actions next_state, next_legal這里的超參數(shù)都值得逐一說(shuō)清楚。batch_size設(shè)256而不是常見(jiàn)的32是因?yàn)槎返刂鳡顟B(tài)張量維度小批量大一點(diǎn)反而更穩(wěn)定target_sync設(shè)為2000步避免目標(biāo)網(wǎng)絡(luò)更新頻率過(guò)高所引發(fā)的Q值高估問(wèn)題epsilon從1.0線性衰減到0.05衰減周期為50萬(wàn)步。探索率衰減過(guò)慢會(huì)導(dǎo)致模型在后期依然大量隨機(jī)出牌過(guò)快則會(huì)讓模型過(guò)早鎖死在次優(yōu)策略上。4.3 關(guān)鍵參數(shù)速查表一眼看懂每個(gè)超參在管什么參數(shù)推薦值作用調(diào)節(jié)方向learning_rate1e-4 ~ 3e-4控制Q網(wǎng)絡(luò)更新步長(zhǎng)不穩(wěn)定就調(diào)小太慢就調(diào)大batch_size128 ~ 512每次更新的樣本數(shù)小批量收斂快但方差大gamma0.99未來(lái)獎(jiǎng)勵(lì)折扣率斗地主適合0.99太低會(huì)短視epsilon_min0.05最小探索率讓模型保持少量隨機(jī)出牌target_sync_step1000 ~ 3000目標(biāo)網(wǎng)絡(luò)同步周期太大訓(xùn)練慢太小Q值震蕩replay_buffer_size100000 ~ 500000經(jīng)驗(yàn)池容量過(guò)大樣本陳舊過(guò)小樣本相關(guān)性強(qiáng)這里要強(qiáng)調(diào)的是gamma0.99這個(gè)參數(shù)斗地主一局耗時(shí)較長(zhǎng)如果gamma設(shè)置過(guò)低模型只會(huì)關(guān)注立刻能看到的收益比如拆王炸去搶一個(gè)小牌權(quán)這在長(zhǎng)期策略上是明確的負(fù)收益。4.4 對(duì)手池設(shè)計(jì)與自我博弈避免模型只打得過(guò)“固定腳本”斗地主RL訓(xùn)練的成敗往往不在算法本身而在對(duì)手是誰(shuí)。如果只跟規(guī)則腳本對(duì)打模型很快就能找到腳本的套路漏洞從而刷出極高勝率但這種勝率沒(méi)有任何遷移性。常見(jiàn)做法是維護(hù)一個(gè)“對(duì)手池”里面同時(shí)存放歷史多個(gè)版本的模型和不同風(fēng)格的規(guī)則AI每局隨機(jī)從對(duì)手池中抽取兩個(gè)對(duì)手。這樣模型面對(duì)的策略分布是變化的它學(xué)到的是更general的決策能力而不是針對(duì)某個(gè)固定行為的鉆空子。對(duì)手池需要定期更新。訓(xùn)練每十萬(wàn)步就把當(dāng)前模型的副本存入池中并隨機(jī)淘汰掉最老的一份池子大小控制在10到20個(gè)模型之間。我見(jiàn)過(guò)有人把對(duì)手池?cái)U(kuò)到100個(gè)結(jié)果訓(xùn)練速度明顯變慢但收益提升并不顯著因?yàn)閷?duì)手之間的策略相似度過(guò)高。斗地主這邊更有效的做法是故意往池子里注入“激進(jìn)型”和“保守型”兩種極端規(guī)則AI讓模型學(xué)會(huì)在面對(duì)不同風(fēng)格時(shí)做動(dòng)態(tài)調(diào)整。5. 斗地主RL模型避坑指南5個(gè)真實(shí)翻車場(chǎng)景與排查路徑5.1 現(xiàn)象模型總是“不出牌”哪怕手上有能壓住的牌這個(gè)翻車場(chǎng)景特別常見(jiàn)。前期訓(xùn)練時(shí)模型把“不出”當(dāng)作最高收益動(dòng)作因?yàn)樗芰⒖桃?guī)避被對(duì)手壓制的負(fù)獎(jiǎng)勵(lì)結(jié)果越訓(xùn)越消極。原因通常是兩個(gè)一是獎(jiǎng)勵(lì)函數(shù)里對(duì)“不出”沒(méi)有顯式懲罰二是動(dòng)作掩碼在“擁有牌權(quán)”時(shí)沒(méi)有強(qiáng)制要求至少出一個(gè)合法動(dòng)作。解決方法是在環(huán)境邏輯里規(guī)定如果當(dāng)前玩家是本輪第一個(gè)出牌者則“不出”不加入合法動(dòng)作集合如果非首個(gè)出牌者但能壓過(guò)上一手就在獎(jiǎng)勵(lì)里給“不出”一個(gè)-0.1的懲罰項(xiàng)。5.2 現(xiàn)象勝率在訓(xùn)練中途突然暴漲又驟降這說(shuō)明訓(xùn)練已經(jīng)進(jìn)入了典型的策略震蕩周期在DQN里很常見(jiàn)。原因是目標(biāo)網(wǎng)絡(luò)更新后舊的Q值被推翻導(dǎo)致模型短期內(nèi)對(duì)同一狀態(tài)的評(píng)估發(fā)生劇烈變化。解決方法是把target_sync_step調(diào)大比如從1000改成3000如果還在震蕩就降低learning_rate到1e-4以下。還可以引入軟更新機(jī)制即每次同步時(shí)只把目標(biāo)網(wǎng)絡(luò)權(quán)重向當(dāng)前網(wǎng)絡(luò)移動(dòng)5%不要直接復(fù)制。5.3 現(xiàn)象模型對(duì)炸彈的態(tài)度兩極分化——要么永遠(yuǎn)不出要么開(kāi)局就炸后者通常是因?yàn)楠?jiǎng)勵(lì)函數(shù)里給“炸彈打出”設(shè)置了單獨(dú)獎(jiǎng)勵(lì)模型發(fā)現(xiàn)打炸彈能立刻拿到正向回報(bào)便不管時(shí)機(jī)地亂炸。正確做法是不要為炸彈設(shè)置單獨(dú)的正向獎(jiǎng)勵(lì)而是讓炸彈的收益通過(guò)終局倍數(shù)自然體現(xiàn)。前者則是因?yàn)間amma值太小模型看不到炸彈帶來(lái)的長(zhǎng)期收益。如果你是做消融實(shí)驗(yàn)時(shí)發(fā)現(xiàn)炸彈行為反常先檢查reward函數(shù)再檢查gamma值。5.4 現(xiàn)象模型在換了一組隨機(jī)種子后訓(xùn)練效果天差地別斗地主環(huán)境的隨機(jī)性來(lái)源很多洗牌、發(fā)牌、叫牌結(jié)果。固定隨機(jī)種子雖然方便調(diào)試卻容易讓模型隱式記憶初始狀態(tài)分布。解決方法是訓(xùn)練過(guò)程中使用滑動(dòng)隨機(jī)種子窗口讓每十萬(wàn)局的牌堆分布緩慢變化。另外驗(yàn)證模型強(qiáng)弱時(shí)至少使用20個(gè)不同隨機(jī)種子各跑1000局取平均勝率和標(biāo)準(zhǔn)差而不是只拿一個(gè)種子下的數(shù)值說(shuō)事。5.5 現(xiàn)象訓(xùn)練日志顯示loss在下降但實(shí)戰(zhàn)勝率紋絲不動(dòng)這是最高級(jí)別的“玄學(xué)翻車”Q網(wǎng)絡(luò)的loss下降只能代表它對(duì)當(dāng)前經(jīng)驗(yàn)池中的狀態(tài)擬合得更好并不代表策略在真實(shí)分布上有改進(jìn)。多半是經(jīng)驗(yàn)池太舊里面的樣本跟當(dāng)前模型策略完全不一樣了。解決方法是限制經(jīng)驗(yàn)池容量到20萬(wàn)條以內(nèi)并把訓(xùn)練與采樣的概率調(diào)整為“越新的樣本采樣概率越高”或者在經(jīng)驗(yàn)池中定時(shí)丟棄最老的30%數(shù)據(jù)。6. 讓模型再上一個(gè)臺(tái)階規(guī)則嫁接與基于混戰(zhàn)的驗(yàn)證方法6.1 規(guī)則嫁接用“前向搜索”幫RL模型糾正一手牌純RL模型在局部殘局中的表現(xiàn)經(jīng)常不如規(guī)則搜索最典型的場(chǎng)景是“還剩最后三張牌三帶還是拆單出”這類問(wèn)題。一個(gè)有效的做法是把蒙特卡洛搜索結(jié)果作為一個(gè)額外特征輸入給網(wǎng)絡(luò)而不是直接用搜索替代模型。具體實(shí)現(xiàn)時(shí)我在出牌階段前先讓規(guī)則引擎模擬未來(lái)三手的出牌路徑估算每種出牌方式的贏牌概率再把這個(gè)概率作為三維特征拼接到狀態(tài)向量末尾。這樣模型不會(huì)丟失自主性同時(shí)能獲得短期的深度信息。這個(gè)嫁接方式的效果非常明顯訓(xùn)練十萬(wàn)局后加入搜索特征的模型在殘局勝率上比純RL模型高出大約12%。代價(jià)是每次出牌都需要額外計(jì)算搜索路徑訓(xùn)練時(shí)間大約增加30%。如果你對(duì)實(shí)時(shí)推理速度有要求可以只在訓(xùn)練時(shí)用搜索特征推理時(shí)用一個(gè)小的蒸餾網(wǎng)絡(luò)近似輸出這部分特征。6.2 驗(yàn)證方法用“混戰(zhàn)淘汰賽”替代單一勝率指標(biāo)驗(yàn)證模型強(qiáng)度時(shí)不要只看它跟對(duì)手池的勝率因?yàn)閯俾蕰?huì)受到對(duì)手策略的影響。我一般會(huì)用8個(gè)模型加4個(gè)規(guī)則AI組成一個(gè)12強(qiáng)循環(huán)賽每?jī)蓚€(gè)模型對(duì)戰(zhàn)500局統(tǒng)計(jì)總得分排名。這樣做的好處是勝率匹配反應(yīng)的是相對(duì)強(qiáng)弱而不是絕對(duì)水平。模型A對(duì)規(guī)則AI勝率90%對(duì)模型B勝率40%綜合下來(lái)可能排名還在第三這時(shí)候就要優(yōu)先研究它面對(duì)不同策略時(shí)的短板。混戰(zhàn)淘汰賽的另一個(gè)作用是發(fā)現(xiàn)“克制鏈”。斗地主模型之間存在明顯的互克關(guān)系激進(jìn)模型容易把保守模型打崩但遇到同樣激進(jìn)的對(duì)手時(shí)又容易被炸彈制裁。通過(guò)循環(huán)賽能直觀看到模型的風(fēng)格傾向從而決定在強(qiáng)化學(xué)習(xí)訓(xùn)練時(shí)是否需要調(diào)整對(duì)手池的組成。6.3 我自己養(yǎng)成的習(xí)慣每版模型都留一個(gè)“可解釋性窗口”黑匣子問(wèn)題在斗地主模型里尤其明顯因?yàn)榕茩?quán)轉(zhuǎn)換、炸彈時(shí)機(jī)這些決策很難一眼看懂。我建議每隔一段時(shí)間記錄模型在特定局面下的動(dòng)作分布比如“手牌只剩三張時(shí)模型選擇單張、對(duì)子、三帶的歷史頻率”。這些數(shù)據(jù)能幫你快速定位是特征問(wèn)題還是獎(jiǎng)勵(lì)問(wèn)題而不是靠瞎猜。沒(méi)有這個(gè)窗口很多訓(xùn)練問(wèn)題要排查好幾天有了它通常一小時(shí)代碼就能定位到根因。這些做法并不高深但確實(shí)是我在多個(gè)斗地主RL模型項(xiàng)目里最受益的日常習(xí)慣。做RL模型真正值錢的地方從來(lái)不是把網(wǎng)絡(luò)跑通而是讓網(wǎng)絡(luò)在未知局面下依然值得信賴。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取