使用 `pytorch.manual_seed(seed)` 时是哪个种子?

Which seed when using `pytorch.manual_seed(seed)`?

我用 ImageNet 训练了一个模型。我有一个新的 GPU,我也想在不同的 GPU 上训练相同的模型。

我想比较结果是否不同,因此我想使用 torch.manual_seed(seed)

阅读文档后https://pytorch.org/docs/stable/generated/torch.manual_seed.html仍然不清楚,我应该为参数种子取哪个数字。

如何选择种子参数?我可以服用 10、100 或 1000 甚至更多或更少吗?为什么?

How to choose the seed parameter? Can I take 10, 100, or 1000 or even more or less and why?

除了声明种子是 64 位整数之外,您指向的 PyTorch 文档页面没有提及任何特殊内容。

是的,1000 就可以了。正如您对现代伪随机数生成器的期望,您所依赖的伪随机序列的统计特性 NOT 取决于种子的选择。

至于大多数 运行,您可能会重复使用前一个 运行 的种子,实际的做法是将随机种子作为命令行参数。在那些你必须拿出一个全新种子的情况下,你可以从头顶偷看一个,或者只是玩骰子来获得它。

重要的是有一个记录用于每个运行的种子。

好的,但是...

话虽如此,很多人似乎对“猜测”某个任意数字的任务感到不舒服。有(至少)两种常见的权宜之计以看似适当的“随机”方式获得一些种子。

第一个是使用操作系统官方源来获得真正的(不是伪的)随机位。在 Python 中,这通常呈现为 os.urandom()。因此,要将 Python 中的种子作为 64 位整数,您可以使用如下代码:

import  functools
import  os

# returns a list of 8 random small integers between 0 and 255
def get8RandomBytesFromOS():
    r8 = os.urandom(8)  # official OS entropy source
    byteCodes = list(map(ord, r8.decode('Latin-1')))  # type conversion
    return byteCodes

# make a single long integer from a list of 8 integers between 0 and 255
def getIntFromBytes(bs):
    # force highest bit to 0 to avoid overflow
    bs2 = [bs[0] if (bs[0] < 128) else (bs[0]-128)]  +  bs[1:8]
    num = functools.reduce(lambda acc,n: acc*256+n, bs2)
    return num

# Main user entry point:
def getRandomSeedFromOS():
   rbs8 = get8RandomBytesFromOS()
   return (getIntFromBytes(rbs8))

第二个常用的权宜之计是散列一个包含当前日期和时间的字符串,可能带有一些前缀。对于 Python,时间包括微秒。当人类用户启动脚本时,启动时间的微秒数可以说是随机。可以使用这样的代码,使用 SHA(安全哈希算法)的一个版本:

import  hashlib
import  datetime

def getRandomSeedFromTime():
    prefix      =  'dl.cs.univ-Whosebug.edu'
    timeString1 =  str(datetime.datetime.now())
    timeString2 =  prefix + ' ' + timeString1
    hash        =  hashlib.sha256(timeString2.encode('ascii'))
    bytes       =  (hash.digest())[24:32]  #  8 rightmost bytes of hash
    byteCodes   =  list(map(ord, bytes.decode('Latin-1')))  # type conversion
    return (getIntFromBytes(byteCodes))

不过,还是那句话,1000基本就OK了。散列时间字符串的想法,而不是仅仅将自 Epoch 以来的微秒数作为种子,可能来自这样一个事实,即一些早期的随机数生成器使用他们的种子作为 offset 到一个普通的但不是那么大的全局序列中。因此,如果您的程序在没有散列的情况下天真地以快速序列获取两个种子,则您的两个序列之间存在重叠的风险。幸运的是,现在的伪随机数生成器比以前好多了。

(附录——摘自评论)

注意种子是外围的东西。重要的是自动机的 state,它可以比种子大得多,因此才有了“种子”这个词。常用的 Mersenne Twister 方案有 ~20,000 位的内部状态,你不能要求用户提供 20,000 位。有时会有行为不当的初始状态,但 随机数库 始终有责任以某种方式将用户提供的任意种子扩展为行为良好的初始状态。