稀疏向量計算優化小結

2022-08-16 10:39:09 字數 4224 閱讀 9598

在各種演算法中,向量計算是最經常使用的一種操作之中的乙個。傳統的向量計算,學過中學數學的同學也能明確怎麼做。但在如今的大資料環境下。資料一般都會比較稀疏,因此稀疏向量的計算,跟普通向量計算。還是存在一些不同。

首先,我們定義兩個向量: a=

[x1,

x2,⋯

,xn]

b=[y1,y

2,⋯,

yn]

定義a、b的點積為a∗

b,要求a∗

b=?最直接的方式,當然就是按中學時候就學過的方法: a∗

b=x1

∗y1+

x2∗y

2+⋯+

xn∗y

n 先不考慮乘法與加法的差別,也不考慮計算精度問題。假設按上述方式進行計算。總共進行了n次乘法,n-1次加法,總複雜度為2n-1。矩陣乘法的基本計算單元是向量之間的乘法,複雜度為n3

。在如今的大資料環境之下,n可能會非常大,比方在計算廣告,或者文字分類中,上百萬維都是非常正常的。並且這樣的向量都有乙個特點,那就是非常稀疏。

假設沒有非常稀疏這個特點,那後面自然就無從談起了。。。

對於稀疏向量。自然而然的能夠想到按一下方式進行儲存: a:

b: 由於是稀疏向量。所以 i≪

n,j≪

n詳細在計算a*b的時候,能夠在向量a中迴圈,然後在向量b中進行二分查詢。比如,在向量a中取出第乙個非零元素。假設為

,loc

atio

n1>

,在b中對location1進行二分。假設找到,計算乘積。假設找不到。自然為0.

那我們來估算一下演算法的複雜度。在b中二分的複雜度為lo

gj,a的長度為

i,則這部分的總複雜度為il

ogj,加法的最大情況為mi

n(i,

j)−1

,總的複雜度為il

ogj+

min(

i,j)

−1當然,假設我們知道

i ,

j 的大小。能夠在小的向量上迴圈,在大的向量上二分,這樣複雜度能夠減少為 mi

n(i,

j)lo

g(ma

x(i,

j))+

min(

i,j)

−1假設咱們不用二分查詢,而是使用hash,則二分查詢部分能夠變為hash。假設hash的複雜度為1,那麼總的複雜度為2m

in(i

,j)。當然。我們忽略了建立hash的複雜度。以及hash碰撞的複雜度。

這樣,總的複雜度就由最初的2n

−1降到了2mi

n(i,

j)。假設n特別特別大,比方鳳巢系統動不動就是號稱上億維度。這樣i,j也不會特別小。假設是兩個矩陣相乘。咱們前面提到的。複雜度為n3

,這樣就必須上平行計算了。

搞資料的同學,對並行肯定不陌生,這裡不再細述了。

以上都是理論分析,為了驗證實際中的執行效果。特意編寫了一部分測試**。測試**例如以下

#!/usr/bin/env python

#coding:utf-8

'''created on 2023年4月22日

@author: lei.wang

'''import time

#二分查詢

defbin_search

(num,list):

low = 0

high = len(list) - 1

while(low <= high):

middle = (low + high) / 2

if list[middle] > num:

high = middle - 1

elif list[middle] < num:

low = middle + 1

else:

return middle

return -1

deft1

(): all = 1000000

sparse_rate = 1000

vec_a = [0

for i in range(all)]

vec_b = [0

for i in range(all)]

list_none_zero = [sparse_rate*i for i in range(all / sparse_rate)]

for i in list_none_zero:

vec_a[i] = vec_b[i] = 1

sum = 0

#a,b分別不為0的位置

location_a = [i for i in range(0,all,sparse_rate)]

location_b = [i for i in range(0,all,sparse_rate)]

start = time.clock()

for i in location_a:

location = bin_search(i, location_b) #相應a不為0的位置。在b不為0的位置陣列中查詢是否存在

if location != -1:

sum += vec_a[i] * vec_b[location_b[location]] #假設存在,將結果相加

end = time.clock()

print

"cost time is:",(end-start)

print

"sum is:",sum

deft2

(): all = 1000000

sparse_rate = 1000

vec_a = [0

for i in range(all)]

vec_b = [0

for i in range(all)]

list_of_none_zero = [sparse_rate*i for i in range(all / sparse_rate)]

for i in list_of_none_zero:

vec_a[i] = vec_b[i] = 1

sum = 0

start = time.clock()

for i in range(all):

sum += vec_a[i] * vec_b[i]

end = time.clock()

print

"cost time is:",(end-start)

print

"sum is:",sum

if __name__ == '__main__':

t1()

print

print

t2()

bin_search是自己實現的二分查詢,t1方法是用上面說到的二分查詢的方式,t2方法就是最簡單的直接遍歷相乘的方式。

在mac上執行以上**。結果例如以下:

cost time

is: 0.002319

sum is: 1000

cost time

is: 0.123861

sum is: 1000

能夠看出,遍歷的方式是二分查詢的方式的54倍!按上述咱們的分析方式,遍歷的方式應該是2∗

106的複雜度。二分查詢的方式應該是103

∗log

1000

,即10

4 左右的複雜度。二分查詢的方式比遍歷的方式應該要快100倍左右。

依據咱們實驗的結果來看,數量級上來說基本是差點兒相同的。假設採取一些優化方式。比方用python自帶的binset模組,應該會有更快的速度。

假設改變上述**中的稀疏度,即改變sparse_rate的數值,比如將sparse_rate由1000改為10000,執行的結果例如以下:

cost time

is: 0.000227

sum is: 100

cost time

is: 0.118492

sum is: 100

假設將sparse_rate改為100。執行的結果為:

cost time

is: 0.034885

sum is: 10000

cost time

is: 0.124176

sum is: 10000

非常easy看出來,對於遍歷的方式來說。無論稀疏度為多少,耗時都是基本不變的。可是對於我們採用二分查詢的方式來說,稀疏度越高,節省的計算資源,就越可觀。

幾何向量 計算光線折射refract向量

其實光線除了反射現象外,還有折射現象,打個比方,你看水塘中魚兒游動,表面上看起來魚兒很貼近水面,同時也感覺水底很淺,結果一腳捅下去,直接沒到大腿了,這就是光的折射產生的一種視覺欺騙。光線折射的產生,其實是因為光線通過不同介質所產生的 偏折 現象。ps 光線的 偏折 現象實際上和光的粒子性有關,這裡我...

複數計算和向量計算的區別

今天接觸到了量子計算,原理正在摸索,但是從數學角度,複數計算應該會用到。以前學習複數的時候,純屬應付考試,現在回想只記得乙個公式 今天週末,有時間縷一下,看幾個問題 1 複數裡用到了虛數,看了阮老師的一篇文章,虛數的意義何在 清晰了好多,上學的時候怎麼沒想過這些問題呢?2 看起來複數計算好像跟向量計...

Numpy中向量與標量計算

加減乘除冪運算 import numpy as np a np.array 1,2,3 b np.array 3,2,1 print a 10 對應位置依次相加 print a 2 print 1,2,3 2 print a b print a b print a b print a b print...