1. 程式人生 > 實用技巧 >libtorch 手打程式碼學習

libtorch 手打程式碼學習

#include <iostream>
#include <memory>
#include <string>
#include <torch/script.h>
#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include "opencv2/imgproc/types_c.h"

using namespace std;
using namespace cv;

int main() {
	//參考:https://www.cnblogs.com/yanghailin/p/12901586.html

	////除錯技巧
	//torch::Tensor box_1 = torch::rand({ 5,4 });
	//std::cout << box_1 << std::endl; //可以打印出數值,以及形狀資訊
	//box_1.print();//只打印形狀

	//CMakeLists.txt 具體寫法

	////0.torch::full_like
	//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;

	////1.生成資料的函式
	////1.1 torch::rand
	//torch::Tensor input = torch::rand({ 1,3,2,3 });
	//cout<<input<<endl;

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

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

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

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

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

	////2. 拼接tensor torch::cat 以及vector 和cat的融合操作
	////2.1 按列拼接
	//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;

	////2.2 按行拼接
	//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;

	////2.3 其他例子
	//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();

	////2.4 vector 和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();
	
	////也可以一句話搞定:
	//torch::Tensor bboxes = torch::cat({ xs_t0,ys_t0,xs_t1,ys_t1 }, 2);

	//3.torch的切片操作 
	//【select(淺拷貝)】【index_select 深拷貝)】【index 深拷貝】【slice 淺拷貝】 narrow,narrow_copy
	//select【淺拷貝】只能指定取某一行或某一列
	//index【深拷貝】只能指定取某一行
	//index_select【深拷貝】可以按行或按列,指定多行或多列
	//slice【淺拷貝】 連續的行或列
	//narrow,narrow_copy

	////當是淺拷貝,又不想影響之前的結果的時候,可以加個clone(),比如:
	//torch::Tensor boxes = torch::tensor({ {1,2,3},{4,5,6} });
	//torch::Tensor x1 = boxes.select(1, 0).clone();
	//cout << boxes << endl;
	//cout << x1 << endl;

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

	////3.1.2 select//按列取
	//torch::Tensor a = torch::rand({ 2,3 });
	//std::cout << a << std::endl;
	//torch::Tensor b = a.select(1, 1);
	//std::cout << b << std::endl;
	
	////3.1.3 select淺拷貝
	////注意:這裡是淺拷貝,就是改變b,同時a的值也會同樣的改變
	//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;

	////3.2 inline Tensor Tensor::index_select(Dimname dim, const Tensor & index) 
	////同樣的,dim0表示按行,1表示按列 index表示取的行號或者列號,這裡比較奇怪,index一定要是toType(torch::kLong)這種型別的。
	////還有一個奇怪的地方是我準備用陣列匯入tensor的,發現idx全是0,原因未知
	//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);//idx全是0  ?????????????????

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

	////3.2.2 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;

	////3.3 index inline Tensor Tensor::index(TensorList indices)
	////這個函式實驗下來,只能按行取,且是深拷貝
	//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;

	////3.4 slice inline Tensor Tensor::slice(int64_t dim, int64_t start, int64_t end, int64_t step)
	////dim0表示按行取,1表示按列取,從start開始,到end(不含)結束. 可以看到結果,是淺拷貝!!!
	//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;
	
	////3.5 narrow narrow_copy
	////inline Tensor Tensor::narrow(int64_t dim, int64_t start, int64_t length) const
	////inline Tensor 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;

	//4.squeeze() unsqueeze()
	//inline Tensor Tensor::squeeze() const//不加引數的,把所有為1的維度都壓縮
	//inline Tensor Tensor::squeeze(int64_t dim)const//加引數的,指定哪個維度壓縮
	//inline Tensor& Tensor::squeeze_() const //_,表示inplace壓縮
	//inline Tensor& Tensor::squeeze_(int64_t dim) const //inplace壓縮
	
	//4.1 squeeze()
	//[Variable[CPUFloatType]{ 2,1,2,1 }]
	//[Variable[CPUFloatType]{ 2,2 }]

	////4.2 squeeze(int64_t dim) 指定壓縮哪個維度
	//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;

	////4.3. unsqueeze
	//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;

	////5.torch::nonzero 輸出非0的座標
	//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;
	
	////6.訪問tensor值 a.item()就把1 * 1 的 tensor的a轉為float
	////取出tensor的某個值 為int或者float == = 》》》auto bbb = a[1][1].item().toFloat();
	////一般情況下取出tensor某個值可以直接下標索引即可。比如a[0][1], 但是這個值還是tensor型別的,要想為c++的int或者float的,如下:
	//torch::Tensor a = torch::rand({ 2,3 });
	//std::cout << a << std::endl;
	//auto bbb = a[1][1].item().toFloat();
	////auto bbb = a.item().toFloat();
	//std::cout << bbb << std::endl;

	////6.1 torch::sort的配合item的例子
	////CAFFE2_API std::tuple<Tensor,Tensor> sort(const Tensor & self, int64_t dim=-1, bool descending=false);
	//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());//std::get<>是tuple的用法
	//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;
	//}
	
	////7.opencv Mat型別轉tensor 或者其他的vector或者陣列資料轉tensor
	////7.1
	//string path = "";
	//Mat m_out = imread(path);//[320,320,3]
	//torch::Tensor input_tensor = torch::from_blob(m_out.data,{320,320,3 }).toType(torch::kFloat32);//torch::kByte 大坑
	//input_tensor = input_tensor.permute({ 2,0,1 });
	//input_tensor = input_tensor.unsqueeze(0);
	//input_tensor = input_tensor.to(torch::kFloat).to(torch::kCPU);

	////這裡需要注意,因為上面圖片被我預處理減均值過的,導致m_out畫素值有負數,如果torch::kByte這種格式,會把負數變成正數,
	////所以需要torch::kFloat32型別的.

	////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 的size sizes() numel()
	//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;

	//9.torch::sort
	//static inline std::tuple<Tensor, Tensor> sort(const Tensor& self, Dimname dim, bool descending)
	//dim0表示按行,1表示按列 descending = false表示升序,true表示降序
	//返回的是元組,第一個表示排序後的值,第二個表示排序之後對應之前的索引。

	//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;
	
	////10.clamp 把數值控制在min max之間,小於min的就為min,大於max的就為max
	////inline Tensor Tensor::clamp(c10::optional 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;

	////11.大於> 小於< 運算,求mask!
	//torch::Tensor a = torch::rand({ 2,3 });
	//std::cout << a << std::endl;
	//torch::Tensor b = a > 0.5;
	//std::cout << b << std::endl;

	//12.轉置Tensor::transpose ,只用於2個維度!
	////inline Tensor 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;
	
	////13.expand_as
	////inline Tensor Tensor::expand_as(const Tensor & other) 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;
	////注意維度有一定要求,我這麼寫torch::Tensor b = torch::ones({2,2});torch::Tensor b = torch::ones({2});都會報錯!

	////14.乘 mul_ 除div 減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.載入模型
	//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.模型forward出來的結果
	//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.resize_ 和zero_
	////Tensor & resize_(IntArrayRef size) 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;
	////注意:這裡如果只定義 torch::Tensor crops;//torch::Tensor crops = torch::rand({1,3,2,2});
	////就會報錯,感覺還是要先初始化一下才會分配記憶體,要不然就會報錯!	

	////18.meshgrid 把tensor變成方陣
	////static inline std::vector meshgrid(TensorList tensors)
	//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;

	////19.flatten 展平tensor
	////Tensor flatten(int64_t start_dim = 0, int64_t end_dim = -1) const;
	////Tensor flatten(int64_t start_dim, int64_t end_dim, Dimname out_dim) const;
	////Tensor flatten(Dimname start_dim, Dimname end_dim, Dimname out_dim) const;
	////Tensor flatten(DimnameList dims, 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;
	
	////20.fill_ tensor填充某個值 就地操作,填充當前tensor
	////Tensor& fill_(Scalar value) const;
	////Tensor& fill_(const Tensor& value) const;
	//torch::Tensor a = torch::rand({ 2,3 });
	//torch::Tensor b = a.fill_(4);

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

	////21.torch::stack
	////static inline Tensor stack(TensorList tensors, 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;

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

	////23.view
	////inline Tensor Tensor::view(IntArrayRef size) const
	////需要先contiguous, 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;

	////24.argmax argmin ,跟想象的反著?
	////static inline Tensor argmax(const Tensor& self, c10::optional<int64_t> dim = c10::nullopt, bool keepdim = false);
	////static inline Tensor argmin(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;

	////25.where
	////static inline Tensor where(const Tensor& condition, const Tensor& self, const Tensor& other);
	////static inline std::vector where(const Tensor& condition);
	////torch::Tensor d = torch::where(a > 0.5, b, c);
	////說明:在a大於0.5的位置設為1,1上用b的1位置上面值填充,其餘的位置上值是c的值
	////25.1
	//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;

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

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

	////26.accessor 訪問器,感覺類似於.item()?
	////TensorAccessor<T, N> accessor() const&
	////auto result_data = result.accessor<float, 2>(); //2代表二維
	////26.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];
	//
	////26.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. torch::max和torch::min
	////static inline std::tuple<Tensor,Tensor> max(const Tensor & self, Dimname dim, bool keepdim=false);
	////static inline Tensor max(const Tensor& self);
	////27.1 某個維度上的max,min
	//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;

	////27.2 全域性max
	//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;

	////28.masked_select 與 masked_fill
	////28.1 Tensor masked_select(const Tensor & mask) 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;

	////28.2 Tensor masked_fill(const Tensor & mask, Scalar value) const;
	////Tensor& masked_fill_(const Tensor& mask, const Tensor& value) const;
	////Tensor masked_fill(const Tensor& mask, const Tensor& value) 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;

	////28.3 masked_fill_ 帶下劃線的都是就地操作
	//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;

	////29.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
	////...
	
	////31.資料型別很重要! .to(torch::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);
	
	////31.2 要把中間處理的圖片Mat轉為float32
	//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);

	////32.指標訪問Tensor資料
	////32.1
	//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;
	////只能用void 或者auto來定義,否則會報錯。比如我用float* ptr = output_cpu.data_ptr(); 會報錯:
	////	error : invalid conversion from ‘void’ to ‘float’[-fpermissive]
	////	float* ptr = output_cpu.data_ptr();
	////那麼void* 編譯通過了,我需要用指標訪問tensor裡面的資料啊!
	
	////32.2
	//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;//列印地址

	////32.3 注意要給void* 做指標型別轉換!
	//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;

	////32.3.1
	//const float* result = reinterpret_cast<const float*>(output_cpu.data_ptr());
	////32.3.2
	//void* ptr = output_cpu.data_ptr();
	//const float* result = (float*)ptr;
	
	////44. 輸出多個tensor(pytorch端)以及取出多個tensor(libtorch端)!
	////pytorch端的輸出:
	//def forward(self, x, batch = None):
	//	output, cnn_feature = self.dla(x)
	//	return (output['ct_hm'], output['wh'], cnn_feature)

	////對應的libtorch端
	//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();
	
	////如果輸出單個tensor,就是
	//at::Tensor output = module->forward(inputs).toTensor();

	////45. torch::Tensor作為函式引數,不管是引用還是不引用,函式內部對形參操作都會影響本來的tensor,即都是引用
	//
	////46. 實現pytorch下標神操作. 注意:libtorch端不支援下標操作,可以用select
	//
	////49.torch.gather

	////50. torch::argsort,是torch::sort的第二個返回值
	//
	////51. 判斷tensor是否為空 ind_mask.sizes().empty()
	
	////52.pytorch程式碼 out = aim[ind_mask],用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;

	////53. pytorch程式碼a4 = arr[...,3,0] 用libtorch如何表達出來 masked_select運用!
	

	return 0;
}

參考:

https://www.cnblogs.com/yanghailin/p/12901586.html (libtorch 常用api函式示例(史上最全、最詳細))