Funcionamiento básico de Libtorch

El tensor en Libtorch corresponde al tensor en Pytorch. Es la estructura de datos central de la biblioteca. Es un tensor que se puede ejecutar en diferentes dispositivos y admite gradientes. El uso es similar a Tensor en Pytorch, pero existen algunas diferencias en la sintaxis admitida por algunos Python pero no admitida por C ++, como la operación Slice.

Los archivos de encabezado de Libtorch deben incluirse antes de usar Libtorch torch/torch.h:

#include <torch/torch.h>

Muchas funciones utilizadas se declaran en este archivo de encabezado y los espacios de nombres de estas funciones son todos torch, por lo que se pueden torch::xxxllamar en forma de .

Crear tensor

El tensor se puede crear de diversas formas, como mediante literales, mediante matrices de C++, mediante vectores o mediante funciones en Libtorch.

Crear tensor por literal:

#include <torch/torch.h>
#include <iostream>

int main(){
    
    
	torch::Tensor x = torch::tensor({
    
    1, 2, 3, 4});
	
	std::cout << x << std::endl;
	
	system("pause");
	
	return 0;
}
---------
1
2
3
4
[ CPULongType{
    
    4} ]

Cree un tensor a partir de una matriz torch::from_blob()y la función cambiará de forma al convertir la matriz en un tensor:

#include <torch/torch.h>
#include <iostream>

int main(){
    
    
	float arr[5] = {
    
    1, 2, 3, 4, 5};
	torch::Tensor x = torch::from_blob(arr, {
    
    1, 5});  // 第一个参数为数组,第二个参数为创建的Tensor shape
	
	std::cout << x << std::endl;
	
	system("pause");
	
	return 0;
}
---------
 1  2  3  4  5
[ CPUFloatType{
    
    1,5} ]

Crear tensor a partir de vector:

#include <torch/torch.h>
#include <iostream>

int main(){
    
    
	std::vector<float> v = {
    
    1.0, 2, 3, 4.0};
	torch::Tensor x = torch::from_blob(v.data(), {
    
    2, 2});
	
	std::cout << x << std::endl;
	
	system("pause");
	
	return 0;
}
---------
1  2
3  4
[ CPUFloatType{
    
    2,2} ]

Cree tensor a través de funciones en Libtorch:

#include <torch/torch.h>
#include <iostream>

int main(){
    
    
	torch::Tensor x1 = torch::arange(4);
	torch::Tensor x2 = torch::arange(12);
	x2 = torch::reshape(x2, {
    
    3, 4});  // C++中没有tuple类型,因此参数不能用小括号,否则会出错
	torch::Tensor x3 = torch::ones(3);
	torch::Tensor x4 = torch::ones({
    
    3, 3});
	torch::Tensor x5 = torch::zeros(4);
	torch::Tensor x6 = torch::eye(3);
	torch::Tensor x7 = torch::rand({
    
    2, 3});
	torch::Tensor x8 = torch::randn({
    
    1, 5});
	
	std::cout << x1 << std::endl;
	std::cout << x2 << std::endl;
	std::cout << x3 << std::endl;
	std::cout << x4 << std::endl;
	std::cout << x5 << std::endl;
	std::cout << x6 << std::endl;
	std::cout << x7 << std::endl;
	std::cout << x8 << std::endl;
	
	system("pause");
	
	return 0;
}
---------
 0
 1
 2
 3
[ CPULongType{
    
    4} ]
 0   1   2   3
 4   5   6   7
 8   9  10  11
[ CPULongType{
    
    3,4} ]
 1
 1
 1
[ CPUFloatType{
    
    3} ]
 1  1  1
 1  1  1
 1  1  1
[ CPUFloatType{
    
    3,3} ]
 0
 0
 0
 0
[ CPUFloatType{
    
    4} ]
 1  0  0
 0  1  0
 0  0  1
[ CPUFloatType{
    
    3,3} ]
 0.1380  0.1055  0.2361
 0.4628  0.0153  0.0506
[ CPUFloatType{
    
    2,3} ]
 0.2509  0.4332 -1.6624 -0.5655  1.4356
[ CPUFloatType{
    
    1,5} ]

Función de propiedad del objeto tensor

Después de crear tensores, a menudo necesitamos verificar algunas de sus propiedades para ver si son como se esperaba. El tensor en Libtorch no tiene propiedades de acceso público y la información de propiedad del tensor debe obtenerse a través de la función de propiedad. Las funciones de atributos comunes son las siguientes:

  • dim(): dimensión tensorial
  • tamaños(): Igual que el atributo de forma en Pytorch
  • tamaño (n): la forma de la enésima dimensión
  • numel(): el número total de elementos, los elementos en tamaños() se multiplican
  • dtype(): tipo de datos
  • dispositivo (): el tipo de dispositivo donde se encuentra el tensor, como CPU, CUDA, MPS, etc.
#include <torch/torch.h>
#include <iostream>

