diff --git a/configs/test_cam1_face_det_rtsp_server.json b/configs/test_cam1_face_det_rtsp_server.json index d6e0d32..0436409 100644 --- a/configs/test_cam1_face_det_rtsp_server.json +++ b/configs/test_cam1_face_det_rtsp_server.json @@ -41,6 +41,8 @@ "max_faces": 10, "output_landmarks": true, "input_format": "rgb", + "input_dtype": "float16", + "normalize": { "mean": [127.5, 127.5, 127.5], "std": [128.0, 128.0, 128.0] }, "debug": { "stats": true, "stats_interval": 30, "log_outputs": true } }, { diff --git a/plugins/ai_face_det/ai_face_det_node.cpp b/plugins/ai_face_det/ai_face_det_node.cpp index e93c327..cfb9182 100644 --- a/plugins/ai_face_det/ai_face_det_node.cpp +++ b/plugins/ai_face_det/ai_face_det_node.cpp @@ -117,6 +117,39 @@ inline float HalfToFloat(uint16_t h) { return out; } +inline uint16_t FloatToHalf(float f) { + uint32_t x; + memcpy(&x, &f, sizeof(x)); + const uint32_t sign = (x >> 16) & 0x8000u; + int exp = static_cast((x >> 23) & 0xFFu) - 127; + uint32_t mant = x & 0x7FFFFFu; + + if (exp <= -15) { + if (exp < -24) return static_cast(sign); + mant |= 0x800000u; + const int shift = (-exp - 14); + uint32_t half_m = mant >> shift; + if (shift > 0 && ((mant >> (shift - 1)) & 1u)) half_m += 1u; + return static_cast(sign | (half_m & 0x03FFu)); + } + if (exp >= 16) { + if (std::isnan(f)) return static_cast(sign | 0x7E00u); + return static_cast(sign | 0x7C00u); + } + + const uint16_t half_e = static_cast(exp + 15); + uint32_t half_m = mant >> 13; + if (mant & 0x00001000u) { + half_m += 1u; + if (half_m == 0x0400u) { + const uint16_t ne = static_cast(half_e + 1u); + if (ne >= 31u) return static_cast(sign | 0x7C00u); + return static_cast(sign | (ne << 10)); + } + } + return static_cast(sign | (half_e << 10) | static_cast(half_m & 0x03FFu)); +} + template inline float Dequant(T q, int32_t zp, float scale) { return (static_cast(q) - static_cast(zp)) * scale; @@ -575,40 +608,74 @@ private: const bool want_nchw = (input_layout_ == "nchw"); input.is_nhwc = !want_nchw; - // Default: keep existing UINT8 behavior. - if (input_dtype_ == "float" || input_dtype_ == "f32" || input_dtype_ == "float32") { - float_input_buf_.resize(static_cast(in_w) * static_cast(in_h) * 3); + const bool want_f16 = (input_dtype_ == "float16" || input_dtype_ == "f16"); + const bool want_f32 = (input_dtype_ == "float" || input_dtype_ == "f32" || input_dtype_ == "float32"); + if (want_f16 || want_f32) { const size_t pix = static_cast(in_w) * static_cast(in_h); const uint8_t* p = reinterpret_cast(input_ptr); - for (size_t i = 0; i < pix; ++i) { - for (int c = 0; c < 3; ++c) { - float x = static_cast(p[i * 3 + static_cast(c)]); - if (norm_use_mean_std_) { - const float st = std::fabs(norm_std_[static_cast(c)]) < 1e-6f ? 1.0f : norm_std_[static_cast(c)]; - x = (x - norm_mean_[static_cast(c)]) / st; - } else { - x = x * norm_scale_ + norm_bias_; + if (want_f32) { + float_input_buf_.resize(pix * 3); + for (size_t i = 0; i < pix; ++i) { + for (int c = 0; c < 3; ++c) { + float x = static_cast(p[i * 3 + static_cast(c)]); + if (norm_use_mean_std_) { + const float st = std::fabs(norm_std_[static_cast(c)]) < 1e-6f ? 1.0f : norm_std_[static_cast(c)]; + x = (x - norm_mean_[static_cast(c)]) / st; + } else { + x = x * norm_scale_ + norm_bias_; + } + float_input_buf_[i * 3 + static_cast(c)] = x; } - float_input_buf_[i * 3 + static_cast(c)] = x; } - } - const float* fp = float_input_buf_.data(); - if (want_nchw) { - float_input_nchw_buf_.resize(pix * 3); - for (int c = 0; c < 3; ++c) { - float* dst = float_input_nchw_buf_.data() + static_cast(c) * pix; - for (size_t i = 0; i < pix; ++i) { - dst[i] = fp[i * 3 + static_cast(c)]; + const float* fp = float_input_buf_.data(); + if (want_nchw) { + float_input_nchw_buf_.resize(pix * 3); + for (int c = 0; c < 3; ++c) { + float* dst = float_input_nchw_buf_.data() + static_cast(c) * pix; + for (size_t i = 0; i < pix; ++i) { + dst[i] = fp[i * 3 + static_cast(c)]; + } + } + input.data = float_input_nchw_buf_.data(); + input.size = float_input_nchw_buf_.size() * sizeof(float); + } else { + input.data = float_input_buf_.data(); + input.size = float_input_buf_.size() * sizeof(float); + } + input.type = RKNN_TENSOR_FLOAT32; + } else { + half_input_buf_.resize(pix * 3); + for (size_t i = 0; i < pix; ++i) { + for (int c = 0; c < 3; ++c) { + float x = static_cast(p[i * 3 + static_cast(c)]); + if (norm_use_mean_std_) { + const float st = std::fabs(norm_std_[static_cast(c)]) < 1e-6f ? 1.0f : norm_std_[static_cast(c)]; + x = (x - norm_mean_[static_cast(c)]) / st; + } else { + x = x * norm_scale_ + norm_bias_; + } + half_input_buf_[i * 3 + static_cast(c)] = FloatToHalf(x); } } - input.data = float_input_nchw_buf_.data(); - input.size = float_input_nchw_buf_.size() * sizeof(float); - } else { - input.data = float_input_buf_.data(); - input.size = float_input_buf_.size() * sizeof(float); + + const uint16_t* hp = half_input_buf_.data(); + if (want_nchw) { + half_input_nchw_buf_.resize(pix * 3); + for (int c = 0; c < 3; ++c) { + uint16_t* dst = half_input_nchw_buf_.data() + static_cast(c) * pix; + for (size_t i = 0; i < pix; ++i) { + dst[i] = hp[i * 3 + static_cast(c)]; + } + } + input.data = half_input_nchw_buf_.data(); + input.size = half_input_nchw_buf_.size() * sizeof(uint16_t); + } else { + input.data = half_input_buf_.data(); + input.size = half_input_buf_.size() * sizeof(uint16_t); + } + input.type = RKNN_TENSOR_FLOAT16; } - input.type = RKNN_TENSOR_FLOAT32; } else { if (want_nchw) { const size_t pix = static_cast(in_w) * static_cast(in_h); @@ -910,6 +977,8 @@ private: std::vector input_nchw_buf_; std::vector float_input_buf_; std::vector float_input_nchw_buf_; + std::vector half_input_buf_; + std::vector half_input_nchw_buf_; ModelHandle model_handle_ = kInvalidModelHandle; int model_w_ = 320; diff --git a/plugins/ai_face_recog/ai_face_recog_node.cpp b/plugins/ai_face_recog/ai_face_recog_node.cpp index 7056c56..1dc9449 100644 --- a/plugins/ai_face_recog/ai_face_recog_node.cpp +++ b/plugins/ai_face_recog/ai_face_recog_node.cpp @@ -80,6 +80,39 @@ inline float HalfToFloat(uint16_t h) { return out; } +inline uint16_t FloatToHalf(float f) { + uint32_t x; + memcpy(&x, &f, sizeof(x)); + const uint32_t sign = (x >> 16) & 0x8000u; + int exp = static_cast((x >> 23) & 0xFFu) - 127; + uint32_t mant = x & 0x7FFFFFu; + + if (exp <= -15) { + if (exp < -24) return static_cast(sign); + mant |= 0x800000u; + const int shift = (-exp - 14); + uint32_t half_m = mant >> shift; + if (shift > 0 && ((mant >> (shift - 1)) & 1u)) half_m += 1u; + return static_cast(sign | (half_m & 0x03FFu)); + } + if (exp >= 16) { + if (std::isnan(f)) return static_cast(sign | 0x7E00u); + return static_cast(sign | 0x7C00u); + } + + const uint16_t half_e = static_cast(exp + 15); + uint32_t half_m = mant >> 13; + if (mant & 0x00001000u) { + half_m += 1u; + if (half_m == 0x0400u) { + const uint16_t ne = static_cast(half_e + 1u); + if (ne >= 31u) return static_cast(sign | 0x7C00u); + return static_cast(sign | (ne << 10)); + } + } + return static_cast(sign | (half_e << 10) | static_cast(half_m & 0x03FFu)); +} + class FaceGallery { public: void SetExpectedDim(int dim) { expected_dim_ = dim; } @@ -841,39 +874,74 @@ private: const bool want_nchw = (input_layout_ == "nchw"); in.is_nhwc = !want_nchw; - if (input_dtype_ == "float" || input_dtype_ == "f32" || input_dtype_ == "float32") { - float_input_buf_.resize(static_cast(model_w_) * static_cast(model_h_) * 3); + const bool want_f16 = (input_dtype_ == "float16" || input_dtype_ == "f16"); + const bool want_f32 = (input_dtype_ == "float" || input_dtype_ == "f32" || input_dtype_ == "float32"); + if (want_f16 || want_f32) { const size_t pix = static_cast(model_w_) * static_cast(model_h_); const uint8_t* p = face_buf_.data(); - for (size_t ii = 0; ii < pix; ++ii) { - for (int c = 0; c < 3; ++c) { - float x = static_cast(p[ii * 3 + static_cast(c)]); - if (norm_use_mean_std_) { - const float st = std::fabs(norm_std_[static_cast(c)]) < 1e-6f ? 1.0f : norm_std_[static_cast(c)]; - x = (x - norm_mean_[static_cast(c)]) / st; - } else { - x = x * norm_scale_ + norm_bias_; + if (want_f32) { + float_input_buf_.resize(pix * 3); + for (size_t ii = 0; ii < pix; ++ii) { + for (int c = 0; c < 3; ++c) { + float x = static_cast(p[ii * 3 + static_cast(c)]); + if (norm_use_mean_std_) { + const float st = std::fabs(norm_std_[static_cast(c)]) < 1e-6f ? 1.0f : norm_std_[static_cast(c)]; + x = (x - norm_mean_[static_cast(c)]) / st; + } else { + x = x * norm_scale_ + norm_bias_; + } + float_input_buf_[ii * 3 + static_cast(c)] = x; } - float_input_buf_[ii * 3 + static_cast(c)] = x; } - } - const float* fp = float_input_buf_.data(); - if (want_nchw) { - float_input_nchw_buf_.resize(pix * 3); - for (int c = 0; c < 3; ++c) { - float* dst = float_input_nchw_buf_.data() + static_cast(c) * pix; - for (size_t i = 0; i < pix; ++i) { - dst[i] = fp[i * 3 + static_cast(c)]; + const float* fp = float_input_buf_.data(); + if (want_nchw) { + float_input_nchw_buf_.resize(pix * 3); + for (int c = 0; c < 3; ++c) { + float* dst = float_input_nchw_buf_.data() + static_cast(c) * pix; + for (size_t i = 0; i < pix; ++i) { + dst[i] = fp[i * 3 + static_cast(c)]; + } + } + in.data = float_input_nchw_buf_.data(); + in.size = float_input_nchw_buf_.size() * sizeof(float); + } else { + in.data = float_input_buf_.data(); + in.size = float_input_buf_.size() * sizeof(float); + } + in.type = RKNN_TENSOR_FLOAT32; + } else { + half_input_buf_.resize(pix * 3); + for (size_t ii = 0; ii < pix; ++ii) { + for (int c = 0; c < 3; ++c) { + float x = static_cast(p[ii * 3 + static_cast(c)]); + if (norm_use_mean_std_) { + const float st = std::fabs(norm_std_[static_cast(c)]) < 1e-6f ? 1.0f : norm_std_[static_cast(c)]; + x = (x - norm_mean_[static_cast(c)]) / st; + } else { + x = x * norm_scale_ + norm_bias_; + } + half_input_buf_[ii * 3 + static_cast(c)] = FloatToHalf(x); } } - in.data = float_input_nchw_buf_.data(); - in.size = float_input_nchw_buf_.size() * sizeof(float); - } else { - in.data = float_input_buf_.data(); - in.size = float_input_buf_.size() * sizeof(float); + + const uint16_t* hp = half_input_buf_.data(); + if (want_nchw) { + half_input_nchw_buf_.resize(pix * 3); + for (int c = 0; c < 3; ++c) { + uint16_t* dst = half_input_nchw_buf_.data() + static_cast(c) * pix; + for (size_t i = 0; i < pix; ++i) { + dst[i] = hp[i * 3 + static_cast(c)]; + } + } + in.data = half_input_nchw_buf_.data(); + in.size = half_input_nchw_buf_.size() * sizeof(uint16_t); + } else { + in.data = half_input_buf_.data(); + in.size = half_input_buf_.size() * sizeof(uint16_t); + } + in.type = RKNN_TENSOR_FLOAT16; } - in.type = RKNN_TENSOR_FLOAT32; } else { if (want_nchw) { const size_t pix = static_cast(model_w_) * static_cast(model_h_); @@ -968,6 +1036,8 @@ private: std::vector input_nchw_buf_; std::vector float_input_buf_; std::vector float_input_nchw_buf_; + std::vector half_input_buf_; + std::vector half_input_nchw_buf_; ModelHandle model_handle_ = kInvalidModelHandle; int model_w_ = 112;