WWDC Quick Look 💓 By SwiftGGTeam
Explore numerical computing in Swift

Explore numerical computing in Swift

元の動画を見る

ハイライト

Apple が Swift Numerics と Float16 をリリースし、Swift 数値アルゴリズムを利用可能にRealこのプロトコルは Float、Double、Float80、Float16 をカバーしており、以下を使用します。Complex型は、C、C++、および Accelerate の複雑なメモリ レイアウトと直接インターフェイスします。

主要内容

数値コードを記述するときは、次のことから始めるのが最も簡単です。Double始める。確率関数、対数関数、および行列ツールを最初に実行できます。プロジェクトが大きくなると問題が発生します。発信者の中には、Float、一部のプラットフォームではFloat80, 新しいデータ パイプラインをもう一度試してみたいと思います。Float16。タイプごとに実装を複製すると、バグ修正でそのうちの 1 つが簡単に失われる可能性があります。

このセッションは以下から始まりますlogit関数の入力。Darwin.logそしてDarwin.log1p書くことができますDoubleただし、「この関数は対数演算を真にサポートするすべての浮動小数点型に適用できます。」を表現することはできません。 Swift ジェネリックには、より正確な制約が必要です。 Swift Numerics によって与えられる入り口は次のとおりです。Realプロトコル (00:5502:32)。

Real標準ライブラリを入れるFloatingPointそしてSwift NumericsではAlgebraicFieldRealFunctions組み合わせたもの。開発者は、基礎となる各プロトコルを毎日分解して理解する必要はありません。汎用パラメータを制約するだけで済みます。Realでは、対数、三角関数、べき乗関数、および一般的な数学関数を呼び出すことができます。この方法で記述されたアルゴリズムは、標準の浮動小数点型を自動的にカバーし、将来的には新しい浮動小数点型にも対応します (03:2006:08)。

その後、話は複素数と半精度浮動小数点の同じ設計セットに戻ります。Complexこれは実数コンポーネントと虚数コンポーネントを保存する通常の Swift 構造体ですが、そのメモリ レイアウトは C および C++ の複合型と一致しています。 Swift 配列ポインターを Accelerate の BLAS 関数に渡すことができます。Float16次に、Swift コア言語と標準ライブラリを入力します。これらは ARM プラットフォームで利用可能で、以下に準拠しています。Real。これにより、バッチはすでに使用されていますRealアルゴリズムは、ソース コードを変更せずに 16 ビット浮動小数点を処理するように作成されています (07:0311:28)。

詳細

1. 使用するRealロジットを書く

(01:05) 元の実装のみが受け入れられましたDouble。これは公式を示すのに適していますが、ジャンルをハードコーディングします。

import Darwin

/// The log-odds function
///
/// https://en.wikipedia.org/wiki/Logit
///
/// - Parameter p:
///   A probability in the range 0...1.
///
/// - Returns:
///   The log of the odds, 'log(p/(1-p))'.
func logit(_ p: Double) -> Double {
    log(p) - log1p(-p)
}

キーポイント:

  • import DarwinC 数学ライブラリで提供されますlogそしてlog1p
  • func logit(_ p: Double) -> Double入力と出力を次のように固定します。Double
  • log(p) - log1p(-p)これは、直接計算を避けるために対数オッズを記述する数値的に安定した方法です。log(p / (1 - p))
  • このコードは直接使用できませんFloatFloat80または、将来追加される新しい浮動小数点型。

(02:33) Swift Numerics を導入した後、logit汎用関数に変更可能。制約は具象タイプから次のように変わります。NumberType: Real

import Numerics

/// The log-odds function
///
/// https://en.wikipedia.org/wiki/Logit
///
/// - Parameter p:
///   A probability in the range 0...1.
///
/// - Returns:
///   The log of the odds, 'log(p/(1-p))'.
func logit<NumberType: Real>(_ p: NumberType) -> NumberType {
    .log(p) - .log(onePlus: -p)
}

キーポイント:

  • import NumericsSwift Numerics パッケージの紹介。 -NumberType: Realこの型が、標準の算術関数および数学関数をサポートする完全な浮動小数点実数型であることを示します。 -.log(p)Numerics を使用して公開される汎用数学関数は、ダーウィンの関数に束縛されなくなりました。Double関数。 -.log(onePlus: -p)オリジナルに対応するlog1p(-p)、0に近いより安定した計算方法を保持します。
  • 戻り値の型はそのままですNumberType、発信者が通過しますFloatただ入手してくださいFloat、通りますDoubleただ入手してくださいDouble

2. Real浮動小数点機能を制約に結び付ける

03:20Real価値は明確な境界の中にあります。その意味は非常に具体的で、完全な浮動小数点演算をサポートするタイプです。講演では、標準ライブラリと Numerics の複数のプロトコルを組み合わせていることが述べられました。

func logit<NumberType: Real>(_ p: NumberType) -> NumberType {
    .log(p) - .log(onePlus: -p)
}