int main(){
    
    
	torch::Tensor x = torch::tensor({
    
    {
    
    1, 2, 3}, {
    
    4, 5, 6}});
	
	auto dim = x.dim();  // 2
	auto sizes = x.sizes();  // [2, 3]
	auto size_0 = x.size(0);  // 2
	auto numel = x.numel();  // 6
	auto dtype = x.dtype();  // int64
	auto device = x.device();  // cpu
	
	std::cout << "dim: \n" << dim << std::endl;
	std::cout << "sizes: \n" << sizes << std::endl;
	std::cout << "size_0: \n" << size_0 << std::endl;
	std::cout << "numel: \n" << numel << std::endl;
	std::cout << "dtype: \n" << dtype << std::endl;
	std::cout << "device: \n" << device << std::endl;
	
	system("pause");
	
	return 0;
}
---------
dim:
2
sizes:
[2, 3]
size_0:
2
numel:
6
dtype:
__int64
device:
cpu

El índice del objeto Tensor.

Tensor en Libtorch también puede obtener elementos por subíndice como Tensor en Pytorch:

#include <torch/torch.h>
#include <iostream>

int main(){
    
    
	torch::Tensor x = torch::tensor({
    
    {
    
    1, 2, 3}, {
    
    4, 5, 6}});
	auto ele = x[0][2];
	
	std::cout << ele << std::endl;
	
	system("pause");
	
	return 0;
}
---------
3
[ CPULongType{
    
    } ]

Además de los métodos anteriores, también puedes utilizar indexlas funciones del objeto Tensor para obtener elementos, una de sus ventajas es el soporte Slice. Para la adquisición de un solo elemento, puede utilizar directamente index({dim_0, dim_1, dim_2})el método para indexar:

#include <torch/torch.h>
#include <iostream>

int main(){
    
    
	torch::Tensor x = torch::rand({
    
    1, 3, 4, 4});  // 生成一个4维的Tensor
	auto ele1 = x.index({
    
    0, 1, 2, 2});  // 通过index方式获取单个元素
	auto ele2 = x[0][1][2][2];  // 通过下标方式获取单个元素
	
	std::cout << ele1 << std::endl;
	std::cout << ele2 << std::endl;
	
	system("pause");
	
	return 0;
}
---------
0.627059
[ CPUFloatType{
    
    } ]
0.627059
[ CPUFloatType{
    
    } ]

Si desea obtener un segmento como x[:, 0:1, 2:, :-1] como Python, ¿cómo debería representarlo en Libtorch? Aquí necesita usar torch::indexing::Sliceobjetos para implementar Slice en Python, los ejemplos son los siguientes:

#include <torch/torch.h>
#include <iostream>
using namespace torch::indexing;  // 使用该命名空间后,在使用Slice时便可直接写成Slice,而无需写成torch::indexing::Slice

int main(){
    
    
	torch::Tensor x = torch::rand({
    
    1, 3, 4, 4});  // 生成一个4维的Tensor
	auto ele = x.index({
    
    Slice(), Slice(0, 1), Slice(2, None), Slice(None, -1)});  // 等效于Python中的x[:, 0:1, 2:, :-1]
	
	std::cout << ele << std::endl;
	
	system("pause");
	
	return 0;
}
---------
(1,1,.,.) =
  0.1014  0.1333  0.8851
  0.1299  0.1242  0.1836
[ CPUFloatType{
    
    1,1,2,3} ]

Obtener los datos en Tensor

Tensor es un objeto Libtorch, entonces, ¿cómo guardar los datos que contiene en un archivo o pasarlos a otras funciones? data_ptrSolo usa la función:

#include <torch/torch.h>
#include <iostream>

int main(){
    
    
	torch::Tensor x = torch::rand({
    
    2, 3});  
	float* data = x.data_prt<float>();
	
	std::cout << data << std::endl;
	
	system("pause");
	
	return 0;
}
---------
00000192CDA7A580

Para el tensor de un solo elemento, también puedes usar itemla función para obtener el valor específico:

#include <torch/torch.h>
#include <iostream>

int main(){
    
    
	torch::Tensor x = torch::tensor({
    
    {
    
    23.27}});  
	float value = x.item<float>();
	
	std::cout << value << std::endl;
	
	system("pause");
	
	return 0;
}
---------
23.27

tipo de datos

Libtorch admite los tipos de datos Tensor de float16, float32, float64, int8, int16, int32, int64, uint8 y se topueden usar funciones para la conversión de tipos:

bar = foo.to(torch::kF16);
bar = foo.to(torch::kF32);
bar = foo.to(torch::kF64);
bar = foo.to(torch::kFloat16);
bar = foo.to(torch::kFloat32);
bar = foo.to(torch::kFloat64);
bar = foo.to(torch::kI8);
bar = foo.to(torch::kI16);
bar = foo.to(torch::kI32);
bar = foo.to(torch::kI64);
bar = foo.to(torch::kInt8);
bar = foo.to(torch::kInt16);
bar = foo.to(torch::kInt32);
bar = foo.to(torch::kInt64);
bar = foo.to(torch::kU8);
bar = foo.to(torch::kUInt8);

