Manual de Libtorch [Transferir]

Ejemplos de funciones API comúnmente utilizadas en libtorch (las más completas y detalladas de la historia)

De hecho, libtorch tiene todas las funciones de pytorch, pero existen algunas diferencias en el método de escritura. Tensor de clase
de enlace de documentación oficial de Libtorch

Es solo que el documento oficial es similar a una declaración de función y no te dice qué hace, solo puedes adivinarlo a través del nombre de la función. Por ejemplo, quiero que cada función tenga la misma forma que una variable torch::Tensor conocida, pero solo complete el valor especificado. Recuerdo haber visto una función que comenzaba con full en alguna parte, y luego busqué full y encontré una función. full_like parece ser lo que necesito. (ver 0)

Tabla de contenido

Consejos de depuración:

torch::Tensor box_1 = torch::rand({5,4});
std::cout<<box_1<<std::endl; //可以打印出数值
box_1.print();//可以打印形状

CMakeLists.txt

cmake_minimum_required(VERSION 3.0 FATAL_ERROR)
project(main)
SET(CMAKE_BUILD_TYPE "Debug")

set(CMAKE_PREFIX_PATH "/data_2/everyday/0429/pytorch/torch")
find_package(Torch REQUIRED)

set(CMAKE_PREFIX_PATH "/home/yhl/software_install/opencv3.2")
find_package(OpenCV REQUIRED)

add_executable(main main.cpp)
target_link_libraries(main "${TORCH_LIBRARIES}")

target_link_libraries(main ${OpenCV_LIBS})
set_property(TARGET main PROPERTY CXX_STANDARD 11)

0.antorcha::full_like

Tensor estático en::full_like(const Tensor &self, Scalar fill_value, const TensorOptions &options = {}, c10::optional Memory_format = c10::nullopt)
Luego, pruébalo tú mismo:

#include <iostream>
#include "torch/script.h"
#include "torch/torch.h"
using namespace std;

int main() {   
    torch::Tensor tmp_1 = torch::rand({2,3});
    torch::Tensor tmp_2 = torch::full_like(tmp_1,1);
    
    cout<<tmp_1<<endl;
    cout<<tmp_2<<endl;
}

Los resultados impresos son los siguientes:
0,8465 0,5771 0,4404
0,9805 0,8665 0,7807
[ Variable[CPUFloatType]{2,3} ]
1 1 1
1 1 1
[ Variable[CPUFloatType]{2,3} ]

1. Crear e inicializar el tensor 1.1 torch::rand 1.2 torch::empty 1.3 torch::ones 1.4 torch::Tensor keep = torch::zeros({scores.size(0)}).to(torch::kLong) .to(scores.device()); 1.5 torch::Tensor num_out = torch::full({ 2,3 }, -2, torch::dtype(torch::kLong)); torch::full crea el tensor especificado Forma 1.6 torch::Tensor a = torch::ones({3,2}).fill_(-8).to(torch::kCUDA); 1.7. torch::full_like (ver 0) crea un tensor con un valor conocido La misma forma y rellena con el valor especificado.

1.1 antorcha::rand

torch::Tensor input = torch::rand({ 1,3,2,3 });

(1,1,.,.) =
0,5943 0,4822 0,6663
0,7099 0,0374 0,9833

(1,2,.,.) =
0,4384 0,4567 0,2143
0,3967 0,4999 0,9196

(1,3,.,.) =
0,2467 0,5066 0,8654
0,7873 0,4758 0,3718
[ Variable[CPUFloatType]{1,3,2,3} ]

1.2 antorcha::vacía

   torch::Tensor a = torch::empty({2, 4});
    std::cout << a << std::endl;

7.0374e+22 5.7886e+22 6.7120e+22 6.7331e+22
6.7120e+22 1.8515e+28 ​​7.3867e+20 9.2358e-01
[ Variable[CPUFloatType]{2,4} ]

1.3 antorcha::unos

    torch::Tensor a = torch::ones({2, 4});
    std::cout << a<< std::endl;

1 1 1 1
1 1 1 1
[ Variable[CPUFloatType]{2,4} ]

1.4 antorcha::ceros

 torch::Tensor scores;
 torch::Tensor keep = torch::zeros({scores.size(0)}).to(torch::kLong).to(scores.device());

1.5 torch::full
en línea en::Tensor full(en::IntArrayRef tamaño, en::Scalar fill_value, c10::nombres opcionales, const en::TensorOptions & options = {}) en línea en::Tensor
full(en: :IntArrayRef tamaño, en::Scalar fill_value, constante en::TensorOptions & opciones = {})

    torch::Tensor num_out = torch::full({ 2,3 }, -2, torch::dtype(torch::kLong));
    std::cout<<num_out<<std::endl;

1.6 antorcha::Tensor a = antorcha::ones({3,2}).fill_(-8).to(torcha::kCUDA);

    torch::Tensor a = torch::ones({3,2}).fill_(-8).to(torch::kCUDA);
    std::cout<<a<<std::endl;

-8 -8
-8 -8
-8 -8
[Variable[CUDAFloatType]{3,2}]

2. Antorcha tensor de empalme :: cat y operación de fusión de vector y cat

2.1 Empalme por columnas

    torch::Tensor a = torch::rand({2,3});
    torch::Tensor b = torch::rand({2,1});
    torch::Tensor cat_1 = torch::cat({a,b},1);//按列拼接--》》前提是行数需要一样

    std::cout<<a<<std::endl;
    std::cout<<b<<std::endl;
    std::cout<<cat_1<<std::endl;

0,3551 0,7215 0,3603
0,1188 0,4577 0,2201
[ Variable[CPUFloatType]{2,3} ]
0,5876
0,3040
[ Variable[CPUFloatType]{2,1} ]
0,3551 0,7215 0,3603 0,5876 0,1 1 88
0,4577 0,2201 0,3040
[Variable[CPUFloatType]{2,4}]
Nota: Si el número de filas es diferente, se informará el siguiente error
: terminación llamada después de generar una instancia de 'std::runtime_error'
what(): argumento no válido 0: Los tamaños de los tensores deben coincidir excepto en la dimensión 1. Obtuve 2 y 4 en la dimensión 0 en / data_2/everyday/0429/pytorch/aten/src/TH/generic/THTensor.cpp:689

2.2 Empalme por filas

    torch::Tensor a = torch::rand({2,3});
    torch::Tensor b = torch::rand({1,3});
    torch::Tensor cat_1 = torch::cat({a,b},0);

    std::cout<<a<<std::endl;
    std::cout<<b<<std::endl;
    std::cout<<cat_1<<std::endl;

0,0004 0,7852 0,4586
0,1612 0,6524 0,7655
[ Variable[CPUFloatType]{2,3} ]
0,5999 0,5445 0,2152
[ Variable[CPUFloatType]{1,3} ]
0,0004 0,7852 0,4586
0,161 2 0,6524 0,7655
0,5999 0,5445 0,2152
[Variable[CPUFloatType]{3,3} ]

2.3 Otros ejemplos

    torch::Tensor box_1 = torch::rand({5,4});
    torch::Tensor score_1 = torch::rand({5,1});
    torch::Tensor label_1 = torch::rand({5,1});
    torch::Tensor result_1 = torch::cat({box_1,score_1,label_1},1);
    result_1.print();

[Variable[CPUFloatType] [5, 6]]

2.4 Operación de fusión de vector y cat

    torch::Tensor xs_t0 = xs - wh_0 / 2;
    torch::Tensor ys_t0 = ys - wh_1 / 2;
    torch::Tensor xs_t1 = xs + wh_0 / 2;
    torch::Tensor ys_t1 = ys + wh_1 / 2;
    xs_t0.print();
    ys_t0.print();
    xs_t1.print();
    ys_t1.print();
    vector<torch::Tensor> abce = {xs_t0,ys_t0,xs_t1,ys_t1};
    torch::Tensor bboxes = torch::cat(abce,2);
    std::cout<<"-----cat   shape---"<<std::endl;
    bboxes.print();
    while(1);

Imprima de la siguiente manera:

[Variable[CUDAType] [1, 100, 1]]
[Variable[CUDAType] [1, 100, 1]]
[Variable[CUDAType] [1, 100, 1]]
[Variable[CUDAType] [1, 100, 1]]
[Variable[CUDAType] [1, 100, 4]]
-----cat   shape---

También se puede hacer en una frase:

 torch::Tensor bboxes = torch::cat({xs_t0,ys_t0,xs_t1,ys_t1},2);

3. Operación de corte de la antorcha [seleccionar (copia superficial)] [index_select copia profunda)] [indexar copia profunda] [cortar copia superficial] estrecha, copia_estrecha

select [copia superficial] solo puede especificar una determinada fila o columna
índice [copia profunda] solo puede especificar una determinada fila
index_select [copia profunda] puede especificar varias filas o columnas por segmento de fila o columna
[copia superficial] fila o columna continua
estrecha, copia_estrecha

Cuando es una copia superficial y no quieres afectar los resultados anteriores, puedes agregar clone(), por ejemplo:

 torch::Tensor x1 = boxes.select(1,0).clone();

3.1 Tensor en línea Tensor::select(int64_t dim, int64_t index); Parece que solo puede ser bidimensional. El primer parámetro es la dimensión, 0 es buscar la fila, 1 es buscar la columna, el segundo parámetro es el número de serie del índice
3.1.1 seleccionar//buscar por fila

    torch::Tensor a = torch::rand({2,3});
    std::cout<<a<<std::endl;
    torch::Tensor b = a.select(0,1);//按行取
    std::cout<<b<<std::endl;

0.6201 0.7021 0.1975
0.3080 0.6304 0.1558
[ Variable[CPUFloatType]{2,3} ]
0.3080
0.6304
0.1558
[ Variable[CPUFloatType]{3} ]
3.1.2 seleccionar//Obtener por columna

    torch::Tensor a = torch::rand({2,3});
    std::cout<<a<<std::endl;

    torch::Tensor b = a.select(1,1);
    std::cout<<b<<std::endl;

0,8295 0,9871 0,1287
0,8466 0,7719 0,2354
[Variable[CPUFloatType]{2,3}]
0,9871
0,7719
[Variable[CPUFloatType]{2}]
Nota: Esta es una copia superficial, es decir, cambiar by el valor de a también cambiará
3.1.3 seleccionar copia superficial

    torch::Tensor a = torch::rand({2,3});
    std::cout<<a<<std::endl;
    
    torch::Tensor b = a.select(1,1);
    std::cout<<b<<std::endl;
    
    b[0] = 0.0;
    std::cout<<a<<std::endl;
    std::cout<<b<<std::endl;

0,0938 0,2861 0,0089
0,3481 0,5806 0,3711
[ Variable[CPUFloatType]{2,3} ]
0,2861
0,5806
[ Variable[CPUFloatType]{2} ]
0,0938 0,0000 0,0089
0,3481 0,580 6 0,3711
[Variable[CPUFloatType]{2,3}]
0,0000
0,5806
[Variable [ CPUFloatType]{2} ]
Puedes ver que b[0] = 0.0; entonces las posiciones correspondientes de a y b son 0. ¡Copia superficial! !

3.2 Tensor en línea Tensor::index_select(Dimname dim, const Tensor & index) // De manera similar, dim0 significa por fila, 1 significa por columna, índice significa el número de fila o de columna, es extraño aquí, el índice debe ser toType(
torch ::kLong) este tipo. Otra cosa extraña es que iba a usar una matriz para importar tensor y descubrí que el idx era todo 0. Se desconoce el motivo.

 torch::Tensor a = torch::rand({2,6});
    std::cout<<a<<std::endl;
slice

     torch::Tensor idx = torch::empty({4}).toType(torch::kLong);
     idx[0]=0;
     idx[1]=2;
     idx[2]=4;
     idx[3]=1;

//    int idx_data[4] = {1,3,2,4};
//    torch::Tensor idx = torch::from_blob(idx_data,{4}).toType(torch::kLong);//idx全是0  ?????????????????

    std::cout<<idx<<std::endl;

    torch::Tensor b = a.index_select(1,idx);
    std::cout<<b<<std::endl;

0,4956 0,5028 0,0863 0,9464 0,6714 0,5348
0,3523 0,2245 0,0924 0,7088 0,6913 0,2237
[ Variable[CPUFloatType]{2,6} ]
0
2
4
1
[ Variable[CPULongType]{4} ]
0,4956 0,0863 0,6714 0,5028 0,3523
0,0924 0,6913 0,2245
[Variable[CPUFloatType]{ 2,4} ]

3.2.2 copia profunda index_select

    torch::Tensor a = torch::rand({2,6});
    std::cout<<a<<std::endl;


     torch::Tensor idx = torch::empty({4}).toType(torch::kLong);
     idx[0]=0;
     idx[1]=2;
     idx[2]=4;
     idx[3]=1;

//    int idx_data[4] = {1,3,2,4};
//    torch::Tensor idx = torch::from_blob(idx_data,{4}).toType(torch::kLong);

    std::cout<<idx<<std::endl;

    torch::Tensor b = a.index_select(1,idx);
    std::cout<<b<<std::endl;

    b[0][0]=0.0;
    std::cout<<a<<std::endl;
    std::cout<<b<<std::endl;

