가속기 백엔드

Tensor 계산을 설명하는 것은 매우 간단하지만 계산이 수행되는 시기와 방법은 Tensor 에 사용되는 백엔드와 호스트 CPU에서 결과가 필요한 시점에 따라 달라집니다.

뒤에서는 Tensor 의 작업이 GPU 또는 TPU와 같은 가속기로 전달되거나 가속기를 사용할 수 없는 경우 CPU에서 실행됩니다. 이는 자동으로 수행되며 고급 인터페이스를 사용하여 복잡한 병렬 계산을 쉽게 수행할 수 있습니다. 그러나 이 디스패치가 어떻게 발생하는지 이해하고 최적의 성능을 위해 이를 사용자 정의할 수 있으면 유용할 수 있습니다.

Swift for TensorFlow에는 가속화된 계산을 수행하기 위한 두 개의 백엔드, 즉 TensorFlow Eager 모드와 X10이 있습니다. 기본 백엔드는 TensorFlow Eager 모드이지만 재정의될 수 있습니다. 다양한 백엔드 사용법을 안내하는 대화형 튜토리얼이 제공됩니다.

TensorFlow 열성 모드

TensorFlow Eager 모드 백엔드는 TensorFlow C API를 활용하여 각 Tensor 작업이 발생하면 GPU 또는 CPU로 보냅니다. 그러면 해당 작업의 결과가 검색되어 다음 작업으로 전달됩니다.

이 작업별 디스패치는 이해하기 쉽고 코드 내에서 명시적인 구성이 필요하지 않습니다. 그러나 많은 경우 작은 작업을 많이 보내는 데 따른 오버헤드와 작업 그래프가 있을 때 발생할 수 있는 작업 융합 및 최적화 부족으로 인해 최적의 성능을 얻지 못합니다. 마지막으로 TensorFlow Eager 모드는 TPU와 호환되지 않으며 CPU 및 GPU에서만 사용할 수 있습니다.

X10(XLA 기반 추적)

X10은 지연 텐서 추적 및 XLA 최적화 컴파일러를 사용하여 많은 경우 작업별 디스패치에 비해 성능을 크게 향상시키는 Swift for TensorFlow 백엔드의 이름입니다. 또한 기계 학습 모델 내에서 발견되는 계산 종류에 맞게 특별히 최적화된 가속기인 TPU 에 대한 호환성을 추가합니다.

Tensor 계산에 X10을 사용하는 것은 기본값이 아니므로 이 백엔드를 선택해야 합니다. Tensor 가 XLA 장치에 배치되도록 지정하면 됩니다.

let tensor1 = Tensor<Float>([0.0, 1.0, 2.0], on: Device.defaultXLA)
let tensor2 = Tensor<Float>([1.5, 2.5, 3.5], on: Device.defaultXLA)

그 이후 계산 설명은 TensorFlow Eager 모드와 완전히 동일합니다.

let tensor3 = tensor1 + tensor2

Tensor 생성할 때 어떤 종류의 가속기를 사용할지, 여러 개가 사용 가능한 경우 어떤 가속기인지 등 더 자세한 정보를 제공할 수 있습니다. 예를 들어, 다음을 사용하여 두 번째 TPU 기기(프로그램이 실행 중인 호스트에 표시된다고 가정)에서 Tensor 생성할 수 있습니다.

let tpuTensor = Tensor<Float>([0.0, 1.0, 2.0], on: Device(kind: .TPU, ordinal: 1, backend: .XLA))

장치 간 Tensor 의 암시적 이동은 수행되지 않으므로 서로 다른 장치에 있는 두 개의 Tensor 가 작업에 함께 사용되면 런타임 오류가 발생합니다. Tensor 의 내용을 새 장치에 수동으로 복사하려면 Tensor(copying:to:) 초기화 프로그램을 사용할 수 있습니다. 모델 및 옵티마이저와 같이 내부에 Tensor 를 포함하는 일부 대규모 구조에는 모든 내부 Tensor 를 한 단계에서 새 장치로 이동하는 도우미 기능이 있습니다.

TensorFlow 열성 모드와 달리 X10 백엔드를 사용하는 작업은 발생 시 개별적으로 전달되지 않습니다. 대신, 가속기로의 디스패치는 계산된 값을 호스트로 다시 읽거나 명시적인 장벽을 배치함으로써만 트리거됩니다. 이것이 작동하는 방식은 런타임이 호스트로 읽혀지는 값(또는 수동 장벽 이전의 마지막 계산)에서 시작하여 해당 값을 초래하는 계산 그래프를 추적하는 것입니다.

그런 다음 이 추적된 그래프는 XLA HLO 중간 표현으로 변환되고 XLA 컴파일러로 전달되어 가속기에서의 실행을 위해 최적화 및 컴파일됩니다. 여기에서 전체 계산이 가속기로 전송되고 최종 결과가 얻어집니다.

계산은 시간이 많이 걸리는 프로세스이므로 X10은 그래프를 통해 표현되고 여러 번 수행되는 대규모 병렬 계산에 가장 적합합니다. 동일한 그래프가 모든 고유 구성에 대해 한 번만 컴파일되도록 해시 값과 캐싱이 사용됩니다.

기계 학습 모델의 경우 훈련 프로세스에는 모델에 동일한 일련의 계산이 반복적으로 적용되는 루프가 포함되는 경우가 많습니다. 내부에 반복되는 단위가 있는 하나의 긴 그래프가 아니라 이러한 각 패스가 동일한 추적의 반복으로 표시되기를 원할 것입니다. 이는 추적을 종료하려는 코드 위치에 LazyTensorBarrier() 함수 호출을 수동으로 삽입하여 활성화됩니다.

X10의 혼합 정밀도 지원

X10을 통한 혼합 정밀도 교육이 지원되며 이를 제어하기 위해 하위 수준 및 상위 수준 API가 모두 제공됩니다. 하위 수준 API는 전체 정밀도와 감소된 정밀도 사이를 변환하는 toReducedPrecisiontoFullPrecision 이라는 두 가지 계산 속성을 제공하고 isReducedPrecision 과 함께 정밀도를 쿼리합니다. Tensor 외에도 모델과 최적화 프로그램은 이 API를 사용하여 전체 정밀도와 감소된 정밀도 사이에서 변환될 수 있습니다.

감소된 정밀도로 변환해도 Tensor 의 논리적 유형은 변경되지 않습니다. t Tensor<Float> 인 경우 t.toReducedPrecision 은 정밀도가 낮은 기본 표현을 사용하는 Tensor<Float> 이기도 합니다.

장치와 마찬가지로 정밀도가 다른 텐서 간의 연산은 허용되지 않습니다. 이렇게 하면 사용자가 감지하기 어려운 조용하고 원치 않는 32비트 부동 소수점 승격을 방지할 수 있습니다.