원시 TensorFlow 연산자

TensorFlow.org에서 보기 GitHub에서 소스 보기

TensorFlow를 기반으로 구축된 Swift for TensorFlow는 API 설계에 대한 새로운 접근 방식을 취합니다. API는 기존 라이브러리에서 신중하게 선별되어 새로운 언어 관용구와 결합됩니다. 즉, 모든 TensorFlow API가 Swift API로 직접 사용 가능하지는 않으며 API 큐레이션을 발전시키려면 시간과 헌신적인 노력이 필요합니다. 그러나 선호하는 TensorFlow 연산자를 Swift에서 사용할 수 없더라도 걱정하지 마십시오. TensorFlow Swift 라이브러리를 사용하면 _Raw 네임스페이스 아래에서 대부분의 TensorFlow 연산자에 투명하게 액세스할 수 있습니다.

시작하려면 TensorFlow 가져오세요.

import TensorFlow

원시 연산자 호출

코드 완성을 통해 _Raw 네임스페이스에서 필요한 함수를 찾으세요.

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

새로운 곱셈 연산자 정의

Multiply는 이미 Tensor 에서 * 연산자로 사용할 수 있지만, .* 라는 새로운 이름으로 사용할 수 있게 만들고 싶다고 가정해 보겠습니다. Swift를 사용하면 extension 선언을 사용하여 기존 유형에 메서드나 계산된 속성을 소급하여 추가할 수 있습니다.

이제 확장을 선언하여 Tensor.* 추가하고 텐서의 Scalar 유형이 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]]

래핑된 함수의 파생물 정의

원시 TensorFlow 연산자에 대한 Swift API를 쉽게 정의할 수 있을 뿐만 아니라 Swift의 일류 자동 미분을 사용하여 미분 가능하게 만들 수도 있습니다.

.* 미분 가능하게 만들려면 미분 함수에 @derivative 특성을 사용하고 원래 함수를 of: 레이블 아래의 특성 인수로 지정합니다. .* 연산자는 일반 유형 Scalar Numeric 준수할 때 정의되므로 Tensor<Scalar> Differentiable 프로토콜을 준수하도록 만드는 것만으로는 충분하지 않습니다. 유형 안전성을 바탕으로 탄생한 Swift는 Scalar TensorFlowFloatingPoint 프로토콜을 준수하도록 요구하기 위해 @differentiable 속성에 일반 제약 조건을 추가해야 한다는 점을 상기시켜 줍니다. 그러면 Tensor<Scalar> 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)

더 많은 예시

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