Opérateurs TensorFlow bruts

Voir sur TensorFlow.org Afficher la source sur GitHub

S'appuyant sur TensorFlow, Swift pour TensorFlow adopte une nouvelle approche de la conception d'API. Les API sont soigneusement sélectionnées à partir de bibliothèques établies et combinées avec de nouveaux langages. Cela signifie que toutes les API TensorFlow ne seront pas directement disponibles en tant qu'API Swift, et notre curation d'API nécessite du temps et des efforts dédiés pour évoluer. Cependant, ne vous inquiétez pas si votre opérateur TensorFlow préféré n'est pas disponible dans Swift : la bibliothèque TensorFlow Swift vous offre un accès transparent à la plupart des opérateurs TensorFlow, sous l'espace de noms _Raw .

Importez TensorFlow pour commencer.

import TensorFlow

Appel d'opérateurs bruts

Recherchez simplement la fonction dont vous avez besoin sous l'espace de noms _Raw via la complétion du code.

print(_Raw.mul(Tensor([2.0, 3.0]), Tensor([5.0, 6.0])))
[10.0, 18.0]

Définir un nouvel opérateur de multiplication

Multiply est déjà disponible en tant qu'opérateur * sur Tensor , mais imaginons que nous voulions le rendre disponible sous un nouveau nom en tant que .* . Swift vous permet d'ajouter rétroactivement des méthodes ou des propriétés calculées aux types existants à l'aide de déclarations extension .

Maintenant, ajoutons .* à Tensor en déclarant une extension et rendons-la disponible lorsque le type Scalar du tensor est conforme à Numeric .

infix operator .* : MultiplicationPrecedence

extension Tensor where Scalar: Numeric {
    static func .* (_ lhs: Tensor, _ rhs: Tensor) -> Tensor {
        return _Raw.mul(lhs, rhs)
    }
}

let x: Tensor<Double> = [[1.0, 2.0], [3.0, 4.0]]
let y: Tensor<Double> = [[8.0, 7.0], [6.0, 5.0]]
print(x .* y)
[[ 8.0, 14.0],
 [18.0, 20.0]]

Définir une dérivée d'une fonction enveloppée

Non seulement vous pouvez facilement définir une API Swift pour un opérateur TensorFlow brut, mais vous pouvez également le rendre différenciable pour qu'il fonctionne avec la différenciation automatique de première classe de Swift.

Pour rendre .* différentiable, utilisez l'attribut @derivative sur la fonction dérivée et spécifiez la fonction d'origine comme argument d'attribut sous l'étiquette of: Puisque l'opérateur .* est défini lorsque le type générique Scalar est conforme à Numeric , il ne suffit pas pour rendre Tensor<Scalar> conforme au protocole Differentiable . Né avec la sécurité des types, Swift nous rappellera d'ajouter une contrainte générique sur l'attribut @differentiable pour exiger que Scalar se conforme au protocole TensorFlowFloatingPoint , ce qui rendrait Tensor<Scalar> conforme à Differentiable .

@differentiable(where Scalar: TensorFlowFloatingPoint)
infix operator .* : MultiplicationPrecedence

extension Tensor where Scalar: Numeric {
    @differentiable(where Scalar: TensorFlowFloatingPoint)
    static func .* (_ lhs: Tensor,  _ rhs: Tensor) -> Tensor {
        return _Raw.mul(lhs, rhs)
    }
}

extension Tensor where Scalar : TensorFlowFloatingPoint { 
    @derivative(of: .*)
    static func multiplyDerivative(
        _ lhs: Tensor, _ rhs: Tensor
    ) -> (value: Tensor, pullback: (Tensor) -> (Tensor, Tensor)) {
        return (lhs * rhs, { v in
            ((rhs * v).unbroadcasted(to: lhs.shape),
            (lhs * v).unbroadcasted(to: rhs.shape))
        })
    }
}

// Now, we can take the derivative of a function that calls `.*` that we just defined.
print(gradient(at: x, y) { x, y in
    (x .* y).sum()
})
(0.0, 0.0)

Plus d'exemples

let matrix = Tensor<Float>([[1, 2], [3, 4]])

print(_Raw.matMul(matrix, matrix, transposeA: true, transposeB: true))
print(_Raw.matMul(matrix, matrix, transposeA: true, transposeB: false))
print(_Raw.matMul(matrix, matrix, transposeA: false, transposeB: true))
print(_Raw.matMul(matrix, matrix, transposeA: false, transposeB: false))
[[ 7.0, 15.0],
 [10.0, 22.0]]
[[10.0, 14.0],
 [14.0, 20.0]]
[[ 5.0, 11.0],
 [11.0, 25.0]]
[[ 7.0, 10.0],
 [15.0, 22.0]]