0,6118 0,6078 0,5052 0,9489 0,6201 0,8975
0,0901 0,2040 0,1452 0,6452 0,9593 0,7454
[ Variable[CPUFloatType]{2,6} ]
0
2
4
1
[ Variable[CPULongType]{4} ]
0,6118 0,5052 0,6201 0,6078 0,0901
0,1452 0,9593 0,2040
[Variable[CPUFloatType]{ 2,4} ]
0,6118 0,6078 0,5052 0,9489 0,6201 0,8975 0,0901
0,2040 0,1452 0,6452 0,9593 0,7454
[ Variable[CPUFloatType]{2,6} ]
0,0000 0,5052 0,6201 0,6078
0,0901 0,1452 0,9593 0,2040
[Variable[CPUFloatType]{2,4}]

3.3 Tensor de índice en línea Tensor::index(TensorList indices)
Después de experimentar con esta función, solo se puede recuperar por fila y es una copia profunda.

    torch::Tensor a = torch::rand({2,6});
    std::cout<<a<<std::endl;


    torch::Tensor idx_1 = torch::empty({2}).toType(torch::kLong);
    idx_1[0]=0;
    idx_1[1]=1;


    torch::Tensor bb = a.index(idx_1);
    bb[0][0]=0;

    std::cout<<bb<<std::endl;
    std::cout<<a<<std::endl;

0,1349 0,8087 0,2659 0,3364 0,0202 0,4498 0,4785 0,4274 0,9348 0,0437 0,6732
0,3174
[ Variable[CPUFloatType]{2,6} ]
0,0000 0,8087 0,2659 0,3364 0,0202 0,4498 0,4785 0,4274 0,9348 0,0437 0,6732
0,3174
[ Variable[CPUFloatType]{2,6} ]
0,1349 0,8087 0,2659 0,3364 0,0202 0,4498
0,4785 0,4274 0,9348 0,0437 0,6732 0,3174
[ Variable[CPUFloatType]{2,6} ]
Tensor en línea de 3,4 cortes Tensor::slice(int64_t dim, int64_t start, int64_t end, int64_t step) //d im0 significa buscar por fila, 1 Significa buscar por columna, comenzando desde el principio y terminando al final (exclusivo), ¡
puedes ver el resultado, que es una copia superficial! ! !

 torch::Tensor a = torch::rand({2,6});
    std::cout<<a<<std::endl;

    torch::Tensor b = a.slice(0,0,1);
    torch::Tensor c = a.slice(1,0,3);

    b[0][0]=0.0;

    std::cout<<b<<std::endl;
    std::cout<<c<<std::endl;

    std::cout<<a<<std::endl;

0,8270 0,7952 0,3743 0,7992 0,9093 0,5945 0,3764 0,8419 0,7977 0,4150 0,8531
0,9207
[ Variable[CPUFloatType]{2,6} ]
0,0000 0,7952 0,3743 0,7992 0,9093 0,5945
[ Variable[CPUFloatType]{1,6} ]
0,0000 0,7952 0,3743 0,3764
0,8419 0,7977
[ Variable[CPUFloatType ]{2,3} ]
0,0000 0,7952 0,3743 0,7992 0,9093 0,5945
0,3764 0,8419 0,7977 0,4150 0,8531 0,9207
[ Variable[CPUFloatType]{2,6} ]

3.5 estrecho
Tensor en línea de copia estrecha Tensor::narrow(int64_t dim, int64_t start, int64_t length) const
Tensor en línea Tensor::narrow_copy(int64_t dim, int64_t start, int64_t length) const

    torch::Tensor a = torch::rand({4,6});
    torch::Tensor b = a.narrow(0,1,2);
    torch::Tensor c = a.narrow_copy(0,1,2);

    std::cout<<a<<std::endl;
    std::cout<<b<<std::endl;
    std::cout<<c<<std::endl;

0.9812 0.4205 0.4169 0.2412 0.8769 0.9873
0.8052 0.0312 0.9901 0.5065 0.6344 0.3408
0.0182 0.6933 0.9375 0.8675 0.5201 0.9521
0.5119 0.3880 0.1117 0.5413 0.8203 0.4163
[ Variable[CPUFloatType]{4,6} ]
0.8052 0.0312 0.9901 0.5065 0.6344 0.3408
0.0182 0.6933 0.9375 0.8675 0.5201 0.9521
[ Variable[ CPUFloatType]{2,6} ]
0,8052 0,0312 0,9901 0,5065 0,6344 0,3408 0,0182 0,6933
0,9375 0,8675 0,5201 0,9521
[ Variable[CPUFloatType]{2,6} ]

4.apretar() descomprimir()

Tensor en línea Tensor::squeeze() const//Sin parámetros, comprime todas las dimensiones de 1
Tensor en línea Tensor::squeeze(int64_t dim)const//Con parámetros, especifica qué dimensión comprimir
Tensor y Tensor en línea: :squeeze_() const //Aún no conozco la diferencia
inline Tensor & Tensor::squeeze_(int64_t dim) const //Aún no conozco la diferencia
4.1 squeeze()

(1,.,.) = 
  0.5516  0.6561  0.3603
  0.7555  0.1048  0.2016
[ Variable[CPUFloatType]{1,2,3} ]
 0.5516  0.6561  0.3603
 0.7555  0.1048  0.2016
[ Variable[CPUFloatType]{2,3} ]
(1,.,.) = 
  0.7675  0.5439  0.5162

(2,.,.) = 
  0.6103  0.1925  0.1222
[ Variable[CPUFloatType]{2,1,3} ]
 0.7675  0.5439  0.5162
 0.6103  0.1925  0.1222
[ Variable[CPUFloatType]{2,3} ]
(1,1,.,.) = 
  0.9875
  0.1980

(2,1,.,.) = 
  0.6973
  0.3272
[ Variable[CPUFloatType]{2,1,2,1} ]
 0.9875  0.1980
 0.6973  0.3272
[ Variable[CPUFloatType]{2,2} ]

4.2 squeeze(int64_t dim) especifica qué dimensión comprimir

    torch::Tensor a = torch::rand({1,1,3});
    std::cout<<a<<std::endl;
    
    torch::Tensor b = a.squeeze();
    std::cout<<b<<std::endl;
    
    torch::Tensor c = a.squeeze(0);
    std::cout<<c<<std::endl;
    
    torch::Tensor d = a.squeeze(1);
    std::cout<<d<<std::endl;
    
    torch::Tensor e = a.squeeze(2);
    std::cout<<e<<std::endl;

(1,.,.) =
0,8065 0,1287 0,8073
[ Variable[CPUFloatType]{1,1,3} ]
0,8065
0,1287
0,8073
[ Variable[CPUFloatType]{3} ]
0,8065 0,1287 0,8073
[ Variable[CPUFloatType]{1,3} ]
0,8065 0,1287 0,8073
[ Variable[CPUFloatType]{1,3} ]
(1,.,.) =
0,8065 0,1287 0,8073
[ Variable[CPUFloatType]{1,1,3} ]
4.3. descomprimir

    torch::Tensor a = torch::rand({2,3});
    std::cout<<a<<std::endl;

    torch::Tensor b = a.unsqueeze(0);
    std::cout<<b<<std::endl;

    torch::Tensor bb = a.unsqueeze(1);
    std::cout<<bb<<std::endl;

    torch::Tensor bbb = a.unsqueeze(2);
    std::cout<<bbb<<std::endl;

0,7945 0,0331 0,1666
0,7821 0,3359 0,0663
[ Variable[CPUFloatType]{2,3} ]
(1,.,.) =
0,7945 0,0331 0,1666
0,7821 0,3359 0,0663
[ Variable[CPUFloatType]{1,2, 3} ]
(1,.,. ) =
0,7945 0,0331 0,1666

(2,.,.) =
0,7821 0,3359 0,0663
[ Variable[CPUFloatType]{2,1,3} ]
(1,.,.) =
0,7945
0,0331
0,1666

(2,.,.) =
0,7821
0,3359
0,0663
[ Variable[CPUFloatType]{2,3,1} ]

5.torch::nonzero genera coordenadas distintas de cero

    torch::Tensor a = torch::rand({2,3});
    a[0][1] = 0;
    a[1][2] = 0;
    std::cout<<a<<std::endl;
     torch::Tensor b = torch::nonzero(a);
     std::cout<<b<<std::endl;

0,4671 0,0000 0,3360
0,9320 0,9246 0,0000
[ Variable[CPUFloatType]{2,3} ]
0 0
0 2
1 0
1 1
[ Variable[CPULongType]{4,2} ]

6. Al acceder al valor del tensor a.item(), convierta la a del tensor 1*1 en flotante.

Saque un cierto valor de tensor como int o float ===》》》auto bbb = a[1][1].item().toFloat(); Generalmente, al sacar un cierto valor de tensor, puede directamente subíndice el índice
... Por ejemplo, a[0][1], pero este valor sigue siendo de tipo tensor. Si quieres que sea C++ int o float, de la siguiente manera:

    torch::Tensor a = torch::rand({2,3});
    std::cout<<a<<std::endl;
    auto bbb = a[1][1].item().toFloat();
    std::cout<<bbb<<std::endl;

0,7303 0,6608 0,0024
0,5917 0,0145 0,6472
[ Variable[CPUFloatType]{2,3} ]
0,014509
[ Variable[CPUFloatType]{} ]
0,014509

Ejemplos adicionales:

    torch::Tensor scores = torch::rand({10});
    std::tuple<torch::Tensor,torch::Tensor> sort_ret = torch::sort(scores.unsqueeze(1), 0, 1);
    torch::Tensor v = std::get<0>(sort_ret).squeeze(1).to(scores.device());
    torch::Tensor idx = std::get<1>(sort_ret).squeeze(1).to(scores.device());
    std::cout<<scores<<std::endl;
    std::cout<<v<<std::endl;
    std::cout<<idx<<std::endl;

    for(int i=0;i<10;i++)
    {
         int idx_1 = idx[i].item<int>();
         float s = v[i].item<float>();

          std::cout<<idx_1<<"  "<<s<<std::endl;
    }

0,1125
0,9524
0,7033
0,3204 0,7907 0,8486
0,7783 0,3215 0,0378 0,7512 [ Variable[CPUFloatType]{10} ] 0,9524 0,8486 0,7907 0,7783 0,7512 0 0,7033 0,3215 0,3204 0,1125 0,0378 [ Variable[CPUFloatType]{10} ] 1 5 4 6 9 2 7 3 0 8 [ Variable [CPULongType]{10} ] 1 0,952351 5 0,848641 4 0,790685 6 0,778329 9 0,751163 2 0,703278 7 0,32146



































3 0,320435
0 0,112517
8 0,0378203

7.opencv Tipo de tapete a tensor u otros datos vectoriales o de matriz a tensor

7.1

   Mat m_out = imread(path);
 //[320,320,3]
    input_tensor = torch::from_blob(
                m_out.data, {m_SIZE_IMAGE, m_SIZE_IMAGE, 3}).toType(torch::kFloat32);//torch::kByte //大坑
    //[3,320,320]
    input_tensor = input_tensor.permute({2,0,1});
    input_tensor = input_tensor.unsqueeze(0);
    input_tensor = input_tensor.to(torch::kFloat).to(m_device);

Cabe señalar aquí que debido a que la imagen de arriba ha sido preprocesada por mí y restada de la media, el valor de píxel m_out tiene un número negativo. Si el formato es torch::kByte, el número negativo se convertirá en un número positivo. por lo que se requiere el tipo torch::kFloat32.
permute({2,0,1});
antes de que fuera opencv Mat era
0 1 2
[320,320,3]
después de permute({2,0,1}), lo que significa que la posición correspondiente se cambia y se convierte en [3,320,320 ]

7.2

std::vector<float> region_priors;
//region_priors.push_back(num)  region_priors的size是6375 × 4
torch::Tensor m_prior = torch::from_blob(region_priors.data(),{6375,4}).cuda();

8.tensor 的tamaño tamaños() numerel()

    torch::Tensor a = torch::rand({2,3});
    std::cout<<a<<std::endl;

    auto aa = a.size(0);
    auto bb = a.size(1);
    auto a_size = a.sizes();
    std::cout<<aa<<std::endl;
    std::cout<<bb<<std::endl;
    std::cout<<a_size<<std::endl;

    int num_ = a.numel();
    std::cout<<num_<<std::endl;

0,6522 0,0480 0,0009
0,1185 0,4639 0,0386
[ Variable[CPUFloatType]{2,3} ]
2
3
[2, 3]
6

8.2
Existe el problema de que cuando torch::Tensor a; define directamente un tensor, luego accede a él

    torch::Tensor a;
     auto a_size = a.sizes();

