日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
Python對陣Julia:機器學習實例

在之前談到的保序回歸加速話題中,我們聊起如何利用Cython改進回歸算法的性能表現(xiàn)。我覺得將Python優(yōu)化代碼的性能表現(xiàn)與原生Julia方案加以比對能夠進一步明確大家對于速度提升的直觀感受。

今天的文章將承接上一篇,因此大家在進行閱讀前,不妨先對前文進行一番回顧、旨在掌握相關(guān)背景信息。

我們將借用前文中提到的兩種算法,并在這里就性能表現(xiàn)在Julia與Python之間展開一番比拼。

線性PAVA

相關(guān)Cython代碼可以通過Github上的scikit-learn進行下載,而Julia代碼則來自GitHub上的Isotonic.jl。

Julia代碼采用的是最為簡單的PAVA表達,不摻雜任何花哨的內(nèi)容與修飾;@inbounds宏的作用是客觀比較Cython的執(zhí)行效果并關(guān)閉bound check。

 
 
  1. function isotonic_regression(y::Vector{Float64}, weights::Vector{Float64})  
  2.     @inbounds begin  
  3.         n = size(y, 1)  
  4.         if n <= 1 
  5.             return y  
  6.         end  
  7.         n -= 1 
  8.         while true  
  9.             i = 1 
  10.             pooled = 0 
  11.             while i <= n  
  12.                 k = i  
  13.                 while k <= n && y[k] >= y[k+1]  
  14.                     k += 1 
  15.                 end  
  16.    
  17.                 # Find a decreasing subsequence, and update  
  18.                 # all points in the sequence to the weighted average.  
  19.                 if y[i] != y[k]  
  20.                     numerator = 0.0 
  21.                     denominator = 0.0 
  22.                     for j in i : k  
  23.                         numerator += y[j] * weights[j]  
  24.                         denominator += weights[j]  
  25.                     end  
  26.    
  27.                     for j in i : k  
  28.                         y[j] = numerator / denominator  
  29.                     end  
  30.                     pooled = 1 
  31.                 end  
  32.                 i = k + 1 
  33.             end  
  34.             if pooled == 0 
  35.                 break 
  36.             end  
  37.         end  
  38.     end  
  39.     return y  
  40. end  
  41.    
  42. isotonic_regression(y::Vector{Float64}) = isotonic_regression(y, ones(size(y, 1)))  

linear_pava.jl hosted with by GitHub

 
 
  1. @cython.boundscheck(False)  
  2. @cython.wraparound(False)  
  3. @cython.cdivision(True)  
  4. def _isotonic_regression(np.ndarray[DOUBLE, ndim=1] y,  
  5.                          np.ndarray[DOUBLE, ndim=1] weight,  
  6.                          np.ndarray[DOUBLE, ndim=1] solution):  
  7.     cdef:  
  8.         DOUBLE numerator, denominator  
  9.         Py_ssize_t i, pooled, n, k  
  10.    
  11.     n = y.shape[0]  
  12.     # The algorithm proceeds by iteratively updating the solution  
  13.     # array.  
  14.    
  15.     # TODO - should we just pass in a pre-copied solution  
  16.     # array and mutate that?  
  17.     for i in range(n):  
  18.         solution[i] = y[i]  
  19.    
  20.     if n <= 1:  
  21.         return solution  
  22.    
  23.     n -= 1 
  24.     while 1:  
  25.         # repeat until there are no more adjacent violators.  
  26.         i = 0 
  27.         pooled = 0 
  28.         while i < n: 
  29.             k = i 
  30.             while k < n and solution[k] >= solution[k + 1]:  
  31.                 k += 1  
  32.             if solution[i] != solution[k]:  
  33.                 # solution[i:k + 1] is a decreasing subsequence, so  
  34.                 # replace each point in the subsequence with the  
  35.                 # weighted average of the subsequence.  
  36.    
  37.                 # TODO: explore replacing each subsequence with a  
  38.                 # _single_ weighted point, and reconstruct the whole  
  39.                 # sequence from the sequence of collapsed points.  
  40.                 # Theoretically should reduce running time, though  
  41.                 # initial experiments weren't promising.  
  42.                 numerator = 0.0  
  43.                 denominator = 0.0  
  44.                 for j in range(i, k + 1):  
  45.                     numerator += solution[j] * weight[j]  
  46.                     denominator += weight[j]  
  47.                 for j in range(i, k + 1):  
  48.                     solution[j] = numerator / denominator  
  49.                 pooled = 1 
  50.             i = k + 1  
  51.         # Check for convergence  
  52.         if pooled == 0:  
  53.             break  
  54.    
  55.     return solution  

_isotonic.pyx hosted with by GitHub

Active Set

Active Set的行數(shù)與Cython代碼基本相當,而且在結(jié)構(gòu)上可能更為簡潔(通過顯式復合type ActiveState實現(xiàn))、旨在維持給定主動雙重變量中的參數(shù)。Active Set會將重復代碼拆分為獨立函數(shù),從而由LLVM對其實現(xiàn)內(nèi)聯(lián)——這一點很難借由Cython中的任何參數(shù)實現(xiàn)。

