DeepSwift

DeepSwift 是一个 Swift 库,用于实现无需编译器魔法的可微编程。 用于编写新的可微类型的“底层”API 如下所示:

struct Foo : Layer {

    /*
    typealias Input = Float
    typealias Output = Float 
    typealias Adjustment = Float 
    typealias AuxiliaryData = Float
    */
    
    func inspectableApply(_ input: Float) -> (result: Float, auxiliaryData: Float) {
        //...
    }
    
    func adjustment(input: Float, auxiliaryData: Float, gradient: Float) -> (adjustment: Float, backprop: Float) {
        //...
    }
    
    mutating func move(_ adjustment: Float) {
        //...
    }
    
    // optional methods
    
    func apply(_ input: Float) -> Float {
        //...
    }
    
    func auxData(at input: Float) -> Float {
        //...
    }
    
    func backprop(input: Float, auxiliaryData: Float, gradient: Float) -> Float {
        //...
    }
    
}

这实际上就是实现反向传播所需的全部内容。 以下是各个方法的作用:

其他方法具有默认实现,但我建议至少实现 backprop,这样在冻结此层时可以加快速度。

注意:Layer 协议要求 InputOutput 符合 Movable - 也就是说,它们也必须提供 move 方法。 adjustment/backprop 中的 gradient 的类型将为 Output.Adjustment,并且返回的 backprop 值将具有类型 Input.Adjustment

以下是三个强制性方法如何协同工作:

extension Layer {
    
    mutating func learn<Loss : Layer>(examples: Input, loss: Loss)  where
    Loss.Adjustment == Void,
          Loss.AuxiliaryData == Output.Adjustment,
          Loss.Input == Output {
              let (result, derivative) = inspectableApply(examples)
              let (adjustment, _) = adjustment(input: examples, auxiliaryData: derivative, gradient: loss.auxData(at: result))
              move(adjustment)
          }
          
}

如果要实现纯函数层,则可以使用 Function 协议,该协议不会要求您实现 move 方法。 相反,您需要指定 Adjustment 类型为 NoAdjustment<Scalar>,并使用适当的标量类型。

虽然 DeepSwift 将具体层和优化器的设计以及高效数值的实现留给其他(下游)仓库,但 DeepSwift 提供了您需要的高级 API,因此您可以编写:

struct MyModel : Learner {

   var body = SomeLayer() |> SomeOtherLayer() |> ThirdLayer()

} 

注意

此 API 仍处于起步阶段,因此可能会发生快速变化。