就会报错
terminate llamado después de lanzar una instancia de 'c10::Error'
what(): size() llamado en un tensor indefinido (tamaños en /data_2/everyday/0429/pytorch/c10/core/UndefinitedTensorImpl.cpp:12)
frame #0: c10::Error::Error(c10::SourceLocation, std::__cxx11::basic_string<char, std::char_traits, std::allocator > const&) + 0x6a (0x7f83b563f0aa en /data_2/everyday/0429/ pytorch/torch/lib/libc10.so)
cuadro n.° 1: c10::UndefinidoTensorImpl::sizes() const + 0x258 (0x7f83b56362b8 en /data_2/everyday/0429/pytorch/torch/lib/libc10.so)
cuadro n.° 2: at::Tensor::sizes() const + 0x27 (0x405fc9 en /data_2/everyday/0516/build-libtorch-syntax-unknown-Default/main) frame #3: main + 0x30 (0x405d06
en /data_2/everyday/0516 /build-libtorch-sintaxis-desconocida-predeterminada/principal)
cuadro n.° 4: __libc_start_main + 0xf0 (0x7f83b4d12830 en /lib/x86_64-linux-gnu/libc.so.6)
cuadro n.° 5: _start + 0x29 (0x405c09 en /data_2/everyday/0516/build-libtorch-sintaxis-desconocida- Predeterminado/principal)

El programa terminó de manera anormal.
No hay problema si usas numel()

    torch::Tensor a;
    int num_ = a.numel();
    std::cout<<num_<<std::endl;

8.3 Obtener el tamaño de la dimensión, como [1,5,8,2], necesito obtener la dimensión 4

auto aaa = img_poly.sizes();
int len_ = aaa.size();

9.antorcha::ordenar

estático en línea std::tuple<Tensor,Tensor> sort(const Tensor & self, Dimname dim, bool descendente)
dim0 significa por fila, 1 significa por columna
descendente=falso significa orden ascendente, verdadero significa orden descendente
devuelve tuplas, la primera El primero representa el valor ordenado y el segundo representa el índice correspondiente al anterior después de ordenar.

    torch::Tensor scores = torch::rand({10});
    std::tuple<torch::Tensor,torch::Tensor> sort_ret = torch::sort(scores.unsqueeze(1), 0, 1);
    torch::Tensor v = std::get<0>(sort_ret).squeeze(1).to(scores.device());
    torch::Tensor idx = std::get<1>(sort_ret).squeeze(1).to(scores.device());
    std::cout<<scores<<std::endl;
    std::cout<<v<<std::endl;
    std::cout<<idx<<std::endl;

0,8355
0,1386
0,7910
0,0988
0,2607
0,7810
0,7855 0,5529 0,5846
0,1403 [ Variable[CPUFloatType]{10} ] 0,8355 0,7910 0,7855 0,7810
0,5846 0 0,5529 0,2607 0,1403 0,1386
0,0988 [ Variable[CPUFloatType]{10} ] 0 2 6 5 8 7 4 9 1 3 [ Variable [CPULongType]{10} ]






















10.clamp controla el valor entre mínimo y máximo, si es menor que el mínimo, es mínimo, y si es mayor que el máximo, es máximo.

Tensor en línea Tensor::clamp(c10::opcional min, c10::optional max) const

    torch::Tensor a = torch::rand({2,3});
    a[0][0] = 20;
    a[0][1] = 21;
    a[0][2] = 22;
    a[1][0] = 23;
    a[1][1] = 24;
    std::cout<<a<<std::endl;

    torch::Tensor b = a.clamp(21,22);
    std::cout<<b<<std::endl;

20.0000 21.0000 22.0000 23.0000
24.0000 0.4792
[ Variable[CPUFloatType]{2,3} ]
21 21 22
22 22 21
[ Variable[CPUFloatType]{2,3} ]
En ingeniería, el valor en tensor generalmente se toma y, a veces, solo se limita a uno. lado, por ejemplo, solo limite min, de la siguiente manera:

 xx1 = xx1.clamp(x1[i].item().toFloat(),INT_MAX*1.0);

11. Operación mayor que > menor que <

    torch::Tensor a = torch::rand({2,3});
    std::cout<<a<<std::endl;
    torch::Tensor b = a > 0.5;
    std::cout<<b<<std::endl;

0,3526 0,0321 0,7098
0,9794 0,6531 0,9410
[ Variable[CPUFloatType]{2,3} ]
0 0 1
1 1 1
[ Variable[CPUBoolType]{2,3} ]

12. Transponer tensor::transponer

Tensor en línea Tensor::transpose(Dimname dim0, Dimname dim1) const

    torch::Tensor a = torch::rand({2,3});
    std::cout<<a<<std::endl;

    torch::Tensor b = a.transpose(1,0);
    std::cout<<b<<std::endl;

0,4039 0,3568 0,9978
0,6895 0,7258 0,5576
[ Variable[CPUFloatType]{2,3} ]
0,4039 0,6895
0,3568 0,7258
0,9978 0,5576
[ Variable[CPUFloatType]{3,2} ]

13.expand_as

Tensor en línea Tensor::expand_as(const Tensor y otros) const

    torch::Tensor a = torch::rand({2,3});;
    //    torch::Tensor b = torch::ones({2,2});
    torch::Tensor b = torch::ones({2,1});
    torch::Tensor c = b.expand_as(a);
    
    std::cout<<a<<std::endl;
    std::cout<<b<<std::endl;
    std::cout<<c<<std::endl;

0,6063 0,4150 0,7665
0,8663 0,9563 0,7461
[ Variable[CPUFloatType]{2,3} ]
1
1
[ Variable[CPUFloatType]{2,1} ]
1 1 1
1 1 1
[ Variable[CPUFloatType]{2,3} ]

