!16667 [assistant][ComplexNorm]

Merge pull request !16667 from QingfengLi/ComplexNorm
This commit is contained in:
i-robot 2021-08-21 02:44:18 +00:00 committed by Gitee
commit 4ba337e0f5
17 changed files with 558 additions and 1 deletions

View File

@ -23,6 +23,7 @@
#include "minddata/dataset/audio/ir/kernels/bandpass_biquad_ir.h"
#include "minddata/dataset/audio/ir/kernels/bandreject_biquad_ir.h"
#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/time_masking_ir.h"
#include "minddata/dataset/audio/ir/kernels/time_stretch_ir.h"
@ -136,6 +137,16 @@ std::shared_ptr<TensorOperation> BassBiquad::Parse() {
return std::make_shared<BassBiquadOperation>(data_->sample_rate_, data_->gain_, data_->central_freq_, data_->Q_);
}
// ComplexNorm Transform Operation.
struct ComplexNorm::Data {
explicit Data(float power) : power_(power) {}
float power_;
};
ComplexNorm::ComplexNorm(float power) : data_(std::make_shared<Data>(power)) {}
std::shared_ptr<TensorOperation> ComplexNorm::Parse() { return std::make_shared<ComplexNormOperation>(data_->power_); }
// FrequencyMasking Transform Operation.
struct FrequencyMasking::Data {
Data(bool iid_masks, int32_t frequency_mask_param, int32_t mask_start, double mask_value)
@ -190,6 +201,7 @@ TimeStretch::TimeStretch(float hop_length, int n_freq, float fixed_rate)
std::shared_ptr<TensorOperation> TimeStretch::Parse() {
return std::make_shared<TimeStretchOperation>(data_->hop_length_, data_->n_freq_, data_->fixed_rate_);
}
} // namespace audio
} // namespace dataset
} // namespace mindspore

View File

