Gemeinsame Funktionsdatensätze von libtorch

Nehmen Sie zuerst eine Grube und sortieren Sie sie später aus.


Link zur offiziellen libtorch-Dokumentation:https://pytorch.org/cppdocs/


CreateTensor

Erstellen Sie einen zufälligen Tensor

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

int main()
{
    
    
    auto options = torch::TensorOptions()
                       .dtype(torch::kFloat32)
                       .layout(torch::kStrided)
                       .device(torch::kCPU)  // device(torch::kCUDA, 1)
                       .requires_grad(false);
    torch::Tensor tensor = torch::rand({
    
    2, 3}, options);
    std::cout << tensor << std::endl;
    std::cout << tensor.sizes() << std::endl;
    std::cout << tensor.dtype() << std::endl;

    return 0;
}

Erstellen Sie einen Nulltensor

torch::Tensor tensor = torch::zeros({
    
    2, 3});

CreateOnesTensor

torch::Tensor tensor = torch::ones({
    
    2, 3});

Lesen Sie Daten aus dem Speicher, um Tensor zu erstellen

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

int main()
{
    
       
    float data[6] = {
    
    1., 2., 3., 4., 5., 6.};

    auto options = torch::TensorOptions()
                       .dtype(torch::kFloat32)
                       .layout(torch::kStrided)
                       .device(torch::kCPU)  // device(torch::kCUDA, 1)
                       .requires_grad(false);
    torch::Tensor tensor = torch::from_blob(data, {
    
    3, 2}, options);
    std::cout << tensor << std::endl;

    return 0;
}

Erstellen Sie einen Tensor aus Opencv Mat-Daten

#include <iostream>
#include <torch/torch.h>
#include <opencv2/opencv.hpp>

using namespace torch::indexing;

int main()
{
    
    
    std::string img_path = "lena.jpg";
    cv::Mat img = cv::imread(img_path);
    std::cout << "size: " << img.size() << std::endl;
    std::cout << "channels: " << img.channels() << std::endl;
    std::cout << "dtype: " << img.type() << std::endl;

    cv::Mat img_fp32;
    img.convertTo(img_fp32, CV_32FC3);
    std::cout << "dtype: " << img_fp32.type() << std::endl;
    std::cout << cv::format(img_fp32(cv::Rect(0, 0, 3, 3)), cv::Formatter::FMT_NUMPY) << std::endl;

    auto options = torch::TensorOptions()
                       .dtype(torch::kFloat32)
                       .layout(torch::kStrided)
                       .device(torch::kCPU)
                       .requires_grad(false);
    torch::Tensor img_tensor = torch::from_blob(img_fp32.data,
                                                {
    
    img_fp32.rows, img_fp32.cols, img_fp32.channels()},
                                                options);
    std::cout << img_tensor.index({
    
    Slice(0, 3), Slice(0, 3), Slice()}) << std::endl;

    return 0;
}

Erstellen Sie eine Opencv-Mat aus Tensor-Daten

#include <iostream>
#include <torch/torch.h>
#include <opencv2/opencv.hpp>

using namespace torch::indexing;

int main()
{
    
       
    torch::manual_seed(1234);
    auto options = torch::TensorOptions()
                       .dtype(torch::kFloat32)
                       .layout(torch::kStrided)
                       .device(torch::kCPU)
                       .requires_grad(false);
    torch::Tensor img_tensor = torch::randn({
    
    224, 224, 3}, options);
    std::cout << img_tensor.index({
    
    Slice(0, 3), Slice(0, 3), Slice()}) << std::endl;
    auto shape = img_tensor.sizes();

    cv::Mat img(shape[0], shape[1], CV_32FC3, (float *) img_tensor.data_ptr());
    std::cout << "size: " << img.size() << std::endl;
    std::cout << "channels: " << img.channels() << std::endl;
    std::cout << "dtype: " << img.type() << std::endl;
    std::cout << cv::format(img(cv::Rect(0, 0, 3, 3)), cv::Formatter::FMT_NUMPY) << std::endl;

    return 0;
}

andere

Scheibe

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

using namespace torch::indexing;

int main()
{
    
    
	// torch::manual_seed(1234);  // 固定随机数种子
    torch::Tensor tensor = torch::rand({
    
    1, 3, 512, 512});
    std::cout << tensor.sizes() << std::endl;

    // tensor[:, :, 10:100, 10:100]
    torch::Tensor slice_tensor = tensor.index({
    
    Slice(), Slice(), Slice(10, 100), Slice(10, 100)});
    std::cout << slice_tensor.sizes() << std::endl;

    return 0;
}

Beachten Sie, dass der Slicing-Vorgang hier eine Referenz ist. Wenn der Inplace-Vorgang im Slicing-Bereich ausgeführt wird, sind die Originaldaten betroffen. Sie können das folgende Beispiel sehen:

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