注意维度有一定要求,我这么写torch::Tensor b = torch::ones({2,2});torch::Tensor b = torch::ones({2});都会报错: terminar llamado después de
lanzar una instancia de 'c10::Error'
what(): El tamaño expandido del tensor (3) debe coincidir con el tamaño existente (2) en la dimensión no singleton 1. Tamaños objetivo: [2, 3]. Tamaños de tensor: [2, 2] (inferExpandGeometry en /data_2/everyday/0429/pytorch/aten/src/ATen/ExpandUtils.cpp:76)
cuadro #0: c10::Error::Error(c10::SourceLocation, std ::__cxx11::basic_string<char, std::char_traits, std::allocator > const&) + 0x6a (0x7f6a488150aa en /data_2/everyday/0429/pytorch/torch/lib/libc10.so)
cuadro #1: en:: inferExpandGeometry(c10::ArrayRef, c10::ArrayRef, c10::ArrayRef) + 0x76b (0x7f6a49df7a4b en /data_2/everyday/0429/pytorch/torch/lib/libtorch.so)
cuadro n.° 2: at::native::expand(at::Tensor const&, c10::ArrayRef, bool) + 0x84 (0x7f6a4a1e4324 in /data_2/everyday/0429/pytorch/torch/lib/libtorch.so)
cuadro n.° 3 : + 0x1aeb9e1 (0x7f6a4a5189e1 en /data_2/everyday/0429/pytorch/torch/lib/libtorch.so)
marco #4: + 0x19e8a2e (0x7f6a4a415a2e en /data_2/everyday/0429/pytorch/torch/lib/libtorch.so)
marco #5: + 0x3509dee (0x7f6a4bf36dee en /data_2/everyday/0429/pytorch/torch/lib/libtorch.so)
cuadro #6: + 0x19e8a2e (0x7f6a4a415a2e en /data_2/everyday/0429/pytorch/torch/lib/libtorch.so )
cuadro n.° 7: + 0x14e8a61 (0x7f6a49f15a61 en /data_2/everyday/0429/pytorch/torch/lib/libtorch.so)
cuadro n.° 8: en::native::expand_as(en::Tensor const&, en::Tensor const& ) + 0x39 (0x7f6a4a1e4d49 en /data_2/everyday/0429/pytorch/torch/lib/libtorch.so)
cuadro n.° 9: + 0x1aece9f (0x7f6a4a519e9f en /data_2/everyday/0429/pytorch/torch/lib/libtorch.so)
cuadro n.° 10: + 0x3680543 (0x7f6a4c0ad543 en /data_2/everyday/0429/pytorch/torch/lib/libtorch. entonces)
cuadro #11: + 0x19e6bb4 (0x7f6a4a413bb4 en /data_2/everyday/0429/pytorch/torch/lib/libtorch.so)
cuadro #12: at::Tensor c10::KernelFunction::callUnboxed<at::Tensor, at ::Tensor const&, en::Tensor const&>(en::Tensor const&, en::Tensor const&) const + 0xb0 (0x433e06 en /data_2/everyday/0516/build-libtorch-sintaxis-unknown-Default/main)
fotograma n.° 13: en::Tensor c10::impl::OperatorEntry::callUnboxed<en::Tensor, en::Tensor const&, en::Tensor const&>(c10::TensorTypeId, en::Tensor const&, en: :Tensor const&) const::{lambda(c10::DispatchTable const&)#1}::operator()(c10::DispatchTable const&) const + 0x79 (0x432525 en /data_2/everyday/0516/build-libtorch- sintaxis- desconocido-predeterminado/principal)
cuadro #14: std::result_of<at::Tensor c10::impl::OperatorEntry::callUnboxed<at::Tensor, at::Tensor const&, at::Tensor const&>(c10::TensorTypeId, at:: Tensor const&, en::Tensor const&) const::{lambda(c10::DispatchTable const&)#1} (c10::DispatchTable const&)>::tipo c10::LeftRightc10::DispatchTable::read<at::Tensor c10::impl::OperatorEntry::callUnboxed<en::Tensor, en::Tensor const&, en::Tensor const&>(c10::TensorTypeId, en::Tensor const&, en::Tensor const&) const::{ lambda(c10::DispatchTable const&)#1}>(at::Tensor c10::impl::OperatorEntry::callUnboxed<at::Tensor, at::Tensor const&, at::Tensor const&>(c10::TensorTypeId , en::Tensor const&, en::Tensor const&) const::{lambda(c10::DispatchTable const&)#1}&&) const + 0x11c (0x4340ba en /data_2/everyday/0516/build-libtorch-sintaxis-unknown-Default/main)
fotograma n.° 15: en::Tensor c10::impl::OperatorEntry::callUnboxed<en::Tensor, en::Tensor const&, en::Tensor const&>(c10::TensorTypeId, en::Tensor const&, en: :Tensor const&) const + 0x5f (0x4325a5 en /data_2/everyday/0516/build-libtorch-syntax-unknown-Default/main)
frame #16: at::Tensor c10::Dispatcher::callUnboxed<at::Tensor, en::Tensor const&, en::Tensor const&>(c10::OperatorHandle const&, c10::TensorTypeId, en::Tensor const&, en::Tensor const&) const + 0x85 (0x42fd5d en /data_2/everyday/0516/build -libtorch- sintaxis-desconocida-Default/main)
frame #17: at::Tensor::expand_as(at::Tensor const&) const + 0x1a5 (0x42ba47 in /data_2/everyday/0516/build-libtorch-sintaxis-unknown- Predeterminado/principal)
cuadro #18:principal + 0xbd (0x427c97 en /data_2/everyday/0516/build-libtorch-sintaxis-unknown-Default/main)
cuadro n.° 19: __libc_start_main + 0xf0 (0x7f6a47ee8830 en /lib/x86_64-linux-gnu/libc.so.6)
cuadro n.° 20: _start + 0x29 (0x426999 en /data_2/everyday/0516/build-libtorch-sintaxis-desconocida- Predeterminado/principal)

14. Multiplica mul_, divide div y resta sub_

        boxes_my.select(1,0).mul_(width);
        boxes_my.select(1,1).mul_(height);
        boxes_my.select(1,2).mul_(width);
        boxes_my.select(1,3).mul_(height);
prediction.select(2, 3).div(2);
      input_tensor[0][0] = input_tensor[0][0].sub_(0.485).div_(0.229);
               input_tensor[0][1] = input_tensor[0][1].sub_(0.456).div_(0.224);
               input_tensor[0][2] = input_tensor[0][2].sub_(0.406).div_(0.225);

15. Cargar el modelo

    torch::Device m_device(torch::kCUDA);
    torch::jit::script::Module m_model = torch::jit::load(path_pt);
    m_model.to(m_device);
    m_model.eval();

16.El resultado del modelo hacia adelante

Cuando el modelo tiene varias salidas,

 auto output = m_model.forward({input_tensor});

    auto tpl = output.toTuple();
    auto arm_loc = tpl->elements()[0].toTensor();
    // arm_loc.print();
    //    std::cout<<arm_loc[0]<<std::endl;
    auto arm_conf = tpl->elements()[1].toTensor();
    //arm_conf.print();
    auto odm_loc = tpl->elements()[2].toTensor();
    //odm_loc.print();
    //     std::cout<<odm_loc[0]<<std::endl;
    auto odm_conf = tpl->elements()[3].toTensor();
    //    odm_conf.print();

17.redimensionar_cero_

Tensor y resize_(tamaño IntArrayRef) const;
Tensor & zero_() const;

    torch::Tensor a = torch::rand({1,3,2,2});

    const int batch_size = a.size(0);
    const int depth = a.size(1);
    const int image_height = a.size(2);
    const int image_width = a.size(3);

    torch::Tensor crops = torch::rand({1,3,2,2});
    //    torch::Tensor crops;
    crops.resize_({ batch_size, depth, image_height, image_width });
    crops.zero_();

    std::cout<<a<<std::endl;
    std::cout<<crops<<std::endl;

(1,1,.,.) =
0,7889 0,3291
0,2541 0,8283

(1,2,.,.) =
0,0209 0,1846
0,2528 0,2755

(1,3,.,.) =
0,0294 0,6623
0,2736 0,3376
[ Variable[CPUFloatType]{1,3,2,2} ]
(1,1,.,.) =
0 0
0 0

(1,2,.,.) =
0 0
0 0

(1,3,.,.) =
0 0
0 0
[ Variable[CPUFloatType]{1,3,2,2} ]
Nota: Si aquí solo se definen cultivos de antorcha::tensor;//antorcha::cultivos de tensor = torch ::rand({1,3,2,2}); informará un error. Siento que aún es necesario inicializarlo antes de asignar memoria; de lo contrario, informará un error.
terminate llamado después de lanzar una instancia de '
c10::Error'
what(): no había argumentos tensoriales para esta función (por ejemplo, pasaste una lista vacía de tensores), pero no hay ninguna función alternativa registrada para el esquema aten::resize_. Esto generalmente significa que esta función requiere una lista no vacía de tensores. Las funciones disponibles son [CUDATensorId, QuantizedCPUTensorId, CPUTensorId, VariableTensorId] (lookup_ at /data_2/everyday/0429/pytorch/torch/include/ATen/core/dispatch/DispatchTable .h:243)
cuadro #0: c10::Error::Error(c10::SourceLocation, std::cxx11::basic_string<char, std::char_traits, std::allocator > const&) + 0x6a (0x7fa2f5f450aa en /data_2/everyday/0429/pytorch/torch/lib/libc10.so)
cuadro #1: c10::KernelFunction const& c10::DispatchTable::lookup
<c10::DispatchTable::lookup(c10::TensorTypeId) const::{lambda()#1}>(c10::DispatchTable::lookup(c10::TensorTypeId) const::{ lambda()#1} const&) const + 0x1da (0x42eaa8 en /data_2/everyday/0516/build-libtorch-syntax-unknown-Default/main) frame #2: c10::DispatchTable::lookup(c10::TensorTypeId
) const + 0x3a (0x42acf4 en /data_2/everyday/0516/build-libtorch-sintaxis-unknown-Default/main)
cuadro #3: en::Tensor& c10::impl::OperatorEntry::callUnboxedOnly<at::Tensor&, en::Tensor&, c10::ArrayRef >(c10::TensorTypeId, en::Tensor&, c10::ArrayRef) const::{lambda(c10::DispatchTable const&)#1}::operator()(c10::DispatchTable const&) const + 0x51 (0x431543 en /data_2/everyday/0516/build-libtorch-syntax-unknown-Default/ principal)
cuadro #4: std::result_of<at::Tensor& c10::impl::OperatorEntry::callUnboxedOnly<at::Tensor&, at::Tensor&, c10::ArrayRef >(c10::TensorTypeId, at::Tensor&, c10::ArrayRef) const::{lambda(c10::DispatchTable const&)#1} (c10::DispatchTable const&)>::tipo c10::LeftRightc10::DispatchTable::read<at::Tensor& c10::impl ::OperatorEntry::callUnboxedOnly<at::Tensor&, at::Tensor&, c10::ArrayRef >(c10::TensorTypeId, at::Tensor&, c10::ArrayRef) const::{lambda(c10::DispatchTable const&) #1}>(at::Tensor& c10::impl::OperatorEntry::callUnboxedOnly<at::Tensor&, at::Tensor&, c10::ArrayRef >(c10::TensorTypeId, at::Tensor&, c10::ArrayRef ) const::{lambda(c10::DispatchTable const&)#1}&&) const + 0x114 (0x4333c6 en /data_2/everyday/0516/build-libtorch-syntax-unknown-Default/main)
cuadro #5: en::Tensor& c10::impl::OperatorEntry::callUnboxedOnly<at::Tensor&, en::Tensor&, c10::ArrayRef >(c10::TensorTypeId, en::Tensor&, c10::ArrayRef) const + 0x63 (0x4315c7 en /data_2/everyday/0516/build-libtorch-syntax-unknown-Default/main)
cuadro #6: at::Tensor& c10::Dispatcher::callUnboxedOnly<at::Tensor&, at::Tensor& , c10::ArrayRef >(c10::OperatorHandle const&, c10::TensorTypeId, at::Tensor&, c10::ArrayRef) const + 0x7b (0x42eff5 en /data_2/everyday/0516/build-libtorch-sintaxis-unknown-Default /main)
cuadro n.° 7: en::Tensor::resize
(c10::ArrayRef) const + 0x1a1 (0x42af3f en /data_2/everyday/0516/build-libtorch-syntax-unknown-Default/main)
cuadro n.° 8: principal + 0x134 (0x42798f en /data_2/everyday/0516/build-libtorch-sintaxis-unknown-Default/main)
cuadro n.° 9: __libc_start_main + 0xf0 (0x7fa2f5618830 en /lib/x86_64-linux-gnu/libc.so.6)
cuadro n.° 10: _start + 0x29 (0x426719 en /data_2/everyday/0516/build-libtorch-sintaxis-desconocida- Predeterminado/principal)

18.meshgrid convierte decenas en matriz cuadrada

estático en línea std::vector meshgrid(tensores TensorList)

    torch::Tensor scales = torch::ones({2});
    torch::Tensor ratios = torch::ones({2});
    ratios  += 2;

    std::cout<<scales<<std::endl;
    std::cout<<ratios<<std::endl;

    std::vector<torch::Tensor> mesh = torch::meshgrid({ scales, ratios });

    torch::Tensor scales_1 = mesh[0];
    torch::Tensor ratios_1 = mesh[1];

    std::cout<<scales_1<<std::endl;
    std::cout<<ratios_1<<std::endl;

1
1
[ Variable[CPUFloatType]{2} ]
3
3
[ Variable[CPUFloatType]{2} ]
1 1
1 1
[ Variable[CPUFloatType]{2,2} ]
3 3
3 3
[ Variable[CPUFloatType]{2,2 } ]

19.aplanar tensor aplanar

Aplanar tensor (int64_t start_dim=0, int64_t end_dim=-1) const;
Tensor aplanado (int64_t start_dim, int64_t end_dim, Dimname out_dim) const;
Tensor aplanado (Dimname start_dim, Dimname end_dim, Dimname out_dim) const;
Tensor aplanado (DimnameList atenua, Dimname out_dim) const;

   torch::Tensor a = torch::rand({2,3});
    torch::Tensor b = a.flatten();
    std::cout<<a<<std::endl;
    std::cout<<b<<std::endl;

0,9953 0,1461 0,0084
0,6169 0,4037 0,7685
[ Variable[CPUFloatType]{2,3} ]
0,9953
0,1461
0,0084
0,6169
0,4037
0,7685

20.fill_tensor llena un determinado valor en su lugar y llena el tensor actual

Tensor y relleno_(valor escalar) const;
Tensor y relleno_(const Tensor y valor) const;

    torch::Tensor a = torch::rand({2,3});
    torch::Tensor b = a.fill_(4);

    std::cout<<a<<std::endl;
    std::cout<<b<<std::endl;

4 4 4
4 4 4
[ Variable[CPUFloatType]{2,3} ]
4 4 4
4 4 4
[ Variable[CPUFloatType]{2,3} ]

21.antorcha::pila

Pila de tensores estática en línea (tensores TensorList, int64_t dim)

    torch::Tensor a = torch::rand({3});
    torch::Tensor b = torch::rand({3});
    torch::Tensor c = torch::stack({a,b},1);

    std::cout<<a<<std::endl;
    std::cout<<b<<std::endl;
    std::cout<<c<<std::endl;

0,6776
0,5610
0,2835
[ Variable[CPUFloatType]{3} ]
0,6846
0,3753
0,3873
[ Variable[CPUFloatType]{3} ]
0,6776 0,6846
0,5610 0,3753
0,2835 0,3873
[ Variable[CPUFloatType]{ 3,2} ]

    torch::Tensor a = torch::rand({3});
    torch::Tensor b = torch::rand({3});
    torch::Tensor c = torch::stack({a,b},0);

    std::cout<<a<<std::endl;
    std::cout<<b<<std::endl;
    std::cout<<c<<std::endl;

0,7129
0,1650
0,6764
[ Variable[CPUFloatType]{3} ]
0,8035
0,1807
0,8100
[ Variable[CPUFloatType]{3} ]
0,7129 0,1650 0,6764
0,8035 0,1807 0,8100
[ Variable[CPUFloatType]{ 2,3} ]

22.reformar

Tensor en línea Tensor::reshape(forma IntArrayRef) const

    torch::Tensor a = torch::rand({2,4});
    torch::Tensor b = a.reshape({-1,2});
    std::cout<<a<<std::endl;
    std::cout<<b<<std::endl;

0,3782 0,6390 0,6919 0,8298
0,3872 0,5923 0,4337 0,9634
[ Variable[CPUFloatType]{2,4} ]
0,3782 0,6390
0,6919 0,8298
0,3872 0,5923
0,4337 0.9634
[Variable[CPUFloatType]{4,2}]

23. ver

Tensor en línea Tensor::view(tamaño IntArrayRef) const

Necesita ser contiguo
a.contiguous().view({-1, 4});

 torch::Tensor a = torch::rand({2,3});
    torch::Tensor b = a.contiguous().view({ -1, 6 });
    torch::Tensor c = a.contiguous().view({ 3, 2 });

    std::cout<<a<<std::endl;
    std::cout<<b<<std::endl;
    std::cout<<c<<std::endl;

0,2069 0,8814 0,8506
0,6451 0,0107 0,7591
[ Variable[CPUFloatType]{2,3} ]
0,2069 0,8814 0,8506 0,6451 0,0107 0,7591
[ Variable[CPUFloatType]{1,6} ]
0,2 0 69 0,8814
0,8506
0,6451 0,0107 0,7591
[Variable[CPUFloatType]{3,2 } ]
Tenga en cuenta que esto es diferente de transponer

24.argmax argmin

Tensor estático en línea argmax(const Tensor & self, c10::optional<int64_t> dim=c10::nullopt, bool keepdim=false);
Tensor argmin estático en línea (const Tensor & self, c10::optional<int64_t> dim=c10::nullopt, bool keepdim=false);

    torch::Tensor a = torch::rand({2,3});
    auto b = torch::argmax(a, 0);

    std::cout<<a<<std::endl;
    std::cout<<b<<std::endl;

0,9337 0,7443 0,1323
0,6514 0,5068 0,5052
[ Variable[CPUFloatType]{2,3} ]
0
0
1
[ Variable[CPULongType]{3} ]

    torch::Tensor a = torch::rand({2,3});
    auto b = torch::argmax(a, 1);

    std::cout<<a<<std::endl;
    std::cout<<b<<std::endl;

0,0062 0,3846 0,4844
0,9555 0,2844 0,4025
[ Variable[CPUFloatType]{2,3} ]
2
0
[ Variable[CPULongType]{2} ]

25.donde

Tensor estático en línea donde (Tensor constante y condición, Tensor constante y propio, Tensor constante y otro);
estático en línea std::vector donde (const Tensor y condición);

torch::Tensor d = torch::where(a>0.5,b,c);
Descripción: Establece la posición donde a es mayor que 0.5 en pos, llena la posición pos de d con el valor por encima de la posición pos de b, y llenar las posiciones restantes el valor es el valor de c

     
    torch::Tensor a = torch::rand({2,3});
    torch::Tensor b = torch::ones({2,3});
    torch::Tensor c = torch::zeros({2,3});

    torch::Tensor d = torch::where(a>0.5,b,c);
    std::cout<<a<<std::endl;
    std::cout<<b<<std::endl;
    std::cout<<c<<std::endl;
    std::cout<<d<<std::endl;

0,7301 0,8926 0,9570
0,0979 0,5679 0,4473
[ Variable[CPUFloatType]{2,3} ]
1 1 1
1 1 1
[ Variable[CPUFloatType]{2,3} ]
0 0 0
0 0 0
[ Variable[CPUFloatType]{2,3} ]
1 1 1
0 1 0
[ Variable[CPUFloatType]{2,3} ]

Otro ejemplo:
auto b = torch::where(a>0.5);


    torch::Tensor a = torch::rand({2,3});
    auto b = torch::where(a>0.5);

    std::cout<<a<<std::endl;
    std::cout<<b<<std::endl;

0,3439 0,1622 0,7149
0,4845 0,5982 0,9443
[ Variable[CPUFloatType]{2,3} ]
0
1
1
[ Variable[CPULongType]{3} ]
2
1
2
[ Variable[CPULongType]{3} ]

26.accesor

TensorAccessor<T,N> accessor() const&
auto result_data = result.accessor<float, 2>(); //2 representa dos dimensiones
Ejemplo 1:

torch::Tensor one = torch::randn({9,6});
auto foo_one=one.accessor<float,2>();
for(int i=0,sum=0;i<foo_one.size(0);i++)
 for(int j=0;j<foo_one.size(1);j++)
     sum+=foo_one[i][j];

Ejemplo 2:

 torch::Tensor result;
    for(int i=1;i<m_num_class;i++) 
    {
        //...
        if(0 == result.numel())
        {
            result = result_.clone();
        }else
        {
            result = torch::cat({result,result_},0);//按行拼接
        }
    }
    result =result.cpu();
    auto result_data = result.accessor<float, 2>();
    
    cv::Mat img_draw = img.clone();
    for(int i=0;i<result_data.size(0);i++)
    {
        float score = result_data[i][4];
        if(score < 0.4) { continue;}
        int x1 = result_data[i][0];
        int y1 = result_data[i][1];
        int x2 = result_data[i][2];
        int y2 = result_data[i][3];
        int id_label = result_data[i][5];
        
        cv::rectangle(img_draw,cv::Point(x1,y1),cv::Point(x2,y2),cv::Scalar(255,0,0),3);
        cv::putText(img_draw,label_map[id_label],cv::Point(x1,y2),CV_FONT_HERSHEY_SIMPLEX,1,cv::Scalar(255,0,55));
    }

27. antorcha::max antorcha::min 同max

static inline std::tuple<Tensor,Tensor> max(const Tensor & self, Dimname dim, bool keepdim=false);
Tensor máximo estático en línea (Tensor constante y propio);

    torch::Tensor a = torch::rand({4,2});
    std::tuple<torch::Tensor, torch::Tensor> max_test = torch::max(a,1);

    auto max_val = std::get<0>(max_test);
    // index
    auto index = std::get<1>(max_test);

    std::cout<<a<<std::endl;
    std::cout<<max_val<<std::endl;
     std::cout<<index<<std::endl;

1 1 1 0 [ Variable [ CPULongType
]
{4} ] _ _ _ _











Otro ejemplo: máximo global

    torch::Tensor a = torch::rand({4,2});
    torch::Tensor max_test = torch::max(a);

    std::cout<<a<<std::endl;
    std::cout<<max_test<<std::endl;

0,1904 0,9493
0,6521
0,5788 0,9216
0,5997 0,1758 0,7384
[Variable[CPUFloatType]{4,2}]
0,94929
[Variable[CPUFloatType]{}]

28.masked_select y masked_fill

28.1 Tensor enmascarado_select(const Tensor & máscara) const;

       torch::Tensor a = torch::rand({2,3});
    torch::Tensor c = (a>0.25);
    torch::Tensor d = a.masked_select(c);

    std::cout<<a<<std::endl;
    std::cout<<c<<std::endl;
    std::cout<<d<<std::endl;

0,0667 0,3812 0,3810
0,3558 0,8628 0,6329
[ Variable[CPUFloatType]{2,3} ]
0 1 1
1 1 1
[ Variable[CPUBoolType]{2,3} ]
0,3812
0,3810
0,3558
0,8628
0,6329
[ Variable[CPUFloatType]{5} ]

28.2 Tensor enmascarado_relleno (const Tensor y máscara, valor escalar) const;

Tensor y masked_fill_(const Tensor y máscara, const Tensor y valor) const;
Tensor enmascarado_relleno (tensor constante y máscara, tensor constante y valor) const;

    torch::Tensor a = torch::rand({2,3});
    torch::Tensor aa = a.clone();
    aa.masked_fill_(aa>0.5,-2);

    std::cout<<a<<std::endl;
    std::cout<<aa<<std::endl;

0,8803 0,2387 0,8577
0,8166 0,0730 0,4682
[ Variable[CPUFloatType]{2,3} ]
-2,0000 0,2387 -2,0000
-2,0000 0,0730 0,4682
[ Variable[CPUFloatType]{2,3} ]

28.3 masked_fill_ Todo lo subrayado es una operación in situ.

Existe el requisito de que la puntuación de Tensor represente la puntuación y la etiqueta de Tensor represente la etiqueta. Ambas son del mismo tamaño. El posprocesamiento es cuando etiqueta = 26 y la puntuación de etiqueta = 26 es inferior a 0,5, luego establezca la posición correspondiente de la etiqueta en 1

 float index[] = {3,2,3,3,5,6,7,8,9,10,11,12,13,14,15,16};
    float score[] = {0.1,0.1,0.9,0.9,0.9,0.1,0.1,0.1,0.1,0.1,0.8,0.8,0.8,0.8,0.8,0.8};

    torch::Tensor aa = torch::from_blob(index, {4,4}).toType(torch::kFloat32);
    torch::Tensor bb = torch::from_blob(score, {4,4}).toType(torch::kFloat32);
    std::cout<<aa<<std::endl;
    std::cout<<bb<<std::endl;

    torch::Tensor tmp = (aa == 3);
    torch::Tensor tmp_2 = (bb >= 0.9);
    std::cout<<tmp<<std::endl;
    std::cout<<tmp_2<<std::endl;
    torch::Tensor condition_111 = tmp * tmp_2;

    std::cout<<condition_111<<std::endl;
    aa.masked_fill_(condition_111,-1);

     std::cout<<aa<<std::endl;

Ejemplo:
3 2 3 3 5
6 7 8
9 10 11 12 13
14 15 16
[ Variable[CPUFloatType]{4,4} ]
0,1000 0,1000 0,9000 0,9000 0,9000 0,1000 0,1000 0,1 000 0,1000
0,1000 0,8000 0,8000 0,8000
0,8000 0,8000
0,8000
[ Variable[CPUFloatType ]{4,4} ]
1 0 1 1
0 0 0 0 0
0 0 0 0
0 0 0 0
[ Variable[CPUByteType]{4,4} ]
0 0 1 1
1 0 0 0 0 0
0 0 0 0
0 0 0
[ Variable[CPUByteType]{4,4} ]
0 0 1 1
0 0 0 0 0
0 0 0
0 0 0 0
[ Variable[CPUByteType]{4,4} ]
3 2 -1 -1
5 6 7 8
9 10 11 12
13 14 15 16
[ Variable[CPUFloatType]{4,4} ]

29.operación integral libtorch 1

   torch::jit::script::Module module = torch::jit::load(argv[1]);
    std::cout << "== Switch to GPU mode" << std::endl;
    // to GPU
    module.to(at::kCUDA);

    if (LoadImage(file_name, image)) {
            auto input_tensor = torch::from_blob(
                    image.data, {1, kIMAGE_SIZE, kIMAGE_SIZE, kCHANNELS});
            input_tensor = input_tensor.permute({0, 3, 1, 2});
            input_tensor[0][0] = input_tensor[0][0].sub_(0.485).div_(0.229);
            input_tensor[0][1] = input_tensor[0][1].sub_(0.456).div_(0.224);
            input_tensor[0][2] = input_tensor[0][2].sub_(0.406).div_(0.225);

            // to GPU
            input_tensor = input_tensor.to(at::kCUDA);

            torch::Tensor out_tensor = module.forward({input_tensor}).toTensor();

            auto results = out_tensor.sort(-1, true);
            auto softmaxs = std::get<0>(results)[0].softmax(0);
            auto indexs = std::get<1>(results)[0];

            for (int i = 0; i < kTOP_K; ++i) {
                auto idx = indexs[i].item<int>();
                std::cout << "    ============= Top-" << i + 1
                          << " =============" << std::endl;
                std::cout << "    Label:  " << labels[idx] << std::endl;
                std::cout << "    With Probability:  "
                          << softmaxs[i].item<float>() * 100.0f << "%" << std::endl;
            }

        }

30.pytorch nms <---------> libtorch nms

pytorch nms
por ejemplo:
cuadros [1742,4]
puntuaciones [1742]

def nms(boxes, scores, overlap=0.5, top_k=200):
    """Apply non-maximum suppression at test time to avoid detecting too many
    overlapping bounding boxes for a given object.
    Args:
        boxes: (tensor) The location preds for the img, Shape: [num_priors,4].
        scores: (tensor) The class predscores for the img, Shape:[num_priors].
        overlap: (float) The overlap thresh for suppressing unnecessary boxes.
        top_k: (int) The Maximum number of box preds to consider.
    Return:
        The indices of the kept boxes with respect to num_priors.
    """
    keep = scores.new(scores.size(0)).zero_().long()
    if boxes.numel() == 0:
        return keep
    x1 = boxes[:, 0]
    y1 = boxes[:, 1]
    x2 = boxes[:, 2]
    y2 = boxes[:, 3]
    area = torch.mul(x2 - x1, y2 - y1)
    v, idx = scores.sort(0)  # sort in ascending order
    # I = I[v >= 0.01]
    idx = idx[-top_k:]  # indices of the top-k largest vals
    xx1 = boxes.new()
    yy1 = boxes.new()
    xx2 = boxes.new()
    yy2 = boxes.new()
    w = boxes.new()
    h = boxes.new()

    # keep = torch.Tensor()
    count = 0
    while idx.numel() > 0:
        i = idx[-1]  # index of current largest val
        # keep.append(i)
        keep[count] = i
        count += 1
        if idx.size(0) == 1:
            break
        idx = idx[:-1]  # remove kept element from view
        # load bboxes of next highest vals
        torch.index_select(x1, 0, idx, out=xx1)
        torch.index_select(y1, 0, idx, out=yy1)
        torch.index_select(x2, 0, idx, out=xx2)
        torch.index_select(y2, 0, idx, out=yy2)
        # store element-wise max with next highest score
        xx1 = torch.clamp(xx1, min=x1[i])
        yy1 = torch.clamp(yy1, min=y1[i])
        xx2 = torch.clamp(xx2, max=x2[i])
        yy2 = torch.clamp(yy2, max=y2[i])
        w.resize_as_(xx2)
        h.resize_as_(yy2)
        w = xx2 - xx1
        h = yy2 - yy1
        # check sizes of xx1 and xx2.. after each iteration
        w = torch.clamp(w, min=0.0)
        h = torch.clamp(h, min=0.0)
        inter = w*h
        # IoU = i / (area(a) + area(b) - i)
        rem_areas = torch.index_select(area, 0, idx)  # load remaining areas)
        union = (rem_areas - inter) + area[i]
        IoU = inter/union  # store result in iou
        # keep only elements with an IoU <= overlap
        idx = idx[IoU.le(overlap)]
    return keep, count

libtorch nms

bool nms(const torch::Tensor& boxes, const torch::Tensor& scores, torch::Tensor &keep, int &count,float overlap, int top_k)
{
    count =0;
    keep = torch::zeros({scores.size(0)}).to(torch::kLong).to(scores.device());
    if(0 == boxes.numel())
    {
        return false;
    }

    torch::Tensor x1 = boxes.select(1,0).clone();
    torch::Tensor y1 = boxes.select(1,1).clone();
    torch::Tensor x2 = boxes.select(1,2).clone();
    torch::Tensor y2 = boxes.select(1,3).clone();
    torch::Tensor area = (x2-x1)*(y2-y1);
    //    std::cout<<area<<std::endl;

    std::tuple<torch::Tensor,torch::Tensor> sort_ret = torch::sort(scores.unsqueeze(1), 0, 0);
    torch::Tensor v = std::get<0>(sort_ret).squeeze(1).to(scores.device());
    torch::Tensor idx = std::get<1>(sort_ret).squeeze(1).to(scores.device());

    int num_ = idx.size(0);
    if(num_ > top_k) //python:idx = idx[-top_k:]
    {
        idx = idx.slice(0,num_-top_k,num_).clone();
    }
    torch::Tensor xx1,yy1,xx2,yy2,w,h;
    while(idx.numel() > 0)
    {
        auto i = idx[-1];
        keep[count] = i;
        count += 1;
        if(1 == idx.size(0))
        {
            break;
        }
        idx = idx.slice(0,0,idx.size(0)-1).clone();

        xx1 = x1.index_select(0,idx);
        yy1 = y1.index_select(0,idx);
        xx2 = x2.index_select(0,idx);
        yy2 = y2.index_select(0,idx);

        xx1 = xx1.clamp(x1[i].item().toFloat(),INT_MAX*1.0);
        yy1 = yy1.clamp(y1[i].item().toFloat(),INT_MAX*1.0);
        xx2 = xx2.clamp(INT_MIN*1.0,x2[i].item().toFloat());
        yy2 = yy2.clamp(INT_MIN*1.0,y2[i].item().toFloat());

        w = xx2 - xx1;
        h = yy2 - yy1;

        w = w.clamp(0,INT_MAX);
        h = h.clamp(0,INT_MAX);

        torch::Tensor inter = w * h;
        torch::Tensor rem_areas = area.index_select(0,idx);

        torch::Tensor union_ = (rem_areas - inter) + area[i];
        torch::Tensor Iou = inter * 1.0 / union_;
        torch::Tensor index_small = Iou < overlap;
        auto mask_idx = torch::nonzero(index_small).squeeze();
        idx = idx.index_select(0,mask_idx);//pthon: idx = idx[IoU.le(overlap)]
    }
    return true;
}

31. ¡El tipo de datos es importante! .to(antorcha::kByte);

31.1

    //[128,512]
    torch::Tensor b = torch::argmax(output_1, 2).cpu();
    //    std::cout<<b<<std::endl;
    b.print();

    cv::Mat mask(T_height, T_width, CV_8UC1, (uchar*)b.data_ptr());
    imshow("mask",mask*255);
    waitKey(0);

[Variable[CPULongType] [128, 512]]

¡Como anteriormente! La b obtenida es el mapa de segmentación [128, 512]. ¡Pero la vida y la muerte no se pueden mostrar! ! Luego verifiqué el valor de b, lo comparé con pytorch y descubrí que era consistente. Pero en la imagen de arriba no puedo obtener la imagen de segmentación deseada. Está toda negra y es 0. Pero cuando escribo los valores, ¡algunos de ellos no son 0!
Así estaba escrito el proyecto antes, jeje. . . Luego busqué la implementación de psenet libtorch en github y descubrí que otros también la escribieron de manera similar.

 cv::Mat tempImg = Mat::zeros(T_height, T_width, CV_8UC1);
 memcpy((void *) tempImg.data, b.data_ptr(), sizeof(torch::kU8) * b.numel());

¡También escribí esto, pero descubrí que todavía no funciona! ! ! Han pasado 2 horas y no hay otra manera, voy a guardar los datos de 128*512 en els para verlos. Experimenté sin rumbo fijo
con cout<<b[0][0].item().toFloat()<<endl;
para que se pueda imprimir el valor, asegúrese de agregar .toFloat(). Escribiendo sin rumbo fijo el bucle
for(int i=0;i<128;i++)
for(int j=0;j<512;j++)
{ } ¡pero no lo acepto! ¿Cuál es el problema?¿Los valores son todos correctos pero no se pueden mostrar? Descubrí que b[0][0].item().toFloat() anterior debe agregarse con .toFloat(). Entonces, ¿qué tipo es mi b? Es tipo tensor. ¿Qué tipo es? Vea la [Variable impresa] [CPULongType] [128, 512]], tipo largo. Oh, déjame cambiar el tipo y ver. Al observar la conversión de tipos anterior, descubrí que solo necesito agregar .to(torch::kFloat32); de manera similar. Como necesito int, lo int primero, torch::Tensor b = torch::argmax(output_1 , 2).cpu().to(torch::kInt); lo intenté pero todavía no funciona. .to(torch::kFloat32); lo probé y todavía no funciona. Cuando escribo torch ::k, el compilador mostrará automáticamente algo que comience con k. El primero es kByte. Luego probé: torch::Tensor b = torch::argmax(output_1, 2).cpu().to(torch::kByte);