@ -26,6 +26,7 @@
#include "minddata/dataset/audio/ir/kernels/bandpass_biquad_ir.h"
#include "minddata/dataset/audio/ir/kernels/bandreject_biquad_ir.h"
#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/time_masking_ir.h"
#include "minddata/dataset/audio/ir/kernels/time_stretch_ir.h"
@ -117,6 +118,17 @@ PYBIND_REGISTER(
}));
}));
PYBIND_REGISTER(
ComplexNormOperation, 1, ([](const py::module *m) {
(void)py::class_<audio::ComplexNormOperation, TensorOperation, std::shared_ptr<audio::ComplexNormOperation>>(
*m, "ComplexNormOperation")
.def(py::init([](float power) {
auto complex_norm = std::make_shared<audio::ComplexNormOperation>(power);
THROW_IF_ERROR(complex_norm->ValidateParams());
return complex_norm;
}));
}));
PYBIND_REGISTER(
FrequencyMaskingOperation, 1, ([](const py::module *m) {
(void)

View File

@ -9,6 +9,7 @@ add_library(audio-ir-kernels OBJECT
bandpass_biquad_ir.cc
bandreject_biquad_ir.cc
bass_biquad_ir.cc
complex_norm_ir.cc
frequency_masking_ir.cc
time_masking_ir.cc
time_stretch_ir.cc

View File

@ -0,0 +1,52 @@
/**
* 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/complex_norm_ir.h"
#include "minddata/dataset/audio/ir/validators.h"
#include "minddata/dataset/audio/kernels/complex_norm_op.h"
namespace mindspore {
namespace dataset {
namespace audio {
ComplexNormOperation::ComplexNormOperation(float power) : power_(power) {}
ComplexNormOperation::~ComplexNormOperation() = default;
Status ComplexNormOperation::ValidateParams() {
RETURN_IF_NOT_OK(ValidateFloatScalarNonNegative("ComplexNorm", "power", power_));
return Status::OK();
}
Status ComplexNormOperation::to_json(nlohmann::json *out_json) {
nlohmann::json args;
args["power"] = power_;
*out_json = args;
return Status::OK();
}
std::shared_ptr<TensorOp> ComplexNormOperation::Build() {
std::shared_ptr<ComplexNormOp> tensor_op = std::make_shared<ComplexNormOp>(power_);
return tensor_op;
}
std::string ComplexNormOperation::Name() const { return kComplexNormOperation; }
} // namespace audio
} // namespace dataset
} // namespace mindspore

View File

@ -0,0 +1,53 @@
/**
* 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_COMPLEX_NORM_IR_H_
#define MINDSPORE_CCSRC_MINDDATA_DATASET_AUDIO_IR_KERNELS_COMPLEX_NORM_IR_H_
#include <memory>
#include <string>
#include <vector>
#include "include/api/status.h"
#include "minddata/dataset/kernels/ir/tensor_operation.h"
namespace mindspore {
namespace dataset {
namespace audio {
constexpr char kComplexNormOperation[] = "ComplexNorm";
class ComplexNormOperation : public TensorOperation {
public:
explicit ComplexNormOperation(float power);
~ComplexNormOperation();
std::shared_ptr<TensorOp> Build() override;
Status ValidateParams() override;
std::string Name() const override;
Status to_json(nlohmann::json *out_json) override;
private:
float power_;
}; // class ComplexNormOperation
} // namespace audio
} // namespace dataset
} // namespace mindspore
#endif // MINDSPORE_CCSRC_MINDDATA_DATASET_AUDIO_IR_KERNELS_COMPLEX_NORM_IR_H_

View File

@ -10,6 +10,7 @@ add_library(audio-kernels OBJECT
bandpass_biquad_op.cc
bandreject_biquad_op.cc
bass_biquad_op.cc
complex_norm_op.cc
frequency_masking_op.cc
time_masking_op.cc
time_stretch_op.cc

View File

@ -16,6 +16,11 @@
#include "minddata/dataset/audio/kernels/audio_utils.h"
#include <complex>
#include "mindspore/core/base/float16.h"
#include "minddata/dataset/core/type_id.h"
#include "minddata/dataset/kernels/data/data_utils.h"
#include "minddata/dataset/util/random.h"
#include "minddata/dataset/util/status.h"
@ -412,5 +417,93 @@ Status MaskAlongAxis(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tenso
*output = input;
return Status::OK();
}
template <typename T>
Status Norm(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output, float power) {
// calcutate total complex num
int32_t dim = input->shape().Size();
int32_t total_num = 1;
for (int32_t i = 0; i < (dim - 1); i++) {
total_num *= (input->shape()[i]);
}
// calculate the output dimension
auto input_size = input->shape().AsVector();
int32_t dim_back = input_size.back();
CHECK_FAIL_RETURN_UNEXPECTED(
dim_back == 2, "ComplexNorm: expect complex input of shape <..., 2>, but got: " + std::to_string(dim_back));
input_size.pop_back();
int32_t complex_num = input_size.back();
int32_t iter_num = total_num / complex_num;
// TensorShape out_put_shape{}
input_size.pop_back();
input_size.emplace_back(2);
TensorShape out_shape = TensorShape(input_size);
RETURN_IF_NOT_OK(Tensor::CreateEmpty(out_shape, input->type(), output));
// slice input into real tensor and imaginary tensor
std::shared_ptr<Tensor> re_tensor;
std::shared_ptr<Tensor> im_tensor;
RETURN_IF_NOT_OK(Tensor::CreateEmpty(TensorShape({total_num, 1}), input->type(), &re_tensor));
RETURN_IF_NOT_OK(Tensor::CreateEmpty(TensorShape({total_num, 1}), input->type(), &im_tensor));
std::vector<SliceOption> slice_re = {};
std::vector<SliceOption> slice_im = {};
for (int32_t i = 0; i < (dim - 1); i++) {
slice_re.emplace_back(SliceOption(true));
slice_im.emplace_back(SliceOption(true));
}
slice_re.emplace_back(SliceOption(std::vector<dsize_t>{0}));
slice_im.emplace_back(SliceOption(std::vector<dsize_t>{1}));
RETURN_IF_NOT_OK(input->Slice(&re_tensor, slice_re));
RETURN_IF_NOT_OK(input->Slice(&im_tensor, slice_im));
// calculate norm, using: .pow(2.).sum(-1).pow(0.5 * power)
auto itr_out = (*output)->begin<T>();
auto itr_re = re_tensor->begin<T>();
auto itr_im = im_tensor->begin<T>();
for (int32_t i = 0; i < iter_num; i++) {
double re = 0.0;
double im = 0.0;
for (int32_t j = complex_num * i; j < complex_num * (i + 1); j++) {
double a = static_cast<double>(*itr_re);
double b = static_cast<double>(*itr_im);
re = re + (pow(a, 2) - pow(b, 2));
im = im + (2 * a * b);
++itr_re;
++itr_im;
}
std::complex<double> comp(re, im);
comp = std::pow(comp, (0.5 * power));
*itr_out = static_cast<T>(comp.real());
++itr_out;
*itr_out = static_cast<T>(comp.imag());
++itr_out;
}
RETURN_IF_NOT_OK((*output)->Reshape(out_shape));
return Status::OK();
}
Status ComplexNorm(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output, float power) {
try {
if (input->type().value() >= DataType::DE_INT8 && input->type().value() <= DataType::DE_FLOAT16) {
// convert the data type to float
std::shared_ptr<Tensor> input_tensor;
RETURN_IF_NOT_OK(Tensor::CreateEmpty(input->shape(), DataType(DataType::DE_FLOAT32), &input_tensor));
RETURN_IF_NOT_OK(TypeCast(input, &input_tensor, DataType(DataType::DE_FLOAT32)));
Norm<float>(input_tensor, output, power);
} else if (input->type().value() == DataType::DE_FLOAT32) {
Norm<float>(input, output, power);
} else if (input->type().value() == DataType::DE_FLOAT64) {
Norm<double>(input, output, power);
} else {
RETURN_STATUS_UNEXPECTED("ComplexNorm: input tensor type should be int, float or double, but got: " +
input->type().ToString());
}
return Status::OK();
} catch (std::runtime_error &e) {
RETURN_STATUS_UNEXPECTED("ComplexNorm: " + std::string(e.what()));
}
}
} // namespace dataset
} // namespace mindspore

View File

@ -245,6 +245,14 @@ Status RandomMaskAlongAxis(const std::shared_ptr<Tensor> &input, std::shared_ptr
/// \return Status code.
Status MaskAlongAxis(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output, int64_t mask_width,
int64_t mask_start, double mask_value, int axis);
/// \brief Compute the norm of complex tensor input.
/// \param power Power of the norm description (optional).
/// \param input Tensor shape of <..., complex=2>.
/// \param output Tensor shape of <..., complex=2>.
/// \return Status code.
Status ComplexNorm(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output, float power);
} // namespace dataset
} // namespace mindspore
#endif // MINDSPORE_CCSRC_MINDDATA_DATASET_AUDIO_KERNELS_AUDIO_UTILS_H_

View File

@ -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/complex_norm_op.h"
#include "minddata/dataset/audio/kernels/audio_utils.h"
namespace mindspore {
namespace dataset {
// constructor
ComplexNormOp::ComplexNormOp(float power) : power_(power) {}
// main function
Status ComplexNormOp::Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) {
IO_CHECK(input, output);
CHECK_FAIL_RETURN_UNEXPECTED(input->Rank() >= 2, "ComplexNorm: input tensor is not in shape of <..., 2>.");
return ComplexNorm(input, output, power_);
}
Status ComplexNormOp::OutputShape(const std::vector<TensorShape> &inputs, std::vector<TensorShape> &outputs) {
RETURN_IF_NOT_OK(TensorOp::OutputShape(inputs, outputs));
outputs.clear();
auto input_size = inputs[0].AsVector();
input_size.pop_back();
input_size.pop_back();
input_size.emplace_back(2);
TensorShape out = TensorShape(input_size);
outputs.emplace_back(out);
if (!outputs.empty()) return Status::OK();
return Status(StatusCode::kMDUnexpectedError, "ComplexNorm: invalid input shape.");
}
Status ComplexNormOp::OutputType(const std::vector<DataType> &inputs, std::vector<DataType> &outputs) {
RETURN_IF_NOT_OK(TensorOp::OutputType(inputs, outputs));
if (inputs[0] == DataType(DataType::DE_FLOAT64)) {
outputs[0] = DataType(DataType::DE_FLOAT64);
} else {
outputs[0] = DataType(DataType::DE_FLOAT32);
}
return Status::OK();
}
void ComplexNormOp::Print(std::ostream &out) const { out << "ComplexNormOp: power " << power_; }
} // namespace dataset
} // namespace mindspore

View File

@ -0,0 +1,54 @@
/**
* 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_COMPLEX_NORM_OP_H_
#define MINDSPORE_CCSRC_MINDDATA_DATASET_AUDIO_KERNELS_COMPLEX_NORM_OP_H_
#include <memory>
#include <string>
#include <vector>
#include "minddata/dataset/core/tensor.h"
#include "minddata/dataset/kernels/tensor_op.h"
#include "minddata/dataset/util/status.h"
namespace mindspore {
namespace dataset {
class ComplexNormOp : public TensorOp {
public:
/// \brief Constructor for ComplexNormOp.
/// \param[in] power Power of the norm (Optional).
explicit ComplexNormOp(float power = 1.0);
~ComplexNormOp() override = default;
void Print(std::ostream &out) const override;
Status Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) override;
Status OutputShape(const std::vector<TensorShape> &inputs, std::vector<TensorShape> &outputs) override;
Status OutputType(const std::vector<DataType> &inputs, std::vector<DataType> &outputs) override;
std::string Name() const override { return kComplexNormOp; }
private:
float power_;
};
} // namespace dataset
} // namespace mindspore
#endif // MINDSPORE_CCSRC_MINDDATA_DATASET_AUDIO_KERNELS_COMPLEX_NORM_OP_H_

View File

@ -188,6 +188,27 @@ class BassBiquad final : public TensorTransform {
std::shared_ptr<Data> data_;
};
/// \brief ComplexNorm TensorTransform.
/// \notes Compute the norm of complex tensor input.
class ComplexNorm final : public TensorTransform {
public:
/// \brief Constructor.
/// \param[in] power Power of the norm, which must be non-negative (Default: 1.0).
explicit ComplexNorm(float power = 1.0);
/// \brief Destructor.
~ComplexNorm() = 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 FrequencyMasking TensorTransform.
/// \notes Apply masking to a spectrogram in the frequency domain.
class FrequencyMasking final : public TensorTransform {

View File

@ -145,6 +145,7 @@ constexpr char kBandBiquadOp[] = "BandBiquadOp";
constexpr char kBandpassBiquadOp[] = "BandpassBiquadOp";
constexpr char kBandrejectBiquadOp[] = "BandrejectBiquadOp";
constexpr char kBassBiquadOp[] = "BassBiquadOp";
constexpr char kComplexNormOp[] = "ComplexNormOp";
constexpr char kFrequencyMaskingOp[] = "FrequencyMaskingOp";
constexpr char kTimeMaskingOp[] = "TimeMaskingOp";
constexpr char kTimeStretchOp[] = "TimeStretchOp";

View File

@ -25,7 +25,7 @@ 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_masking, check_time_stretch
check_bandreject_biquad, check_bass_biquad, check_complex_norm, check_masking, check_time_stretch
class AudioTensorOperation(TensorOperation):
@ -244,6 +244,29 @@ class BassBiquad(AudioTensorOperation):
return cde.BassBiquadOperation(self.sample_rate, self.gain, self.central_freq, self.Q)
class ComplexNorm(AudioTensorOperation):
"""
Compute the norm of complex tensor input.
Args:
power (float, optional): Power of the norm, which must be non-negative (default=1.0).
Examples:
>>> import numpy as np
>>>
>>> waveform = np.random.random([2, 4, 2])
>>> numpy_slices_dataset = ds.NumpySlicesDataset(data=waveform, column_names=["audio"])
>>> transforms = [audio.ComplexNorm()]
>>> numpy_slices_dataset = numpy_slices_dataset.map(operations=transforms, input_columns=["audio"])
"""
@check_complex_norm
def __init__(self, power=1.0):
self.power = power
def parse(self):
return cde.ComplexNormOperation(self.power)
class FrequencyMasking(AudioTensorOperation):
"""
Apply masking to a spectrogram in the frequency domain.

View File

@ -208,3 +208,14 @@ def check_masking(method):
return method(self, *args, **kwargs)
return new_method
def check_complex_norm(method):
"""Wrapper method to check the parameters of ComplexNorm."""
@wraps(method)
def new_method(self, *args, **kwargs):
[power], _ = parse_user_args(method, *args, **kwargs)
check_non_negative_float32(power, "power")
return method(self, *args, **kwargs)
return new_method

View File

@ -549,3 +549,61 @@ TEST_F(MindDataTestPipeline, TestFrequencyMaskingWrongArgs) {
// Expect failure
EXPECT_EQ(iter, nullptr);
}
TEST_F(MindDataTestPipeline, TestComplexNormBasic) {
MS_LOG(INFO) << "Doing MindDataTestPipeline-TestComplexNormBasic.";
// Original waveform
std::shared_ptr<SchemaObj> schema = Schema();
ASSERT_OK(schema->add_column("inputData", mindspore::DataType::kNumberTypeInt64, {3, 2, 4, 2}));
std::shared_ptr<Dataset> ds = RandomData(50, schema);
EXPECT_NE(ds, nullptr);
ds = ds->SetNumWorkers(4);
EXPECT_NE(ds, nullptr);
auto ComplexNormOp = audio::ComplexNorm(3.0);
ds = ds->Map({ComplexNormOp});
EXPECT_NE(ds, nullptr);
// Filtered waveform by ComplexNorm
std::shared_ptr<Iterator> iter = ds->CreateIterator();
EXPECT_NE(ds, nullptr);
std::unordered_map<std::string, mindspore::MSTensor> row;
ASSERT_OK(iter->GetNextRow(&row));
std::vector<int64_t> expected = {3, 2, 2};
int i = 0;
while (row.size() != 0) {
auto col = row["inputData"];
ASSERT_EQ(col.Shape(), expected);
ASSERT_EQ(col.DataType(), mindspore::DataType::kNumberTypeFloat32);
ASSERT_OK(iter->GetNextRow(&row));
i++;
}
EXPECT_EQ(i, 50);
iter->Stop();
}
TEST_F(MindDataTestPipeline, TestComplexNormWrongArgs) {
MS_LOG(INFO) << "Doing MindDataTestPipeline-TestComplexNormWrongArgs.";
// Original waveform
std::shared_ptr<SchemaObj> schema = Schema();
ASSERT_OK(schema->add_column("inputData", mindspore::DataType::kNumberTypeInt64, {3, 2, 4, 2}));
std::shared_ptr<Dataset> ds = RandomData(50, schema);
EXPECT_NE(ds, nullptr);
ds = ds->SetNumWorkers(4);
EXPECT_NE(ds, nullptr);
auto ComplexNormOp = audio::ComplexNorm(-10);
ds = ds->Map({ComplexNormOp});
std::shared_ptr<Iterator> iter1 = ds->CreateIterator();
EXPECT_EQ(iter1, nullptr);
}

View File

@ -641,3 +641,18 @@ TEST_F(MindDataTestExecute, TestRGB2BGREager) {
EXPECT_EQ(rc, Status::OK());
}
TEST_F(MindDataTestExecute, TestComplexNormEager) {
MS_LOG(INFO) << "Doing MindDataTestExecute-TestComplexNormEager.";
// testing
std::shared_ptr<Tensor> input_tensor_;
Tensor::CreateFromVector(std::vector<float>({1.0, 1.0, 2.0, 3.0, 4.0, 4.0}), TensorShape({3, 2}), &input_tensor_);
auto input_02 = mindspore::MSTensor(std::make_shared<mindspore::dataset::DETensor>(input_tensor_));
std::shared_ptr<TensorTransform> complex_norm_01 = std::make_shared<audio::ComplexNorm>(4.0);
// Filtered waveform by complexnorm
mindspore::dataset::Execute Transform01({complex_norm_01});
Status s01 = Transform01(input_02, &input_02);
EXPECT_TRUE(s01.IsOk());
}

View File

@ -0,0 +1,82 @@
# 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 ComplexNorm op in DE.
"""
import numpy as np
from numpy import random
import mindspore.dataset as ds
import mindspore.dataset.audio.transforms as audio
from mindspore import log as logger
def test_complex_norm():
"""
Test complex_norm (pipeline).
"""
logger.info("Test ComplexNorm.")
def gen():
data = np.array([[1.0, 1.0], [2.0, 3.0], [4.0, 4.0]])
yield (np.array(data, dtype=np.float32),)
dataset = ds.GeneratorDataset(source=gen, column_names=["multi_dim_data"])
dataset = dataset.map(operations=audio.ComplexNorm(2.), input_columns=["multi_dim_data"])
for i in dataset.create_dict_iterator(num_epochs=1, output_numpy=True):
assert i["multi_dim_data"].shape == (2,)
expected = np.array([-5., 46.])
assert np.array_equal(i["multi_dim_data"], expected)
logger.info("Finish testing ComplexNorm.")
def test_complex_norm_eager():
"""
Test complex_norm callable (eager).
"""
logger.info("Test ComplexNorm callable.")
input_t = np.array([[1.0, 1.0], [2.0, 3.0], [4.0, 4.0]])
output_t = audio.ComplexNorm(3)(input_t)
assert output_t.shape == (2,)
expected = np.array([-255.6179621231501, 183.64515392460598])
assert np.array_equal(output_t, expected)
logger.info("Finish testing ComplexNorm.")
def test_complex_norm_uncallable():
"""
Test complex_norm_op not callable.
"""
logger.info("Test ComplexNorm not callable.")
try:
input_t = random.rand(2, 4, 3, 2)
output_t = audio.ComplexNorm(-3.)(input_t)
assert output_t.shape == (2, 4, 2)
except ValueError as e:
assert 'Input power is not within the required interval of [0, 16777216].' in str(e)
logger.info("Finish testing ComplexNorm.")
if __name__ == "__main__":
test_complex_norm()
test_complex_norm_eager()
test_complex_norm_uncallable()