[feat] [assistant] [I3ALCA] add new LowpassBiquad operator bugfix fix fixtags/v1.5.0-rc1
| @@ -25,6 +25,7 @@ | |||
| #include "minddata/dataset/audio/ir/kernels/bass_biquad_ir.h" | |||
| #include "minddata/dataset/audio/ir/kernels/complex_norm_ir.h" | |||
| #include "minddata/dataset/audio/ir/kernels/frequency_masking_ir.h" | |||
| #include "minddata/dataset/audio/ir/kernels/lowpass_biquad_ir.h" | |||
| #include "minddata/dataset/audio/ir/kernels/time_masking_ir.h" | |||
| #include "minddata/dataset/audio/ir/kernels/time_stretch_ir.h" | |||
| @@ -168,6 +169,21 @@ std::shared_ptr<TensorOperation> FrequencyMasking::Parse() { | |||
| data_->mask_start_, data_->mask_value_); | |||
| } | |||
| // LowpassBiquad Transform Operation. | |||
| struct LowpassBiquad::Data { | |||
| Data(int32_t sample_rate, float cutoff_freq, float Q) : sample_rate_(sample_rate), cutoff_freq_(cutoff_freq), Q_(Q) {} | |||
| int32_t sample_rate_; | |||
| float cutoff_freq_; | |||
| float Q_; | |||
| }; | |||
| LowpassBiquad::LowpassBiquad(int32_t sample_rate, float cutoff_freq, float Q) | |||
| : data_(std::make_shared<Data>(sample_rate, cutoff_freq, Q)) {} | |||
| std::shared_ptr<TensorOperation> LowpassBiquad::Parse() { | |||
| return std::make_shared<LowpassBiquadOperation>(data_->sample_rate_, data_->cutoff_freq_, data_->Q_); | |||
| } | |||
| // TimeMasking Transform Operation. | |||
| struct TimeMasking::Data { | |||
| Data(bool iid_masks, int32_t time_mask_param, int32_t mask_start, float mask_value) | |||
| @@ -28,6 +28,7 @@ | |||
| #include "minddata/dataset/audio/ir/kernels/bass_biquad_ir.h" | |||
| #include "minddata/dataset/audio/ir/kernels/complex_norm_ir.h" | |||
| #include "minddata/dataset/audio/ir/kernels/frequency_masking_ir.h" | |||
| #include "minddata/dataset/audio/ir/kernels/lowpass_biquad_ir.h" | |||
| #include "minddata/dataset/audio/ir/kernels/time_masking_ir.h" | |||
| #include "minddata/dataset/audio/ir/kernels/time_stretch_ir.h" | |||
| @@ -142,6 +143,17 @@ PYBIND_REGISTER( | |||
| })); | |||
| })); | |||
| PYBIND_REGISTER( | |||
| LowpassBiquadOperation, 1, ([](const py::module *m) { | |||
| (void)py::class_<audio::LowpassBiquadOperation, TensorOperation, std::shared_ptr<audio::LowpassBiquadOperation>>( | |||
| *m, "LowpassBiquadOperation") | |||
| .def(py::init([](int sample_rate, float cutoff_freq, float Q) { | |||
| auto lowpass_biquad = std::make_shared<audio::LowpassBiquadOperation>(sample_rate, cutoff_freq, Q); | |||
| THROW_IF_ERROR(lowpass_biquad->ValidateParams()); | |||
| return lowpass_biquad; | |||
| })); | |||
| })); | |||
| PYBIND_REGISTER( | |||
| TimeMaskingOperation, 1, ([](const py::module *m) { | |||
| (void)py::class_<audio::TimeMaskingOperation, TensorOperation, std::shared_ptr<audio::TimeMaskingOperation>>( | |||
| @@ -11,6 +11,7 @@ add_library(audio-ir-kernels OBJECT | |||
| bass_biquad_ir.cc | |||
| complex_norm_ir.cc | |||
| frequency_masking_ir.cc | |||
| lowpass_biquad_ir.cc | |||
| time_masking_ir.cc | |||
| time_stretch_ir.cc | |||
| ) | |||
| @@ -0,0 +1,50 @@ | |||
| /** | |||
| * Copyright 2021 Huawei Technologies Co., Ltd | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| * You may obtain a copy of the License at | |||
| * | |||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||
| * | |||
| * Unless required by applicable law or agreed to in writing, software | |||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| * See the License for the specific language governing permissions and | |||
| * limitations under the License. | |||
| */ | |||
| #include "minddata/dataset/audio/ir/kernels/lowpass_biquad_ir.h" | |||
| #include "minddata/dataset/audio/ir/validators.h" | |||
| #include "minddata/dataset/audio/kernels/lowpass_biquad_op.h" | |||
| namespace mindspore { | |||
| namespace dataset { | |||
| namespace audio { | |||
| // LowpassBiquadOperation | |||
| LowpassBiquadOperation::LowpassBiquadOperation(int32_t sample_rate, float cutoff_freq, float Q) | |||
| : sample_rate_(sample_rate), cutoff_freq_(cutoff_freq), Q_(Q) {} | |||
| Status LowpassBiquadOperation::ValidateParams() { | |||
| RETURN_IF_NOT_OK(ValidateScalarNotZero("LowpassBiquad", "sample_rate", sample_rate_)); | |||
| RETURN_IF_NOT_OK(ValidateScalar("LowpassBiquad", "Q", Q_, {0, 1.0}, true, false)); | |||
| return Status::OK(); | |||
| } | |||
| std::shared_ptr<TensorOp> LowpassBiquadOperation::Build() { | |||
| std::shared_ptr<LowpassBiquadOp> tensor_op = std::make_shared<LowpassBiquadOp>(sample_rate_, cutoff_freq_, Q_); | |||
| return tensor_op; | |||
| } | |||
| Status LowpassBiquadOperation::to_json(nlohmann::json *out_json) { | |||
| nlohmann::json args; | |||
| args["sample_rate"] = sample_rate_; | |||
| args["cutoff_freq"] = cutoff_freq_; | |||
| args["Q"] = Q_; | |||
| *out_json = args; | |||
| return Status::OK(); | |||
| } | |||
| } // namespace audio | |||
| } // namespace dataset | |||
| } // namespace mindspore | |||
| @@ -0,0 +1,59 @@ | |||
| /** | |||
| * Copyright 2021 Huawei Technologies Co., Ltd | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| * You may obtain a copy of the License at | |||
| * | |||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||
| * | |||
| * Unless required by applicable law or agreed to in writing, software | |||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| * See the License for the specific language governing permissions and | |||
| * limitations under the License. | |||
| */ | |||
| #ifndef MINDSPORE_CCSRC_MINDDATA_DATASET_AUDIO_IR_KERNELS_LOWPASS_BIQUAD_IR_H_ | |||
| #define MINDSPORE_CCSRC_MINDDATA_DATASET_AUDIO_IR_KERNELS_LOWPASS_BIQUAD_IR_H_ | |||
| #include <memory> | |||
| #include <string> | |||
| #include <utility> | |||
| #include <vector> | |||
| #include "include/api/status.h" | |||
| #include "minddata/dataset/include/dataset/constants.h" | |||
| #include "minddata/dataset/include/dataset/transforms.h" | |||
| #include "minddata/dataset/kernels/ir/tensor_operation.h" | |||
| namespace mindspore { | |||
| namespace dataset { | |||
| namespace audio { | |||
| // Char arrays storing name of corresponding classes (in alphabetical order) | |||
| constexpr char kLowpassBiquadOperation[] = "LowpassBiquad"; | |||
| class LowpassBiquadOperation : public TensorOperation { | |||
| public: | |||
| LowpassBiquadOperation(int32_t sample_rate, float cutoff_freq, float Q); | |||
| ~LowpassBiquadOperation() = default; | |||
| std::shared_ptr<TensorOp> Build() override; | |||
| Status ValidateParams() override; | |||
| std::string Name() const override { return kLowpassBiquadOperation; } | |||
| Status to_json(nlohmann::json *out_json) override; | |||
| private: | |||
| int32_t sample_rate_; | |||
| float cutoff_freq_; | |||
| float Q_; | |||
| }; // class LowpassBiquad | |||
| } // namespace audio | |||
| } // namespace dataset | |||
| } // namespace mindspore | |||
| #endif // MINDSPORE_CCSRC_MINDDATA_DATASET_AUDIO_IR_KERNELS_LOWPASS_BIQUAD_IR_H_ | |||
| @@ -12,6 +12,7 @@ add_library(audio-kernels OBJECT | |||
| bass_biquad_op.cc | |||
| complex_norm_op.cc | |||
| frequency_masking_op.cc | |||
| lowpass_biquad_op.cc | |||
| time_masking_op.cc | |||
| time_stretch_op.cc | |||
| ) | |||
| @@ -0,0 +1,60 @@ | |||
| /** | |||
| * Copyright 2021 Huawei Technologies Co., Ltd | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| * You may obtain a copy of the License at | |||
| * | |||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||
| * | |||
| * Unless required by applicable law or agreed to in writing, software | |||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| * See the License for the specific language governing permissions and | |||
| * limitations under the License. | |||
| */ | |||
| #include "minddata/dataset/audio/kernels/lowpass_biquad_op.h" | |||
| #include "minddata/dataset/audio/kernels/audio_utils.h" | |||
| #include "minddata/dataset/util/status.h" | |||
| namespace mindspore { | |||
| namespace dataset { | |||
| const float LowpassBiquadOp::kQ = 0.707; | |||
| // constructor | |||
| Status LowpassBiquadOp::Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) { | |||
| IO_CHECK(input, output); | |||
| TensorShape input_shape = input->shape(); | |||
| // check input tensor dimension, it should be greater than 0. | |||
| CHECK_FAIL_RETURN_UNEXPECTED(input_shape.Size() > 0, "LowpassBiquad: input tensor is not in shape of <..., time>."); | |||
| // check input type, it should be DE_FLOAT32 or DE_FLOAT16 or DE_FLOAT64 | |||
| CHECK_FAIL_RETURN_UNEXPECTED( | |||
| input->type() == DataType(DataType::DE_FLOAT32) || input->type() == DataType(DataType::DE_FLOAT16) || | |||
| input->type() == DataType(DataType::DE_FLOAT64), | |||
| "LowpassBiquad: input tensor type should be float, but got: " + input->type().ToString()); | |||
| double w0 = 2 * PI * cutoff_freq_ / sample_rate_; | |||
| double alpha = sin(w0) / 2 / Q_; | |||
| double b0 = (1 - cos(w0)) / 2; | |||
| double b1 = 1 - cos(w0); | |||
| double b2 = b0; | |||
| double a0 = 1 + alpha; | |||
| double a1 = -2 * cos(w0); | |||
| double a2 = 1 - alpha; | |||
| if (input->type() == DataType(DataType::DE_FLOAT32)) { | |||
| return Biquad(input, output, static_cast<float>(b0), static_cast<float>(b1), static_cast<float>(b2), | |||
| static_cast<float>(a0), static_cast<float>(a1), static_cast<float>(a2)); | |||
| } else if (input->type() == DataType(DataType::DE_FLOAT64)) { | |||
| return Biquad(input, output, static_cast<double>(b0), static_cast<double>(b1), static_cast<double>(b2), | |||
| static_cast<double>(a0), static_cast<double>(a1), static_cast<double>(a2)); | |||
| } else { | |||
| return Biquad(input, output, static_cast<float16>(b0), static_cast<float16>(b1), static_cast<float16>(b2), | |||
| static_cast<float16>(a0), static_cast<float16>(a1), static_cast<float16>(a2)); | |||
| } | |||
| } | |||
| } // namespace dataset | |||
| } // namespace mindspore | |||
| @@ -0,0 +1,56 @@ | |||
| /** | |||
| * Copyright 2021 Huawei Technologies Co., Ltd | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| * You may obtain a copy of the License at | |||
| * | |||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||
| * | |||
| * Unless required by applicable law or agreed to in writing, software | |||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| * See the License for the specific language governing permissions and | |||
| * limitations under the License. | |||
| */ | |||
| #ifndef MINDSPORE_CCSRC_MINDDATA_DATASET_AUDIO_KERNELS_LOWPASS_BIQUAD_OP_H_ | |||
| #define MINDSPORE_CCSRC_MINDDATA_DATASET_AUDIO_KERNELS_LOWPASS_BIQUAD_OP_H_ | |||
| #include <cmath> | |||
| #include <memory> | |||
| #include <string> | |||
| #include <vector> | |||
| #include "minddata/dataset/core/tensor.h" | |||
| #include "minddata/dataset/kernels/tensor_op.h" | |||
| namespace mindspore { | |||
| namespace dataset { | |||
| class LowpassBiquadOp : public TensorOp { | |||
| public: | |||
| /// default values; | |||
| static const float kQ; | |||
| LowpassBiquadOp(int32_t sample_rate, float cutoff_freq, float Q) | |||
| : sample_rate_(sample_rate), cutoff_freq_(cutoff_freq), Q_(Q) {} | |||
| ~LowpassBiquadOp() override = default; | |||
| void Print(std::ostream &out) const override { | |||
| out << Name() << ": sample_rate: " << sample_rate_ << ", cutoff_freq: " << cutoff_freq_ << ", Q: " << Q_ | |||
| << std::endl; | |||
| } | |||
| Status Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) override; | |||
| std::string Name() const override { return kLowpassBiquadOp; } | |||
| private: | |||
| int32_t sample_rate_; | |||
| float cutoff_freq_; | |||
| float Q_; | |||
| }; | |||
| } // namespace dataset | |||
| } // namespace mindspore | |||
| #endif // MINDSPORE_CCSRC_MINDDATA_DATASET_AUDIO_KERNELS_LOWPASS_BIQUAD_OP_H_ | |||
| @@ -237,6 +237,28 @@ class FrequencyMasking final : public TensorTransform { | |||
| std::shared_ptr<Data> data_; | |||
| }; | |||
| /// \brief Design biquad lowpass filter and perform filtering. Similar to SoX implementation. | |||
| class LowpassBiquad final : public TensorTransform { | |||
| public: | |||
| /// \brief Constructor. | |||
| /// \param[in] sample_rate Sampling rate of the waveform, e.g. 44100 (Hz), the value can't be zero. | |||
| /// \param[in] cutoff_freq Filter cutoff frequency. | |||
| /// \param[in] Q Quality factor, https://en.wikipedia.org/wiki/Q_factor, range: (0, 1] (Default: 0.707). | |||
| LowpassBiquad(int32_t sample_rate, float cutoff_freq, float Q = 0.707); | |||
| /// \brief Destructor. | |||
| ~LowpassBiquad() = default; | |||
| protected: | |||
| /// \brief Function to convert TensorTransform object into a TensorOperation object. | |||
| /// \return Shared pointer to TensorOperation object. | |||
| std::shared_ptr<TensorOperation> Parse() override; | |||
| private: | |||
| struct Data; | |||
| std::shared_ptr<Data> data_; | |||
| }; | |||
| /// \brief TimeMasking TensorTransform. | |||
| /// \notes Apply masking to a spectrogram in the time domain. | |||
| class TimeMasking final : public TensorTransform { | |||
| @@ -147,6 +147,7 @@ constexpr char kBandrejectBiquadOp[] = "BandrejectBiquadOp"; | |||
| constexpr char kBassBiquadOp[] = "BassBiquadOp"; | |||
| constexpr char kComplexNormOp[] = "ComplexNormOp"; | |||
| constexpr char kFrequencyMaskingOp[] = "FrequencyMaskingOp"; | |||
| constexpr char kLowpassBiquadOp[] = "LowpassBiquadOp"; | |||
| constexpr char kTimeMaskingOp[] = "TimeMaskingOp"; | |||
| constexpr char kTimeStretchOp[] = "TimeStretchOp"; | |||
| @@ -25,7 +25,8 @@ import mindspore._c_dataengine as cde | |||
| from ..transforms.c_transforms import TensorOperation | |||
| from .utils import ScaleType | |||
| from .validators import check_allpass_biquad, check_amplitude_to_db, check_band_biquad, check_bandpass_biquad, \ | |||
| check_bandreject_biquad, check_bass_biquad, check_complex_norm, check_masking, check_time_stretch | |||
| check_bandreject_biquad, check_bass_biquad, check_complex_norm, check_lowpass_biquad, check_masking, \ | |||
| check_time_stretch | |||
| class AudioTensorOperation(TensorOperation): | |||
| @@ -299,6 +300,34 @@ class FrequencyMasking(AudioTensorOperation): | |||
| self.mask_value) | |||
| class LowpassBiquad(AudioTensorOperation): | |||
| """ | |||
| Design biquad lowpass filter and perform filtering. Similar to SoX implementation. | |||
| Args: | |||
| sample_rate (int): Sampling rate of the waveform, e.g. 44100 (Hz), the value can't be zero. | |||
| cutoff_freq (float): Filter cutoff frequency. | |||
| Q(float, optional): Quality factor, https://en.wikipedia.org/wiki/Q_factor, range: (0, 1] (default=0.707). | |||
| Examples: | |||
| >>> import numpy as np | |||
| >>> | |||
| >>> waveform = np.array([[0.8236, 0.2049, 0.3335], [0.5933, 0.9911, 0.2482], | |||
| ... [0.3007, 0.9054, 0.7598], [0.5394, 0.2842, 0.5634], [0.6363, 0.2226, 0.2288]]) | |||
| >>> numpy_slices_dataset = ds.NumpySlicesDataset(data=waveform, column_names=["audio"]) | |||
| >>> transforms = [audio.LowpassBiquad(4000, 1500, 0.7)] | |||
| >>> numpy_slices_dataset = numpy_slices_dataset.map(operations=transforms, input_columns=["audio"]) | |||
| """ | |||
| @check_lowpass_biquad | |||
| def __init__(self, sample_rate, cutoff_freq, Q=0.707): | |||
| self.sample_rate = sample_rate | |||
| self.cutoff_freq = cutoff_freq | |||
| self.Q = Q | |||
| def parse(self): | |||
| return cde.LowpassBiquadOperation(self.sample_rate, self.cutoff_freq, self.Q) | |||
| class TimeMasking(AudioTensorOperation): | |||
| """ | |||
| Apply masking to a spectrogram in the time domain. | |||
| @@ -169,6 +169,26 @@ def check_bass_biquad(method): | |||
| return new_method | |||
| def check_biquad_cutoff_freq(cutoff_freq): | |||
| """Wrapper method to check the parameters of cutoff_freq.""" | |||
| type_check(cutoff_freq, (float, int), "cutoff_freq") | |||
| check_float32(cutoff_freq, "cutoff_freq") | |||
| def check_lowpass_biquad(method): | |||
| """Wrapper method to check the parameters of LowpassBiquad.""" | |||
| @wraps(method) | |||
| def new_method(self, *args, **kwargs): | |||
| [sample_rate, cutoff_freq, Q], _ = parse_user_args(method, *args, **kwargs) | |||
| check_biquad_sample_rate(sample_rate) | |||
| check_biquad_cutoff_freq(cutoff_freq) | |||
| check_biquad_Q(Q) | |||
| return method(self, *args, **kwargs) | |||
| return new_method | |||
| def check_time_stretch(method): | |||
| """Wrapper method to check the parameters of TimeStretch.""" | |||
| @@ -490,6 +490,61 @@ TEST_F(MindDataTestPipeline, TestAnglePipelineError) { | |||
| EXPECT_ERROR(iter->GetNextRow(&row)); | |||
| } | |||
| TEST_F(MindDataTestPipeline, TestLowpassBiquadSuccess) { | |||
| MS_LOG(INFO) << "Doing MindDataTestPipeline-TestLowpassBiquadSuccess."; | |||
| // Create an input tensor | |||
| std::shared_ptr<SchemaObj> schema = Schema(); | |||
| ASSERT_OK(schema->add_column("col1", mindspore::DataType::kNumberTypeFloat32, {1, 200})); | |||
| std::shared_ptr<Dataset> ds = RandomData(8, schema); | |||
| EXPECT_NE(ds, nullptr); | |||
| // Create a filter object | |||
| std::shared_ptr<TensorTransform> lowpass_biquad(new audio::LowpassBiquad(44100, 3000.5, 0.707)); | |||
| auto ds1 = ds->Map({lowpass_biquad}, {"col1"}, {"audio"}); | |||
| EXPECT_NE(ds1, nullptr); | |||
| std::shared_ptr<Iterator> iter = ds1->CreateIterator(); | |||
| EXPECT_NE(iter, nullptr); | |||
| std::unordered_map<std::string, mindspore::MSTensor> row; | |||
| ASSERT_OK(iter->GetNextRow(&row)); | |||
| uint64_t i = 0; | |||
| while (row.size() != 0) { | |||
| i++; | |||
| ASSERT_OK(iter->GetNextRow(&row)); | |||
| } | |||
| EXPECT_EQ(i, 8); | |||
| iter->Stop(); | |||
| } | |||
| TEST_F(MindDataTestPipeline, TestLowpassBiquadWrongArgs) { | |||
| MS_LOG(INFO) << "Doing MindDataTestPipeline-TestLowpassBiquadWrongArgs."; | |||
| std::shared_ptr<SchemaObj> schema = Schema(); | |||
| // Original waveform | |||
| ASSERT_OK(schema->add_column("inputData", mindspore::DataType::kNumberTypeFloat32, {2, 10})); | |||
| std::shared_ptr<Dataset> ds = RandomData(50, schema); | |||
| std::shared_ptr<Dataset> ds01; | |||
| std::shared_ptr<Dataset> ds02; | |||
| EXPECT_NE(ds, nullptr); | |||
| // Check sample_rate | |||
| MS_LOG(INFO) << "sample_rate is zero."; | |||
| auto lowpass_biquad_op_01 = audio::LowpassBiquad(0, 200.0, 0.7); | |||
| ds01 = ds->Map({lowpass_biquad_op_01}); | |||
| EXPECT_NE(ds01, nullptr); | |||
| std::shared_ptr<Iterator> iter01 = ds01->CreateIterator(); | |||
| EXPECT_EQ(iter01, nullptr); | |||
| // Check Q | |||
| MS_LOG(INFO) << "Q is zero."; | |||
| auto lowpass_biquad_op_02 = audio::LowpassBiquad(44100, 2000.0, 0); | |||
| ds02 = ds->Map({lowpass_biquad_op_02}); | |||
| EXPECT_NE(ds02, nullptr); | |||
| std::shared_ptr<Iterator> iter02 = ds02->CreateIterator(); | |||
| EXPECT_EQ(iter02, nullptr); | |||
| } | |||
| TEST_F(MindDataTestPipeline, TestFrequencyMaskingPipeline) { | |||
| MS_LOG(INFO) << "Doing MindDataTestPipeline-TestFrequencyMaskingPipeline."; | |||
| // Original waveform | |||
| @@ -642,6 +642,55 @@ TEST_F(MindDataTestExecute, TestRGB2BGREager) { | |||
| EXPECT_EQ(rc, Status::OK()); | |||
| } | |||
| TEST_F(MindDataTestExecute, TestLowpassBiquadEager) { | |||
| MS_LOG(INFO) << "Doing MindDataTestExecute-TestLowpassBiquadEager."; | |||
| int sample_rate = 44100; | |||
| float cutoff_freq = 2000.0; | |||
| float Q = 0.6; | |||
| std::vector<mindspore::MSTensor> output; | |||
| std::shared_ptr<Tensor> test; | |||
| std::vector<double> test_vector = {23.5, 13.2, 62.5, 27.1, 15.5, 30.3, 44.9, 25.0, | |||
| 11.3, 37.4, 67.1, 33.8, 73.4, 53.3, 93.7, 31.1}; | |||
| Tensor::CreateFromVector(test_vector, TensorShape({4,4}), &test); | |||
| auto input = mindspore::MSTensor(std::make_shared<mindspore::dataset::DETensor>(test)); | |||
| std::shared_ptr<TensorTransform> lowpass_biquad(new audio::LowpassBiquad({sample_rate, cutoff_freq, Q})); | |||
| auto transform = Execute({lowpass_biquad}); | |||
| Status rc = transform({input}, &output); | |||
| ASSERT_TRUE(rc.IsOk()); | |||
| } | |||
| TEST_F(MindDataTestExecute, TestLowpassBiuqadParamCheckQ) { | |||
| MS_LOG(INFO) << "Doing MindDataTestExecute-TestLowpassBiuqadParamCheckQ."; | |||
| std::vector<mindspore::MSTensor> output; | |||
| std::shared_ptr<Tensor> test; | |||
| std::vector<double> test_vector = {0.8236, 0.2049, 0.3335, 0.5933, 0.9911, 0.2482, | |||
| 0.3007, 0.9054, 0.7598, 0.5394, 0.2842, 0.5634, 0.6363, 0.2226, 0.2288}; | |||
| Tensor::CreateFromVector(test_vector, TensorShape({5,3}), &test); | |||
| auto input = mindspore::MSTensor(std::make_shared<mindspore::dataset::DETensor>(test)); | |||
| // Check Q | |||
| std::shared_ptr<TensorTransform> lowpass_biquad_op = std::make_shared<audio::LowpassBiquad>(44100, 3000.5, 0); | |||
| mindspore::dataset::Execute transform({lowpass_biquad_op}); | |||
| Status rc = transform({input}, &output); | |||
| ASSERT_FALSE(rc.IsOk()); | |||
| } | |||
| TEST_F(MindDataTestExecute, TestLowpassBiuqadParamCheckSampleRate) { | |||
| MS_LOG(INFO) << "Doing MindDataTestExecute-TestLowpassBiuqadParamCheckSampleRate."; | |||
| std::vector<mindspore::MSTensor> output; | |||
| std::shared_ptr<Tensor> test; | |||
| std::vector<double> test_vector = {0.5, 4.6, 2.2, 0.6, 1.9, 4.7, | |||
| 2.3, 4.9, 4.7, 0.5, 0.8, 0.9}; | |||
| Tensor::CreateFromVector(test_vector, TensorShape({6,2}), &test); | |||
| auto input = mindspore::MSTensor(std::make_shared<mindspore::dataset::DETensor>(test)); | |||
| // Check sample_rate | |||
| std::shared_ptr<TensorTransform> lowpass_biquad_op = std::make_shared<audio::LowpassBiquad>(0, 2000.5, 0.7); | |||
| mindspore::dataset::Execute transform({lowpass_biquad_op}); | |||
| Status rc = transform({input}, &output); | |||
| ASSERT_FALSE(rc.IsOk()); | |||
| } | |||
| TEST_F(MindDataTestExecute, TestComplexNormEager) { | |||
| MS_LOG(INFO) << "Doing MindDataTestExecute-TestComplexNormEager."; | |||
| // testing | |||
| @@ -0,0 +1,112 @@ | |||
| # Copyright 2021 Huawei Technologies Co., Ltd | |||
| # | |||
| # Licensed under the Apache License, Version 2.0 (the "License"); | |||
| # you may not use this file except in compliance with the License. | |||
| # You may obtain a copy of the License at | |||
| # | |||
| # http://www.apache.org/licenses/LICENSE-2.0 | |||
| # | |||
| # Unless required by applicable law or agreed to in writing, software | |||
| # distributed under the License is distributed on an "AS IS" BASIS, | |||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| # See the License for the specific language governing permissions and | |||
| # limitations under the License. | |||
| # ============================================================================== | |||
| """ | |||
| Testing LowpassBiquad op in DE | |||
| """ | |||
| import numpy as np | |||
| import pytest | |||
| import mindspore.dataset as ds | |||
| import mindspore.dataset.audio.transforms as audio | |||
| from mindspore import log as logger | |||
| def count_unequal_element(data_expected, data_me, rtol, atol): | |||
| assert data_expected.shape == data_me.shape | |||
| total_count = len(data_expected.flatten()) | |||
| error = np.abs(data_expected - data_me) | |||
| greater = np.greater(error, atol + np.abs(data_expected) * rtol) | |||
| loss_count = np.count_nonzero(greater) | |||
| assert (loss_count / total_count) < rtol, "\ndata_expected_std:{0}\ndata_me_error:{1}\nloss:{2}".format( | |||
| data_expected[greater], data_me[greater], error[greater]) | |||
| def test_lowpass_biquad_eager(): | |||
| """ mindspore eager mode normal testcase:lowpass_biquad op""" | |||
| # Original waveform | |||
| waveform = np.array([[0.8236, 0.2049, 0.3335], [0.5933, 0.9911, 0.2482], | |||
| [0.3007, 0.9054, 0.7598], [0.5394, 0.2842, 0.5634], [0.6363, 0.2226, 0.2288]]) | |||
| # Expect waveform | |||
| expect_waveform = np.array([[0.2745, 0.6174, 0.4308], [0.1978, 0.7259, 0.8753], | |||
| [0.1002, 0.5023, 0.9237], [0.1798, 0.4543, 0.4971], [0.2121, 0.4984, 0.3661]]) | |||
| lowpass_biquad_op = audio.LowpassBiquad(4000, 1000.0, 1) | |||
| # Filtered waveform by lowpass_biquad | |||
| output = lowpass_biquad_op(waveform) | |||
| count_unequal_element(expect_waveform, output, 0.0001, 0.0001) | |||
| def test_lowpass_biquad_pipeline(): | |||
| """ mindspore pipeline mode normal testcase:lowpass_biquad op""" | |||
| # Original waveform | |||
| waveform = np.array([[3.5, 3.2, 2.5, 7.1], [5.5, 0.3, 4.9, 5.0], | |||
| [1.3, 7.4, 7.1, 3.8], [3.4, 3.3, 3.7, 1.1]]) | |||
| # Expect waveform | |||
| expect_waveform = np.array([[0.0481, 0.2029, 0.4180, 0.6830], [0.0755, 0.2538, 0.4555, 0.7107], | |||
| [0.0178, 0.1606, 0.5220, 0.9729], [0.0467, 0.1997, 0.4322, 0.6546]]) | |||
| dataset = ds.NumpySlicesDataset(waveform, ["col1"], shuffle=False) | |||
| lowpass_biquad_op = audio.LowpassBiquad(44100, 2000.0, 0.3) | |||
| # Filtered waveform by lowpass_biquad | |||
| dataset = dataset.map( | |||
| input_columns=["col1"], operations=lowpass_biquad_op, num_parallel_workers=4) | |||
| i = 0 | |||
| for _ in dataset.create_dict_iterator(output_numpy=True): | |||
| count_unequal_element(expect_waveform[i, :], | |||
| _["col1"], 0.0001, 0.0001) | |||
| i += 1 | |||
| def test_lowpass_biquad_invalid_input(): | |||
| """ | |||
| Test invalid input of LowpassBiquad | |||
| """ | |||
| def test_invalid_input(test_name, sample_rate, cutoff_freq, Q, error, error_msg): | |||
| logger.info("Test LowpassBiquad with bad input: {0}".format(test_name)) | |||
| with pytest.raises(error) as error_info: | |||
| audio.LowpassBiquad(sample_rate, cutoff_freq, Q) | |||
| assert error_msg in str(error_info.value) | |||
| test_invalid_input("invalid sample_rate parameter type as a float", 44100.5, 1000, 0.707, TypeError, | |||
| "Argument sample_rate with value 44100.5 is not of type [<class 'int'>]," | |||
| " but got <class 'float'>.") | |||
| test_invalid_input("invalid sample_rate parameter type as a String", "44100", 1000, 0.707, TypeError, | |||
| "Argument sample_rate with value 44100 is not of type [<class 'int'>]," | |||
| " but got <class 'str'>.") | |||
| test_invalid_input("invalid cutoff_freq parameter type as a String", 44100, "1000", 0.707, TypeError, | |||
| "Argument cutoff_freq with value 1000 is not of type [<class 'float'>, <class 'int'>]," | |||
| " but got <class 'str'>.") | |||
| test_invalid_input("invalid Q parameter type as a String", 44100, 1000, "0.707", TypeError, | |||
| "Argument Q with value 0.707 is not of type [<class 'float'>, <class 'int'>]," | |||
| " but got <class 'str'>.") | |||
| test_invalid_input("invalid sample_rate parameter value", 441324343243242342345300, 1000, 0.707, ValueError, | |||
| "Input sample_rate is not within the required interval of [-2147483648, 0) and (0, 2147483647].") | |||
| test_invalid_input("invalid cutoff_freq parameter value", 44100, 32434324324234321, 0.707, ValueError, | |||
| "Input cutoff_freq is not within the required interval of [-16777216, 16777216].") | |||
| test_invalid_input("invalid sample_rate parameter value", None, 1000, 0.707, TypeError, | |||
| "Argument sample_rate with value None is not of type [<class 'int'>], " | |||
| "but got <class 'NoneType'>.") | |||
| test_invalid_input("invalid cutoff_rate parameter value", 44100, None, 0.707, TypeError, | |||
| "Argument cutoff_freq with value None is not of type [<class 'float'>, <class 'int'>]," | |||
| " but got <class 'NoneType'>.") | |||
| test_invalid_input("invalid Q parameter value", 44100, 1000, 0, ValueError, | |||
| "Input Q is not within the required interval of (0, 1].") | |||
| if __name__ == "__main__": | |||
| test_lowpass_biquad_eager() | |||
| test_lowpass_biquad_pipeline() | |||
| test_lowpass_biquad_invalid_input() | |||