キーポイント:

  • FloatingPoint浮動小数点比較、指数と有効数字の分割、無限大、piおよびその他の基本的な能力。 -AlgebraicField存在するSignedNumeric四則演算の完全な数体系を表現するために、上に除算が追加されています。 -ElementaryFunctions三角関数、対数、指数、根、べき乗をカバーします。 -RealFunctionsガンマ関数、誤差関数、およびその他の三角関数のバリエーションに拡張されました。
  • 日常的なアルゴリズムは通常直接記述されますReal、新しい数値型を実装する場合にのみ、これらのプロトコルを深く分割する必要があります。

3. ComplexSwift struct で複素数を表現する

(07:10) Swift Numerics は、複数の型の完全なセットを提供します。最小限の使用法は簡単です。Numerics をインポートし、実数と虚数の組み合わせを構築します。

import Numerics

let z = Complex(1.0, 2.0) // z = 1 + 2 i

キーポイント:

  • Complex(1.0, 2.0)実数部 1 と虚数部 2 からなる複素数を作成します。
  • 両方のリテラルのデフォルトは次のとおりです。Double、それではここでz次のように推測されますComplex<Double>
  • Complexこれはそれ自体がジェネリック型であり、基礎となる数値型が以下に準拠する必要があります。Real

(07:38) このスピーチは次のことを示していますComplex基本的な形状: 2 つのフィールド、初期化子。

public struct Complex<NumberType> where NumberType: Real {
    /// The real component
    public var real: NumberType

    /// The imaginary component
    public var imaginary: NumberType

    /// Construct a complex number with specified real and imaginary parts
    public init(_ real: NumberType, _ imaginary: NumberType) {
        self.real = real
        self.imaginary = imaginary
    }
}

キーポイント:

  • where NumberType: Real実数部と虚数部の両方に完全な浮動小数点演算機能を持たせます。 -real実部を保存し、imaginary虚数部を保存します。
  • イニシャライザは余分な状態を隠しません。複素数は同じ型の 2 つの浮動小数点値の組み合わせです。
  • このレイアウトは、その後の C と C++ の相互運用性の基礎も築きます。

4. 複素数演算と極座標依存性Real数学関数

08:04Complexに準拠できるSignedNumeric加算、減算、乗算を定義しているためです。

extension Complex: SignedNumeric {
    /// The sum of 'z' and 'w'
    public static func +(z: Complex, w: Complex) -> Complex {
        return Complex(z.real + w.real, z.imaginary + w.imaginary)
    }

    /// The difference of 'z' and 'w'
    public static func -(z: Complex, w: Complex) -> Complex {
        return Complex(z.real - w.real, z.imaginary - w.imaginary)
    }

    /// The product of 'z' and 'w'
    public static func *(z: Complex, w: Complex) -> Complex {
        return Complex(z.real * w.real - z.imaginary * w.imaginary,
                       z.real * w.imaginary + z.imaginary * w.real)
    }
}

キーポイント:

  • +2 つの複素数の実数部と虚数部をそれぞれ加算します。 --2 つの複素数の実数部と虚数部をそれぞれ減算します。 -*標準の複素乗算公式を使用して、実数部と虚数部が相互乗算されます。 -SignedNumericさせてComplexより一般的な数値アルゴリズムへのアクセス。

(08:19) 極座標インターフェイスは次のようになりますReal関数のコレクションによって次のことがもたらされました。hypotatan2cossinジェネリックで使用できますNumberTypeに使用されます。

extension Complex {
    /// The Euclidean norm (a.k.a. 2-norm) of the number.
    public var length: NumberType {
        return .hypot(real, imaginary)
    }

    /// The phase (angle, or "argument").
    ///
    /// Returns the angle (measured above the real axis) in radians.
    public var phase: NumberType {
        return .atan2(y: imaginary, x: real)
    }

    /// A complex value with specified polar coordinates.
    public init(length: NumberType, phase: NumberType) {
        self = Complex(.cos(phase), .sin(phase)).multiplied(by: length)
    }
}

キーポイント:

  • length使用.hypot(real, imaginary)ユークリッドノルムを計算します。 -phase使用.atan2(y:x:)複素位相角を計算します。 -init(length:phase:)最初に使用するcosそしてsin単位の方向を取得し、長さによってスケールします。
  • これらの関数は以下から派生します。Real制約がある場合、コードは基礎となる制約を考慮する必要はありません。FloatまだDouble

5. Swift の複数形は Accelerate に直接渡すことができます

09:16Complexは、2 つの浮動小数点値のみを含む通常の構造体です。この講演では、メモリ レイアウトが C および C++ の複合型と一致するため、Swift バッファを対応する C または C++ ライブラリに渡すことができると明確に述べられています。この例では、Accelerate の BLAS 関数を使用して 2 ノルムを計算します。

import Numerics
import Accelerate

/// Array of 100 random Complex<Double> numbers
let z = (0 ..< 100).map {
    Complex(length: 1.0, phase: Double.random(in: -.pi ... .pi))
}

/// Compute the Euclidean norm of z
let norm = cblas_dznrm2(z.count, &z, 1)

