You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何持久化Python random状态以跨程序运行复现随机游戏?

如何正确持久化random生成器状态以复现特定游戏过程

我需要保存应用当前的random生成器状态,用来复现过程中执行的大量随机操作。

初始实现及问题

初始代码如下:

import random
import pickle
from Model import Resnet
def main():
    fileName = "09-08-2022T200803"
    with open("data/" + fileName + ".txt", "rb") as rb:
        data = pickle.load(rb)
        random.setstate(data[0][0])
# data[0][0]是已保存的随机状态对象,文件仅做追加操作,该对象始终相同

    myNetwork = Resnet.Network()
    model = myNetwork.getModel()

    playGame(model, 4, fileName)

首次运行得到游戏结果:

Turn: 14, Action:251
Turn: 15, Action:33
Turn: 15, Action:186
Turn: 15, Action:16
GAME_FINISHED

但关闭程序重新运行后,结果不一致:

Turn: 13, Action:251
Turn: 14, Action:29
Turn: 14, Action:251
Turn: 15, Action:33
GAME_FINISHED

我发现同一程序内循环运行时能完全复现,但重启程序后不行,推测是Resnet.Network()初始化过程修改了随机状态。

第二种尝试及问题

另一种实现方式在同一程序运行时结果一致,但跨程序运行仍有差异:

def main():
    myNetwork = Resnet.Network()
    model = myNetwork.getModel()

    fileName = "09-08-2022T200803"
    with open("data/"+fileName+".txt", "rb") as rb:
        while True:
            data = pickle.load(rb)
            playGame(model, 4, fileName, data[0][0])
# 每次读取文件得到的data[0][0]是同一个对象,因此单程序运行时有效


def playGame(model, simulations, fileName, seedObject = None):
    if seedObject != None:
        random.setstate(seedObject)
    # ... 游戏逻辑

问题

请问如何正确将random生成器状态持久化到文件,以复现特定出问题的游戏过程?(当前游戏逻辑完全基于随机数)


解决方案

核心问题是任何在random.setstate()之后、游戏逻辑执行之前的代码,只要调用了random模块的随机方法,都会改变生成器状态,导致复现失败。你的情况就是Resnet.Network()初始化过程中使用了随机数(比如权重初始化),打乱了已经恢复的状态。

方案1:分离随机实例(推荐)

为神经网络初始化和游戏逻辑分别使用独立的随机生成器,避免状态冲突:

  1. 修改Resnet.Network()的初始化逻辑,使用专属的random.Random()实例:
# Resnet.py中的Network类修改
class Network:
    def __init__(self):
        # 创建独立随机实例用于网络初始化
        self.rng = random.Random()
        # 后续权重初始化等操作都用self.rng,比如 self.rng.randn(...) 代替 random.randn(...)
    def getModel(self):
        # ... 原有逻辑
  1. 主程序中先恢复游戏用的随机状态,再初始化网络:
import random
import pickle
from Model import Resnet
def main():
    fileName = "09-08-2022T200803"
    with open("data/" + fileName + ".txt", "rb") as rb:
        data = pickle.load(rb)
        # 先恢复游戏逻辑的随机状态
        random.setstate(data[0][0])

    # 网络初始化用独立随机实例,不会干扰全局random状态
    myNetwork = Resnet.Network()
    model = myNetwork.getModel()

    playGame(model, 4, fileName)

方案2:固定前置操作顺序(无法修改Resnet代码时使用)

如果不能修改Resnet的代码,需保证首次运行和复现时的前置操作完全一致,再恢复游戏前的随机状态:

  1. 首次运行时,先初始化网络,再保存游戏开始前的随机状态:
def main():
    # 先完成所有会消耗随机数的初始化操作
    myNetwork = Resnet.Network()
    model = myNetwork.getModel()

    # 保存此时的全局随机状态(游戏开始前的基准状态)
    game_start_state = random.getstate()
    fileName = "09-08-2022T200803"
    # 将game_start_state写入文件保存
    with open("data/" + fileName + ".txt", "wb") as wb:
        pickle.dump([[game_start_state]], wb)
    
    # 运行游戏
    playGame(model, 4, fileName)
  1. 复现时,重复相同的初始化步骤,再恢复保存的状态:
def main():
    # 完全复刻首次运行的初始化流程
    myNetwork = Resnet.Network()
    model = myNetwork.getModel()

    fileName = "09-08-2022T200803"
    with open("data/" + fileName + ".txt", "rb") as rb:
        data = pickle.load(rb)
        # 恢复到游戏开始前的随机状态
        random.setstate(data[0][0])

    playGame(model, 4, fileName)

关键注意事项

  • 所有会调用随机数的前置操作(如模块导入、对象初始化),在首次运行和复现时的顺序必须完全一致;
  • 保存的随机状态必须是游戏逻辑开始前的最终状态,而非程序启动时的初始状态;
  • pickle序列化random.getstate()的返回值是官方支持的可靠方式,无需担心兼容性问题。

内容的提问来源于stack exchange,提问作者Lidbey

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 21:27:29