Tensor 基礎¶
支援 PyTorch 的 ATen Tensor 函式庫是一個簡單的 Tensor 函式庫,它直接在 C++17 中公開 Torch 中的 Tensor 運算。ATen 的 API 是從 PyTorch 使用的相同宣告自動產生,因此這兩個 API 會隨著時間相互追蹤。
Tensor 類型是動態解析的,因此 API 是通用的,不包含模板。也就是說,只有一種 Tensor
類型。它可以保存 CPU 或 CUDA Tensor,並且 Tensor 可能具有 Doubles、Float、Ints 等。這種設計使得編寫通用程式碼變得容易,而無需對所有內容進行模板化。
請參閱 https://pytorch.dev.org.tw/cppdocs/api/namespace_at.html#functions 以取得提供的 API。摘錄
Tensor atan2(const Tensor & other) const;
Tensor & atan2_(const Tensor & other);
Tensor pow(Scalar exponent) const;
Tensor pow(const Tensor & exponent) const;
Tensor & pow_(Scalar exponent);
Tensor & pow_(const Tensor & exponent);
Tensor lerp(const Tensor & end, Scalar weight) const;
Tensor & lerp_(const Tensor & end, Scalar weight);
Tensor histc() const;
Tensor histc(int64_t bins) const;
Tensor histc(int64_t bins, Scalar min) const;
Tensor histc(int64_t bins, Scalar min, Scalar max) const;
也提供就地運算,並且總是以後綴 _ 表示它們將修改 Tensor。
有效率地存取 Tensor 元素¶
當使用 Tensor 範圍的運算時,動態分派的相對成本非常小。但是,在某些情況下,尤其是在您自己的核心中,需要有效率的逐元素存取,並且逐元素迴圈內部的動態分派成本非常高。ATen 提供了存取器,這些存取器是透過單一動態檢查(檢查 Tensor 是否為該類型和維度數量)來建立的。然後,存取器公開一個 API,用於有效率地存取 Tensor 元素。
存取器是 Tensor 的暫時性檢視。它們僅在它們所檢視的 Tensor 的生命週期內有效,因此應僅在函式中本地使用,例如迭代器。
請注意,存取器與核心函數內的 CUDA Tensor 不相容。相反,您必須使用封裝的存取器,它的行為方式相同,但會複製 Tensor 元數據,而不是指向它。
因此,建議 CPU Tensor 使用存取器,CUDA Tensor 使用封裝的存取器。
CPU 存取器¶
torch::Tensor foo = torch::rand({12, 12});
// assert foo is 2-dimensional and holds floats.
auto foo_a = foo.accessor<float,2>();
float trace = 0;
for(int i = 0; i < foo_a.size(0); i++) {
// use the accessor foo_a to get tensor data.
trace += foo_a[i][i];
}
CUDA 存取器¶
__global__ void packed_accessor_kernel(
torch::PackedTensorAccessor64<float, 2> foo,
float* trace) {
int i = threadIdx.x;
gpuAtomicAdd(trace, foo[i][i]);
}
torch::Tensor foo = torch::rand({12, 12});
// assert foo is 2-dimensional and holds floats.
auto foo_a = foo.packed_accessor64<float,2>();
float trace = 0;
packed_accessor_kernel<<<1, 12>>>(foo_a, &trace);
除了 PackedTensorAccessor64
和 packed_accessor64
之外,還有對應的 PackedTensorAccessor32
和 packed_accessor32
,它們使用 32 位元整數進行索引。這在 CUDA 上可能會快很多,但可能會導致索引計算中的溢位。
請注意,模板可以包含其他參數,例如指標限制和用於索引的整數類型。有關存取器和封裝的存取器的完整模板說明,請參閱文件。
使用外部建立的資料¶
如果您已經在記憶體(CPU 或 CUDA)中分配了 Tensor 資料,則可以在 ATen 中將該記憶體視為 Tensor
float data[] = { 1, 2, 3,
4, 5, 6 };
torch::Tensor f = torch::from_blob(data, {2, 3});
這些 Tensor 無法調整大小,因為 ATen 不擁有記憶體,但其他方面表現為正常 Tensor。
純量和零維張量¶
除了 Tensor
物件之外,ATen 也包含代表單一數字的 Scalar
。與 Tensor 類似,Scalars 是動態型別的,並且可以保存任何一種 ATen 的數字型別。Scalars 可以從 C++ 數字型別隱式構造。之所以需要 Scalars,是因為有些函數(例如 addmm
)會同時接受數字和 Tensors,並期望這些數字與 tensor 具有相同的動態型別。它們也用於 API 中,以指示函數*總是*會返回 Scalar 值的地方,例如 sum
。
namespace torch {
Tensor addmm(Scalar beta, const Tensor & self,
Scalar alpha, const Tensor & mat1,
const Tensor & mat2);
Scalar sum(const Tensor & self);
} // namespace torch
// Usage.
torch::Tensor a = ...
torch::Tensor b = ...
torch::Tensor c = ...
torch::Tensor r = torch::addmm(1.0, a, .5, b, c);
除了 Scalar
之外,ATen 也允許 Tensor
物件為零維。這些 Tensors 保存單一值,並且可以是較大 Tensor
中單一元素的參考。它們可以用於任何期望 Tensor
的地方。它們通常由像 select 這樣的運算子創建,這些運算子會減少 Tensor
的維度。
torch::Tensor two = torch::rand({10, 20});
two[1][2] = 4;
// ^^^^^^ <- zero-dimensional Tensor