キーポイント:

  • import AccelerateApple の高性能数値ライブラリを紹介します。 -z100ですComplex<Double>長さとランダムな位相で作成された各値からなる配列。 -&zSwift 配列をポインターとして C API に渡します。 -cblas_dznrm2複素数の配列を受け取り、ユークリッド 2 ノルムを返します。
  • このスピーチは、C または C++ コードを移植するときは、無限大と NaN の規則の違いに注意を払う必要があることを思い出させました。 Swift で採用されている規則はより単純であり、パフォーマンスも向上します。

6. Float16 は 16 ビットをメモリとスループットと交換します。

11:28Float16これは、Swift の新しい IEEE 754 浮動小数点形式です。標準ライブラリコアプロトコルに準拠しており、Real。これは重要です:それは書かれていますNumberType: Realアルゴリズムはそうである必要はないFloat16別のコピーを作成します。

func logit<NumberType: Real>(_ p: NumberType) -> NumberType {
    .log(p) - .log(onePlus: -p)
}

キーポイント:

  • Float1616 ビット、つまり 2 バイトを占めます。 -Float4バイトを占有し、Double8バイトを占有します。
  • 要素が小さいほど、より多くの値を同じ SIMD レジスタまたはメモリの同じページに収容できるようになります。
  • 精度と範囲が小さくなりますが、表現可能な最大値は 65,000 をわずかに超えます。FloatまたはDoubleコードにオーバーフローのリスクがないかチェックする必要があります。
  • Apple GPU は半精度を長期サポートし、Apple CPU は A11 Bionic から直接サポートします。古い CPU は使用しますFloatシミュレーション、結果は同じですが、速度が遅くなります。

(14:07) 講義では、BNNS 畳み込みベンチマークを使用したパフォーマンス数値を示します: 単精度Float約 49 ギガフロップ、Float16約 119 ギガフロップ。この例は、半精度誤差が許容される機械学習、画像処理、信号処理などのワークロードに適しています。

キーポイント:

  • まずはアルゴリズムが耐えられるか確認してくださいFloat16精度と範囲。
  • 次に、コアの一般的な制約を次のように記述します。Real、させてFloat16他の浮動小数点型と同じソース コードを共有します。
  • 最後に、古い CPU では半精度がシミュレートされるため、実際のデバイスのベンチマークを使用して利点を検証します。

重要ポイント

1. プロジェクトにアイテムを配置しますDoubleツール関数が汎用数値関数に変更されました

何をすべきか: 確率、統計、曲線、補間などのツール関数を検索し、のみを受け入れます。Doubleインターフェースは次のように変更されます。NumberType: Real

実行する価値がある理由: セッションlogitコピーの例DoubleFloatFloat80バージョン維持コスト。Realこれらの実装は組み合わせることができます。

開始方法: まず、Swift Numerics を導入し、関数シグネチャを次のように変更します。func f<NumberType: Real>(_ x: NumberType) -> NumberType次に、ダーウィンの数学関数を一般的な形式の Numerics に置き換えます。たとえば、.log.log(onePlus:).hypot

2. オーディオまたは信号処理アプリに複雑なパイプラインを追加する

何をすべきか: を使用しますComplex<Double>またはComplex<Float>周波数領域データを表し、バッファを Accelerate に渡してノルムまたは線形代数の結果を計算します。

実行する価値がある理由: Talk Notes SwiftComplexメモリ レイアウトは C および C++ の複合型と一致しており、Accelerate の BLAS API に直接接続できます。

開始方法: 最初に使用しますComplex(length:phase:)テストデータを構築して使用するcblas_dznrm2このタイプの関数は、ポインタの転送と結果を検証します。検証後、実際の FFT またはフィルターの結果は同じ構造に接続されます。

3. 画像または機械学習パスについて Float16 を試してみる

やるべきこと: 半精度エラーを許容できる畳み込み、埋め込み、ピクセル バッチ処理、または特徴キャッシュを変更してサポートします。Float16

実行する価値がある理由: セッションによって得られた BNNS ベンチマークでは、Float16畳み込みは最大 49 ギガフロップから最大 119 ギガフロップに増加します。半精度ではメモリ使用量も削減されます。

開始方法: まずコア計算からコミッションを受け取りますReal汎用関数。その後、同じ入力セットを使用して個別に実行されます。FloatそしてFloat16;ターゲットデバイス上のエラー、オーバーフロー時間、経過時間を記録します。

4. カスタム数値型の分割プロトコル実装

対処方法: アイテムに固定小数点、角度、確率、または小数タイプがある場合は、AdditiveArithmeticSignedNumericAlgebraicFieldRealFunctions階層設計機能の境界。

実行する価値がある理由: スピーチで説明しますReal複数のプロトコルのセットで構成されます。境界をクリアした後は、呼び出し元は本当に必要な機能のみに頼ることができます。

開始方法: まず加算、減算、乗算を実装し、次に除算、三角関数、指数、対数が実際にサポートされているかどうかを判断します。完全な浮動小数点セマンティクスを備えている場合にのみ、コンプライアンスを考慮してください。Real

関連セッション

コメント

GitHub Issues · utterances