1 /*
2 * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "modules/audio_processing/agc2/rnn_vad/rnn_fc.h"
12
13 #include <array>
14 #include <vector>
15
16 #include "api/array_view.h"
17 #include "modules/audio_processing/agc2/cpu_features.h"
18 #include "modules/audio_processing/agc2/rnn_vad/test_utils.h"
19 #include "modules/audio_processing/test/performance_timer.h"
20 #include "rtc_base/logging.h"
21 #include "rtc_base/system/arch.h"
22 #include "test/gtest.h"
23 #include "third_party/rnnoise/src/rnn_vad_weights.h"
24
25 namespace webrtc {
26 namespace rnn_vad {
27 namespace {
28
29 using ::rnnoise::kInputDenseBias;
30 using ::rnnoise::kInputDenseWeights;
31 using ::rnnoise::kInputLayerInputSize;
32 using ::rnnoise::kInputLayerOutputSize;
33
34 // Fully connected layer test data.
35 constexpr std::array<float, 42> kFullyConnectedInputVector = {
36 -1.00131f, -0.627069f, -7.81097f, 7.86285f, -2.87145f, 3.32365f,
37 -0.653161f, 0.529839f, -0.425307f, 0.25583f, 0.235094f, 0.230527f,
38 -0.144687f, 0.182785f, 0.57102f, 0.125039f, 0.479482f, -0.0255439f,
39 -0.0073141f, -0.147346f, -0.217106f, -0.0846906f, -8.34943f, 3.09065f,
40 1.42628f, -0.85235f, -0.220207f, -0.811163f, 2.09032f, -2.01425f,
41 -0.690268f, -0.925327f, -0.541354f, 0.58455f, -0.606726f, -0.0372358f,
42 0.565991f, 0.435854f, 0.420812f, 0.162198f, -2.13f, 10.0089f};
43 constexpr std::array<float, 24> kFullyConnectedExpectedOutput = {
44 -0.623293f, -0.988299f, 0.999378f, 0.967168f, 0.103087f, -0.978545f,
45 -0.856347f, 0.346675f, 1.f, -0.717442f, -0.544176f, 0.960363f,
46 0.983443f, 0.999991f, -0.824335f, 0.984742f, 0.990208f, 0.938179f,
47 0.875092f, 0.999846f, 0.997707f, -0.999382f, 0.973153f, -0.966605f};
48
49 class RnnFcParametrization
50 : public ::testing::TestWithParam<AvailableCpuFeatures> {};
51
52 // Checks that the output of a fully connected layer is within tolerance given
53 // test input data.
TEST_P(RnnFcParametrization,CheckFullyConnectedLayerOutput)54 TEST_P(RnnFcParametrization, CheckFullyConnectedLayerOutput) {
55 FullyConnectedLayer fc(kInputLayerInputSize, kInputLayerOutputSize,
56 kInputDenseBias, kInputDenseWeights,
57 ActivationFunction::kTansigApproximated,
58 /*cpu_features=*/GetParam(),
59 /*layer_name=*/"FC");
60 fc.ComputeOutput(kFullyConnectedInputVector);
61 ExpectNearAbsolute(kFullyConnectedExpectedOutput, fc, 1e-5f);
62 }
63
TEST_P(RnnFcParametrization,DISABLED_BenchmarkFullyConnectedLayer)64 TEST_P(RnnFcParametrization, DISABLED_BenchmarkFullyConnectedLayer) {
65 const AvailableCpuFeatures cpu_features = GetParam();
66 FullyConnectedLayer fc(kInputLayerInputSize, kInputLayerOutputSize,
67 kInputDenseBias, kInputDenseWeights,
68 ActivationFunction::kTansigApproximated, cpu_features,
69 /*layer_name=*/"FC");
70
71 constexpr int kNumTests = 10000;
72 ::webrtc::test::PerformanceTimer perf_timer(kNumTests);
73 for (int k = 0; k < kNumTests; ++k) {
74 perf_timer.StartTimer();
75 fc.ComputeOutput(kFullyConnectedInputVector);
76 perf_timer.StopTimer();
77 }
78 RTC_LOG(LS_INFO) << "CPU features: " << cpu_features.ToString() << " | "
79 << (perf_timer.GetDurationAverage() / 1000) << " +/- "
80 << (perf_timer.GetDurationStandardDeviation() / 1000)
81 << " ms";
82 }
83
84 // Finds the relevant CPU features combinations to test.
GetCpuFeaturesToTest()85 std::vector<AvailableCpuFeatures> GetCpuFeaturesToTest() {
86 std::vector<AvailableCpuFeatures> v;
87 v.push_back(NoAvailableCpuFeatures());
88 AvailableCpuFeatures available = GetAvailableCpuFeatures();
89 if (available.sse2) {
90 v.push_back({/*sse2=*/true, /*avx2=*/false, /*neon=*/false});
91 }
92 if (available.avx2) {
93 v.push_back({/*sse2=*/false, /*avx2=*/true, /*neon=*/false});
94 }
95 if (available.neon) {
96 v.push_back({/*sse2=*/false, /*avx2=*/false, /*neon=*/true});
97 }
98 return v;
99 }
100
101 INSTANTIATE_TEST_SUITE_P(
102 RnnVadTest,
103 RnnFcParametrization,
104 ::testing::ValuesIn(GetCpuFeaturesToTest()),
__anonfc6bf9760202(const ::testing::TestParamInfo<AvailableCpuFeatures>& info) 105 [](const ::testing::TestParamInfo<AvailableCpuFeatures>& info) {
106 return info.param.ToString();
107 });
108
109 } // namespace
110 } // namespace rnn_vad
111 } // namespace webrtc
112