! ! ! !
¡Eso es todo! Sale el diagrama de segmentación que quiero.
Lo que me mata es el problema del tipo de datos. ¡Tardaron al menos 2 horas!

31.2
Convertir las imágenes procesadas intermediamente a tensor

 Mat m_tmp = grayMat.clone();
    torch::Tensor label_deal = torch::from_blob(
                m_tmp.data, {grayMat.rows, grayMat.cols}).toType(torch::kByte).to(m_device);
//    label_deal = label_deal.to(m_device);
    auto aaa = torch::max(label_deal);
    std::cout<<label_deal<<std::endl;
    std::cout<<aaa<<std::endl;
    while(1);

¡Otro gran hoyo! ! ! Al principio pensé que estaba bien, pero luego los resultados del procesamiento posterior fueron incorrectos, así que verifiqué paso a paso dónde estaba el problema y luego lo localicé aquí. ¡El valor de píxel de m_tmp no coincidía en absoluto en el tensor! ! ! Sé que el valor máximo de píxeles de m_tmp es 34, ¡pero el valor máximo de píxeles del tensor impreso es 255! ! ! ¡Oye, es del tipo antorcha::kByte! De ninguna manera, cambiar a kFloat32 aún no funcionará, el valor es aún más escandaloso y nan. . UH uh uh. Luego descubrí que .toType(torch::kByte) y .to(torch::kByte) están escritos de esta manera ¿Cuál debería usar o sigue igual? Luego continué el experimento y todavía tenía el mismo problema, y ​​todavía no funcionó para separar .to(m_device); porque según la experiencia anterior, torch::Tensor tmp = tmp.cpu(); parecía necesitar ser Escrito por separado, de lo contrario habría dudas. Entonces, ¿cuál es el problema aquí? ¡El valor del píxel simplemente no se puede poner correctamente en el tensor! ! ! ¿Qué está sucediendo? ? ?
Luego estuve deprimido durante mucho tiempo, entonces, ¿debería cambiar también el tipo de Mat?

 Mat m_tmp = grayMat.clone();
    m_tmp.convertTo(m_tmp,CV_32FC1);/又是个大坑 图片要先转float32啊
    torch::Tensor label_deal = torch::from_blob(
                m_tmp.data, {grayMat.rows, grayMat.cols}).toType(torch::kByte).to(m_device);

