【Python 】性能優(yōu)化系列:隨機數

最近在做的項目重點部分與大量生成隨機數有關,維度高達[1700000,10000],需要生成 10 x 30 次左右,這里遇到內存和速度的雙重瓶頸,特地研究了一下如何優(yōu)化隨機數。

優(yōu)化時間測試所需的分析工具在另一篇博客《性能優(yōu)化系列一:分析工具》中提到。

如何生成隨機數

原生的python中也有隨機模塊生成random.randintrandom.random等,但是速度非常慢,numpy 速度可以大幅提升。一般都采用numpy生成隨機數。

from numpy import random
random.rand()#生成0-1隨機float數
random.rand(n)#生成0-1 n長度arrayl
random.randn(n)#一樣生成正太分布n個隨機數
random.uniform(a,b)#生成(a,b)之間均勻隨機數
random.randint(a,b,size,dtype)
#a必須<b,b可以不填表示無窮大,dtype表示int32 or float64等
random.choice(a,[,size,replace])#從a中隨機選擇隨機數
random.shuffle(x[.random])#將一個列表打亂
random.permutation(x)#隨機擾動一個序列
random exponential/binomial...()#各種分布的隨機數
random.seed()

比較常用的就是以上幾種。在需要生成大量隨機數的情況下,或生成偽隨機數的情況下,python 3.7 常用 RandomState

rng = np.random.RandomState(seed)
rng.standard_normal(size)
rng.randint(low,high,size)
...

內存問題

共享seed

直接生成大規(guī)模非稀疏矩陣如下,經常遇到MemoryError的錯誤,大概是同時生成多個float64精度的大規(guī)模隨機矩陣服務器內存不夠,而random state 似乎也沒提供調整類型的attr,

def getRandomMatrix(seed,D,d):
    rng = np.random.RandomState(seed)
    A = rng.standard_normal((D, d),dtype=np.double)
    return A

這時最好使用即使生成即使銷毀,僅保留種子作為索引,同樣,多個CPU之間共享大規(guī)模矩陣涉及到共享內存或數據傳輸同步較慢的問題,最好也共享seed而不是直接共享矩陣。

ps. 這里注意一般我們設置time.time()為種子時,對于并發(fā)性程序是無效的,不要在并發(fā)程序中同時定義,建議生成一個seed list 列表再從中取。

分片操作

這里可以對大規(guī)模矩陣進行分片以進行后續(xù)的np 乘法,再切片賦值,以時間換內存。這種情況的麻煩在于如果設定隨機數種子會導致每個分片的隨機數相同??梢岳靡粋€最初seed(爺爺種子)randint生成 一組切片組數的seed(父親種子),再每次從中取不同的隨機數。

def function(x,y,seed,s,D,d):
    tmp = np.empty((D,))
    for j in range(0,D,s):
        if j+s > D:
            s = D-1-j
        tmp[j:j+s,] = np.dot(getRandomVector(seed,s,D,d),y)
        x = 1.0 * x + tmp
    return x

時間優(yōu)化

在上述切片方法嘗試之后,可以解決內存問題。但是時間非常慢,特別是采取s = 1時在standard normal 上調用170萬次的時間長達3000s,line search一下搜索了大約100000為切片值仍然太慢。在文檔中發(fā)現了BitGeneratorGenerator,大約可以提速到原來的 1/3。

# RandomState
def getRandomVector2(ini_seed,idx,s,D,d):
    rng = np.random.RandomState(ini_seed)
    child_seed = rng.randint(0,999999,size = (D,))
    rng = np.random.RandomState(child_seed[idx])
    random_vector = rng.standard_normal((s,d))
    return random_vector

# Generator
def getRandomVector(ini_seed,idx,s,D,d):
    rng = default_rng(ini_seed)
    child_seed = rng.integers(0,999999,size = (D,))
    rng2 = default_rng(child_seed[idx])
    return rng2.standard_normal((s,d))

其他方法

除了Numpy和基本模塊之外,AES CTR 加密算法生成隨機數也很快,但是并不能有比較方便的方式控制每次生成的一樣。參見以下reference。

tensorflow 和 pytorch 也都有大規(guī)模生成隨機tensor的方式。性能待考。

Reference

1. 超快生成隨機數的方式CSDN博客
2. tensorflow 生成隨機tensor

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內容