我繼承了一些代碼,并且有一個特定的操作花費了過多的時間。
操作定義為:
cutoff = 0.2
# X has shape (76187, 247, 20)
X_flat = X.reshape((X.shape[0], X.shape[1] * X.shape[2]))
weightfun = lambda x: 1.0 / np.sum(np.dot(X_flat, x) / np.dot(x, x) > 1 - cutoff)
# This is expensive...
N_list = np.array(list(map(weightfun, X_flat)))
這需要數小時才能在我的機器上進行計算。我想知道是否有辦法優化這一點。該代碼正在計算向量序列之間的歸一化漢明距離。
uj5u.com熱心網友回復:
weightfun 對 的每一行執行兩個點積運算X_flat。最糟糕的是np.dot(X_flat, x),對整個X_flat矩陣執行點積。但是有一個技巧可以加快速度。第一個點積中的迭代部分只能計算一次:
X_matmut = X_flat @ X_flat.T
另外,我注意到第二個點積只不過是第一個結果的對角線。
重寫后的代碼如下所示:
cutoff = 0.2
# X has shape (76187, 247, 20)
X_flat = X.reshape((X.shape[0], X.shape[1] * X.shape[2]))
X1 = X_flat @ X_flat.T
X2 = X1.diagonal()
N_list = 1.0 / (X1/X2 > 1 - cutoff).sum(axis=0)
編輯
對于如此大的輸入,當執行上面的操作時,記憶體成為新的瓶頸,因為新矩陣不適合 RAM。因此,還可以選擇將計算分解為塊,如下面的代碼所示。代碼有點亂,但至少它沒有試圖破壞我的 PC :-P
import numpy as np
import time
# Sample data
X = np.random.random([76187, 247, 20])
start = time.time()
cutoff = 0.2
X_flat = X.reshape((X.shape[0], X.shape[1] * X.shape[2]))
# Divide data into 20 chuncks
X_parts = np.array_split(X_flat, 20)
# Diagonal will be saved incrementally
diagonal = []
for i in range(len(X_parts)):
part = X_parts[i]
X_parts[i] = part @ X_flat.T
diagonal.extend(X_parts[i][range(len(X_parts[i])), range(len(diagonal), len(diagonal) len(X_parts[i]))])
# Performs the second part of the calculation
diagonal = np.array(diagonal)
X_list = np.zeros(len(diagonal))
for x in X_parts:
X_list = (x/diagonal > 1 - cutoff).sum(axis=0)
X_list = 1.0 / X_list
print('Time to solve: %.2f secs' % (time.time() - start))
我希望能夠在單個回圈中執行所有計算并丟棄使用過的塊,但必須遍歷整個矩陣一次以檢索對角線。不要相信將所有內容計算兩次以節省記憶體是值得的。
雖然我使用了不錯的設定(i7 英特爾和 SSD 驅動器中的 16 GB RAM 用于存盤),但整個處理程序花了我大約 15 分鐘。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/368012.html
上一篇:向量化“在”
