ไลบรารีการจัดการเมทริกซ์ที่รวดเร็วสำหรับ Elixir ที่ใช้งานในโค้ดเนทิฟ C พร้อมด้วย CBLAS sgemm() ที่ได้รับการปรับปรุงประสิทธิภาพอย่างสูง ซึ่งใช้สำหรับการคูณเมทริกซ์
ตัวอย่างเช่น การถดถอยเชิงเส้นแบบเวกเตอร์จะเร็วกว่าการใช้เธรดเดี่ยวระดับแปดเทฟประมาณ 13 เท่า
นอกจากนี้ยังมีหน่วยความจำที่มีประสิทธิภาพ ดังนั้นคุณจึงสามารถทำงานกับเมทริกซ์ขนาดใหญ่ซึ่งมีขนาดประมาณพันล้านองค์ประกอบได้
อิงตามโค้ดเมทริกซ์จากhttps://gitlab.com/sdwolfz/experimental/-/tree/master/exlearn
MacBook Pro ปี 2015, Core i7 2.2 GHz, RAM 16 GB
การดำเนินการจะดำเนินการกับเมทริกซ์ขนาด 3,000 × 3,000 ที่เต็มไปด้วยตัวเลขสุ่ม
คุณสามารถเรียกใช้การวัดประสิทธิภาพได้จากโฟลเดอร์ /bench
ด้วยคำสั่ง python numpy_bench.py
และ MIX_ENV=bench mix bench
benchmark iterations average time
logistic_cost() 1000 1.23 ms/op
np.divide(A, B) 100 15.43 ms/op
np.add(A, B) 100 14.62 ms/op
sigmoid(A) 50 93.28 ms/op
np.dot(A, B) 10 196.57 ms/op
benchmark iterations average time
logistic_cost() 1000 1.23 ms/op (on par)
divide(A, B) 200 7.32 ms/op (~ 2× faster)
add(A, B) 200 7.71 ms/op (~ 2× faster)
sigmoid(A) 50 71.47 ms/op (23% faster)
dot(A, B) 10 213.31 ms/op (8% slower)
การสังหารผู้บริสุทธิ์จริงๆ
MacBook Pro ปี 2015, Core i7 2.2 GHz, RAM 16 GB
ดอทโปรดัคของเมทริกซ์ขนาด 500×500
ห้องสมุด | การดำเนินการ/วินาที | เทียบกับเมเทร็กซ์ |
---|---|---|
แมทริกซ์ | 674.70 | |
เมทริกซ์ | 0.0923 | 7 312.62× ช้าลง |
นูเม็กซี่ | 0.0173 | 38 906.14× ช้าลง |
เอ็กซ์แมทริกซ์ | 0.0129 | 52 327.40× ช้าลง |
ดอทโปรดัคของเมทริกซ์ 3×3
ห้องสมุด | ปฏิบัติการ/วินาที | เทียบกับเมเทร็กซ์ |
---|---|---|
แมทริกซ์ | 3624.36 ก | |
กราฟคณิตศาสตร์ | 1310.16 ก | ช้าลง 2.77 เท่า |
เมทริกซ์ | 372.58 ก | ช้าลง 9.73 เท่า |
นูเม็กซี่ | 89.72 ก | ช้าลง 40.40 เท่า |
เอ็กซ์แมทริกซ์ | 35.76 ก | ช้าลง 101.35 เท่า |
การย้ายเมทริกซ์ขนาด 1,000x1000
ห้องสมุด | การดำเนินการ/วินาที | เทียบกับเมเทร็กซ์ |
---|---|---|
แมทริกซ์ | 428.69 | |
เอ็กซ์แมทริกซ์ | 9.39 | ช้าลง 45.64× |
เมทริกซ์ | 8.54 | ช้าลง 50.17× |
นูเม็กซี่ | 6.83 | ช้าลง 62.80× |
ตัวอย่างที่สมบูรณ์ของไลบรารี Matrex ในที่ทำงาน: การถดถอยเชิงเส้นบนตัวเลข MNIST (สมุดบันทึก Jupyter)
Matrex ใช้ Inspect
protocol และดูดีในคอนโซลของคุณ:
มันยังสามารถวาดแผนที่ความร้อนของเมทริกซ์ของคุณในคอนโซลได้อีกด้วย! นี่คือภาพเคลื่อนไหวของการฝึกอบรมการถดถอยโลจิสติกด้วยไลบรารี Matrex และแผนที่ความร้อนเมทริกซ์บางส่วน:
สามารถติดตั้งแพ็คเกจได้โดยการเพิ่ม matrex
ในรายการการพึ่งพาของคุณใน mix.exs
:
def deps do
[
{ :matrex , "~> 0.6" }
]
end
ทุกอย่างทำงานนอกกรอบได้ด้วยเฟรมเวิร์ก Accelerate หากคุณพบข้อผิดพลาดในการรวบรวม
native/src/matrix_dot.c:5:10: fatal error: 'cblas.h' file not found
จากนั้นตรวจสอบให้แน่ใจว่าได้ติดตั้งเครื่องมือบรรทัดคำสั่ง XCode แล้ว ( xcode-select --install
) หากข้อผิดพลาดยังคงไม่ได้รับการแก้ไข สำหรับ MacOS Mojave ให้รัน open /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg
เพื่อกู้คืน /usr/include และ /usr/lib
บน MacOS 10.15 ข้อผิดพลาดนี้สามารถแก้ไขได้ด้วย
export CPATH=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/
หรือด้วย
C_INCLUDE_PATH=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/Accelerate.framework/Frameworks/vecLib.framework/Headers mix compile
คุณต้องติดตั้งไลบรารีวิทยาศาสตร์สำหรับแพ็คเกจนี้เพื่อคอมไพล์:
> sudo apt-get install build-essential erlang-dev libatlas-base-dev
มันจะใช้งานได้บน Windows แน่นอน แต่เราต้องการคำแนะนำ makefile และการติดตั้ง กรุณามีส่วนร่วม
ด้วยความช่วยเหลือของตัวแปรสภาพแวดล้อม MATREX_BLAS
คุณสามารถเลือกไลบรารี BLAS ที่จะเชื่อมโยงกับได้ มันสามารถรับค่า blas
(ค่าเริ่มต้น), atlas
, openblas
หรือ noblas
ตัวเลือกสุดท้ายหมายความว่าคุณคอมไพล์โค้ด C โดยไม่มีการพึ่งพาภายนอก ดังนั้นจึงควรทำงานได้ทุกที่ที่มีคอมไพเลอร์ C:
$ mix clean
$ MATREX_BLAS=noblas mix compile
พฤติกรรมการเข้าถึงบางส่วนถูกนำมาใช้กับ Matrex ดังนั้นคุณจึงสามารถ:
iex > m = Matrex . magic ( 3 )
#Matrex[3×3]
┌ ┐
│ 8.0 1.0 6.0 │
│ 3.0 5.0 7.0 │
│ 4.0 9.0 2.0 │
└ ┘
iex > m [ 2 ] [ 3 ]
7.0
หรือแม้กระทั่ง:
iex > m [ 1 .. 2 ]
#Matrex[2×3]
┌ ┐
│ 8.0 1.0 6.0 │
│ 3.0 5.0 7.0 │
└ ┘
นอกจากนี้ยังมีทางลัดหลายทางในการรับมิติของเมทริกซ์:
iex > m [ :rows ]
3
iex > m [ :size ]
{ 3 , 3 }
การคำนวณค่าสูงสุดของเมทริกซ์ทั้งหมด:
iex > m [ :max ]
9.0
หรือเพียงแถวเดียว:
iex > m [ 2 ] [ :max ]
7.0
การคำนวณดัชนีฐานเดียวขององค์ประกอบสูงสุดสำหรับเมทริกซ์ทั้งหมด:
iex > m [ :argmax ]
8
และแถว:
iex > m [ 2 ] [ :argmax ]
3
โมดูล Matrex.Operators
กำหนดตัวดำเนินการทางคณิตศาสตร์ Kernel
ใหม่ (+, -, *, / <|>) และกำหนดฟังก์ชันอำนวยความสะดวกบางอย่าง เพื่อให้คุณสามารถเขียนโค้ดการคำนวณในลักษณะที่เป็นธรรมชาติมากขึ้น
ควรใช้ด้วยความระมัดระวังอย่างยิ่ง เราขอแนะนำให้ใช้เฉพาะภายในฟังก์ชันเฉพาะและเพื่อให้อ่านง่ายขึ้นเท่านั้น เนื่องจากการใช้ฟังก์ชันโมดูล Matrex
โดยเฉพาะอย่างยิ่งฟังก์ชันที่ดำเนินการสองครั้งขึ้นไปในการเรียกครั้งเดียว จะเร็วขึ้น 2-3 เท่า
def lr_cost_fun_ops ( % Matrex { } = theta , { % Matrex { } = x , % Matrex { } = y , lambda } = _params )
when is_number ( lambda ) do
# Turn off original operators
import Kernel , except: [ -: 1 , +: 2 , -: 2 , *: 2 , /: 2 , <|>: 2 ]
import Matrex.Operators
import Matrex
m = y [ :rows ]
h = sigmoid ( x * theta )
l = ones ( size ( theta ) ) |> set ( 1 , 1 , 0.0 )
j = ( - t ( y ) * log ( h ) - t ( 1 - y ) * log ( 1 - h ) + lambda / 2 * t ( l ) * pow2 ( theta ) ) / m
grad = ( t ( x ) * ( h - y ) + ( theta <|> l ) * lambda ) / m
{ scalar ( j ) , grad }
end
ฟังก์ชั่นเดียวกันที่เข้ารหัสด้วยการเรียกวิธีการโมดูล (เร็วกว่า 2.5 เท่า):
def lr_cost_fun ( % Matrex { } = theta , { % Matrex { } = x , % Matrex { } = y , lambda } = _params )
when is_number ( lambda ) do
m = y [ :rows ]
h = Matrex . dot_and_apply ( x , theta , :sigmoid )
l = Matrex . ones ( theta [ :rows ] , theta [ :cols ] ) |> Matrex . set ( 1 , 1 , 0 )
regularization =
Matrex . dot_tn ( l , Matrex . square ( theta ) )
|> Matrex . scalar ( )
|> Kernel . * ( lambda / ( 2 * m ) )
j =
y
|> Matrex . dot_tn ( Matrex . apply ( h , :log ) , - 1 )
|> Matrex . subtract (
Matrex . dot_tn (
Matrex . subtract ( 1 , y ) ,
Matrex . apply ( Matrex . subtract ( 1 , h ) , :log )
)
)
|> Matrex . scalar ( )
|> ( fn
:nan -> :nan
x -> x / m + regularization
end ) . ( )
grad =
x
|> Matrex . dot_tn ( Matrex . subtract ( h , y ) )
|> Matrex . add ( Matrex . multiply ( theta , l ) , 1.0 , lambda )
|> Matrex . divide ( m )
{ j , grad }
end
Matrex ใช้ Enumerable
ดังนั้นฟังก์ชัน Enum
ทุกประเภทจึงสามารถใช้ได้:
iex > Enum . member? ( m , 2.0 )
true
iex > Enum . count ( m )
9
iex > Enum . sum ( m )
45
สำหรับฟังก์ชันที่มีอยู่ทั้งใน Enum
และใน Matrex
แนะนำให้ใช้เวอร์ชัน Matrex เพราะโดยปกติแล้วจะเร็วกว่ามาก กล่าวคือ สำหรับเมทริกซ์ 1,000 x 1,000 Matrex.sum/1
และ Matrex.to_list/1
จะเร็วกว่าเมทริกซ์ Enum
438 และ 41 เท่าตามลำดับ
คุณสามารถบันทึก/โหลดเมทริกซ์ด้วยรูปแบบไฟล์ไบนารีดั้งเดิม (เร็วเป็นพิเศษ) และ CSV (ช้า โดยเฉพาะบนเมทริกซ์ขนาดใหญ่)
รูปแบบ Matrex CSV เข้ากันได้กับเอาต์พุต GNU Octave CSV ดังนั้นคุณจึงสามารถใช้เพื่อแลกเปลี่ยนข้อมูลระหว่างสองระบบได้
iex > Matrex . random ( 5 ) |> Matrex . save ( "rand.mtx" )
:ok
iex > Matrex . load ( "rand.mtx" )
#Matrex[5×5]
┌ ┐
│ 0.05624 0.78819 0.29995 0.25654 0.94082 │
│ 0.50225 0.22923 0.31941 0.3329 0.78058 │
│ 0.81769 0.66448 0.97414 0.08146 0.21654 │
│ 0.33411 0.59648 0.24786 0.27596 0.09082 │
│ 0.18673 0.18699 0.79753 0.08101 0.47516 │
└ ┘
iex > Matrex . magic ( 5 ) |> Matrex . divide ( Matrex . eye ( 5 ) ) |> Matrex . save ( "nan.csv" )
:ok
iex > Matrex . load ( "nan.csv" )
#Matrex[5×5]
┌ ┐
│ 16.0 ∞ ∞ ∞ ∞ │
│ ∞ 4.0 ∞ ∞ ∞ │
│ ∞ ∞ 12.0 ∞ ∞ │
│ ∞ ∞ ∞ 25.0 ∞ │
│ ∞ ∞ ∞ ∞ 8.0 │
└ ┘
ค่าพิเศษลอยตัว เช่น :nan
และ :inf
ใช้งานได้ดีภายในเมทริกซ์ สามารถโหลดและบันทึกลงในไฟล์ได้ แต่เมื่อนำพวกมันเข้าสู่ Elixir พวกเขาจะถูกโอนไปยังอะตอม :nan
, :inf
และ :neg_inf
เนื่องจาก BEAM ไม่ยอมรับค่าพิเศษเป็นการลอยตัวที่ถูกต้อง
iex > m = Matrex . eye ( 3 )
#Matrex[3×3]
┌ ┐
│ 1.0 0.0 0.0 │
│ 0.0 1.0 0.0 │
│ 0.0 0.0 1.0 │
└ ┘
iex > n = Matrex . divide ( m , Matrex . zeros ( 3 ) )
#Matrex[3×3]
┌ ┐
│ ∞ NaN NaN │
│ NaN ∞ NaN │
│ NaN NaN ∞ │
└ ┘
iex > n [ 1 ] [ 1 ]
:inf
iex > n [ 1 ] [ 2 ]
:nan
iex ( 166 ) > matrex_logo =
... ( 166 ) > "../emnist/emnist-letters-test-images-idx3-ubyte"
.. . ( 166 ) > |> Matrex . load ( :idx )
.. . ( 166 ) > |> Access . get ( 9601 .. 10200 )
.. . ( 166 ) > |> Matrex . list_of_rows ( )
.. . ( 166 ) > |> Enum . reduce ( fn x , sum -> add ( x , sum ) end )
.. . ( 166 ) > |> Matrex . reshape ( 28 , 28 )
.. . ( 166 ) > |> Matrex . transpose ( )
.. . ( 166 ) > |> Matrex . resize ( 2 )
.. . ( 166 ) > |> Matrex . heatmap ( :color24bit )