using namespace torch::indexing;

int main()
{
    
    
    torch::manual_seed(1234);
    torch::Tensor tensor = torch::rand({
    
    5, 5});
    std::cout << tensor << std::endl;

    torch::Tensor slice_tensor = tensor.index({
    
    Slice(0, 2), Slice(0, 2)});
    std::cout << slice_tensor << std::endl;

    slice_tensor.add_(5);
    std::cout << slice_tensor << std::endl;
    std::cout << tensor << std::endl;

    return 0;
}

Wenn Sie einen neuen Teil des Speichers erstellen müssen, können Sie nach dem Slicing einenclone-Vorgang hinzufügen.

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

using namespace torch::indexing;

int main()
{
    
    
    torch::manual_seed(1234);
    torch::Tensor tensor = torch::rand({
    
    5, 5});
    std::cout << tensor << std::endl;

    torch::Tensor slice_tensor = tensor.index({
    
    Slice(0, 2), Slice(0, 2)}).clone();
    std::cout << slice_tensor << std::endl;

    slice_tensor.add_(5);
    std::cout << slice_tensor << std::endl;
    std::cout << tensor << std::endl;

    return 0;
}

Bestimmen/stellen Sie die Tensor-Speicherkontinuität ein

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

using namespace torch::indexing;

int main()
{
    
    
    torch::Tensor tensor = torch::rand({
    
    3, 2});
    std::cout << tensor.is_contiguous() << std::endl;

    // 这里切片后并不是内存连续的
    torch::Tensor new_tensor = tensor.index({
    
    Slice(), 0});
    std::cout << new_tensor.is_contiguous() << std::endl;

    new_tensor = new_tensor.contiguous();
    std::cout << new_tensor.is_contiguous() << std::endl;
	
	return 0;
}

Erzwungene Datentypkonvertierung

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


int main()
{
    
    
    torch::Tensor tensor = torch::rand({
    
    3, 2}) * 10;
    std::cout << tensor << std::endl;

    torch::Tensor new_tensor = tensor.to(torch::kInt32);
    std::cout << new_tensor << std::endl;
	
	return 0;
}

SwitchTensorDevice

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


int main()
{
    
    
    torch::Tensor tensor = torch::rand({
    
    3, 2}, torch::kCPU);
    std::cout << tensor << std::endl;

    torch::Tensor new_tensor = tensor.to(torch::Device(torch::kCUDA, 0));
    std::cout << new_tensor << std::endl;
	
	return 0;
}

Squeeze/Unsqueeze-Nutzung

Squeeze kann Dimensionen komprimieren, Unsqueeze kann neue Dimensionen hinzufügen. Im folgenden Code wird die Inplace-Operation verwendet, d. h. durch die Verarbeitung der Originaldaten werden keine neuen Daten generiert. Wenn Sie neue Daten generieren möchten, müssen Sie die entsprechende Funktion ohne Unterstreichung verwenden.

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

int main()
{
    
    
    torch::Tensor tensor = torch::rand({
    
    3, 512, 512});
    tensor.unsqueeze_(0);  // inplace
    // torch::Tensor new_tensor = tensor.unsqueeze(); // no inplace
    std::cout << tensor.sizes() << std::endl;

    tensor.squeeze_(0);  // inplace
    // torch::Tensor new_tensor = tensor.squeeze();  // no inplace
    std::cout << tensor.sizes() << std::endl;
	
	return 0;
}

Verwendung permutieren

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

namespace F = torch::nn::functional;

int main()
{
    
    
	// [N, C, H, W]
    torch::Tensor tensor = torch::rand({
    
    1, 3, 512, 512});
    std::cout << tensor.sizes() << std::endl;
	
	// [N, C, H, W] -> [N, H, W, C]
    torch::Tensor new_tensor = tensor.permute({
    
    0, 2, 3, 1});
    std::cout << new_tensor.sizes() << std::endl;

	return 0;
}

Interpolation verwenden

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

namespace F = torch::nn::functional;

int main()
{
    
    
    torch::Tensor tensor = torch::rand({
    
    1, 3, 512, 512});
    std::cout << tensor.sizes() << std::endl;

    int64_t h = 1024;
    int64_t w = 1024;
    auto cfg = F::InterpolateFuncOptions()
                   .size(std::vector<int64_t>{
    
    h, w})
                   .mode(torch::kBilinear)
                   .align_corners(false);
    torch::Tensor new_tensor = F::interpolate(tensor, cfg);
    std::cout << new_tensor.sizes() << std::endl;

    return 0;
}

Umdrehen

Flip wird sehr häufig bei der Konvertierung zwischen RGB und BGR verwendet:

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

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

    torch::Tensor new_tensor = tensor.flip({
    
    1});
    std::cout << new_tensor << std::endl;
	
	return 0;
}

