-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsface.cpp
208 lines (151 loc) · 8 KB
/
sface.cpp
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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
#include <fstream>
#include <iostream>
#include <opencv2/opencv.hpp>
#include "NvInfer.h"
#include "sface.hpp"
using namespace nvinfer1;
// تابع چک که اگر اروری چیزی خورد معلوم بشه برای ساده شدن برنامه
#define CHECK(status) \
do\
{\
auto ret = (status);\
if (ret != 0)\
{\
std::cerr << "Cuda failure: " << ret << std::endl;\
abort();\
}\
} while (0)
class Logger : public ILogger {
void log(Severity severity, const char* msg) noexcept override {
// suppress info-level messages
if (severity <= Severity::kERROR)
std::cout << msg << std::endl;
}
} gLogger;
// سازنده پیش فرض
sface::sface() {}
// سازنده پارامتر دار که میاد فایل مدل تی آر تی میخواند
sface::sface(const std::string engine_file_path) {
char *trtModelStream = nullptr; // پوینتر برای ذخیره محتویات فایل مدل
size_t size = 0; // اندازه فایل مدل بر حسب بایت
// باز کردن فایل مدل به صورت باینری اگر نتوانست باز کند خطا میدهد
std::ifstream file(engine_file_path, std::ios::binary);
if (file.good()) {
file.seekg(0, file.end); // اشاره گر فایل را به انتهای فایل می برد
size = file.tellg(); // موقعیت اشاره گر اندازه فایل را ذخیره میکند
file.seekg(0, file.beg); // اشاره گر را دوباره به ابتدای فایل برمیگرداند
trtModelStream = new char[size]; // یک آرایه پویا به اندازه فایل مدل ایجاد و محتویات فایل به این آرایه کپی میشود
assert(trtModelStream); //
file.read(trtModelStream, size);
file.close(); // اتمام کار
} else {
std::cerr << "could not open engine!" << std::endl;
return;
}
// رابط اصلی تی آر تی رو ایجاد میکند اگر اجرا نشد به خطا میخورد
runtime = createInferRuntime(gLogger);
assert(runtime != nullptr);
// trtModelStream محتوای فایل ذخیره شده در
// deserializeCudaEngine از طریق
// یک موتور کودا تبدیل میشود
// اگر عملیات انجام نشد به خطا میخورد
engine = runtime->deserializeCudaEngine(trtModelStream, size);
assert(engine != nullptr);
// ایجاد محیط اجرا برای انجام عملیات اینفرنس یا استنتاج مدل
context = engine->createExecutionContext();
assert(context != nullptr);
// آزاد سازی حافظه
delete[] trtModelStream;
// بررسی ورودی و خروجی های مدل که دوتا زده شده
assert(engine->getNbBindings() == 2);
// INPUT_BLOB_NAME ورودی مدل با استفاده از نام ها شناسایی میشوند
inputIndex = engine->getBindingIndex(INPUT_BLOB_NAME);
assert(engine->getBindingDataType(inputIndex) == nvinfer1::DataType::kFLOAT);
// OUTPUT_BLOB_NAME خروجی مدل با استفاده از نام ها شناسایی میشوند
outputIndex = engine->getBindingIndex(OUTPUT_BLOB_NAME);
assert(engine->getBindingDataType(outputIndex) == nvinfer1::DataType::kFLOAT);
}
// تمام منابع اختصاص داده شده در کلاس را آزاد میکند
sface::~sface() {
delete context;
delete engine;
delete runtime;
delete input;
delete output;
}
// تبدیل آر جی بی به بی جی آر
// void sface::imagePreProcess(cv::Mat& img, cv::Mat& img_resized) {
// cv::cvtColor(img, img_resized, cv::COLOR_BGR2RGB);
// cv::Size dsize = cv::Size(INPUT_W, INPUT_H);
// cv::resize(img_resized, img_resized, dsize);
// }
void sface::imagePreProcess(cv::Mat& img, cv::Mat& img_resized) {
// رنگ تصویر را تغییر ندهید
cv::Size dsize = cv::Size(INPUT_W, INPUT_H);
cv::resize(img, img_resized, dsize); // فقط اندازه تصویر را تغییر میدهیم
}
/*
پیکسلهای تصویر به اعداد اعشاری تبدیل میشوند
این اعداد نرمالسازی میشوند تا در بازه [-1, 1] قرار گیرند
دادهها به ترتیب مناسب برای ورودی مدل ذخیره میشوند
(ترتیب CHW )
*/
void sface::blobFromImage(cv::Mat& img, float* input) {
int channels = 3;
for (int c = 0; c < channels; c++) {
for (int h = 0; h < INPUT_H; h++) {
for (int w = 0; w < INPUT_W; w++) {
input[c * INPUT_W * INPUT_H + h * INPUT_W + w] =
((float)img.at<cv::Vec3b>(h, w)[c] / 255.0 - 0.5) / 0.5;
}
}
}
}
// وظیفه ی اجرای عملیات پیش بینی اینفرنس روی مدل دارد یعنی داده ها رو از سی پی یو به جی پی یو انتقال میدهد
void sface::doInference(IExecutionContext& context, float* input, float* output) {
// ایجاد بافر که همان حافظه ای روی جی پی یو
void* buffers[2];
// بافر محل ذخیره داده های ورودی
CHECK(cudaMalloc(&buffers[inputIndex], INPUT_SIZE * sizeof(float))); //cudaMalloc ==>> یعنی حافظه را از جی پی یو
// بافر محل ذخیره خروجی مدل
CHECK(cudaMalloc(&buffers[outputIndex], OUTPUT_SIZE * sizeof(float)));
/*
یک استریم کودا ایجاد میشود کهیک کانالی تشکیل میدهد جی پی یو میتواند به طور غیر همزمان آسینکرون عملیات انجام دهد
یعنی چندتا کار به طور همزمان انجام شود بدون اینکه منتظر عملیات قبلی بماند
*/
cudaStream_t stream;
CHECK(cudaStreamCreate(&stream));
// داده های پیش پردازش شده از حافظه هاست که همون سی پی یو به حافظه دیوایس جی پی یو کپی میشود
CHECK(cudaMemcpyAsync(buffers[inputIndex], input, INPUT_SIZE * sizeof(float), cudaMemcpyHostToDevice, stream));
// اجرای مدل روی جی پی یو
context.enqueueV2(buffers, stream, nullptr);
// خروجی مدل را از حافظه هاست به جی پی یو انتقال میدهد که به طور غیر همزمان انجام میشود و الان سی پی یو به نتایج دسترسی دارد
CHECK(cudaMemcpyAsync(output, buffers[outputIndex], OUTPUT_SIZE * sizeof(float), cudaMemcpyDeviceToHost, stream));
// منتظر اتمام کار فرآیند های بالا میماند تا عملیات ها انجام شوند
cudaStreamSynchronize(stream);
// استریم کودا حذف میشود تا منابع آزاد شوند
cudaStreamDestroy(stream);
// حافظه هایی که برای خروجی و ورودی جی پی یو ازاد میشود
CHECK(cudaFree(buffers[inputIndex]));
CHECK(cudaFree(buffers[outputIndex]));
}
// عکس رو بهش میدیدم و خروجی را برای ما نمایش میدهد
std::vector<float> sface::infer(cv::Mat& img) {
cv::Mat img_resized;
imagePreProcess(img, img_resized);
blobFromImage(img_resized, input);
doInference(*context, input, output);
// چاپ 128 ویژگی خروجی
// std::cout << "Feature vector : " << output << "\n";
// تبدیل خروجی به یک بردار برای بازگشت
std::vector<float> featureVector(output, output + OUTPUT_SIZE);
std::cout << "Feature vector (128-dimensional output):" << "\n";
for (int i = 0; i < OUTPUT_SIZE; i++) {
std::cout << output[i];
if (i != OUTPUT_SIZE - 1) {
std::cout << ", "; // جدا کردن ویژگیها با کاما
}
}
return featureVector; // بازگشت بردار ویژگی
std::cout << "\n"; // پایان خط
}