zoukankan      html  css  js  c++  java
  • Pytorch中的随机性问题:np.random.seed()、np.random.RandomState()、cudnn.benchmark和cudnn.deterministic

    一、

    在利用python处理数据的时候,经常会用到numpy API:

    np.random.seed() 与 np.random.RandomState()

    但这两个函数的用法,一直不太好理解。在网上查找了许多文章,研究了下他们的异同。做个记录。

    1,np.random.seed()

    设置seed()里的数字就相当于设置了一个盛有随机数的“聚宝盆”,一个数字代表一个“聚宝盆”。

    当在seed()的括号里设置相同的seed,“聚宝盆”就是一样的,当然每次拿出的随机数就会相同。

    如果不设置seed,则每次会生成不同的随机数,但是有时候明明设置了seed()没有变,生成的随机数组还是不同。

    np.random.seed(0)
    a = np.random.rand(10)
    b = np.random.rand(10)
    print(a)
    print("
    ")
    print(b)
    
    
    #输出结果
    [0.5488135  0.71518937 0.60276338 0.54488318 0.4236548  0.64589411
     0.43758721 0.891773   0.96366276 0.38344152]
    
    
    [0.79172504 0.52889492 0.56804456 0.92559664 0.07103606 0.0871293
     0.0202184  0.83261985 0.77815675 0.87001215]

    设置了seed没变,但是输出不一样。

    其实,第二遍的np.random.rand(10)已经不是在之前设置的np.random.seed(0)下了,所以第二遍的随机数组只是在默认random下随机挑选的样本数值。

    那如何让两次随机数组一样?

    只需要再输入一遍np.random.seed(0)。

    np.random.seed(0)
    a = np.random.rand(4,3)
    
    np.random.seed(0)
    b =  np.random.rand(4,3)
    
    print(a)
    print("
    ")
    print(b)
    
    
    #输出
    [[0.5488135  0.71518937 0.60276338]
     [0.54488318 0.4236548  0.64589411]
     [0.43758721 0.891773   0.96366276]
     [0.38344152 0.79172504 0.52889492]]
    
    
    [[0.5488135  0.71518937 0.60276338]
     [0.54488318 0.4236548  0.64589411]
     [0.43758721 0.891773   0.96366276]
     [0.38344152 0.79172504 0.52889492]]

    用两个自定义函数举例,进一步理解下np.random.seed()的用法

    def rng():
        for i in range(5):
            np.random.seed(123)
            print(np.random.rand(4))
    
    rng()
    
    
    #输出
    [0.69646919 0.28613933 0.22685145 0.55131477]
    [0.69646919 0.28613933 0.22685145 0.55131477]
    [0.69646919 0.28613933 0.22685145 0.55131477]
    [0.69646919 0.28613933 0.22685145 0.55131477]
    [0.69646919 0.28613933 0.22685145 0.55131477]
    
    
    
    def rng2():
        np.random.seed(123)
        for i in range(5):
            print(np.random.rand(4))
            
    rng2()
    
    
    #输出
    [0.69646919 0.28613933 0.22685145 0.55131477]
    [0.71946897 0.42310646 0.9807642  0.68482974]
    [0.4809319  0.39211752 0.34317802 0.72904971]
    [0.43857224 0.0596779  0.39804426 0.73799541]
    [0.18249173 0.17545176 0.53155137 0.53182759]

     

    2,np.random.RandomState()

    numpy.random.RandomState()是一个伪随机数生成器, 此命令将会产生一个随机状态种子,在该状态下生成的随机序列(正态分布)一定会有相同的模式。

    伪随机数是用确定性的算法计算出来的似来自[0,1]均匀分布的随机数序列。并不真正的随机,但具有类似于随机数的统计特征,如均匀性、独立性等。(来自百度)

     

    但是,不同的随机种子状态将会有不同的数据生成模式。这一特点在随机数据生成的统计格式控制显得很重要。

    np.random.RandomState()跟numpy.random.seed()的用法几乎一样。

    rng = np.random.RandomState(0)
    a = rng.rand(4)
    
    rng = np.random.RandomState(0)
    b = rng.rand(4)
    
    print(a)
    print("
    ")
    print(b)
    
    #输出
    [0.5488135  0.71518937 0.60276338 0.54488318]
    
    
    [0.5488135  0.71518937 0.60276338 0.54488318]

    生成一样的随机数组,这点和numpy.random.seed()是一样的因为是伪随机数,所以必须在rng这个变量下使用,如果不这样做,就得不到相同的随机数组。

    即便再次输入numpy.random.RandomState(),这是因为np.random.rand()在默认状态下,是从默认随机数组里挑出的随机样本

    rng = np.random.RandomState(0)
    a = rng.randn(4)
    b = rng.randn(4)
    
    print(a)
    print(b)
    
    #输出
    [1.76405235 0.40015721 0.97873798 2.2408932 ]
    [ 1.86755799 -0.97727788  0.95008842 -0.15135721]

    同样用用两个自定义函数举例,进一步理解下np.random.RandomState()的用法

    def rng1():
        for i in range(4):
            rng = np.random.RandomState(0)
            print("i = ",i)
            print(rng.rand(3,2))
    rng1()
    
    
    #输出
    i =  0
    [[0.5488135  0.71518937]
     [0.60276338 0.54488318]
     [0.4236548  0.64589411]]
    i =  1
    [[0.5488135  0.71518937]
     [0.60276338 0.54488318]
     [0.4236548  0.64589411]]
    i =  2
    [[0.5488135  0.71518937]
     [0.60276338 0.54488318]
     [0.4236548  0.64589411]]
    i =  3
    [[0.5488135  0.71518937]
     [0.60276338 0.54488318]
     [0.4236548  0.64589411]]
    
    
    
    
    def rng3():
        rng =np.random.RandomState(0)
        for i in range(4):
            print("i = ",i)
            print(rng.rand(3,2))
    rng3()
    
    #输出
    i =  0
    [[0.5488135  0.71518937]
     [0.60276338 0.54488318]
     [0.4236548  0.64589411]]
    i =  1
    [[0.43758721 0.891773  ]
     [0.96366276 0.38344152]
     [0.79172504 0.52889492]]
    i =  2
    [[0.56804456 0.92559664]
     [0.07103606 0.0871293 ]
     [0.0202184  0.83261985]]
    i =  3
    [[0.77815675 0.87001215]
     [0.97861834 0.79915856]
     [0.46147936 0.78052918]]
    编辑于 2020-11-06
    原文链接:https://zhuanlan.zhihu.com/p/66507920#:~:text=numpy.random.RandomState()%E6%98%AF,%E4%BC%9A%E6%9C%89%E7%9B%B8%E5%90%8C%E7%9A%84%E6%A8%A1%E5%BC%8F%E3%80%82&text=%E4%BD%86%E6%98%AF%EF%BC%8C%E4%B8%8D%E5%90%8C%E7%9A%84%E9%9A%8F%E6%9C%BA%E7%A7%8D%E5%AD%90,%E4%B8%8D%E5%90%8C%E7%9A%84%E6%95%B0%E6%8D%AE%E7%94%9F%E6%88%90%E6%A8%A1%E5%BC%8F%E3%80%82

    问题

    在很多情况下我们都能看到代码里有这样一行:

    torch.backends.cudnn.benchmark = true

    1

    torch.backends.cudnn.benchmark = true

    而且大家都说这样可以增加程序的运行效率。那到底有没有这样的效果,或者什么情况下应该这样做呢?

    解决办法

    总的来说,大部分情况下,设置这个 flag 可以让内置的 cuDNN 的 auto-tuner 自动寻找最适合当前配置的高效算法,来达到优化运行效率的问题。

    一般来讲,应该遵循以下准则:

    1. 如果网络的输入数据维度或类型上变化不大,设置  torch.backends.cudnn.benchmark = true  可以增加运行效率;
    2. 如果网络的输入数据在每次 iteration 都变化的话,会导致 cnDNN 每次都会去寻找一遍最优配置,这样反而会降低运行效率。

    这下就清晰明了很多了。

    转载:https://www.pytorchtutorial.com/when-should-we-set-cudnn-benchmark-to-true/


    为什么使用相同的网络结构,跑出来的效果完全不同,用的学习率,迭代次数,batch size 都是一样?固定随机数种子是非常重要的。但是如果你使用的是PyTorch等框架,还要看一下框架的种子是否固定了。还有,如果你用了cuda,别忘了cuda的随机数种子。这里还需要用到torch.backends.cudnn.deterministic.

    torch.backends.cudnn.deterministic是啥?顾名思义,将这个 flag 置为True的话,每次返回的卷积算法将是确定的,即默认算法。如果配合上设置 Torch 的随机种子为固定值的话,应该可以保证每次运行网络的时候相同输入的输出是固定的,代码大致这样

    def init_seeds(seed=0):
        torch.manual_seed(seed) # sets the seed for generating random numbers.
        torch.cuda.manual_seed(seed) # Sets the seed for generating random numbers for the current GPU. It’s safe to call this function if CUDA is not available; in that case, it is silently ignored.
        torch.cuda.manual_seed_all(seed) # Sets the seed for generating random numbers on all GPUs. It’s safe to call this function if CUDA is not available; in that case, it is silently ignored.
    
        if seed == 0:
            torch.backends.cudnn.deterministic = True
            torch.backends.cudnn.benchmark = False
    编辑于 2020-05-15
     
    原文链接:https://zhuanlan.zhihu.com/p/141063432



    如果这篇文章帮助到了你,你可以请作者喝一杯咖啡

  • 相关阅读:
    Security and Cryptography in Python
    Security and Cryptography in Python
    Security and Cryptography in Python
    Security and Cryptography in Python
    Security and Cryptography in Python
    Security and Cryptography in Python
    Security and Cryptography in Python
    微信小程序TodoList
    C语言88案例-找出数列中的最大值和最小值
    C语言88案例-使用指针的指针输出字符串
  • 原文地址:https://www.cnblogs.com/sddai/p/14606613.html
Copyright © 2011-2022 走看看