Julia中的檢索機制也會對算法作出一定程度的精簡。

 
 
  1. immutable ActiveState  
  2.     weighted_label::Float64  
  3.     weight::Float64  
  4.     lower::Int64  
  5.     upper::Int64  
  6.    
  7. end  
  8.    
  9. function merge_state(l::ActiveState, r::ActiveState)  
  10.     return ActiveState(l.weighted_label + r.weighted_label,  
  11.                        l.weight + r.weight,  
  12.                        l.lower,  
  13.                        r.upper)  
  14. end  
  15.    
  16. function below(l::ActiveState, r::ActiveState)  
  17.     return l.weighted_label * r.weight <= l.weight * r.weighted_label  
  18. end  
  19.    
  20. function active_set_isotonic_regression(y::Vector{Float64}, weights::Vector{Float64})  
  21.     @inbounds begin  
  22.         active_set = [ActiveState(weights[i] * y[i], weights[i], i, i) for i in 1 : size(y, 1)]  
  23.         current = 1 
  24.         while current < size(active_set, 1)  
  25.             while current < size(active_set, 1) && below(active_set[current], active_set[current+1])  
  26.                 current += 1 
  27.             end  
  28.             if current == size(active_set, 1)  
  29.                 break 
  30.             end  
  31.    
  32.             merged = merge_state(active_set[current], active_set[current+1])  
  33.             splice!(active_set, current:current+1, [merged])  
  34.             while current > 1 && !below(active_set[current-1], active_set[current])  
  35.                 current -= 1 
  36.                 merged = merge_state(active_set[current], active_set[current+1])  
  37.                 splice!(active_set, current:current+1, [merged])  
  38.             end  
  39.         end  
  40.    
  41.         for as in active_set  
  42.             y[as.lower:as.upper] = as.weighted_label / as.weight  
  43.         end  
  44.     end  
  45.     return y  
  46. end  
  47.    
  48. active_set_isotonic_regression(y::Vector{Float64}) = active_set_isotonic_regression(y, ones(size(y, 1)))  

active_set.jl hosted with by GitHub

 
 
  1. @cython.boundscheck(False)  
  2. @cython.wraparound(False)  
  3. @cython.cdivision(True)  
  4. def _isotonic_regression(np.ndarray[DOUBLE, ndim=1] y,  
  5.                          np.ndarray[DOUBLE, ndim=1] weight,  
  6.                          np.ndarray[DOUBLE, ndim=1] solution):  
  7.    
  8.     cdef:  
  9.         Py_ssize_t current, i  
  10.         unsigned int len_active_set  
  11.         DOUBLE v, w  
  12.    
  13.     len_active_set = y.shape[0]  
  14.     active_set = [[weight[i] * y[i], weight[i], [i, ]]  
  15.                   for i in range(len_active_set)]  
  16.     current = 0 
  17.    
  18.     while current < len_active_set - 1:  
  19.         while current < len_active_set -1 and \  
  20.               (active_set[current][0] * active_set[current + 1][1] <=   
  21.                active_set[current][1] * active_set[current + 1][0]):  
  22.             current += 1 
  23.    
  24.         if current == len_active_set - 1:  
  25.             break 
  26.    
  27.         # merge two groups  
  28.         active_set[current][0] += active_set[current + 1][0]  
  29.         active_set[current][1] += active_set[current + 1][1]  
  30.         active_set[current][2] += active_set[current + 1][2]  
  31.    
  32.         active_set.pop(current + 1)  
  33.         len_active_set -= 1 
  34.         while current > 0 and \  
  35.               (active_set[current - 1][0] * active_set[current][1] >   
  36.                active_set[current - 1][1] * active_set[current][0]):  
  37.             current -= 1 
  38.             active_set[current][0] += active_set[current + 1][0]  
  39.             active_set[current][1] += active_set[current + 1][1]  
  40.             active_set[current][2] += active_set[current + 1][2]  
  41.    
  42.             active_set.pop(current + 1)  
  43.             len_active_set -= 1 
  44.    
  45.     for v, w, idx in active_set:  
  46.         solution[idx] = v / w  
  47.     return solution  

_isotonic.pyx hosted with  by GitHub

性能表現(xiàn)

可以看到,在與Cython實例進行比對時,我們發(fā)現(xiàn)即使是同樣的算法在Julia中的平均執(zhí)行速度也會更快。


[點擊擴大]

對于上述Active Set實例,Julia在處理回歸計算時的表現(xiàn)都能實現(xiàn)5倍到300倍的速度提升。

對于線性PAVA實例,Julia的速度提升效果則為1.1倍到4倍之間。

這樣的結(jié)果證明,Julia在性能敏感型機器學習應用領(lǐng)域具有顯著吸引力。

大家可以點擊此處了解更多關(guān)于上述性能測試結(jié)果的獲取方法。

英文原文:http://tullo.ch/articles/python-vs-julia/


文章標題:Python對陣Julia:機器學習實例
標題鏈接:http://www.dlmjj.cn/article/djihggj.html