¡eso es todo! ! ! Ajá, ¿tengo que convertirlo a CV_32FC1? ¡tal vez!

32. Acceso de puntero a datos de Tensor

        torch::Tensor output = m_model->forward({input_tensor}).toTensor()[0];
        torch::Tensor output_cpu = output.cpu();
        //output_cpu     Variable[CPUFloatType] [26, 480, 480]]
        output_cpu.print();

        void *ptr = output_cpu.data_ptr();
        //std::cout<<(float*)ptr[0]<<std::endl;

Solo se puede definir con void  o auto; de lo contrario, se informará un error. Por ejemplo, si uso float  ptr = output_cpu.data_ptr(); se informará un error:
error: conversión no válida de 'void
' a 'float
' [-fpermissive]
float *ptr = output_cpu.data_ptr();
entonces void * pases de compilación, necesito ¡Usar punteros para acceder a los datos en tensor!

torch::Tensor output = m_model->forward({input_tensor}).toTensor()[0];
        torch::Tensor output_cpu = output.cpu();
        //output_cpu     Variable[CPUFloatType] [26, 480, 480]]
        output_cpu.print();
        void *ptr = output_cpu.data_ptr();
        std::cout<<(float*)ptr<<std::endl;

Como se escribió anteriormente, el resultado es:

[Variable[CPUFloatType] [26, 480, 480]]
0x7fab195ee040

La salida es una dirección, entonces, ¿cómo acceder a los datos? Naturalmente, se escribe así:
std::cout<<(float )ptr[0]<<std::endl;
cuando se escribe así, se informa un error ! ! ! !
: error: 'void
' no es un tipo de puntero a objeto y luego escribe:
std::cout<<(float*)ptr[0][0][0]<<std::endl; todavía se informa lo mismo ¡error! . No había manera, así que busqué en Google y encontré que había el mismo error que el mío, así como la solución:
 


¡en realidad! resuelto!

        void *ptr = output_cpu.data_ptr();
//        std::cout<<*((float*)ptr[0][0][0])<<std::endl;
//        std::cout<<(float*)ptr[0][0][0]<<std::endl;

         std::cout<<*((float*)(ptr+2))<<std::endl;

Hay otra forma de escribir:

const float* result = reinterpret_cast<const float *>(output_cpu.data_ptr());

Y la forma en que lo acabo de escribir:

 void *ptr = output_cpu.data_ptr();
 const float* result = (float*)ptr;

33 Comparación de métodos de asignación de tensores por índice en PyTorch

Comparación de los métodos de asignación de valores de Tensor por índice en PyTorch [ Comparación de los métodos de asignación de valores de Tensor por índice en PyTorch - Libro corto ]

44 Genera múltiples tensores (lado pytorch) y saca múltiples tensores (lado libtorch)

Salida en el lado de pytorch:

    def forward(self, x, batch=None):
        output, cnn_feature = self.dla(x)
        return (output['ct_hm'],output['wh'],cnn_feature)

El extremo libtorch correspondiente

    auto out = m_model->forward({input_tensor});
    auto tpl = out.toTuple();
    auto out_ct_hm = tpl->elements()[0].toTensor();
    out_ct_hm.print();
    auto out_wh = tpl->elements()[1].toTensor();
    out_wh.print();
    auto out_cnn_feature = tpl->elements()[2].toTensor();
    out_cnn_feature.print();

Si se genera un solo tensor, es

at::Tensor output = module->forward(inputs).toTensor();

45. torch :: El tensor se utiliza como parámetro de función, ya sea una referencia o no, la operación de los parámetros formales dentro de la función afectará el tensor original, es decir, es una referencia.

void test_tensor(torch::Tensor a)
{
    a[0][0] = -100;

}

int main(int argc, const char* argv[])
{

    torch::Tensor p = torch::rand({2,2});
    std::cout<<p<<std::endl;
    std::cout<<"~~~~#########~~~~~~~~~~~~~~~~~~~~~~~~~~"<<std::endl;
    test_tensor(p);
    std::cout<<p<<std::endl;
    while (1);
}

El resultado es el siguiente:

 0.0509  0.3509
 0.8019  0.1350
[ Variable[CPUType]{2,2} ]
~~~~#########~~~~~~~~~~~~~~~~~~~~~~~~~~
-100.0000    0.3509
   0.8019    0.1350
[ Variable[CPUType]{2,2} ]

Se puede ver que aunque la función void test_tensor(torch::Tensor a) no es una referencia, ¡el valor ha cambiado después de pasar esta función!

46. ​​​​Implementar la operación de subíndice de pytorch

Por ejemplo, en el lado de pytorch, está escrito de la siguiente manera:

c=b[a]

Entre ellos, la forma de a es [1,100] y la forma de b es [1,100,40,2], por lo que todos adivinan cuál es la forma de c. . Oh, otra condición conocida es que a es equivalente a una máscara. Los valores en a son solo 0 o 1. Supongamos que los primeros cinco valores de a son 1 y el resto son 0. La forma de c obtenido es [5, 40,
2], probablemente puedas adivinar que las filas que son 1 se eliminan y el resto no. Entonces, ¿cómo puede libtorch implementarlo de manera elegante?
Ajá, todavía no he pensado en ninguna buena solución, porque el lado de libtorch no admite subíndices. . Muy problemático. . . Luego escribí el bucle yo mismo:
para que sea más fácil ver los valores, solo asumo 10.

// aim [1,10,2,2]   ind_mask_ [1,10] 比如前5个是1余都是0  得到的结果形状是[5,40,2]  即pytorch里面的操作 aim = aim[ind_mask]
torch::Tensor deal_mask_index22(torch::Tensor aim_,torch::Tensor ind_mask_)
{
    torch::Tensor aim = aim_.clone().squeeze(0);//[1,100,40,2]  -->> [100,40,2]
    torch::Tensor ind_mask = ind_mask_.clone().squeeze(0);[1,100]  -->> [100]
    int row = ind_mask.size(0);
    int cnt = 0;
    for(int i=0;i<row;i++)
    {
        if(ind_mask[i].item().toInt())
        {
            cnt += 1;
        }
    }
    torch::Tensor out = torch::zeros({cnt,aim.size(1),aim.size(2)});
    int index_ = 0;
    for(int i=0;i<row;i++)
    {
        if(ind_mask[i].item().toInt())
        {
            out[index_++] = aim[i];
//            std::cout<<i<<std::endl;
        }
    }

    std::cout<<"##############################################"<<std::endl;
    std::cout<<out<<std::endl;
    
    return out;
}

int main(int argc, const char* argv[])
{
    torch::Tensor ind_mask = torch::ones({1,10});
    ind_mask[0][0] = 0;
    ind_mask[0][1] = 0;
    ind_mask[0][2] = 0;
    ind_mask[0][4] = 0;

    torch::Tensor aim = torch::rand({1,10,2,2});
    std::cout<<aim<<std::endl;

    deal_mask_index22(aim,ind_mask);


    while (1);
}

47.pytorch libtorch precisión de verificación del tensor

[Precisión de verificación del tensor de pytorch libtorch](Precisión de verificación del tensor de pytorch libtorch)
https://www.cnblogs.com/yanghailin/p/13669046.html

48. Otros: mapeo de colores

 /
    auto t1 = std::chrono::steady_clock::now();
