عملگرهای خام TensorFlow

مشاهده در TensorFlow.org مشاهده منبع در GitHub

با تکیه بر TensorFlow، Swift for TensorFlow رویکرد جدیدی به طراحی API دارد. API ها با دقت از کتابخانه های تاسیس شده و با اصطلاحات زبان جدید ترکیب شده اند. این بدان معنی است که همه APIهای TensorFlow مستقیماً به عنوان APIهای Swift در دسترس نخواهند بود و تنظیم API ما برای تکامل نیاز به زمان و تلاش اختصاصی دارد. با این حال، اگر اپراتور TensorFlow مورد علاقه شما در Swift در دسترس نیست نگران نباشید - کتابخانه TensorFlow Swift به شما امکان دسترسی شفاف به اکثر اپراتورهای TensorFlow را در زیر فضای نام _Raw می دهد.

برای شروع، 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]]

تعریف یک مشتق از یک تابع پیچیده

نه تنها می‌توانید به راحتی یک API Swift را برای یک اپراتور خام TensorFlow تعریف کنید، بلکه می‌توانید آن را برای کار با تمایز خودکار درجه یک سوئیفت متمایز کنید.

برای متمایز کردن .* ، از صفت @derivative روی تابع مشتق استفاده کنید و تابع اصلی را به عنوان آرگومان ویژگی در زیر برچسب of: مشخص کنید. از آنجایی که عملگر .* زمانی تعریف می شود که نوع عمومی Scalar با Numeric مطابقت داشته باشد، برای تطبیق Tensor<Scalar> با پروتکل Differentiable کافی نیست. Swift که با ایمنی نوع متولد شده است، به ما یادآوری می‌کند که یک محدودیت عمومی در ویژگی @differentiable اضافه کنیم تا Scalar با پروتکل TensorFlowFloatingPoint مطابقت دهیم، که باعث می‌شود 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]]