DL4S

License Releases Documentation
Supports Linux, macOS, iOS, tvOS and watchOS Build Status

DL4S 提供了一个高级 API,用于神经网络和深度学习中常见的许多加速运算。此外,它还内置了自动微分功能,这使您无需手动实现反向传播即可创建和训练神经网络 - 无需特殊的 Swift 工具链。

功能包括许多基本二元和一元运算符的实现、广播、矩阵运算、卷积和循环神经网络、常用优化器、二阶导数等等。 DL4S 提供了常用网络架构的实现,例如 VGG、AlexNet、ResNet 和 Transformers。

虽然其主要目的是深度学习和优化,但 DL4S 可以用作矢量化数学运算库,例如 numpy。

阅读完整文档

概述

  1. 安装
  2. 功能特性
    1. 优化器
    2. 损失函数
    3. 张量运算
    4. 引擎
    5. 架构
  3. 示例

安装

iOS / tvOS / macOS

  1. 在 Xcode 中,选择 “File” > “Swift Packages” > “Add Package Dependency”
  2. 在 Package URL 字段中输入 https://github.com/palle-k/DL4S.git,然后单击 “Next”。
  3. 选择 “Branch”、“master”,然后单击 “Next”。
  4. 在 “Add to Target” 列中启用 Package Product DL4S 和您的应用,然后单击 “Next”。

注意:较新版本不再支持通过 CocoaPods 安装。

Swift Package

将依赖项添加到您的 Package.swift 文件

.package(url: "https://github.com/palle-k/DL4S.git", .branch("master"))

然后将 DL4S 作为依赖项添加到您的目标

.target(name: "MyPackage", dependencies: ["DL4S"])

MKL / IPP / OpenMP 支持

DL4S 可以通过 Intel 的 Math Kernel Library、Integrated Performance Primitives 和 OpenMP 加速(安装说明)。

在 Apple 设备上,DL4S 默认使用内置 Accelerate 框架提供的矢量化函数。 如果没有可用的加速库,则使用后备实现。

使用 MKL/IPP 编译

# After adding the APT repository as described in the installation instructions
sudo apt-get install intel-mkl-64bit-2019.5-075 intel-ipp-64bit-2019.5-075 libiomp-dev

export MKLROOT=/opt/intel/mkl
export IPPROOT=/opt/intel/ipp
export LD_LIBRARY_PATH=${MKLROOT}/lib/intel64:${IPPROOT}/lib/intel64:${LD_LIBRARY_PATH}

swift build -c release \
    -Xswiftc -DMKL_ENABLE \
    -Xlinker -L${MKLROOT}/lib/intel64 \
    -Xlinker -L${IPPROOT}/lib/intel64

TensorBoard 支持

DL4S-Tensorboard 提供了一个摘要写入器,可以写入与 tensorboard 兼容的日志。

LLDB 扩展

DL4S 包含一个 LLDB python 脚本,该脚本为张量提供自定义描述 (util/debugger_support/tensor.py)。

要使用增强的摘要,请直接在 LLDB 中执行 command script import /path/to/DL4S/util/debugger_support/tensor.py,或将该命令添加到您的 ~/.lldbinit 文件中。

然后您可以使用 printframe variable 命令来打印张量的可读描述。

功能特性

核心

池化

范数

实用工具

激活函数

Transformer

优化器

损失函数

张量运算

广播运算的行为与 numpy 规则一致。

引擎

对于实验性的早期 GPU 加速版本,请查看 feature/arrayfire

架构

为以下架构提供了默认实现

示例

一些高级示例已在其他存储库中实现

算术运算和微分

DL4S 为张量上的许多矢量化运算提供了一个高级接口。

let a = Tensor<Float, CPU>([[1,2],[3,4],[5,6]], requiresGradient: true)
let prod = a.transposed().matrixMultipled(with: a)
let s = prod.reduceSum()
let l = log(s)
print(l) // 5.1873856

当张量被标记为需要梯度时,将捕获计算图。 该图存储所有直接或间接使用该张量作为操作数的操作。

然后可以使用 gradients(of:) 函数通过该图进行反向传播

// Backpropagate
let dl_da = l.gradients(of: [a])[0]

print(dl_da)
/*
[[0.034, 0.034]
 [0.078, 0.078]
 [0.123, 0.123]]
*/

二阶导数

反向传播期间使用的操作本身是可微分的。 因此,可以通过计算梯度的梯度来计算二阶导数。

当需要更高阶的导数时,必须显式保留反向传递的计算图。

let t = Tensor<Float, CPU>([1,2,3,4], requiresGradient: true)

let result = t * t * t
print(result) // [1, 8, 27, 64]

let grad = result.gradients(of: [t], retainBackwardsGraph: true)[0]
print(grad) // [3, 12, 27, 48]

let secondGrad = grad.gradients(of: [t], retainBackwardsGraph: true)[0]
print(secondGrad) // [6, 12, 18, 24]

let thirdGrad = secondGrad.gradients(of: [t])[0]
print(thirdGrad) // [6, 6, 6, 6]

卷积神经网络

MNIST 分类示例

// Input must be batchSizex1x28x28
var model = Sequential {
   Convolution2D<Float, CPU>(inputChannels: 1, outputChannels: 6, kernelSize: (5, 5))
   Relu<Float, CPU>()
   MaxPool2D<Float, CPU>(windowSize: 2, stride: 2)
   
   Convolution2D<Float, CPU>(inputChannels: 6, outputChannels: 16, kernelSize: (5, 5))
   Relu<Float, CPU>()
   MaxPool2D<Float, CPU>(windowSize: 2, stride: 2)
   
   Flatten<Float, CPU>()
   
   Dense<Float, CPU>(inputSize: 256, outputSize: 120)
   Relu<Float, CPU>()
   
   Dense<Float, CPU>(inputSize: 120, outputSize: 10)
   LogSoftmax<Float, CPU>()
}

var optimizer = Adam(model: model, learningRate: 0.001)

// Single iteration of minibatch gradient descent
let batch: Tensor<Float, CPU> = ... // shape: [batchSize, 1, 28, 28]
let y_true: Tensor<Int32, CPU> = ... // shape: [batchSize]

// use optimizer.model, not model
let pred = optimizer.model(batch)
let loss = categoricalNegativeLogLikelihood(expected: y_true, actual: pred)

let gradients = loss.gradients(of: optimizer.model.parameters)
optimizer.update(along: gradients)

循环神经网络

MNIST 分类示例

门控循环单元从上到下扫描图像,并将最终隐藏状态用于分类。

let model = Sequential {
    GRU<Float, CPU>(inputSize: 28, hiddenSize: 128, direction: .forward)
    Lambda<GRU<Float, CPU>.Outputs, Tensor<Float, CPU>, Float, CPU> { inputs in
        inputs.0
    }
    Dense<Float, CPU>(inputSize: 128, outputSize: 10)
    LogSoftmax<Float, CPU>()
}

var optimizer = Adam(model: model, learningRate: 0.001)

let batch: Tensor<Float, CPU> = ... // shape: [batchSize, 28, 28]
let y_true: Tensor<Int32, CPU> = ... // shape: [batchSize]

let x = batch.permuted(to: 1, 0, 2) // Swap first and second axis
let pred = optimizer.model(x)
let loss = categoricalNegativeLogLikelihood(expected: y_true, actual: pred)

let gradients = loss.gradients(of: optimizer.model.parameters)
optimizer.update(along: gradients)