| 245 | } |
| 246 | |
| 247 | FeatureNormalizeOutput normalize_batch_impl( |
| 248 | const std::vector<float> & features, |
| 249 | const std::vector<int64_t> & seq_len, |
| 250 | int64_t batch, |
| 251 | int64_t feature_dim, |
| 252 | int64_t frames, |
| 253 | FeatureNormalizeType normalize_type) { |
| 254 | if (static_cast<int64_t>(features.size()) != checked_product({batch, feature_dim, frames})) { |
| 255 | throw std::runtime_error("FeatureNormalizer input size mismatch"); |
| 256 | } |
| 257 | if (static_cast<int64_t>(seq_len.size()) != batch) { |
| 258 | throw std::runtime_error("FeatureNormalizer seq_len size mismatch"); |
| 259 | } |
| 260 | |
| 261 | FeatureNormalizeOutput output; |
| 262 | output.normalized.shape = {batch, feature_dim, frames}; |
| 263 | output.normalized.values = features; |
| 264 | |
| 265 | if (normalize_type == FeatureNormalizeType::None) { |
| 266 | output.mean.shape = {batch}; |
| 267 | output.mean.values.assign(static_cast<size_t>(batch), 0.0f); |
| 268 | output.stddev.shape = {batch}; |
| 269 | output.stddev.values.assign(static_cast<size_t>(batch), 0.0f); |
| 270 | return output; |
| 271 | } |
| 272 | |
| 273 | if (normalize_type == FeatureNormalizeType::PerFeature) { |
| 274 | output.mean.shape = {batch, feature_dim}; |
| 275 | output.mean.values.assign(static_cast<size_t>(batch * feature_dim), 0.0f); |
| 276 | output.stddev.shape = {batch, feature_dim}; |
| 277 | output.stddev.values.assign(static_cast<size_t>(batch * feature_dim), 0.0f); |
| 278 | |
| 279 | #ifdef _OPENMP |
| 280 | #pragma omp parallel for if(batch * feature_dim >= 32) |
| 281 | #endif |
| 282 | for (int64_t b = 0; b < batch; ++b) { |
| 283 | const int64_t valid = std::clamp<int64_t>(seq_len[static_cast<size_t>(b)], 0, frames); |
| 284 | for (int64_t f = 0; f < feature_dim; ++f) { |
| 285 | float mean = 0.0f; |
| 286 | for (int64_t t = 0; t < valid; ++t) { |
| 287 | mean += features[static_cast<size_t>(((b * feature_dim) + f) * frames + t)]; |
| 288 | } |
| 289 | if (valid > 0) { |
| 290 | mean /= static_cast<float>(valid); |
| 291 | } |
| 292 | output.mean.values[static_cast<size_t>(b * feature_dim + f)] = mean; |
| 293 | |
| 294 | float variance_sum = 0.0f; |
| 295 | for (int64_t t = 0; t < valid; ++t) { |
| 296 | const float delta = features[static_cast<size_t>(((b * feature_dim) + f) * frames + t)] - mean; |
| 297 | variance_sum += delta * delta; |
| 298 | } |
| 299 | float stddev = 0.0f; |
| 300 | if (valid > 1) { |
| 301 | stddev = std::sqrt(variance_sum / static_cast<float>(valid - 1)); |
| 302 | } |
| 303 | stddev += 1e-5f; |
| 304 | output.stddev.values[static_cast<size_t>(b * feature_dim + f)] = stddev; |
no test coverage detected