Raw 텐서플로 연산자

TensorFlow.org에서 보기 구글 코랩(Colab)에서 실행하기 깃허브(GitHub)소스 보기

스위프트를 위한 텐서플로는 텐서플로를 기반으로 API 디자인에 새로운 접근을 할 수 있게 합니다. API들은 확립된 라이브러리들로 부터 세밀하게 조직되어 있고, 새로운 관용구로 결합되어 있습니다. 이것은 모든 텐서플로우 API들이 직접적으로 Swift APIs로 사용되어질 수 있는 것은 아니라는 걸 뜻하고, 또 우리의 API 큐레이션이 상당한 시간과 발전 시키기 위한 헌신적인 노력이 필요하다는 것을 의미합니다. 만약 당신의 가장 좋아하는 텐서플로우 연산자가 Swift에서 사용 가능 하지 않는다고 해도 걱정하지 마세요. – 텐서플로우 Swift 라이브러리는 당신에게 Raw 네임스페이스 아래에서 대부분의 텐서플로우 연산자에 접근할 수 있도록 합니다.

텐서플로를 시작하기 위해 불러오세요.

import TensorFlow

Raw 연산자 호출하기

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

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

새로운 곱셈 연산자를 정의하기

곱셈은 이미 Tensor 에서 * 연산자로 사용이 가능하지만, .*라는 새로운 이름의 연산자로 이용 가능 할 수 있도록 만들고 싶다고 가정해봅시다. 스위프트는 당신이 소급적으로 메소드를 추가할 수 있도록 하거나 extension 선언을 사용하는 타입들이 존재할 가능성을 계산할 수 있게 해줍니다.

지금, extension을 선언하여 .*연산자를 Tensor에 추가해봅시다. 그리고 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]]
x .* y
[[ 8.0, 14.0],
 [18.0, 20.0]]

래퍼 함수에서 파생된 것을 정의하기

당신은 쉽게 스위프트 API를 다듬어지지 않은 텐서플로우 연산자에서 정의할 수 있을 뿐만 아니라, 스위프트가 가지고 있는 최고 수준의 일급 자동 미분 기능을 이용하여 Raw 텐서플로우 연산자를 미분할 수 있습니다.

.*연산자를 미분 가능하게 만들기 위해서, @differentiable 속성을 이용하세요. 그리고 vjp: 레이블에서 고안된 함수를 속성 인자로써 구체화 시키세요. .*연산자가 제네릭 타입의 ScalarNumeric를 따르도록 정의되었기 때문에, Tensor<Scalar>Differentiable 프로토콜을 따르도록 만들기엔 충분하지(적절하지) 않습니다. 타입 세이프티를 지키는, 스위프트는 우리에게 @differentiable 속성의 ScalarTensorFlowFloatingPoint 프로토콜을 따르도록 요구하기 위해서, 제네릭 제약 조건을 추가하도록 요구할 것입니다. TensorFlowFloatingPointTensor<Scalar>Differentiable을 따르도록 만드는 프로토콜 입니다.

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

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

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

// 이제, 우리는 방금 정의한 `.*`연산자를 호출하는 함수의 도함수를 구할 수 있습니다.
gradient(at: x, y) { x, y in
    (x .* y).sum()
}
▿ 2 elements
  - .0 : [[8.0, 7.0],
 [6.0, 5.0]]
  - .1 : [[1.0, 2.0],
 [3.0, 4.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]]