首先举几个使用seed()函数的例子:
# 生成随机数,以便固定后续随机数,方便复现代码
random.seed(args.seed)
# 没有使用GPU的时候设置的固定生成的随机数
np.random.seed(args.seed)
# 为CPU设置种子用于生成随机数,以使得结果是确定的
torch.manual_seed(args.seed)
# torch.cuda.manual_seed()为当前GPU设置随机种子
torch.cuda.manual_seed(args.seed)
从代码的复现结果上来讲,seed()的作用还是很大的,一般情况下,我们设置seed就是为了方便用来复现别人的代码或为了方便别人来复线自己的代码,使最终的结果保持一致,增加结果的稳定性。
这里先借鉴一下其他大佬们总结的一些关于seed的见解:
seed()用于指定随机数生成时所用算法开始的整数值,如果使用相同的seed()值,则每次生成的随即数都相同,如果不设置这个值,则系统根据时间来自己选择这个值,此时每次生成的随机数因时间差异而不同。且seed()可以一直生效直到下一次定义seed()时,若每次只调用一次seed(),则后续生成的随机数是固定的(根据一定的算法生成的固定随机数序列),若每次输出前都调用seed()函数,且种子数值相同,则输出的值是固定的,seed()作用是设定生成随机数的种子,目的是为了让结果具有重复性,重现结果。
这里想强调一个问题就是,seed()是仅一次有效还是一直有效直到下一个seed()的定义时失效?在我看来,是一直有效的直到下一个seed()的定义时失效,只要把seed(arg.sum)方法定义出来了,那么后续的代码中用到的随机数都是固定的。我们使用代码来验证一下:
import numpy as np
if __name__ == '__main__':
i = 0
print('====================第一个while循环开始====================')
while(i<8):
if(i<4):
# 每输出一次,在其之前就定义一次seed,看其四次的数值是否相同
np.random.seed(0)
print(np.random.randn(1,5))
else:
print(np.random.randn(1,5))
pass
i +=1
print('====================第一个while循环结束====================')
print('*'*50)
print('====================第二个while循环开始====================')
# 注意一下,看一下第二个while循环是否会受到第一个while循环中的seed的影响,是否是定义一次就失效了?
i = 0
while(i<2):
# 这是在循环里的输出随机数
print(np.random.randn(1,5))
i +=1
# 这是在循环外的输出随机数,看与上面循环里的输出是否有关系
print(np.random.randn(2,5))
# 注意这个seed是在第二个循环中定义的,目的是看是否会影响第三个while循环中的随机数值
np.random.seed(0)
print('====================第二个while循环结束====================')
print('*'*50)
# 第三个循环的目的就是为了和上述两个循环中的整体随机数进行比较
# 看一下seed的作用效果,是否一直生效,还是仅生效一次
print('====================第三个while循环开始====================')
i = 0
while(i<9):
print(np.random.randn(1,5))
i +=1
print('====================第三个while循环结束====================')
接下来我们看输出:
====================第一个while循环开始====================
[[1.76405235 0.40015721 0.97873798 2.2408932 1.86755799]]
[[1.76405235 0.40015721 0.97873798 2.2408932 1.86755799]]
[[1.76405235 0.40015721 0.97873798 2.2408932 1.86755799]]
[[1.76405235 0.40015721 0.97873798 2.2408932 1.86755799]]
[[-0.97727788 0.95008842 -0.15135721 -0.10321885 0.4105985 ]]
[[0.14404357 1.45427351 0.76103773 0.12167502 0.44386323]]
[[ 0.33367433 1.49407907 -0.20515826 0.3130677 -0.85409574]]
[[-2.55298982 0.6536186 0.8644362 -0.74216502 2.26975462]]
====================第一个while循环结束====================
**************************************************
====================第二个while循环开始====================
[[-1.45436567 0.04575852 -0.18718385 1.53277921 1.46935877]]
[[ 0.15494743 0.37816252 -0.88778575 -1.98079647 -0.34791215]]
[[ 0.15634897 1.23029068 1.20237985 -0.38732682 -0.30230275]
[-1.04855297 -1.42001794 -1.70627019 1.9507754 -0.50965218]]
====================第二个while循环结束====================
**************************************************
====================第三个while循环开始====================
[[1.76405235 0.40015721 0.97873798 2.2408932 1.86755799]]
[[-0.97727788 0.95008842 -0.15135721 -0.10321885 0.4105985 ]]
[[0.14404357 1.45427351 0.76103773 0.12167502 0.44386323]]
[[ 0.33367433 1.49407907 -0.20515826 0.3130677 -0.85409574]]
[[-2.55298982 0.6536186 0.8644362 -0.74216502 2.26975462]]
[[-1.45436567 0.04575852 -0.18718385 1.53277921 1.46935877]]
[[ 0.15494743 0.37816252 -0.88778575 -1.98079647 -0.34791215]]
[[ 0.15634897 1.23029068 1.20237985 -0.38732682 -0.30230275]]
[[-1.04855297 -1.42001794 -1.70627019 1.9507754 -0.50965218]]
====================第三个while循环结束====================
这里,我们主要使用了numpy中的seed()来进行示例,简单讲解一下三个循环的过程:
第一个循环我们前四次的输出分别使用了一次seed(),注意,里面的数值是相同的。从结果可以观察到,四次输出是一样的,这就说明了每当调用一次seed(),且里面的参数一样时,生成的随机数是一样的。但是后四次则不然,因为它仅使用了i=3时的seed(),往后则是有规律的生成了一系列的随机数。
第二个循环我们可能发现数值并没有什么规律,但是呢,第二次循环内未定义seed()函数,但是第一次循环里定义了seed(),那么则第二次循环会使用第一次循环的最后一次的seed(),也就是说第一次循环内定义的seed()会继续生效至下一次seed()定义之前,所以第二次无论是循环内还是循环外都是在用第一次循环内的seed(),故第二次循环内外的输出是使用的是第一次循环内的seed(),直到下一个seed()的定义。
第三次循环,我们可以发现在循环外定义了一个seed(),则第一个循环内定义的seed()已经失效了。第三个循环之前的seed()初始化为了新的seed()。我们可以发现,这两次seed()的定义内部的参数都是0,则表明它们生成的随机数值是相同的(这里指只定义一次)。
综上可知,对比第一次和第二次循环与第三次循环,我们可以得出结论:
(1) seed()会一直生效直到下一次定义时结束其使命
(2) seed(arg.num)内的arg.num不同,则生成的随机数值是不同的,数字不同,产生的结果不同(产生的随机数值不同)。只有数字相同,别人才能复现出来跟你一样的结果。所以有些老师让学生作业上用seed(ID)来防止作弊。
(3) 每当在输出前均调用一次同一个seed()时,输出的随机数值是相同的
(4) seed()用于指定随机数生成时所用算法开始的整数值
(5) 一个seed()定义后并一直生效的情况下,其往后生成的随机数值都是“固定的”,“有顺序的”。
(6) seed()的主要作用是为了代码的可复现性,其内部的数值一般不会对整体造成过大的影响,Stata的说明里说 “Without loss of pseudorandomness, the seed may be set to small numbers; e.g., seed(2),即可以设置很小,(不丢失伪随机性的前提下)没问题的。
以上就是个人的理解,总之,感觉seed的作用还是挺大的,但是在代码中显得十分弱小,容易使人忽略,其实seed()关乎全局的随机数的生成,关乎代码的可复现性。因此,其作用是不可小觑的。
以上就是个人对seed()的理解,感谢大家的阅读~