gpt4 book ai didi

python - Clojure 与 Numpy 中的矩阵乘法

转载 作者:IT老高 更新时间:2023-10-28 21:34:07 28 4
gpt4 key购买 nike

我正在使用 Clojure 开发一个应用程序,该应用程序需要将大型矩阵相乘,与相同的 Numpy 版本相比,我遇到了一些较大的性能问题。 Numpy 似乎能够在一秒钟内将一个 1,000,000x23 矩阵乘以它的转置,而等效的 clojure 代码则需要六分钟以上。 (我可以从 Numpy 打印出结果矩阵,所以它肯定会评估所有内容)。

我在这个 Clojure 代码中做错了什么吗?是否有一些我可以尝试模仿的 Numpy 技巧?

这是 python :

import numpy as np

def test_my_mult(n):
A = np.random.rand(n*23).reshape(n,23)
At = A.T

t0 = time.time()
res = np.dot(A.T, A)
print time.time() - t0
print np.shape(res)

return res

# Example (returns a 23x23 matrix):
# >>> results = test_my_mult(1000000)
#
# 0.906938076019
# (23, 23)

还有clojure:

(defn feature-vec [n]
(map (partial cons 1)
(for [x (range n)]
(take 22 (repeatedly rand)))))

(defn dot-product [x y]
(reduce + (map * x y)))

(defn transpose
"returns the transposition of a `coll` of vectors"
[coll]
(apply map vector coll))

(defn matrix-mult
[mat1 mat2]
(let [row-mult (fn [mat row]
(map (partial dot-product row)
(transpose mat)))]
(map (partial row-mult mat2)
mat1)))

(defn test-my-mult
[n afn]
(let [xs (feature-vec n)
xst (transpose xs)]
(time (dorun (afn xst xs)))))

;; Example (yields a 23x23 matrix):
;; (test-my-mult 1000 i/mmult) => "Elapsed time: 32.626 msecs"
;; (test-my-mult 10000 i/mmult) => "Elapsed time: 628.841 msecs"

;; (test-my-mult 1000 matrix-mult) => "Elapsed time: 14.748 msecs"
;; (test-my-mult 10000 matrix-mult) => "Elapsed time: 434.128 msecs"
;; (test-my-mult 1000000 matrix-mult) => "Elapsed time: 375751.999 msecs"


;; Test from wikipedia
;; (def A [[14 9 3] [2 11 15] [0 12 17] [5 2 3]])
;; (def B [[12 25] [9 10] [8 5]])

;; user> (matrix-mult A B)
;; ((273 455) (243 235) (244 205) (102 160))

更新:我使用 JBLAS 实现了相同的基准测试。库并发现了巨大的速度改进。感谢大家的意见!是时候用 Clojure 包装这个傻瓜了。这是新代码:

(import '[org.jblas FloatMatrix])

(defn feature-vec [n]
(FloatMatrix.
(into-array (for [x (range n)]
(float-array (cons 1 (take 22 (repeatedly rand))))))))

(defn test-mult [n]
(let [xs (feature-vec n)
xst (.transpose xs)]
(time (let [result (.mmul xst xs)]
[(.rows result)
(.columns result)]))))

;; user> (test-mult 10000)
;; "Elapsed time: 6.99 msecs"
;; [23 23]

;; user> (test-mult 100000)
;; "Elapsed time: 43.88 msecs"
;; [23 23]

;; user> (test-mult 1000000)
;; "Elapsed time: 383.439 msecs"
;; [23 23]

(defn matrix-stream [rows cols]
(repeatedly #(FloatMatrix/randn rows cols)))

(defn square-benchmark
"Times the multiplication of a square matrix."
[n]
(let [[a b c] (matrix-stream n n)]
(time (.mmuli a b c))
nil))

;; forma.matrix.jblas> (square-benchmark 10)
;; "Elapsed time: 0.113 msecs"
;; nil
;; forma.matrix.jblas> (square-benchmark 100)
;; "Elapsed time: 0.548 msecs"
;; nil
;; forma.matrix.jblas> (square-benchmark 1000)
;; "Elapsed time: 107.555 msecs"
;; nil
;; forma.matrix.jblas> (square-benchmark 2000)
;; "Elapsed time: 793.022 msecs"
;; nil

最佳答案

Python 版本正在编译为 C 中的循环,而 Clojure 版本正在为此代码中的每个映射调用构建一个新的中间序列。您看到的性能差异很可能来自数据结构的差异。

为了比这更好,您可以使用像 Incanter 这样的库。或按照 this SO question 中的说明编写您自己的版本.另见this one , neanderthalnd4j .如果您真的想保留序列以保持惰性评估属性等,那么您可以通过查看 transients 获得真正的提升。用于内部矩阵计算

编辑:忘记添加调优clojure的第一步,打开“反射警告”

关于python - Clojure 与 Numpy 中的矩阵乘法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8899773/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com