Operatori grezzi di TensorFlow

Visualizza su TensorFlow.org Visualizza la fonte su GitHub

Basandosi su TensorFlow, Swift per TensorFlow adotta un nuovo approccio alla progettazione delle API. Le API sono attentamente curate da librerie consolidate e combinate con nuovi idiomi linguistici. Ciò significa che non tutte le API TensorFlow saranno direttamente disponibili come API Swift e la nostra gestione delle API richiede tempo e impegno dedicato per evolversi. Tuttavia, non preoccuparti se il tuo operatore TensorFlow preferito non è disponibile in Swift: la libreria TensorFlow Swift ti offre accesso trasparente alla maggior parte degli operatori TensorFlow, nello spazio dei nomi _Raw .

Importa TensorFlow per iniziare.

import TensorFlow

Chiamare gli operatori grezzi

Trova semplicemente la funzione che ti serve nello spazio dei nomi _Raw tramite il completamento del codice.

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

Definizione di un nuovo operatore di moltiplicazione

Multiply è già disponibile come operatore * su Tensor , ma facciamo finta di volerlo rendere disponibile con un nuovo nome come .* . Swift ti consente di aggiungere retroattivamente metodi o proprietà calcolate ai tipi esistenti utilizzando dichiarazioni extension .

Ora aggiungiamo .* a Tensor dichiarando un'estensione e rendiamola disponibile quando il tipo Scalar del tensore è conforme a 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]]

Definizione di una derivata di una funzione incapsulata

Non solo puoi definire facilmente un'API Swift per un operatore TensorFlow grezzo, ma puoi anche renderla differenziabile per lavorare con la differenziazione automatica di prima classe di Swift.

Per rendere .* differenziabile, utilizzare l'attributo @derivative sulla funzione derivativa e specificare la funzione originale come argomento di attributo sotto l'etichetta of: Poiché l'operatore .* è definito quando il tipo generico Scalar è conforme a Numeric , non è sufficiente per rendere Tensor<Scalar> conforme al protocollo Differentiable . Nato con l'indipendenza dal tipo, Swift ci ricorderà di aggiungere un vincolo generico sull'attributo @differentiable per richiedere Scalar di conformarsi al protocollo TensorFlowFloatingPoint , che renderebbe Tensor<Scalar> conforme a 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)

Altri esempi

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]]