` 深度解析:概率動作列表、隨機性來源與采樣實戰(zhàn))
人工智能強化學習深度學習【免費下載鏈接】open_spielOpenSpiel is a collection of environments and algorithms for research in general reinforcement learning and search/planning in games.項目地址https://gitcode.com/gh_mirrors/op/open_spiel點擊查看免費下載導讀本文圍繞 OpenSpiel 核心 State API 中的chance_outcomes()方法展開講解如何獲取隨機節(jié)點Chance Node的概率分布、理解is_chance_node()與其配合的判定邏輯并通過 Leduc Poker、外部采樣 MCCFR、CFR 等真實用例展示如何讀取、校驗與采樣這一分布。讀完本文你將掌握在 OpenSpielPython 與 C中處理隨機性來源的標準姿勢以及kExplicitStochastic/kSampledStochastic兩種隨機模式對chance_outcomes()行為的影響。1.chance_outcomes()是什么chance_outcomes()是 State 類提供的核心方法之一返回一個(action, probability)二元組列表表示當前狀態(tài)下的隨機動作及其概率分布。其 C 簽名在 spiel.h 中定義// Get the chance outcomes and their probabilities. // // Chance actions do not have a separate UID space from regular actions. // // Note: what is returned here depending on the games chance_mode (in // its GameType): // - Option 1. kExplicit. All chance node outcomes are returned along with // their respective probabilities. Then State::ApplyAction(...) is // deterministic. // - Option 2. kSampled. Return a dummy single action here with probability // 1, and then State::ApplyAction(...) does the real sampling. In this // case, the game has to maintain its own RNG. virtual ActionsAndProbs ChanceOutcomes() const { SpielFatalError(ChanceOutcomes unimplemented!); }其中ActionsAndProbs即std::vectorstd::pairAction, double。幾個關鍵語義返回值(動作 ID, 概率)列表概率之和應為 1合法離散分布只在隨機節(jié)點調用才有意義非隨機節(jié)點調用會觸發(fā)SpielFatalError(ChanceOutcomes unimplemented!)或返回空/未定義結果因此調用前務必用is_chance_node()判定動作 ID 與普通動作共享編號空間隨機動作沒有獨立 UID 空間見 spiel.h這保證了整個博弈樹中動作編號的統(tǒng)一性隨機性來源由chance_mode決定若游戲聲明為kExplicitStochasticchance_outcomes()返回完整分布且ApplyAction是確定性的若為kSampledStochastic則只返回一個概率為 1 的占位動作真正的采樣在ApplyAction內部完成需要游戲自身維護 RNG。ChanceMode枚舉定義在 spiel.henum class ChanceMode { kDeterministic, // No chance nodes kExplicitStochastic, // Has at least one chance node, all with // deterministic ApplyAction() kSampledStochastic, // At least one chance node with non-deterministic // ApplyAction() };源碼注釋spiel.h建議實現(xiàn)隨機游戲時優(yōu)先采用kExplicitStochastic因為學習算法能看到完整的隨機結果分布而不只是單個采樣結果。2. Python 中的典型用法以 Leduc Poker 為例在 Python 中通過pyspiel訪問該方法其綁定位于 open_spiel/python/pybind11/pyspiel.cc.def(chance_outcomes, State::ChanceOutcomes)。Leduc Poker 是驗證chance_outcomes()的經(jīng)典游戲發(fā)牌由隨機節(jié)點完成每輪從牌堆中抽取手牌。文檔示例state_chance_outcomes.md完整復現(xiàn)如下import pyspiel import numpy as np game pyspiel.load_game(leduc_poker) state game.new_initial_state() # First players private card. print(state.chance_outcomes()) # Output: # [(0, 0.16666666666666666), (1, 0.16666666666666666), (2, 0.16666666666666666), (3, 0.16666666666666666), (4, 0.16666666666666666), (5, 0.16666666666666666)] state.apply_action(0) # Second players private card. outcomes state.chance_outcomes() print() # Output: # [(1, 0.2), (2, 0.2), (3, 0.2), (4, 0.2), (5, 0.2)] # Sampling an outcome and applying it. action_list, prob_list zip(*outcomes) action np.random.choice(action_list, pprob_list) state.apply_action(action)這段代碼展示了兩個關鍵觀察概率隨牌堆變化初始 6 張牌每張概率1/6 ≈ 0.1667第一位玩家抽走動作0后剩余 5 張牌每張概率變?yōu)?/5 0.2且動作0不再出現(xiàn)——chance_outcomes()返回的是當前狀態(tài)下真實的剩余牌分布不是固定常量手動采樣 應用把(action, probability)拆成兩個列表用np.random.choice(action_list, pprob_list)按概率采樣再apply_action(action)推進狀態(tài)。2.1 源碼印證Leduc 發(fā)牌分布的生成邏輯Leduc 的ChanceOutcomes()實現(xiàn)在 open_spiel/games/leduc_poker/leduc_poker.ccstd::vectorstd::pairAction, double LeducState::ChanceOutcomes() const { SPIEL_CHECK_TRUE(IsChanceNode()); std::vectorstd::pairAction, double outcomes; if (suit_isomorphism_) { const double p 1.0 / deck_size_; // Consecutive cards in deck are viewed identically. for (int card 0; card deck_.size() / 2; card) { if (deck_[card * 2] ! kInvalidCard deck_[card * 2 1] ! kInvalidCard) { outcomes.push_back({card, p * 2}); } else if (deck_[card * 2] ! kInvalidCard || deck_[card * 2 1] ! kInvalidCard) { outcomes.push_back({card, p}); } } return outcomes; } const double p 1.0 / deck_size_; for (int card 0; card deck_.size(); card) { // This card is still in the deck, prob is 1/decksize. if (deck_[card] ! kInvalidCard) outcomes.push_back({card, p}); } return outcomes; }實現(xiàn)細節(jié)值得注意第一行SPIEL_CHECK_TRUE(IsChanceNode())明確要求該方法只能在隨機節(jié)點被調用這正是 Python 示例中初始狀態(tài)發(fā)牌節(jié)點可調用的原因非同構模式下概率恒為1 / deck_size_deck_size_是剩余牌數(shù)見 leduc_poker.h 注釋 Number of cards remaining與示例中 1/6、1/5 的輸出完全吻合同構suit_isomorphism_模式下花色被折疊連續(xù)兩張花色牌視為同一張概率相應翻倍p * 2這是可配置游戲參數(shù)引起的分布差異。3. 配合is_chance_node()使用先判定再取值由于chance_outcomes()只在隨機節(jié)點有定義實踐中總是先調用is_chance_node()判斷當前狀態(tài)是否為隨機節(jié)點。該方法的 C 默認實現(xiàn)在 spiel.h// Is this state a chance node? Chance nodes are states whose actions // represent stochastic outcomes. Chance or Nature is thought of as a // player with a fixed (randomized) policy. virtual bool IsChanceNode() const { return CurrentPlayer() kChancePlayerId; }Python 綁定同樣位于 pyspiel.cc.def(is_chance_node, State::IsChanceNode)。kChancePlayerId是 OpenSpiel 中自然/環(huán)境玩家的特殊 IDkChancePlayerId -1一類的保留值。從語義上講隨機性被抽象為一名使用固定隨機策略的玩家這使得博弈樹可以統(tǒng)一地按玩家輪流行動的框架處理隨機節(jié)點只是行動者恰為自然。is_chance_node()的判定測試state_is_chance_node.mdimport pyspiel game pyspiel.load_game(tic_tac_toe) state game.new_initial_state() print(state.is_chance_node()) # Output: False game pyspiel.load_game(leduc_poker) state game.new_initial_state() print(state.is_chance_node()) # Output: True game pyspiel.load_game(matrix_sh) state game.new_initial_state() print(state.is_chance_node()) # Output: Falsetic_tac_toe完全確定性的完美信息游戲初始狀態(tài)是玩家 0 的決策節(jié)點返回Falseleduc_poker初始狀態(tài)就是發(fā)牌隨機節(jié)點返回Truematrix_sh單回合同時行動的矩陣博弈沒有隨機節(jié)點返回False。這種先is_chance_node()判定、再chance_outcomes()取值、最后apply_action()推進的三步模式是遍歷含隨機性博弈樹的標準套路。LegalActions()的默認實現(xiàn)甚至直接復用了這一判定邏輯spiel.hvirtual std::vectorAction LegalActions(Player player) const { if (!IsTerminal() player CurrentPlayer()) { return IsChanceNode() ? LegalChanceOutcomes() : LegalActions(); } else { return {}; } }即在隨機節(jié)點上合法動作列表就是合法隨機結果LegalChanceOutcomes()默認由ChanceOutcomes()取出所有動作 ID 構成見 spiel.h。因此state.legal_actions()在隨機節(jié)點同樣可用返回的正是可抽到的全部結果。4. 深入OpenSpiel 內部如何采樣隨機結果4.1 C 側SampleAction從隨機分布中抽取一個結果OpenSpiel 提供全局函數(shù)SampleAction聲明于 spiel.h實現(xiàn)于 spiel.ccstd::pairAction, double SampleAction(const ActionsAndProbs outcomes, double z) { SPIEL_CHECK_GE(z, 0); SPIEL_CHECK_LT(z, 1); // Special case for one-item lists. if (outcomes.size() 1) { SPIEL_CHECK_FLOAT_EQ(outcomes[0].second, 1.0); return outcomes[0]; } // First do a check that this is indeed a proper discrete distribution. double sum 0; for (const std::pairAction, double outcome : outcomes) { double prob outcome.second; SPIEL_CHECK_PROB(prob); sum prob; } SPIEL_CHECK_FLOAT_EQ(sum, 1.0); // Now sample an outcome. sum 0; for (const std::pairAction, double outcome : outcomes) { double prob outcome.second; if (sum z z (sum prob)) { return outcome; } sum prob; } SpielFatalError(Failed to sample an action, this should never happen.); }要點該函數(shù)是累加區(qū)間采樣把[0, 1)按概率切成連續(xù)區(qū)間z落在哪個區(qū)間就選哪個動作復雜度 O(n)采樣前會做分布合法性校驗概率必須在[0, 1]內且總和為 1SPIEL_CHECK_PROB、SPIEL_CHECK_FLOAT_EQ這提醒調用方chance_outcomes()返回的分布理論上必須歸一化另有一個接受隨機數(shù)生成器的重載spiel.ccSampleAction(outcomes, absl::Uniform(rng, 0.0, 1.0))把z的生成與采樣封裝在一起。4.2 Python 側np.random.choice的等價替代Python 中除文檔示例的np.random.choice(action_list, pprob_list)外pyspiel也直接暴露了 C 的采樣能力。更貼近 OpenSpiel 內部風格的做法是import pyspiel game pyspiel.load_game(leduc_poker) state game.new_initial_state() outcomes state.chance_outcomes() actions [a for a, p in outcomes] probs [p for a, p in outcomes] assert abs(sum(probs) - 1.0) 1e-9 # 概率和應為 1 action pyspiel.sample_action(outcomes) # 等價于 C SampleAction state.apply_action(action)不過以當前倉庫 pyspiel.cc 的綁定為準chance_outcomes直接返回(action, prob)列表配合zip(*outcomes)拆解、np.random.choice采樣即可無需依賴額外 API。需要強調的一點是不要手動修改返回的概率值OpenSpiel 約定該分布已歸一化算法代碼如SampleAction會按合法離散分布處理。5. 實戰(zhàn)價值算法中的標準消費模式chance_outcomes()并非孤立 API它是眾多強化學習與博弈論算法處理隨機性的樞紐。倉庫中大量算法通過is_chance_node()ChanceOutcomes()SampleAction的組合遍歷含隨機的博弈樹。5.1 CFR遍歷完整隨機分布CFRCounterfactual Regret Minimization在初始化信息狀態(tài)節(jié)點時對每個隨機節(jié)點窮舉其全部隨機結果并遞歸展開子節(jié)點open_spiel/algorithms/cfr.ccif (state.IsChanceNode()) { for (const auto action_prob : state.ChanceOutcomes()) { InitializeInfostateNodes(*state.Child(action_prob.first)); } return; }這里action_prob.first是動作 IDstate.Child(...)生成對應子狀態(tài)。CFR 依賴完整分布計算期望后悔值因此要求游戲采用kExplicitStochastic模式——這也解釋了 spiel.h 注釋中顯式隨機更有利于學習算法的建議。5.2 外部采樣 MCCFR按分布隨機抽樣與 CFR 的窮舉不同外部采樣 MCCFR 在隨機節(jié)點按概率抽樣一次open_spiel/algorithms/external_sampling_mccfr.cc} else if (state.IsChanceNode()) { Action action SampleAction(state.ChanceOutcomes(), dist_(*rng)).first;同樣的模式還出現(xiàn)在 outcome_sampling_mccfr.cc、mcts.cc、evaluate_bots.cc 等處——MCTS 在隨機節(jié)點通過SampleAction(working_state-ChanceOutcomes(), rng_)抽取環(huán)境結果mcts.cc??梢姼F舉分布 vs 按分布采樣是確定性搜索類算法CFR、值迭代與隨機采樣類算法MCCFR、MCTS、DQN 環(huán)境模擬在隨機節(jié)點上的核心差異而兩者的共同輸入都是chance_outcomes()。5.3 智能體評估統(tǒng)一的環(huán)境隨機性接口open_spiel/algorithms/evaluate_bots.cc 中評估器在隨機節(jié)點同樣調用SampleAction(state-ChanceOutcomes(), rng)保證所有被評估的 bot 面對一致的環(huán)境隨機性接口。6. 常見問題與注意事項在非隨機節(jié)點調用chance_outcomes()C 側 Leduc 實現(xiàn)直接SPIEL_CHECK_TRUE(IsChanceNode())斷言多數(shù)游戲會崩潰/報錯調用前務必用is_chance_node()判定或用state.get_type()返回StateType::kChance確認節(jié)點類型參見 state_get_type.md 中對 Chance 類型的說明。kSampledStochastic模式的假分布若游戲聲明該模式chance_outcomes()只返回一個概率為 1 的占位動作真實隨機性藏在ApplyAction內部。此時不要依賴該分布做概率計算從源碼角度看這種模式下的狀態(tài)序列化也存在限制spiel.h 注釋明確說明默認序列化方案對kSampledStochastic游戲不適用。概率浮點誤差返回概率是double比較時建議用容差如abs(sum(probs) - 1.0) 1e-9不要用精確比較。返回值順序ChanceOutcomes()無強制排序保證但LegalChanceOutcomes()文檔約定合法動作升序spiel.h若你的算法依賴順序請基于legal_actions()或自行排序。7. 關聯(lián) API 速覽chance_outcomes()與以下 API 協(xié)同工作相關文檔見 api_reference.md方法作用對應文檔is_chance_node()判斷當前是否為隨機節(jié)點state_is_chance_node.mdchance_outcomes()返回 (動作, 概率) 列表state_chance_outcomes.mdapply_action(action)應用隨機結果推進狀態(tài)state_apply_action.mdlegal_actions()隨機節(jié)點上返回合法隨機結果state_legal_actions.mdmax_chance_outcomes()單個隨機節(jié)點的最大結果數(shù)上限game_max_chance_outcomes.mdmax_chance_nodes_in_history()任意歷史中隨機節(jié)點最大數(shù)量game_max_chance_nodes_in_history.md其中game.max_chance_outcomes()是游戲級元信息隨機節(jié)點結果數(shù)的上界C 默認返回 0 表示無隨機節(jié)點見 spiel.h可用于為隨機動作預留張量/緩存空間Leduc 的實現(xiàn)返回剩余牌數(shù)leduc_poker.cc 附近。8. 小結chance_outcomes()是 OpenSpiel 處理環(huán)境隨機性的統(tǒng)一入口它把自然的隨機選擇暴露為普通動作的帶概率列表讓 CFR 等算法可以窮舉、讓 MCCFR/MCTS 等算法可以采樣。理解它需要同時掌握三個層面接口語義返回歸一化的 (動作, 概率) 對僅隨機節(jié)點有效、游戲聲明kExplicitStochastic給出完整分布kSampledStochastic只給占位動作、消費模式is_chance_node()判定 →chance_outcomes()取值 →apply_action()/SampleAction()推進。以此為起點即可在自己的博弈算法中正確處理任何含隨機性的游戲環(huán)境。贊分享人工智能強化學習深度學習【免費下載鏈接】open_spielOpenSpiel is a collection of environments and algorithms for research in general reinforcement learning and search/planning in games.項目地址https://gitcode.com/gh_mirrors/op/open_spiel點擊查看免費下載相關推薦PyTorch3D sample_pdf 深度解析NeRF 分層采樣中的概率密度采樣器PyTorch3D sample_pdf 深度解析NeRF 分層采樣中的概率密度采樣器 本篇文章聚焦 PyTorch3D 中 pytorch3d.render人工智能深度學習計算機視覺圖形學微信、QQ、TIM 防撤回完整指南RevokeMsgPatcher 補丁操作步驟與報錯排查微信、QQ、TIM 防撤回完整指南RevokeMsgPatcher 補丁操作步驟與報錯排查 消息剛發(fā)出來轉眼就要被撤走還能不能留住RevokeMsgPa桌面應用即時通訊Loki日志采樣算法深度解析隨機采樣與系統(tǒng)采樣的終極對比指南Loki日志采樣算法深度解析隨機采樣與系統(tǒng)采樣的終極對比指南 Loki是一個開源、高擴展性和多租戶的日志聚合系統(tǒng)由Grafana Labs開發(fā)。它主要用于收可觀測性日志分析后端微服務對象存儲云原生上一篇IcemacOS菜單欄管理的終極解決方案讓你的桌面整潔如新下一篇Marketing Skills 項目中的 SavvyCal 調度平臺集成指南API 與 CLI 實戰(zhàn)全解創(chuàng)作聲明:本文部分內容由AI輔助生成(AIGC),僅供參考