प्रयोज्यता के मामले में डिफरेंशियल स्विफ्ट ने एक लंबा सफर तय किया है। यहां उन हिस्सों के बारे में जानकारी दी गई है जो अभी भी थोड़े अस्पष्ट हैं। जैसे-जैसे प्रगति जारी रहेगी, यह मार्गदर्शिका छोटी होती जाएगी, और आप विशेष सिंटैक्स की आवश्यकता के बिना अलग-अलग कोड लिखने में सक्षम होंगे।
छोरों
लूप अलग-अलग होते हैं, उनके बारे में जानने के लिए बस एक ही विवरण है। जब आप लूप लिखते हैं, तो उस बिट को लपेटें जहां आप निर्दिष्ट करते हैं कि आप withoutDerivative(at:)
में क्या लूप कर रहे हैं
var a: [Float] = [1,2,3]
उदाहरण के लिए:
for _ in a.indices
{}
बन जाता है
for _ in withoutDerivative(at: a.indices)
{}
या:
for _ in 0..<a.count
{}
बन जाता है
for _ in 0..<withoutDerivative(at: a.count)
{}
यह आवश्यक है क्योंकि Array.count
सदस्य सरणी के संबंध में व्युत्पन्न में योगदान नहीं करता है। सरणी में केवल वास्तविक तत्व ही व्युत्पन्न में योगदान करते हैं।
यदि आपके पास एक लूप है जहां आप मैन्युअल रूप से एक पूर्णांक को ऊपरी सीमा के रूप में उपयोग करते हैं, तो withoutDerivative(at:)
उपयोग करने की कोई आवश्यकता नहीं है:
let iterations: Int = 10
for _ in 0..<iterations {} //this is fine as-is.
मानचित्र और कम करें
map
और reduce
के विशेष भिन्न-भिन्न संस्करण हैं जो बिल्कुल वैसे ही काम करते हैं जैसे आप करते थे:
a = [1,2,3]
let aPlusOne = a.differentiableMap {$0 + 1}
let aSum = a.differentiableReduce(0, +)
print("aPlusOne", aPlusOne)
print("aSum", aSum)
aPlusOne [2.0, 3.0, 4.0] aSum 6.0
ऐरे सबस्क्रिप्ट सेट
ऐरे सबस्क्रिप्ट सेट ( array[0] = 0
) बॉक्स के बाहर भिन्न नहीं हैं, लेकिन आप इस एक्सटेंशन को पेस्ट कर सकते हैं:
extension Array where Element: Differentiable {
@differentiable(where Element: Differentiable)
mutating func updated(at index: Int, with newValue: Element) {
self[index] = newValue
}
@derivative(of: updated)
mutating func vjpUpdated(at index: Int, with newValue: Element)
-> (value: Void, pullback: (inout TangentVector) -> (Element.TangentVector))
{
self.updated(at: index, with: newValue)
return ((), { v in
let dElement = v[index]
v.base[index] = .zero
return dElement
})
}
}
और फिर वर्कअराउंड सिंटैक्स इस प्रकार है:
var b: [Float] = [1,2,3]
इसके अलावा:
b[0] = 17
इसे लिखें:
b.updated(at: 0, with: 17)
आइए सुनिश्चित करें कि यह काम करता है:
func plusOne(array: [Float]) -> Float{
var array = array
array.updated(at: 0, with: array[0] + 1)
return array[0]
}
let plusOneValAndGrad = valueWithGradient(at: [2], in: plusOne)
print(plusOneValAndGrad)
(value: 3.0, gradient: [1.0])
इस समाधान के बिना आपको जो त्रुटि मिलेगी वह यह है कि Differentiation of coroutine calls is not yet supported
। इस समाधान को अनावश्यक बनाने की प्रगति देखने के लिए यहां लिंक दिया गया है: https://bugs.swift.org/browse/TF-1277 (यह Array.subscript._modify के बारे में बात करता है, जब आप कोई सरणी बनाते हैं तो इसे पर्दे के पीछे कहा जाता है) सबस्क्रिप्ट सेट)।
Float
<-> Double
रूपांतरण
यदि आप Float
और Double
के बीच स्विच कर रहे हैं, तो उनके कंस्ट्रक्टर पहले से ही अलग-अलग नहीं हैं। यहां एक फ़ंक्शन है जो आपको Float
से Double
तक अलग-अलग तरीके से जाने देगा।
(नीचे दिए गए कोड में Float
और Double
स्विच करें, और आपको एक फ़ंक्शन मिलेगा जो Double
से Float
में कनवर्ट करता है।)
आप किसी अन्य वास्तविक संख्यात्मक प्रकार के लिए समान कनवर्टर्स बना सकते हैं।
@differentiable
func convertToDouble(_ a: Float) -> Double {
return Double(a)
}
@derivative(of: convertToDouble)
func convertToDoubleVJP(_ a: Float) -> (value: Double, pullback: (Double) -> Float) {
func pullback(_ v: Double) -> Float{
return Float(v)
}
return (value: Double(a), pullback: pullback)
}
यहाँ एक उदाहरण उपयोग है:
@differentiable
func timesTwo(a: Float) -> Double {
return convertToDouble(a * 2)
}
let input: Float = 3
let valAndGrad = valueWithGradient(at: input, in: timesTwo)
print("grad", valAndGrad.gradient)
print("type of input:", type(of: input))
print("type of output:", type(of: valAndGrad.value))
print("type of gradient:", type(of: valAndGrad.gradient))
grad 2.0 type of input: Float type of output: Double type of gradient: Float
ट्रान्सेंडैंटल और अन्य कार्य (पाप, कॉस, पेट, अधिकतम)
Float
और Double
के लिए बहुत सारे ट्रान्सेंडैंटल और अन्य सामान्य अंतर्निहित फ़ंक्शंस को पहले से ही अलग किया जा चुका है। Float
तुलना में Double
के लिए कम हैं। कुछ किसी के लिए भी उपलब्ध नहीं हैं। तो यहां कुछ मैनुअल व्युत्पन्न परिभाषाएं दी गई हैं, जिससे आपको यह पता चलेगा कि आपको जो चाहिए वह कैसे बनाया जाए, यदि यह पहले से उपलब्ध नहीं है:
पाउ (व्युत्पन्न स्पष्टीकरण के लिए लिंक देखें)
import Foundation
@usableFromInline
@derivative(of: pow)
func powVJP(_ base: Double, _ exponent: Double) -> (value: Double, pullback: (Double) -> (Double, Double)) {
let output: Double = pow(base, exponent)
func pullback(_ vector: Double) -> (Double, Double) {
let baseDerivative = vector * (exponent * pow(base, exponent - 1))
let exponentDerivative = vector * output * log(base)
return (baseDerivative, exponentDerivative)
}
return (value: output, pullback: pullback)
}
अधिकतम
@usableFromInline
@derivative(of: max)
func maxVJP<T: Comparable & Differentiable>(_ x: T, _ y: T) -> (value: T, pullback: (T.TangentVector)
-> (T.TangentVector, T.TangentVector))
{
func pullback(_ v: T.TangentVector) -> (T.TangentVector, T.TangentVector) {
if x < y {
return (.zero, v)
} else {
return (v, .zero)
}
}
return (value: max(x, y), pullback: pullback)
}
पेट
@usableFromInline
@derivative(of: abs)
func absVJP<T: Comparable & SignedNumeric & Differentiable>(_ x: T)
-> (value: T, pullback: (T.TangentVector) -> T.TangentVector)
{
func pullback(_ v: T.TangentVector) -> T.TangentVector{
if x < 0 {
return .zero - v
}
else {
return v
}
}
return (value: abs(x), pullback: pullback)
}
sqrt (व्युत्पन्न स्पष्टीकरण के लिए लिंक देखें)
@usableFromInline
@derivative(of: sqrt)
func sqrtVJP(_ x: Double) -> (value: Double, pullback: (Double) -> Double) {
let output = sqrt(x)
func pullback(_ v: Double) -> Double {
return v / (2 * output)
}
return (value: output, pullback: pullback)
}
आइए देखें कि ये काम करते हैं:
let powGrad = gradient(at: 2, 2, in: pow)
print("pow gradient: ", powGrad, "which is", powGrad == (4.0, 2.772588722239781) ? "correct" : "incorrect")
let maxGrad = gradient(at: 1, 2, in: max)
print("max gradient: ", maxGrad, "which is", maxGrad == (0.0, 1.0) ? "correct" : "incorrect")
let absGrad = gradient(at: 2, in: abs)
print("abs gradient: ", absGrad, "which is", absGrad == 1.0 ? "correct" : "incorrect")
let sqrtGrad = gradient(at: 4, in: sqrt)
print("sqrt gradient: ", sqrtGrad, "which is", sqrtGrad == 0.25 ? "correct" : "incorrect")
pow gradient: (4.0, 2.772588722239781) which is correct max gradient: (0.0, 1.0) which is correct abs gradient: 1.0 which is correct sqrt gradient: 0.25 which is correct
कंपाइलर त्रुटि जो आपको कुछ इस तरह की आवश्यकता के प्रति सचेत करती है वह है: Expression is not differentiable. Cannot differentiate functions that have not been marked '@differentiable' and that are defined in other files
KeyPath
सबस्क्रिप्टिंग
KeyPath
सबस्क्रिप्टिंग (प्राप्त या सेट) बॉक्स से बाहर काम नहीं करती है, लेकिन एक बार फिर, कुछ एक्सटेंशन हैं जिन्हें आप जोड़ सकते हैं, और फिर वर्कअराउंड सिंटैक्स का उपयोग कर सकते हैं। यह रहा:
https://github.com/tensorflow/swift/issues/530#issuecomment-687400701
यह समाधान दूसरों की तुलना में थोड़ा बदसूरत है। यह केवल कस्टम ऑब्जेक्ट के लिए काम करता है, जो डिफरेंशियल और एडिटिवअरिथमेटिक के अनुरूप होना चाहिए। आपको एक .tmp
सदस्य और एक .read()
फ़ंक्शन जोड़ना होगा, और KeyPath
सबस्क्रिप्ट प्राप्त करते समय आप .tmp
सदस्य को इंटरमीडिएट स्टोरेज के रूप में उपयोग करते हैं (लिंक किए गए कोड में एक उदाहरण है)। KeyPath
सबस्क्रिप्ट सेट .write()
फ़ंक्शन के साथ बहुत सरलता से काम करते हैं।