//    static torch::Tensor tensor_m0 = torch::zeros({m_height,m_width}).to(torch::kByte).to(torch::kCPU);
//    static torch::Tensor tensor_m1 = torch::zeros({m_height,m_width}).to(torch::kByte).to(torch::kCPU);
//    static torch::Tensor tensor_m2 = torch::zeros({m_height,m_width}).to(torch::kByte).to(torch::kCPU);

    static torch::Tensor tensor_m0 = torch::zeros({m_height,m_width}).to(torch::kByte);
    static torch::Tensor tensor_m1 = torch::zeros({m_height,m_width}).to(torch::kByte);
    static torch::Tensor tensor_m2 = torch::zeros({m_height,m_width}).to(torch::kByte);
    tensor_m0 = tensor_m0.to(torch::kCUDA);
    tensor_m1 = tensor_m1.to(torch::kCUDA);
    tensor_m2 = tensor_m2.to(torch::kCUDA);
    for(int i=1;i<m_color_cnt;i++)
    {
        tensor_m0.masked_fill_(index==i,colormap[i * 3]);
        tensor_m1.masked_fill_(index==i,colormap[i * 3 + 1]);
        tensor_m2.masked_fill_(index==i,colormap[i * 3 + 2]);
    }
    torch::Tensor tensor_m00 = tensor_m0.cpu();
    torch::Tensor tensor_m11 = tensor_m1.cpu();
    torch::Tensor tensor_m22 = tensor_m2.cpu();
    cv::Mat m0 = cv::Mat(m_height, m_width, CV_8UC1, (uchar*)tensor_m00.data_ptr());
    cv::Mat m1 = cv::Mat(m_height, m_width, CV_8UC1, (uchar*)tensor_m11.data_ptr());
    cv::Mat m2 = cv::Mat(m_height, m_width, CV_8UC1, (uchar*)tensor_m22.data_ptr());
    std::vector<cv::Mat> channels = {m0,m1,m2};
    cv::Mat mergeImg;
    cv::merge(channels, mergeImg);
    mergeImg = mergeImg.clone();
    auto ttt1 = std::chrono::duration_cast<std::chrono::milliseconds>
            (std::chrono::steady_clock::now() - t1).count();
    std::cout << "merge time="<<ttt1<<"ms"<<std::endl;
    /

Se necesitan aproximadamente 35 ms con CPU y 2-3 ms con GPU. El siguiente código implementa la misma función en 2-3 ms.

 auto t0 = std::chrono::steady_clock::now();
    for (int i = 0; i<labelMat.rows; i++)
    {
        for (int j = 0; j<labelMat.cols; j++)
        {
            int id = labelMat.at<uchar>(i,j);
            if(0 == id)
            {
                continue;
            }
            colorMat.at<cv::Vec3b>(i, j)[0] = colormap[id * 3];
            colorMat.at<cv::Vec3b>(i, j)[1] = colormap[id * 3 + 1];
            colorMat.at<cv::Vec3b>(i, j)[2] = colormap[id * 3 + 2];
        }
    }
    auto ttt = std::chrono::duration_cast<std::chrono::milliseconds>
            (std::chrono::steady_clock::now() - t0).count();
    std::cout << "consume time="<<ttt<<"ms"<<std::endl;

49.antorcha.reunir

Lado de pytorch puro: (Reimpreso en https://www.jianshu.com/p/5d1f8cd5fe31)
torch.gather(input, dim, index, out=None) → Tensor
dim a lo largo del eje dado, especifique el índice de entrada índice tensor El Los valores de las posiciones se agregan.
Para un tensor tridimensional, la salida se puede definir como:

out[i][j][k] = input[index[i][j][k]][j][k]  # if dim == 0
out[i][j][k] = input[i][index[i][j][k]][k]  # if dim == 1
out[i][j][k] = input[i][j][index[i][j][k]]  # if dim == 2

Parámetros:
entrada (Tensor) – tensor de origen
tenue (int) – índice de eje
del índice (LongTensor) – subíndice del elemento agregado (el índice debe ser del tipo torch.longTensor)
out (Tensor, opcional) – tensor de destino

Ejemplo:
tenue = 1

import torch
a = torch.randint(0, 30, (2, 3, 5))
print(a)
#tensor([[[ 18.,   5.,   7.,   1.,   1.],
#         [  3.,  26.,   9.,   7.,   9.],
#         [ 10.,  28.,  22.,  27.,   0.]],

#        [[ 26.,  10.,  20.,  29.,  18.],
#         [  5.,  24.,  26.,  21.,   3.],
#         [ 10.,  29.,  10.,   0.,  22.]]])
index = torch.LongTensor([[[0,1,2,0,2],
                          [0,0,0,0,0],
                          [1,1,1,1,1]],
                        [[1,2,2,2,2],
                         [0,0,0,0,0],
                         [2,2,2,2,2]]])
print(a.size()==index.size())
b = torch.gather(a, 1,index)
print(b)
#True
#tensor([[[ 18.,  26.,  22.,   1.,   0.],
#         [ 18.,   5.,   7.,   1.,   1.],
#         [  3.,  26.,   9.,   7.,   9.]],

#        [[  5.,  29.,  10.,   0.,  22.],
#         [ 26.,  10.,  20.,  29.,  18.],
#         [ 10.,  29.,  10.,   0.,  22.]]])

tenue =2

c = torch.gather(a, 2,index)
print(c)
#tensor([[[ 18.,   5.,   7.,  18.,   7.],
#         [  3.,   3.,   3.,   3.,   3.],
#         [ 28.,  28.,  28.,  28.,  28.]],

#       [[ 10.,  20.,  20.,  20.,  20.],
#        [  5.,   5.,   5.,   5.,   5.],
#        [ 10.,  10.,  10.,  10.,  10.]]])

tenue = 0

index2 = torch.LongTensor([[[0,1,1,0,1],
                          [0,1,1,1,1],
                          [1,1,1,1,1]],
                        [[1,0,0,0,0],
                         [0,0,0,0,0],
                         [1,1,0,0,0]]])
d = torch.gather(a, 0,index2)
print(d)
#tensor([[[ 18.,  10.,  20.,   1.,  18.],
#         [  3.,  24.,  26.,  21.,   3.],
#         [ 10.,  29.,  10.,   0.,  22.]],

#       [[ 26.,   5.,   7.,   1.,   1.],
#         [  3.,  26.,   9.,   7.,   9.],
#         [ 10.,  29.,  22.,  27.,   0.]]])

Ya había visto esto antes y me confundí cuando lo volví a ver, ¡así que lo grabé aquí! Lo principal es esto
out[i][j][k] = input[i][index[i][j][k]][k] # if dim == 1 Pero, ¿qué puede hacer esta función de recopilación
? Intuitivamente, las formas de salida y entrada son las mismas. Puede derivar una o dos de ellas usted mismo, por ejemplo, dim=1
salida[0][0][0] = entrada[0] [índice[0][0] ][0] ] [0], luego primero busque el índice y encuentre el índice [0] [0] [0] = 0, y luego busque la entrada [0] [0] [0]. Este es el proceso. Por lo tanto , índice es el índice de subíndice y su
valor ¡No puede exceder la dimensión de tenue!
Intuitivamente, se implementa una nueva regla de mapeo en una determinada dimensión para obtener el resultado. ¡La clave está en el índice! Ésta es la regla.

50. torch::argsort (libtorch1.0 no tiene esta función) torch::sort

Se escribió un proyecto libtorch en 1.1. Dado que el proyecto usa 1.0, convertí el 1.1 escrito a 1.0. Luego apareció:
error: 'argsort' no es miembro de 'torch'
Bueno, lo sé, es porque hay un problema de versión causó que los nombres de las funciones no coincidieran, pero ¿dónde fui para encontrar argsort? Luego, vi que el máximo anterior parecía tener un índice de registro, y luego vi sort, y luego experimenté, y el resultado fue el mismo que argsort !
//pytorch1.1
antorcha::Tensor edge_idx_sort2 = antorcha::argsort(edge_num, 2, true);
//pytorch1.0
std::tupletorch::Tensor,torch::Tensor sort_ret = antorcha::sort(edge_num, 2 , verdadero);
// antorcha::Tensor v = std::get<0>(sort_ret);
antorcha::Tensor edge_idx_sort = std::get<1>(sort_ret);

51. Determinar si el tensor está vacío ind_mask.sizes().empty()

int row = ind_mask.size(0);
Si ind_mask está vacío, el código fallará y reportará un error.

terminate called after throwing an instance of 'c10::Error'
  what():  dimension specified as 0 but tensor has no dimensions (maybe_wrap_dim at /data_1/leon_develop/pytorch/aten/src/ATen/core/WrapDimMinimal.h:9)
frame #0: c10::Error::Error(c10::SourceLocation, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) + 0x6a (0x7f4cf0a4af5a in /data_2/project_202009/chejian/3rdparty/libtorch/lib/libc10.so)
frame #1: <unknown function> + 0x48a74f (0x7f4d010af74f in /data_2/project_202009/chejian/3rdparty/libtorch/lib/libcaffe2.so)
frame #2: at::native::size(at::Tensor const&, long) + 0x20 (0x7f4d010afac0 in /data_2/project_202009/chejian/3rdparty/libtorch/lib/libcaffe2.so)
frame #3: at::Tensor::size(long) const + 0x36 (0x467fba in /data_2/project_202009/libtorch/snake_libtorch_cuda8/cmake-build-debug/example-app)
frame #4: deal_mask_index(at::Tensor, at::Tensor) + 0x1a7 (0x45a83e in /data_2/project_202009/libtorch/snake_libtorch_cuda8/cmake-build-debug/example-app)
frame #5: get_gcn_feature(at::Tensor, at::Tensor, at::Tensor, int, int) + 0x4f3 (0x45e092 in /data_2/project_202009/libtorch/snake_libtorch_cuda8/cmake-build-debug/example-app)
frame #6: init_poly(std::shared_ptr<torch::jit::script::Module> const&, std::shared_ptr<torch::jit::script::Module> const&, at::Tensor const&, std::tuple<at::Tensor, at::Tensor, at::Tensor> const&) + 0x168 (0x45e777 in /data_2/project_202009/libtorch/snake_libtorch_cuda8/cmake-build-debug/example-app)
frame #7: main + 0xaee (0x463ab5 in /data_2/project_202009/libtorch/snake_libtorch_cuda8/cmake-build-debug/example-app)
frame #8: __libc_start_main + 0xf0 (0x7f4ced29c840 in /lib/x86_64-linux-gnu/libc.so.6)
frame #9: _start + 0x29 (0x456b89 in /data_2/project_202009/libtorch/snake_libtorch_cuda8/cmake-build-debug/example-app)

Por tanto, es necesario determinar si el tensor está vacío, pero:

ind_mask.numel() //返回总个数,但是为空的时候返回1
ind_mask.sizes()// 返回类似python list的东东,[1, 100, 40, 2]  [1, 40, 2]

ind_mask.sizes() Luego seguí la definición de la función de libtorch tamaños() que es de tipo IntList, y luego la tracé, usando IntList = ArrayRef<int64_t>; y luego tracé ArrayRef, y luego miré esta clase y encontré

  /// empty - Check if the array is empty.
  constexpr bool empty() const {
    return Length == 0;
  }

Por lo tanto, significa que hay una función miembro que se considera vacía y se puede llamar.
if(ind_mask.sizes().empty())
{ } %%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ¡Es demasiado difícil para mí! ¡Pensé que ya estaba hecho!



if(ind_mask.sizes().empty())
    {
        torch::Tensor tmp;
        return tmp;
    }

Cuando se considera que un tensor está vacío, creo un tensor y salgo, porque la función devuelve un tipo torch::Tensor.
Sin embargo, el tensor creado directamente también informará un error al acceder a los tamaños. ! !
como sigue:

 torch::Tensor tmp;
 tmp.print(); //打印[UndefinedTensor]

if(tmp.sizes().empty())
{
}
[UndefinedTensor]
terminate called after throwing an instance of 'c10::Error'
  what():  sizes() called on undefined Tensor (sizes at /data_1/leon_develop/pytorch/aten/src/ATen/core/UndefinedTensorImpl.cpp:12)
frame #0: c10::Error::Error(c10::SourceLocation, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) + 0x6a (0x7f35f1b21f5a in /data_2/project_202009/chejian/3rdparty/libtorch/lib/libc10.so)
frame #1: at::UndefinedTensorImpl::sizes() const + 0x77 (0x7f360217d6b7 in /data_2/project_202009/chejian/3rdparty/libtorch/lib/libcaffe2.so)
frame #2: at::Tensor::sizes() const + 0x27 (0x45e921 in /data_2/project_202009/libtorch/snake_libtorch_cuda8/cmake-build-debug/example-app)
frame #3: main + 0x55 (0x45bcaa in /data_2/project_202009/libtorch/snake_libtorch_cuda8/cmake-build-debug/example-app)
frame #4: __libc_start_main + 0xf0 (0x7f35ee373840 in /lib/x86_64-linux-gnu/libc.so.6)
frame #5: _start + 0x29 (0x44f889 in /data_2/project_202009/libtorch/snake_libtorch_cuda8/cmake-build-debug/example-app)

Pero esta vez:

 torch::Tensor tmp;
tmp.print();
std::cout<<tmp.numel()<<std::endl; // 输出为0

! ! ! !
Por lo tanto, defina el tensor directamente y .numel () en este momento es 0.

52.código pytorch out = aim[ind_mask], escrito con libtorch.