Tipo de equipo

El tipo de dispositivo es el tipo de dispositivo que guarda Tensor. Dado que Libtorch no solo admite CPU, sino que también admite varios tipos de GPU, existen muchos tipos de dispositivos.

Todos los tipos de dispositivos compatibles con Libtorch se enumeran a continuación:

Variable c10::kCPU
Variable c10::kCUDA
Variable c10::kFPGA
Variable c10::kHIP
Variable c10::kHPU
Variable c10::kIPU
Variable c10::kLazy
Variable c10::kMeta
Variable c10::kMetal
Variable c10::kMPS
Variable c10::kMTIA
Variable c10::kORT
Variable c10::kPrivateUse1
Variable c10::kVE
Variable c10::kVulkan
Variable c10::kXLA
Variable c10::kXPU

Cabe señalar que el dispositivo está fuertemente relacionado con la configuración en el momento de la compilación y si la máquina lo admite, y algunos dispositivos no lo admiten bien.

Función de deformación del tensor

Muchas veces necesitamos modificar la forma de Tensor, Libtorch también tiene más soporte al respecto, el soporte específico es el siguiente:

  • remodelar
  • aplanar
  • estrujar
  • descomprimir
  • transponer
  • cat/concat/concatenar

Y admitir torch::reshapeeste tipo de función estática y tensor.reshapeeste tipo de función de objeto.

#include <torch/torch.h>
#include <iostream>

int main(){
    
    
	torch::Tensor x = torch::arange(12);
	
	auto x1 = x.reshape({
    
    3, 4});  // 也可以写成torch::reshape({3, 4});
	auto x2 = x1.flatten();  // 所有维度展平成一维向量
	auto x3 = x1.unsqueeze(0);  // 在第0维增加一个维度
	auto x4 = x3.squeeze();  // 压缩维度,将所有数值为1的维度删除
	auto x5 = x1.transpose(1, 0);  // 转置,将x1的第一维放到x5的第0维,将x1的第0维放到x5的第一维
	auto x6 = torch::cat({
    
    x1, x1}, 1);  // 沿着第一维进行拼接
	
	std::cout << x1 << std::endl;
	std::cout << x2 << std::endl;
	std::cout << x3 << std::endl;
	std::cout << x4 << std::endl;
	std::cout << x5 << std::endl;
	std::cout << x6 << std::endl;
	
	system("pause");
	
	return 0;
}
---------
 0   1   2   3
 4   5   6   7
 8   9  10  11
[ CPULongType{
    
    3,4} ]
  0
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
[ CPULongType{
    
    12} ]
(1,.,.) =
   0   1   2   3
   4   5   6   7
   8   9  10  11
[ CPULongType{
    
    1,3,4} ]
  0   1   2   3
  4   5   6   7
  8   9  10  11
[ CPULongType{
    
    3,4} ]
  0   4   8
  1   5   9
  2   6  10
  3   7  11
[ CPULongType{
    
    4,3} ]
  0   1   2   3   0   1   2   3
  4   5   6   7   4   5   6   7
  8   9  10  11   8   9  10  11
[ CPULongType{
    
    3,8} ]

Una característica especial es que la transposición solo admite el intercambio de dos ejes, y el intercambio de múltiples ejes debe llamarse varias veces para lograrlo.

Funciones de operación entre tensor

En la biblioteca Tensor, las operaciones entre Tensor y Tensor son muy comunes, como multiplicar matrices, calcular productos internos, calcular productos externos, etc. El soporte de funciones incorporado puede evitar una gran cantidad de trabajo de desarrollo adicional.

#include <torch/torch.h>
#include <iostream>

int main(){
    
    
	torch::Tensor x = torch::tensor({
    
    {
    
    1, 2, 3}, {
    
    4, 5, 6}});
	torch::Tensor y = torch::tensor({
    
    {
    
    10, 20}, {
    
    30, 40}, {
    
    50, 60}});
	torch::Tensor z = torch::tensor({
    
    {
    
    10, 20, 30}, {
    
    40, 50, 60}});
	
	auto z1 = torch::matmul(x, y);  // 矩阵乘法
	auto z2 = torch::mul(x, z);  // 矩阵点乘,两个矩阵的维度需一致
	
	std::cout << z1 << std::endl;
	std::cout << z2 << std::endl;
	
	system("pause");
	
	return 0;
}
---------
 220  280
 490  640
[ CPULongType{
    
    2,2} ]
  10   40   90
 160  250  360
[ CPULongType{
    
    2,3} ]

Funciones de correlación de redes neuronales

La red neuronal es el módulo central de Torch. Algunas capas convolucionales comunes y capas completamente conectadas se pueden aplicar a Tensor en forma de funciones. A continuación se muestran algunos ejemplos simples:

bar = torch::softmax(foo, -1);
bar = torch::sigmoid(foo);
bar = torch::relu(foo);
bar = torch::gelu(foo);

Supongo que te gusta

Origin blog.csdn.net/weixin_48158964/article/details/132302333
Recomendado
Clasificación