Ceci est le premier message. Comme le titre l'indique, j'ai créé une bibliothèque d'opérations matricielles à N dimensions ** Matft (https://github.com/jjjkkjjj/Matft) ** avec Swift. Vu. (** Opération Mat ** rix, Swi ** ft **, qui signifie Matft lol)
Le début de l'affaire était un mot d'un senior de l'entreprise, "Je veux que vous écriviez un code pour trouver la matrice inverse de 3 lignes et 3 colonnes en Swift." Je pensais que Swift aurait une bibliothèque d'opérations matricielles à N dimensions comme Numpy en Python, mais quand je l'ai recherchée, ce n'était pas surprenant. .. .. L'accélération officielle semble être gênante, et le fameux surtension fait jusqu'à 2 dimensions? C'était comme. C'est pourquoi j'ai décidé de créer ma propre bibliothèque d'opérations matricielles à N dimensions. (C'est complètement sur-spec pour le code qui trouve la matrice inverse de 3 lignes et 3 colonnes, mais lol)
De plus, Matft a été créé comme ça. Et comme c'est un gros problème, je vais le partager, et je suis à la hauteur du présent.
Fondamentalement, il a été créé selon Numpy de Python, de sorte que les noms et l'utilisation des fonctions sont presque les mêmes que Numpy.
La déclaration crée un tableau multidimensionnel avec «MfArray», qui est «ndarray».
let a = MfArray([[[ -8, -7, -6, -5],
[ -4, -3, -2, -1]],
[[ 0, 1, 2, 3],
[ 4, 5, 6, 7]]])
print(a)
/*
mfarray =
[[[ -8.0, -7.0, -6.0, -5.0],
[ -4.0, -3.0, -2.0, -1.0]],
[[ 0.0, 1.0, 2.0, 3.0],
[ 4.0, 5.0, 6.0, 7.0]]], type=Float, shape=[2, 2, 4]
*/
Je voulais le rendre compatible avec différents types, alors j'ai préparé un certain type. Ce n'est pas «dtype» mais «MfType».
let a = MfArray([[[ -8, -7, -6, -5],
[ -4, -3, -2, -1]],
[[ 0, 1, 2, 3],
[ 4, 5, 6, 7]]], mftype: .Float)
print(a)
/*
mfarray =
[[[ -8.0, -7.0, -6.0, -5.0],
[ -4.0, -3.0, -2.0, -1.0]],
[[ 0.0, 1.0, 2.0, 3.0],
[ 4.0, 5.0, 6.0, 7.0]]], type=Float, shape=[2, 2, 4]
*/
let aa = MfArray([[[ -8, -7, -6, -5],
[ -4, -3, -2, -1]],
[[ 0, 1, 2, 3],
[ 4, 5, 6, 7]]], mftype: .UInt)
print(aa)
/*
mfarray =
[[[ 4294967288, 4294967289, 4294967290, 4294967291],
[ 4294967292, 4294967293, 4294967294, 4294967295]],
[[ 0, 1, 2, 3],
[ 4, 5, 6, 7]]], type=UInt, shape=[2, 2, 4]
*/
//Above output is same as numpy!
/*
>>> np.arange(-8, 8, dtype=np.uint32).reshape(2,2,4)
array([[[4294967288, 4294967289, 4294967290, 4294967291],
[4294967292, 4294967293, 4294967294, 4294967295]],
[[ 0, 1, 2, 3],
[ 4, 5, 6, 7]]], dtype=uint32)
La liste de types est définie par le type Enum suivant.
Float
ou Double
dans les coulisses, ʻUInt` débordera si la valeur est grande. Cependant, je ne pense pas qu'il y ait de problème d'utilisation pratique. public enum MfType: Int{
case None // Unsupportted
case Bool
case UInt8
case UInt16
case UInt32
case UInt64
case UInt
case Int8
case Int16
case Int32
case Int64
case Int
case Float
case Double
case Object // Unsupported
}
Indexing
Des tranches comme ʻa [:, :: -1] dans Numpy sont également implémentées avec
~ <. (Au départ, il était implémenté avec
~, mais
~ 2` etc.
Nous avons également implémenté des indices négatifs tels que -1. (Cela a peut-être été le plus difficile ...)
let a = Matft.mfarray.arange(start: 0, to: 27, by: 1, shape: [3,3,3])
print(a)
/*
mfarray =
[[[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8]],
[[ 9, 10, 11],
[ 12, 13, 14],
[ 15, 16, 17]],
[[ 18, 19, 20],
[ 21, 22, 23],
[ 24, 25, 26]]], type=Int, shape=[3, 3, 3]
*/
print(a[2,1,0])
// 21
print(a[1~<3]) //same as a[1:3] for numpy
/*
mfarray =
[[[ 9, 10, 11],
[ 12, 13, 14],
[ 15, 16, 17]],
[[ 18, 19, 20],
[ 21, 22, 23],
[ 24, 25, 26]]], type=Int, shape=[2, 3, 3]
*/
print(a[-1~<-3])
/*
mfarray =
[], type=Int, shape=[0, 3, 3]
*/
print(a[~<~<-1]) // print(a[~<<-1])Avec un alias~<<Est également équivalent
/*
mfarray =
[[[ 18, 19, 20],
[ 21, 22, 23],
[ 24, 25, 26]],
[[ 9, 10, 11],
[ 12, 13, 14],
[ 15, 16, 17]],
[[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8]]], type=Int, shape=[3, 3, 3]*/
Voici une liste de fonctions spécifiques. Puisque le calcul principal est laissé à Accélérer, je pense que le temps de calcul est garanti dans une certaine mesure.
\ * Signifie que cette méthode existe également. En d'autres termes, si ʻa est
MfArray, vous pouvez utiliser ʻa.shallowcopy ()
.
--Système de génération
Matft | Numpy |
---|---|
*Matft.shallowcopy | *numpy.copy |
*Matft.deepcopy | copy.deepcopy |
Matft.nums | numpy.ones * N |
Matft.arange | numpy.arange |
Matft.eye | numpy.eye |
Matft.diag | numpy.diag |
Matft.vstack | numpy.vstack |
Matft.hstack | numpy.hstack |
Matft.concatenate | numpy.concatenate |
--Système de conversion
Matft | Numpy |
---|---|
*Matft.astype | *numpy.astype |
*Matft.transpose | *numpy.transpose |
*Matft.expand_dims | *numpy.expand_dims |
*Matft.squeeze | *numpy.squeeze |
*Matft.broadcast_to | *numpy.broadcast_to |
*Matft.conv_order | *numpy.ascontiguousarray |
*Matft.flatten | *numpy.flatten |
*Matft.flip | *numpy.flip |
*Matft.clip | *numpy.clip |
*Matft.swapaxes | *numpy.swapaxes |
*Matft.moveaxis | *numpy.moveaxis |
*Matft.sort | *numpy.sort |
*Matft.argsort | *numpy.argsort |
--Lié aux fichiers la sauvegarde est incomplète.
Matft | Numpy |
---|---|
Matft.file.loadtxt | numpy.loadtxt |
Matft.file.genfromtxt | numpy.genfromtxt |
--Système de calcul
La deuxième ligne est l'opérateur.
Matft | Numpy |
---|---|
Matft.add + |
numpy.add + |
Matft.sub - |
numpy.sub - |
Matft.div / |
numpy.div . |
Matft.mul * |
numpy.multiply * |
Matft.inner *+ |
numpy.inner n/a |
Matft.cross *^ |
numpy.cross n/a |
Matft.matmul *& |
numpy.matmul @ |
Matft.equal === |
numpy.equal == |
Matft.not_equal !== |
numpy.not_equal != |
Matft.allEqual == |
numpy.array_equal n/a |
Matft.neg - |
numpy.negative - |
Matft | Numpy |
---|---|
Matft.math.sin | numpy.sin |
Matft.math.asin | numpy.asin |
Matft.math.sinh | numpy.sinh |
Matft.math.asinh | numpy.asinh |
Matft.math.sin | numpy.cos |
Matft.math.acos | numpy.acos |
Matft.math.cosh | numpy.cosh |
Matft.math.acosh | numpy.acosh |
Matft.math.tan | numpy.tan |
Matft.math.atan | numpy.atan |
Matft.math.tanh | numpy.tanh |
Matft.math.atanh | numpy.atanh |
Puisqu'il est gênant, je vais l'omettre. .. .. Lol Voir ici
--Système statistique
Matft | Numpy |
---|---|
*Matft.stats.mean | *numpy.mean |
*Matft.stats.max | *numpy.max |
*Matft.stats.argmax | *numpy.argmax |
*Matft.stats.min | *numpy.min |
*Matft.stats.argmin | *numpy.argmin |
*Matft.stats.sum | *numpy.sum |
Matft.stats.maximum | numpy.maximum |
Matft.stats.minimum | numpy.minimum |
Matft | Numpy |
---|---|
Matft.linalg.solve | numpy.linalg.solve |
Matft.linalg.inv | numpy.linalg.inv |
Matft.linalg.det | numpy.linalg.det |
Matft.linalg.eigen | numpy.linalg.eig |
Matft.linalg.svd | numpy.linalg.svd |
Matft.linalg.polar_left | scipy.linalg.polar |
Matft.linalg.polar_right | scipy.linalg.polar |
Matft.linalg.normlp_vec | scipy.linalg.norm |
Matft.linalg.normfro_mat | scipy.linalg.norm |
Matft.linalg.normnuc_mat | scipy.linalg.norm |
Ajout du support pour SwiftPM, CocoaPod et Carthage.
SwiftPM
CocoaPods
--Créer Podfile (ignorer s'il existe déjà)
pod init
target 'your project' do
pod 'Matft'
end
--Installation
pod install
-Créer dans Cartfile et lire.
echo 'github "realm/realm-cocoa"' > Cartfile
carthage update ###or append '--platform ios'
――C'est OK si vous chargez le Matft.framework
terminé dans le projet.
Performance
J'ai dit que le calcul est garanti car je le laisse à Accélérer, mais j'ai calculé la vitesse uniquement en ajoutant. Si j'ai le temps, j'étudierai d'autres fonctions. .. ..
case | Matft | Numpy |
---|---|---|
1 | 1.14ms | 962 µs |
2 | 4.20ms | 5.68 ms |
3 | 4.17ms | 3.92 ms |
func testPefAdd1() {
do{
let a = Matft.mfarray.arange(start: 0, to: 10*10*10*10*10*10, by: 1, shape: [10,10,10,10,10,10])
let b = Matft.mfarray.arange(start: 0, to: -10*10*10*10*10*10, by: -1, shape: [10,10,10,10,10,10])
self.measure {
let _ = a+b
}
/*
'-[MatftTests.ArithmeticPefTests testPefAdd1]' measured [Time, seconds] average: 0.001, relative standard deviation: 23.418%, values: [0.001707, 0.001141, 0.000999, 0.000969, 0.001029, 0.000979, 0.001031, 0.000986, 0.000963, 0.001631]
1.14ms
*/
}
}
func testPefAdd2(){
do{
let a = Matft.arange(start: 0, to: 10*10*10*10*10*10, by: 1, shape: [10,10,10,10,10,10])
let b = a.transpose(axes: [0,3,4,2,1,5])
let c = a.T
self.measure {
let _ = b+c
}
/*
'-[MatftTests.ArithmeticPefTests testPefAdd2]' measured [Time, seconds] average: 0.004, relative standard deviation: 5.842%, values: [0.004680, 0.003993, 0.004159, 0.004564, 0.003955, 0.004200, 0.003998, 0.004317, 0.003919, 0.004248]
4.20ms
*/
}
}
func testPefAdd3(){
do{
let a = Matft.arange(start: 0, to: 10*10*10*10*10*10, by: 1, shape: [10,10,10,10,10,10])
let b = a.transpose(axes: [1,2,3,4,5,0])
let c = a.T
self.measure {
let _ = b+c
}
/*
'-[MatftTests.ArithmeticPefTests testPefAdd3]' measured [Time, seconds] average: 0.004, relative standard deviation: 16.815%, values: [0.004906, 0.003785, 0.003702, 0.005981, 0.004261, 0.003665, 0.004083, 0.003654, 0.003836, 0.003874]
4.17ms
*/
}
}
In [1]:
import numpy as np
#import timeit
a = np.arange(10**6).reshape((10,10,10,10,10,10))
b = np.arange(0, -10**6, -1).reshape((10,10,10,10,10,10))
#timeit.timeit("b+c", repeat=10, globals=globals())
%timeit -n 10 a+b
962 µs ± 273 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [2]:
a = np.arange(10**6).reshape((10,10,10,10,10,10))
b = a.transpose((0,3,4,2,1,5))
c = a.T
#timeit.timeit("b+c", repeat=10, globals=globals())
%timeit -n 10 b+c
5.68 ms ± 1.45 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [3]:
a = np.arange(10**6).reshape((10,10,10,10,10,10))
b = a.transpose((1,2,3,4,5,0))
c = a.T
#timeit.timeit("b+c", repeat=10, globals=globals())
%timeit -n 10 b+c
3.92 ms ± 897 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
flag
qui contient l'ordre de MfArray, il y a des endroits où vous faites des copies inutiles.en
MfArray` (je veux utiliser vDSP)J'ai réussi sur un coup de tête, mais j'ai obtenu quelque chose de mieux que ce à quoi je m'attendais. Il existe peut-être une meilleure bibliothèque simplement à cause de mon manque de puissance de recherche, mais je vous serais reconnaissant de bien vouloir l'essayer. (La vérification dépendant de l'environnement n'est pas terminée, n'hésitez donc pas à nous contacter ...) Quoi qu'il en soit, c'était une bonne étude. Merci beaucoup.
numpy scipy Accelerate Écrivez NDArray dans Swift (j'ai fait référence au scénario de test.)
Recommended Posts