código pytorch
out = aim[ind_mask]
donde la forma es la siguiente:
aim [21, 40, 2]
ind_mask [21] #Los elementos son 0 o 1. Por ejemplo, hay 12 unos.
La forma de salida de out es [ 12, 40, 2]
## ################################### Cómo expresar
= apuntar[ ind_mask] en el código pytorch anterior usando el código libtorch

    torch::Tensor a = torch::rand({5,3,2});
    torch::Tensor idx = torch::zeros({5}).toType(torch::kLong);
    idx[3] = 1;
    idx[1] = 1;

    torch::Tensor abc = torch::nonzero(idx);
    torch::Tensor b = a.index_select(0,abc.squeeze());

    std::cout<<a<<std::endl;
    std::cout<<abc<<std::endl;
    std::cout<<b<<std::endl;

El resultado es el siguiente:

(1,.,.) = 
  0.1767  0.8695
  0.3779  0.3531
  0.3413  0.3734

(2,.,.) = 
  0.9664  0.7723
  0.8640  0.7289
  0.8395  0.6344

(3,.,.) = 
  0.9043  0.2671
  0.9901  0.2966
  0.0347  0.1650

(4,.,.) = 
  0.1457  0.1169
  0.7983  0.5157
  0.6405  0.2213

(5,.,.) = 
  0.7977  0.4066
  0.6691  0.7191
  0.5897  0.7400
[ Variable[CPUFloatType]{5,3,2} ]
 1
 3
[ Variable[CPULongType]{2,1} ]
(1,.,.) = 
  0.9664  0.7723
  0.8640  0.7289
  0.8395  0.6344

(2,.,.) = 
  0.1457  0.1169
  0.7983  0.5157
  0.6405  0.2213
[ Variable[CPUFloatType]{2,3,2} ]

53. ¡Cómo expresar el código pytorch a4 = arr[...,3,0] usando libtorch y usar masked_select!

>>> import numpy as np
>>> arr = np.arange(40).reshape(1,5,4,2)
>>> arr
array([[[[ 0,  1],
         [ 2,  3],
         [ 4,  5],
         [ 6,  7]],

        [[ 8,  9],
         [10, 11],
         [12, 13],
         [14, 15]],

        [[16, 17],
         [18, 19],
         [20, 21],
         [22, 23]],

        [[24, 25],
         [26, 27],
         [28, 29],
         [30, 31]],

        [[32, 33],
         [34, 35],
         [36, 37],
         [38, 39]]]])
>>> a1 = arr[...,0,1]
>>> a2 = arr[...,1,0]
>>> a3 = arr[...,2,1]
>>> a4 = arr[...,3,0]
>>> print(a1)
[[ 1  9 17 25 33]]
>>> print(a2)
[[ 2 10 18 26 34]]
>>> print(a3)
[[ 5 13 21 29 37]]
>>> print(a4)
[[ 6 14 22 30 38]]
>>> 

Al principio luché durante mucho tiempo, pero parecía que no había una buena manera, y luego usé un bucle for para completarlo.

//ex shape[1,5,4,2]      ex[..., 0, 1]  -->>[1,5]
torch::Tensor index_tensor_3(const torch::Tensor &ex,const int &idx1,const int &idx2)
{
//    ex.print();
    int dim_ = ex.size(1);
    torch::Tensor out = torch::empty({1,dim_}).to(ex.device());
    int size_ = ex.size(1);
    for(int i=0;i<size_;i++)
    {
        auto a = ex[0][i][idx1][idx2];
        out[0][i] = a;
        //        std::cout<<a<<std::endl;
    }
    
    return out;
}

Luego optimice y complete con funciones puras de libtorch:

//ex shape[1,5,4,2]      ex[..., 0, 1] -->>[1,5]
torch::Tensor index_tensor_3(const torch::Tensor &ex,const int &idx1,const int &idx2)
{
    const int dim0 = ex.size(0);
    const int dim1 = ex.size(1);
    const int dim2 = ex.size(2);
    const int dim3 = ex.size(3);

    std::vector<int> v_index(ex.numel());//初始化:ex.numel() 个0
    int offset = dim2 * dim3;
    for(int i=0;i<dim1;i++)
    {
        int index_ = idx1 * dim3 + idx2;
        v_index[i * offset + index_] = 1;
    }

    torch::Tensor index = torch::tensor(v_index).to(ex.device());
    index = index.reshape(ex.sizes()).toType(torch::kByte);//这里需要kByte类型
//    std::cout<<index<<std::endl;

    torch::Tensor selete = ex.masked_select(index).unsqueeze(0);
    return selete;
}

Conecte la función y llame a esta función unas 10 veces en total. La primera tarda 15 ms, mientras que la siguiente tarda 5 ms.

54. Nuevamente, ¡la tipografía es importante! ! A veces es necesario forzar la escritura kernel = kernel.toType(torch::kByte);

Un requisito hoy es usar libtorch1.8 para ejecutar el modelo pt de libtorch1.0. Si la sintaxis se cambia ligeramente, la versión anterior se puede compilar y pasar a la versión superior y se puede ejecutar, pero el resultado de la ejecución es incorrecto. Esto es bastante problemático.
Porque no sé dónde está el problema. Lo primero que es cuestionable es la falta de apoyo. Para verificar este problema, primero ejecute la inferencia con las mismas entradas de la versión alta y la versión anterior para ver si los resultados del modelo son consistentes. Por supuesto, esto también es bastante problemático, porque la versión superior de pytorch
necesita ejecutar la versión inferior y es necesario cambiar muchas cosas. No hay manera, lo cambié, se informan todo tipo de errores, soy psenet, esto se ejecuta en cuda8, ​​​​python2.7, no solo imprime, sino también varios otros problemas, el motivo son varios datos Varias bibliotecas eran necesarios para el procesamiento, pero luego los eliminé todos de todos modos,
porque descubrí que al ejecutar la inferencia, se usaba la oración
"out = model(img) ", y solo necesitaba preparar el mismo img.
Condensé el archivo test.py muy largo en lo siguiente:

#encoding=utf-8
import os
import cv2
import sys
import time
import collections
import torch
import argparse
import numpy as np


import models
#import util


def test(args):


    # Setup Model
    if args.arch == "resnet50":
        model = models.resnet50(pretrained=True, num_classes=7, scale=args.scale)
    elif args.arch == "resnet101":
        model = models.resnet101(pretrained=True, num_classes=7, scale=args.scale)
    elif args.arch == "resnet152":
        model = models.resnet152(pretrained=True, num_classes=7, scale=args.scale)
    
    for param in model.parameters():
        param.requires_grad = False

    model = model.cuda()
    
    if args.resume is not None:                                         
        if os.path.isfile(args.resume):
            print("Loading model and optimizer from checkpoint '{}'".format(args.resume))
            checkpoint = torch.load(args.resume)
            
            # model.load_state_dict(checkpoint['state_dict'])
            d = collections.OrderedDict()
            for key, value in checkpoint['state_dict'].items():
                tmp = key[7:]
                d[tmp] = value
            model.load_state_dict(d)

            print("Loaded checkpoint '{}' (epoch {})"
                  .format(args.resume, checkpoint['epoch']))
            sys.stdout.flush()
        else:
            print("No checkpoint found at '{}'".format(args.resume))
            sys.stdout.flush()

    model.eval()

    img_tmp = torch.rand(1, 3, 963, 1280).cuda()
    traced_script_module = torch.jit.trace(model, img_tmp)
    traced_script_module.save("./myfile/22.pt")

    init_seed = 1 #设置同样的种子确保产生一样的随机数
    torch.manual_seed(init_seed)
    torch.cuda.manual_seed(init_seed)

    img_tmp = torch.rand(1, 3, 64, 64).cuda()
    out = model(img_tmp)
    print(img_tmp)
    print(out)


    print("save pt ok!")
    return 1


if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Hyperparams')
    parser.add_argument('--arch', nargs='?', type=str, default='resnet50')
    parser.add_argument('--resume', nargs='?', type=str, default="./myfile/checkpoint.pth.tar",    
                        help='Path to previous saved model to restart from')
    parser.add_argument('--binary_th', nargs='?', type=float, default=1.0,
                        help='Path to previous saved model to restart from')
    parser.add_argument('--kernel_num', nargs='?', type=int, default=3,
                        help='Path to previous saved model to restart from')
    parser.add_argument('--scale', nargs='?', type=int, default=1,
                        help='Path to previous saved model to restart from')
    parser.add_argument('--long_size', nargs='?', type=int, default=1280,
                        help='Path to previous saved model to restart from')
    parser.add_argument('--min_kernel_area', nargs='?', type=float, default=10.0,
                        help='min kernel area')
    parser.add_argument('--min_area', nargs='?', type=float, default=300.0,
                        help='min area')
    parser.add_argument('--min_score', nargs='?', type=float, default=0.93,
                        help='min score')
    
    args = parser.parse_args()
    test(args)

Esto es muy importante:
init_seed = 1 #Establezca la misma semilla para garantizar que se genere el mismo número aleatorio
torch.manual_seed(init_seed)
torch.cuda.manual_seed(init_seed)
Porque necesito verificar la precisión del modelo tanto en torch1.0 como en torch1.8, necesito Las entradas de control son las mismas, por lo que establecer la misma semilla garantiza que se generen los mismos números aleatorios. imprimir para verificar que sean consistentes.
Luego descubrí que hay una diferencia entre afuera, pero solo los tres dígitos después del punto decimal son diferentes, y los primeros son iguales, así que creo que está bien cargar la versión alta con el peso de la versión baja. ! Pero los resultados en libtorch son muy diferentes. ¿Por qué? ¡
Debes mirar el código de libtorch con atención! ! !
Luego experimente e imprima sin rumbo fijo. . ¡Es importante hablar aquí sobre impresión! ! !
La parte que imprimí en mi versión inferior de libtorch es la siguiente:

[ Variable[CPUByteType]{7,703,1280} ]
[Variable[CPUByteType] [7, 703, 1280]]
[Variable[CPUByteType] [3, 703, 1280]]
kernel_size=3
[Variable[CPUByteType] [3, 703, 1280]]

Luego, la versión superior se imprime de la siguiente manera:

[CUDAFloatType [1, 7, 703, 1280]]
[CPUFloatType [7, 703, 1280]]
[CPUFloatType [3, 703, 1280]]
kernel_size=3
[CPUFloatType [3, 703, 1280]]

Um, ¿viste que los tipos de datos son diferentes? ¿Por qué son diferentes? Entonces sé cuál es el problema del tipo de datos.
Luego agregó esta oración,

kernel = kernel.toType(torch::kByte);

¡Solución perfecta!
Algunas operaciones tienen por defecto CPUByteType en versiones inferiores, pero se convierten en CPUFloatType en versiones superiores.
¡Esta frase aparentemente simple me tomó la mayor parte del día!
En resumen, lo anterior es mi proceso de pensamiento para encontrar el problema y resolverlo perfectamente. En resumen, debemos buscar constantemente problemas de posicionamiento y experimentar constantemente para resolverlos.

Luego compartiré un problema de tipo de datos del Mat de opencv que encontré recientemente.

Mat convertTo3Channels_2(const Mat& binImg)
{
    Mat three_channel = Mat::zeros(binImg.rows,binImg.cols,CV_8UC3);
    vector<Mat> channels;
    for (int i=0;i<3;i++)
    {
        channels.push_back(binImg);
    }
    merge(channels,three_channel);
    three_channel.convertTo(three_channel,CV_8UC3); //重要,还要再写一次!!
    return three_channel;
}

Mirando el código,
declaré el tipo CV_8UC3 al principio, Mat three_channel = Mat::zeros(binImg.rows,binImg.cols,CV_8UC3);. Porque cuando se pasa la función, necesito el tipo uint.
three_channel.convertTo(tres_canales,CV_8UC3); //Importante, ¡tengo que escribirlo de nuevo! !
Aquí, debe escribirlo nuevamente aquí; de lo contrario, lo que se envía no es de este tipo. Mat no sabe cómo ver o imprimir este tipo, pero estoy mirando esta imagen a través de mi depurador gdb imagewatch y el tipo se mostrará a continuación.
Lo reproduje y tomé una captura de pantalla. Interrumpí
debajo de la oración merge(channels,tres_channel); y mi gdb imagewatch mostró el siguiente tipo.
 


¿Viste? Claramente inicialicé Mat three_channel = Mat::zeros(binImg.rows,binImg.cols,CV_8UC3);
tipo CV_8UC3, este debería ser de tipo uint, pero después de fusionarlo se convierte en tipo flotante, tal vez sea fusionar. Esta función tiene Cambió el tipo para mí.
Algunas de las operaciones posteriores que provocaron que la función se desactivara fueron extrañas y no sé dónde radica el problema.

Luego simplemente fuerce la transferencia nuevamente.
three_channel.convertTo(tres_canales,CV_8UC3); //Importante, ¡tengo que escribirlo de nuevo! !
 


Resumen:
El tipo es importante
. El tipo es importante.
El tipo es importante.
Diga cosas importantes tres veces.

Supongo que te gusta

Origin blog.csdn.net/m0_72734364/article/details/133428012
Recomendado
Clasificación