Clip-Nutzung

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

int main()
{
    
    
    torch::Tensor tensor = torch::randn({
    
    3, 2});
    std::cout << tensor << std::endl;

    tensor.clip_(0., 1.);  // inplace
    // torch::Tensor new_tensor = tensor.clip(0., 1.);  // no inplace
    std::cout << tensor << std::endl;
	
	return 0;
}

Rot90-Nutzung

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

int main()
{
    
    
    torch::Tensor tensor = torch::randn({
    
    1, 1, 3, 2});
    std::cout << tensor << std::endl;

    // torch.rot90(tensor, k=1, dims=[2, 3])
    // 逆时针旋转90度, 如果要顺时针将dims改为[3, 2]
    torch::Tensor new_tensor = torch::rot90(tensor, 1, {
    
    2, 3});
    std::cout << new_tensor << std::endl;
	
	return 0;
}

Deaktivieren Sie die Verlaufsverfolgung

Wenn es nur als Inferenzrahmen verwendet wird, können die Gradientenfunktionen deaktiviert werden. Dies führt zu einer besseren Leistung.

Im Vergleich zu NoGradMode erzielt Code, der in diesem Modus ausgeführt wird, eine bessere Leistung, indem er Autograd-bezogene Arbeiten wie Ansichtsverfolgung und Versionszähler-Stöße deaktiviert.

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

int main()
{
    
       
    // like python torch.inference_mode()
    torch::InferenceMode();

    torch::Tensor tensor = torch::rand({
    
    1, 3, 512, 512});
    std::cout << tensor.sizes() << std::endl;

    return 0;
}

VSCODE-Konfiguration

CMakeLists.txtAufbau:

cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
project(example-app)

find_package(Torch REQUIRED)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${TORCH_CXX_FLAGS}")

add_executable(example-app example-app.cpp)
target_link_libraries(example-app "${TORCH_LIBRARIES}")
set_property(TARGET example-app PROPERTY CXX_STANDARD 17)

tasks.json-Konfiguration, bitte beachten Sie, dass -DCMAKE_PREFIX_PATH als libtorch der absolute Pfad des Ordners konfiguriert werden muss:

{
    
    
    "version": "2.0.0",
    "tasks": [
        {
    
    
            "label": "mkdir",
            "type": "shell",
            "command": "mkdir",
            "args": [
                "-p", "build"
            ],
            "options": {
    
    
                "cwd": "${workspaceFolder}"
            },            
        },
        {
    
    
            "label": "cmake",
            "type": "shell",
            "command": "cmake",
            "args": [
                "-DCMAKE_PREFIX_PATH=/absolute/path/to/libtorch",
                "../"
            ],
            "options": {
    
    
                "cwd": "${workspaceFolder}/build"
            },           
            "dependsOn": ["mkdir"] 
        },
        {
    
    
            "label": "make",
            "type": "shell",
            "command": "cmake",
            "args": [
                "--build",
                ".",
                "--config", "Release"
            ],
            "options": {
    
    
                "cwd": "${workspaceFolder}/build"
            }, 
            "dependsOn": ["cmake"]
        },
        {
    
    
            "label": "build",
            "dependsOn": ["make"]
        },
    ],
}

launch.jsonAufbau:

{
    
    
    "version": "0.2.0",
    "configurations": [
        {
    
    
            "name": "Build and debug active file",
            "type": "cppdbg",
            "request": "launch",
            "program": "${workspaceFolder}/build/${fileBasenameNoExtension}",
            "args": [],
            "stopAtEntry": false,
            "cwd": "${workspaceFolder}",
            "environment": [],
            "externalConsole": false,
            "MIMode": "gdb",
            "setupCommands": [
                {
    
    
                    "description": "Enable pretty-printing for gdb",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true
                }
            ],
            "preLaunchTask": "build",
            "miDebuggerPath": "/usr/bin/gdb"
        }
    ]
}

Wenn Sie relevante Header-Dateien hinzufügen müssen, um die Verwendung der intelligenten Vervollständigung zu erleichtern, können Sie die Datei c_cpp_properties.json konfigurieren:

{
    
    
    "configurations": [
        {
    
    
            "name": "linux",
            "intelliSenseMode": "linux-gcc-x64",
            "compilerPath": "/usr/bin/gcc",
            "cStandard": "c17",
            "cppStandard": "gnu++17",
            "includePath": ["/usr/local/include/opencv4/",
                            "/usr/local/include/opencv4/opencv2/",
                            "/absolute/path/to/libtorch/include",
                            "/absolute/path/to/libtorch/include/torch/csrc/api/include"]
        }
    ],
    "version": 4
}

Guess you like

Origin blog.csdn.net/qq_37541097/article/details/134844089