[feat][assistant][I3CECZ] add op griffinlim

This commit is contained in:
chenx2ovo 2022-03-21 18:49:33 +08:00
parent 2886b66281
commit e19dc02b47
27 changed files with 1151 additions and 5 deletions

View File

@ -37,6 +37,7 @@
#include "minddata/dataset/audio/ir/kernels/flanger_ir.h"
#include "minddata/dataset/audio/ir/kernels/frequency_masking_ir.h"
#include "minddata/dataset/audio/ir/kernels/gain_ir.h"
#include "minddata/dataset/audio/ir/kernels/griffin_lim_ir.h"
#include "minddata/dataset/audio/ir/kernels/highpass_biquad_ir.h"
#include "minddata/dataset/audio/ir/kernels/lfilter_ir.h"
#include "minddata/dataset/audio/ir/kernels/lowpass_biquad_ir.h"
@ -413,6 +414,41 @@ Gain::Gain(float gain_db) : data_(std::make_shared<Data>(gain_db)) {}
std::shared_ptr<TensorOperation> Gain::Parse() { return std::make_shared<GainOperation>(data_->gain_db_); }
// GriffinLim Transform Operation.
struct GriffinLim::Data {
Data(int32_t n_fft, int32_t n_iter, int32_t win_length, int32_t hop_length, WindowType window_type, float power,
float momentum, int32_t length, bool rand_init)
: n_fft_(n_fft),
n_iter_(n_iter),
win_length_(win_length),
hop_length_(hop_length),
window_type_(window_type),
power_(power),
momentum_(momentum),
length_(length),
rand_init_(rand_init) {}
int32_t n_fft_;
int32_t n_iter_;
int32_t win_length_;
int32_t hop_length_;
WindowType window_type_;
float power_;
float momentum_;
int32_t length_;
bool rand_init_;
};
GriffinLim::GriffinLim(int32_t n_fft, int32_t n_iter, int32_t win_length, int32_t hop_length, WindowType window_type,
float power, float momentum, int32_t length, bool rand_init)
: data_(std::make_shared<Data>(n_fft, n_iter, win_length, hop_length, window_type, power, momentum, length,
rand_init)) {}
std::shared_ptr<TensorOperation> GriffinLim::Parse() {
return std::make_shared<GriffinLimOperation>(data_->n_fft_, data_->n_iter_, data_->win_length_, data_->hop_length_,
data_->window_type_, data_->power_, data_->momentum_, data_->length_,
data_->rand_init_);
}
// HighpassBiquad Transform Operation.
struct HighpassBiquad::Data {
Data(int32_t sample_rate, float cutoff_freq, float Q) : sample_rate_(sample_rate), cutoff_freq_(cutoff_freq), Q_(Q) {}

View File

@ -41,6 +41,7 @@
#include "minddata/dataset/audio/ir/kernels/flanger_ir.h"
#include "minddata/dataset/audio/ir/kernels/frequency_masking_ir.h"
#include "minddata/dataset/audio/ir/kernels/gain_ir.h"
#include "minddata/dataset/audio/ir/kernels/griffin_lim_ir.h"
#include "minddata/dataset/audio/ir/kernels/highpass_biquad_ir.h"
#include "minddata/dataset/audio/ir/kernels/lfilter_ir.h"
#include "minddata/dataset/audio/ir/kernels/lowpass_biquad_ir.h"
@ -334,6 +335,19 @@ PYBIND_REGISTER(GainOperation, 1, ([](const py::module *m) {
}));
}));
PYBIND_REGISTER(
GriffinLimOperation, 1, ([](const py::module *m) {
(void)py::class_<audio::GriffinLimOperation, TensorOperation, std::shared_ptr<audio::GriffinLimOperation>>(
*m, "GriffinLimOperation")
.def(py::init([](int32_t n_fft, int32_t n_iter, int32_t win_length, int32_t hop_length, WindowType window_type,
float power, float momentum, int32_t length, bool rand_init) {
auto griffin_lim = std::make_shared<audio::GriffinLimOperation>(
n_fft, n_iter, win_length, hop_length, window_type, power, momentum, length, rand_init);
THROW_IF_ERROR(griffin_lim->ValidateParams());
return griffin_lim;
}));
}));
PYBIND_REGISTER(
HighpassBiquadOperation, 1, ([](const py::module *m) {
(void)py::class_<audio::HighpassBiquadOperation, TensorOperation, std::shared_ptr<audio::HighpassBiquadOperation>>(

View File

@ -23,6 +23,7 @@ add_library(audio-ir-kernels OBJECT
flanger_ir.cc
frequency_masking_ir.cc
gain_ir.cc
griffin_lim_ir.cc
highpass_biquad_ir.cc
lfilter_ir.cc
lowpass_biquad_ir.cc

View File

@ -0,0 +1,92 @@
/**
* Copyright 2022 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/griffin_lim_ir.h"
#include "minddata/dataset/audio/ir/validators.h"
#include "minddata/dataset/audio/kernels/griffin_lim_op.h"
namespace mindspore {
namespace dataset {
namespace audio {
// GriffinLim
GriffinLimOperation::GriffinLimOperation(int32_t n_fft, int32_t n_iter, int32_t win_length, int32_t hop_length,
WindowType window_type, float power, float momentum, int32_t length,
bool rand_init)
: n_fft_(n_fft),
n_iter_(n_iter),
win_length_(win_length),
hop_length_(hop_length),
window_type_(window_type),
power_(power),
momentum_(momentum),
length_(length),
rand_init_(rand_init) {}
GriffinLimOperation::~GriffinLimOperation() = default;
std::string GriffinLimOperation::Name() const { return kGriffinLimOperation; }
Status GriffinLimOperation::ValidateParams() {
RETURN_IF_NOT_OK(ValidateIntScalarPositive("GriffinLim", "n_fft", n_fft_));
RETURN_IF_NOT_OK(ValidateIntScalarPositive("GriffinLim", "n_iter", n_iter_));
RETURN_IF_NOT_OK(ValidateIntScalarNonNegative("GriffinLim", "win_length", win_length_));
RETURN_IF_NOT_OK(ValidateIntScalarNonNegative("GriffinLim", "hop_length", hop_length_));
RETURN_IF_NOT_OK(ValidateFloatScalarPositive("GriffinLim", "power", power_));
RETURN_IF_NOT_OK(ValidateFloatScalarNonNegative("GriffinLim", "momentum", momentum_));
RETURN_IF_NOT_OK(ValidateIntScalarNonNegative("GriffinLim", "length", length_));
if (length_ != 0 && n_fft_ >= length_) {
std::string err_msg = "GriffinLim: n_fft must be less than length.";
LOG_AND_RETURN_STATUS_SYNTAX_ERROR(err_msg);
}
CHECK_FAIL_RETURN_SYNTAX_ERROR(
momentum_ < 1,
"GriffinLim: momentum equal to or greater than 1 can be unstable, but got: " + std::to_string(momentum_));
CHECK_FAIL_RETURN_SYNTAX_ERROR(momentum_ >= 0,
"GriffinLim: momentum can not be less than 0, but got: " + std::to_string(momentum_));
CHECK_FAIL_RETURN_SYNTAX_ERROR(win_length_ <= n_fft_,
"GriffinLim: win_length must be less than or equal to n_fft, but got win_length: " +
std::to_string(win_length_) + ", n_fft: " + std::to_string(n_fft_));
return Status::OK();
}
std::shared_ptr<TensorOp> GriffinLimOperation::Build() {
int32_t win_length = (win_length_ == 0) ? n_fft_ : win_length_;
int32_t hop_length = (hop_length_ == 0) ? win_length / 2 : hop_length_;
float momentum = momentum_ / (1 + momentum_);
std::shared_ptr<GriffinLimOp> tensor_op = std::make_shared<GriffinLimOp>(
n_fft_, n_iter_, win_length, hop_length, window_type_, power_, momentum, length_, rand_init_);
return tensor_op;
}
Status GriffinLimOperation::to_json(nlohmann::json *out_json) {
nlohmann::json args;
args["n_fft"] = n_fft_;
args["n_iter"] = n_iter_;
args["win_length"] = win_length_;
args["hop_length"] = hop_length_;
args["window_type"] = window_type_;
args["power"] = power_;
args["momentum"] = momentum_;
args["length"] = length_;
args["rand_init"] = rand_init_;
*out_json = args;
return Status::OK();
}
} // namespace audio
} // namespace dataset
} // namespace mindspore

View File

@ -0,0 +1,61 @@
/**
* Copyright 2022 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_GRIFFIN_LIM_IR_H_
#define MINDSPORE_CCSRC_MINDDATA_DATASET_AUDIO_IR_KERNELS_GRIFFIN_LIM_IR_H_
#include <memory>
#include <string>
#include "include/api/status.h"
#include "minddata/dataset/include/dataset/constants.h"
#include "minddata/dataset/kernels/ir/tensor_operation.h"
namespace mindspore {
namespace dataset {
namespace audio {
constexpr char kGriffinLimOperation[] = "GriffinLim";
class GriffinLimOperation : public TensorOperation {
public:
GriffinLimOperation(int32_t n_fft, int32_t n_iter, int32_t win_length, int32_t hop_length, WindowType window_type,
float power, float momentum, int32_t length, bool rand_init);
~GriffinLimOperation();
std::shared_ptr<TensorOp> Build() override;
Status ValidateParams() override;
std::string Name() const override;
Status to_json(nlohmann::json *out_json) override;
private:
int32_t n_fft_;
int32_t n_iter_;
int32_t win_length_;
int32_t hop_length_;
WindowType window_type_;
float power_;
float momentum_;
int32_t length_;
bool rand_init_;
};
} // namespace audio
} // namespace dataset
} // namespace mindspore
#endif // MINDSPORE_CCSRC_MINDDATA_DATASET_AUDIO_IR_KERNELS_GRIFFIN_LIM_IR_H_

View File

@ -24,6 +24,7 @@ add_library(audio-kernels OBJECT
flanger_op.cc
frequency_masking_op.cc
gain_op.cc
griffin_lim_op.cc
highpass_biquad_op.cc
lfilter_op.cc
lowpass_biquad_op.cc

View File

@ -1769,5 +1769,286 @@ Status ComputeDeltas(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tenso
RETURN_IF_NOT_OK((*output)->Reshape(raw_shape));
return Status::OK();
}
/// \brief IRFFT.
Status IRFFT(const Eigen::MatrixXcd &stft_matrix, Eigen::MatrixXd *inverse) {
int32_t n = 2 * (stft_matrix.rows() - 1);
int32_t s = stft_matrix.rows() - 1;
Eigen::FFT<double> fft;
for (int k = 0; k < stft_matrix.cols(); ++k) {
Eigen::VectorXcd output_complex(n);
// pad input
Eigen::VectorXcd input(n);
input.head(s + 1) = stft_matrix.col(k);
auto reverse_pad = stft_matrix.col(k).segment(1, s - 1).colwise().reverse().conjugate();
input.segment(s + 1, s - 1) = reverse_pad;
fft.inv(output_complex, input);
Eigen::VectorXd output_real = output_complex.real().eval();
inverse->col(k) = Eigen::Map<Eigen::MatrixXd>(output_real.data(), n, 1);
}
return Status::OK();
}
/// \brief Overlap Add
Status OverlapAdd(Eigen::VectorXd *out_buf, const Eigen::MatrixXd &win_inverse_stft, int32_t hop_lengh) {
int32_t n_fft = win_inverse_stft.rows();
for (int frame = 0; frame < win_inverse_stft.cols(); frame++) {
int32_t sample = frame * hop_lengh;
out_buf->middleRows(sample, n_fft) += win_inverse_stft.col(frame);
}
return Status::OK();
}
/// \brief Window Sum Square
Status WindowSumSquare(const Eigen::MatrixXf &window_matrix, Eigen::VectorXf *win_sum_square, const int32_t n_frames,
int32_t n_fft, int32_t hop_length) {
Eigen::MatrixXf win_norm = window_matrix.array().pow(2);
// window sum square fill
int32_t n = n_fft + hop_length * (n_frames - 1);
// check n_fft
CHECK_FAIL_RETURN_UNEXPECTED(
n_fft == win_norm.rows(),
"GriffinLim: n_fft must be equal to the length of the window during window sum square calculation.");
for (int ind = 0; ind < n_frames; ind++) {
int sample = ind * hop_length;
int end_ss = std::min(n, sample + n_fft);
int end_win = std::max(0, std::min(n_fft, n - sample));
win_sum_square->segment(sample, end_ss - sample) += win_norm.col(0).head(end_win);
}
return Status::OK();
}
/// \brief ISTFT.
/// \param input: Complex matrix of eigen, shape of <freq, time>.
/// \param output: Tensor of shape <time>.
/// \param n_fft: Size of Fourier transform.
/// \param hop_length: The distance between neighboring sliding window frames.
/// \param win_length: The size of window frame and STFT filter.
/// \param window_type: The type of window function.
/// \param center: Whether input was padded on both sides so that the `t`-th frame is centered at time
/// `t * hop_length`.
/// \param normalized: Whether the STFT was normalized.
/// \param onesided: Whether the STFT was onesided.
/// \param length: The amount to trim the signal by (i.e. the original signal length).
/// \return Status code.
template <typename T>
Status ISTFT(const Eigen::MatrixXcd &stft_matrix, std::shared_ptr<Tensor> *output, int32_t n_fft, int32_t hop_length,
int32_t win_length, WindowType window_type, bool center, bool normalized, bool onesided, int32_t length) {
// check input
CHECK_FAIL_RETURN_UNEXPECTED(n_fft == ((stft_matrix.rows() - 1) * 2),
"GriffinLim: the frequency of the input should equal to n_fft / 2 + 1");
// window
std::shared_ptr<Tensor> ifft_window_tensor;
RETURN_IF_NOT_OK(Window(&ifft_window_tensor, window_type, win_length));
if (win_length == 1) {
RETURN_IF_NOT_OK(Tensor::CreateEmpty(TensorShape({1}), DataType(DataType::DE_FLOAT32), &ifft_window_tensor));
auto win = ifft_window_tensor->begin<float>();
*(win) = 1;
}
// pad window to match n_fft, and add a broadcasting axis
std::shared_ptr<Tensor> ifft_window_pad;
ifft_window_pad = ifft_window_tensor;
if (win_length < n_fft) {
RETURN_IF_NOT_OK(Tensor::CreateEmpty(TensorShape({n_fft}), DataType(DataType::DE_FLOAT32), &ifft_window_pad));
int pad_left = (n_fft - win_length) / 2;
int pad_right = n_fft - win_length - pad_left;
RETURN_IF_NOT_OK(Pad<float>(ifft_window_tensor, &ifft_window_pad, pad_left, pad_right, BorderType::kConstant));
}
int32_t n_frames = 0;
if ((length != 0) && (hop_length != 0)) {
int32_t padded_length = center ? (length + n_fft) : length;
n_frames = std::min(static_cast<int32_t>(stft_matrix.cols()),
static_cast<int32_t>(std::ceil(static_cast<float>(padded_length) / hop_length)));
} else {
n_frames = stft_matrix.cols();
}
int32_t expected_signal_len = n_fft + hop_length * (n_frames - 1);
Eigen::VectorXd y(expected_signal_len);
y.setZero();
// constrain STFT block sizes to 256 KB
int32_t max_mem_block = std::pow(2, 8) * std::pow(2, 10);
int32_t n_columns = max_mem_block / (stft_matrix.rows() * sizeof(T) * TWO);
n_columns = std::max(n_columns, 1);
// turn window to eigen matrix
auto data_ptr = &*ifft_window_pad->begin<float>();
Eigen::Map<Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic>> ifft_window_matrix(data_ptr,
ifft_window_pad->shape()[0], 1);
for (int bl_s = 0, frame = 0; bl_s < n_frames;) {
int bl_t = std::min(bl_s + n_columns, n_frames);
// calculate ifft
Eigen::MatrixXcd stft_temp = stft_matrix.middleCols(bl_s, bl_t - bl_s).eval();
Eigen::MatrixXd inverse(TWO * (stft_temp.rows() - 1), stft_temp.cols());
inverse.setZero();
RETURN_IF_NOT_OK(IRFFT(stft_temp, &inverse));
auto ytmp = ifft_window_matrix.template cast<double>().replicate(1, inverse.cols()).cwiseProduct(inverse);
RETURN_IF_NOT_OK(OverlapAdd(&y, ytmp, hop_length));
frame += bl_t - bl_s;
bl_s += n_columns;
}
// normalize by sum of squared window
int32_t n = n_fft + hop_length * (n_frames - 1);
Eigen::VectorXf ifft_win_sum(n);
ifft_win_sum.setZero();
RETURN_IF_NOT_OK(WindowSumSquare(ifft_window_matrix, &ifft_win_sum, n_frames, n_fft, hop_length));
for (int32_t ind = 0; ind < y.rows(); ind++) {
if (ifft_win_sum[ind] > std::numeric_limits<float>::min()) {
y[ind] /= ifft_win_sum[ind];
}
}
std::shared_ptr<Tensor> res_tensor;
if (length == 0 && center) {
int32_t y_start = n_fft / 2;
int32_t y_end = y.rows() - y_start;
auto tmp = y.middleRows(y_start, y_end - y_start);
std::vector<T> y_res(tmp.data(), tmp.data() + tmp.rows() * tmp.cols());
RETURN_IF_NOT_OK(Tensor::CreateFromVector(y_res, TensorShape({tmp.size()}), &res_tensor));
} else {
int32_t start = center ? n_fft / 2 : 0;
auto tmp = y.tail(y.rows() - start);
// fix length
std::vector<T> y_res(tmp.data(), tmp.data() + tmp.rows() * tmp.cols());
if (length > y_res.size()) {
while (y_res.size() != length) {
y_res.push_back(0);
}
} else if (length < tmp.rows()) {
while (y_res.size() != length) {
y_res.pop_back();
}
}
RETURN_IF_NOT_OK(Tensor::CreateFromVector(y_res, TensorShape({length}), &res_tensor));
}
*output = res_tensor;
return Status::OK();
}
template <typename T>
Status GriffinLimImpl(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output, int32_t n_fft,
int32_t n_iter, int32_t win_length, int32_t hop_length, WindowType window_type, float power,
float momentum, int32_t length, bool rand_init, std::mt19937 rnd) {
// pack
TensorShape shape = input->shape();
TensorShape new_shape({input->Size() / shape[-1] / shape[-2], shape[-2], shape[-1]});
RETURN_IF_NOT_OK(input->Reshape(new_shape));
// power
CHECK_FAIL_RETURN_UNEXPECTED(power != 0, "GriffinLim: power can not be zero.");
for (auto itr = input->begin<T>(); itr != input->end<T>(); itr++) {
*itr = pow(*itr, 1 / power);
}
// window
std::shared_ptr<Tensor> fft_window_tensor;
RETURN_IF_NOT_OK(Window(&fft_window_tensor, window_type, win_length));
if (win_length == 1) {
RETURN_IF_NOT_OK(Tensor::CreateEmpty(TensorShape({1}), DataType(DataType::DE_FLOAT32), &fft_window_tensor));
auto win = fft_window_tensor->begin<float>();
*(win) = 1;
}
std::shared_ptr<Tensor> final_results;
for (int dim = 0; dim < new_shape[0]; dim++) {
// init complex phase
Eigen::MatrixXcd angles(shape[(-1) * TWO], shape[-1]);
if (rand_init) {
// static std::default_random_engine e;
std::uniform_real_distribution<double> dist(0, 1);
angles = angles.unaryExpr(
[&dist, &rnd](std::complex<double> value) { return std::complex<double>(dist(rnd), dist(rnd)); });
} else {
angles = angles.unaryExpr([](std::complex<double> value) { return std::complex<double>(1, 0); });
}
// slice and squeeze the first dim
std::shared_ptr<Tensor> spec_tensor_slice;
RETURN_IF_NOT_OK(input->Slice(
&spec_tensor_slice,
std::vector<SliceOption>({SliceOption(std::vector<dsize_t>{dim}), SliceOption(true), SliceOption(true)})));
TensorShape new_slice_shape({shape[-2], shape[-1]});
RETURN_IF_NOT_OK(spec_tensor_slice->Reshape(new_slice_shape));
// turn tensor into eigen MatrixXd
auto data_ptr = &*spec_tensor_slice->begin<T>();
Eigen::Map<Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>> spec_matrix_transpose(data_ptr, shape[-1],
shape[(-1) * TWO]);
Eigen::MatrixXd spec_matrix = spec_matrix_transpose.transpose().template cast<double>();
auto stft_complex = angles.cwiseProduct(spec_matrix);
// init tprev zero mat
Eigen::MatrixXcd tprev(shape[(-1) * TWO], shape[-1]);
Eigen::MatrixXcd rebuilt(shape[(-1) * TWO], shape[-1]);
tprev.setZero();
rebuilt.setZero();
for (int iter = 0; iter < n_iter; iter++) {
// istft
std::shared_ptr<Tensor> inverse;
RETURN_IF_NOT_OK(
ISTFT<T>(stft_complex, &inverse, n_fft, hop_length, win_length, window_type, true, false, true, length));
// stft
std::shared_ptr<Tensor> stft_out;
RETURN_IF_NOT_OK(SpectrogramImpl<T>(inverse, &stft_out, 0, window_type, n_fft, hop_length, win_length, 0, false,
true, BorderType::kReflect, true));
rebuilt.transposeInPlace();
Tensor::TensorIterator<T> itr = stft_out->begin<T>();
rebuilt = rebuilt.unaryExpr([&itr](std::complex<double> value) {
T real = *(itr++);
T img = *(itr++);
return std::complex<double>(real, img);
});
rebuilt.transposeInPlace();
angles = rebuilt.array();
if (momentum != 0) {
tprev = tprev * ((momentum) / (1 + momentum));
angles = angles.array() - tprev.array();
}
float eps = 1e-16;
auto angles_abs = angles.cwiseAbs().eval();
angles_abs.array() += eps;
angles = angles.array() / angles_abs.array();
tprev = rebuilt.array();
}
// istft calculate final phase
auto stft_complex_fin = angles.cwiseProduct(spec_matrix);
std::shared_ptr<Tensor> waveform;
RETURN_IF_NOT_OK(
ISTFT<T>(stft_complex_fin, &waveform, n_fft, hop_length, win_length, window_type, true, false, true, length));
if (shape.Rank() == TWO) {
// do not expand dim
final_results = waveform;
continue;
}
if (final_results != nullptr) {
RETURN_IF_NOT_OK(final_results->InsertTensor({dim}, waveform));
} else {
RETURN_IF_NOT_OK(
Tensor::CreateEmpty(TensorShape({new_shape[0], waveform->shape()[0]}), waveform->type(), &final_results));
RETURN_IF_NOT_OK(final_results->InsertTensor({dim}, waveform));
}
}
*output = final_results;
return Status::OK();
}
Status GriffinLim(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output, int32_t n_fft, int32_t n_iter,
int32_t win_length, int32_t hop_length, WindowType window_type, float power, float momentum,
int32_t length, bool rand_init, std::mt19937 rnd) {
std::shared_ptr<Tensor> input_tensor;
if (input->type() != DataType::DE_FLOAT64) {
RETURN_IF_NOT_OK(TypeCast(input, &input_tensor, DataType(DataType::DE_FLOAT32)));
return GriffinLimImpl<float>(input_tensor, output, n_fft, n_iter, win_length, hop_length, window_type, power,
momentum, length, rand_init, rnd);
} else {
input_tensor = input;
return GriffinLimImpl<double>(input_tensor, output, n_fft, n_iter, win_length, hop_length, window_type, power,
momentum, length, rand_init, rnd);
}
}
} // namespace dataset
} // namespace mindspore

View File

@ -17,6 +17,7 @@
#define MINDSPORE_CCSRC_MINDDATA_DATASET_AUDIO_KERNELS_AUDIO_UTILS_H_
#include <Eigen/Dense>
#include <unsupported/Eigen/FFT>
#include <algorithm>
#include <cmath>
@ -1469,6 +1470,24 @@ Status Dither(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *out
return Status::OK();
}
/// \brief Apply GriffinLim to calculate waveform from linear scalar amplitude spectrogram.
/// \param input Tensor of shape <..., freq, time>.
/// \param output Tensor of shape <..., time>.
/// \param n_fft Size of FFT.
/// \param n_iter Number of iteration for phase recovery.
/// \param win_length Window size for GriffinLim.
/// \param hop_length Length of hop between STFT windows.
/// \param window_type Window type for GriffinLim.
/// \param power Exponent for the magnitude spectrogram.
/// \param momentum The momentum for fast GriffinLim.
/// \param length Length of the expected output waveform.
/// \param rand_init Flag for random phase initialization or all-zero phase initialization.
/// \param rnd Random generator.
/// \return Status code.
Status GriffinLim(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output, int32_t n_fft, int32_t n_iter,
int32_t win_length, int32_t hop_length, WindowType window_type, float power, float momentum,
int32_t length, bool rand_init, std::mt19937 rnd);
} // namespace dataset
} // namespace mindspore
#endif // MINDSPORE_CCSRC_MINDDATA_DATASET_AUDIO_KERNELS_AUDIO_UTILS_H_

View File

@ -0,0 +1,42 @@
/**
* Copyright 2022 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/griffin_lim_op.h"
#include "minddata/dataset/audio/kernels/audio_utils.h"
#include "minddata/dataset/kernels/data/data_utils.h"
#include "minddata/dataset/util/status.h"
namespace mindspore {
namespace dataset {
Status GriffinLimOp::Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) {
IO_CHECK(input, output);
return GriffinLim(input, output, n_fft_, n_iter_, win_length_, hop_length_, window_type_, power_, momentum_, length_,
rand_init_, rnd_);
}
Status GriffinLimOp::OutputType(const std::vector<DataType> &inputs, std::vector<DataType> &outputs) {
RETURN_IF_NOT_OK(TensorOp::OutputType(inputs, outputs));
RETURN_IF_NOT_OK(
ValidateTensorType("GriffinLim", inputs[0].IsNumeric(), "[int, float, double]", inputs[0].ToString()));
if (inputs[0] == DataType(DataType::DE_FLOAT64)) {
outputs[0] = DataType(DataType::DE_FLOAT64);
} else {
outputs[0] = DataType(DataType::DE_FLOAT32);
}
return Status::OK();
}
} // namespace dataset
} // namespace mindspore

View File

@ -0,0 +1,68 @@
/**
* Copyright 2022 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_GRIFFIN_LIM_OP_H_
#define MINDSPORE_CCSRC_MINDDATA_DATASET_AUDIO_KERNELS_GRIFFIN_LIM_OP_H_
#include <memory>
#include <string>
#include <vector>
#include "minddata/dataset/include/dataset/constants.h"
#include "minddata/dataset/kernels/tensor_op.h"
#include "minddata/dataset/util/random.h"
namespace mindspore {
namespace dataset {
class GriffinLimOp : public TensorOp {
public:
GriffinLimOp(int32_t n_fft, int32_t n_iter, int32_t win_length, int32_t hop_length, WindowType window_type,
float power, float momentum, int32_t length, bool rand_init)
: n_fft_(n_fft),
n_iter_(n_iter),
win_length_(win_length),
hop_length_(hop_length),
window_type_(window_type),
power_(power),
momentum_(momentum),
length_(length),
rand_init_(rand_init) {
rnd_.seed(GetSeed());
}
~GriffinLimOp() override = default;
Status Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) override;
std::string Name() const override { return kGriffinLimOp; }
Status OutputType(const std::vector<DataType> &inputs, std::vector<DataType> &outputs) override;
private:
int32_t n_fft_;
int32_t n_iter_;
int32_t win_length_;
int32_t hop_length_;
WindowType window_type_;
float power_;
float momentum_;
int32_t length_;
bool rand_init_;
std::mt19937 rnd_;
};
} // namespace dataset
} // namespace mindspore
#endif // MINDSPORE_CCSRC_MINDDATA_DATASET_AUDIO_KERNELS_GRIFFIN_LIM_OP_H_

View File

@ -528,6 +528,41 @@ class MS_API Gain final : public TensorTransform {
std::shared_ptr<Data> data_;
};
/// \brief Waveform calculation from linear scalar amplitude spectrogram using GriffinLim transform.
class MS_API GriffinLim final : public TensorTransform {
public:
/// \brief Constructor.
/// \notes Calculated by formula:
/// x(n)=\frac{\sum_{m=-\infty}^{\infty} w(m S-n) y_{w}(m S, n)}{\sum_{m=-\infty}^{\infty} w^{2}(m S-n)}
/// where w represents the window function, y represents the reconstructed signal of each frame and x represents
/// the whole signal.
/// \param[in] n_fft Size of FFT (Default: 400).
/// \param[in] n_iter Number of iteration for phase recovery (Default: 32).
/// \param[in] win_length Window size for GriffinLim (Default: 0, will be set to n_fft).
/// \param[in] hop_length Length of hop between STFT windows (Default: 0, will be set to win_length / 2).
/// \param[in] window_type Window type for GriffinLim (Default: WindowType::kHann).
/// \param[in] power Exponent for the magnitude spectrogram (Default: 2.0).
/// \param[in] momentum The momentum for fast Griffin-Lim (Default: 0.99).
/// \param[in] length Length of the expected output waveform (Default: 0.0, will be set to the value of last
/// dimension of the stft matrix).
/// \param[in] rand_init Flag for random phase initialization or all-zero phase initialization (Default: true).
explicit GriffinLim(int32_t n_fft = 400, int32_t n_iter = 32, int32_t win_length = 0, int32_t hop_length = 0,
WindowType window_type = WindowType::kHann, float power = 2.0, float momentum = 0.99,
int32_t length = 0, bool rand_init = true);
/// \brief Destructor.
~GriffinLim() = 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 HighpassBiquad TensorTransform. Apply highpass biquad filter on audio.
class MS_API HighpassBiquad final : public TensorTransform {
public:

View File

@ -168,6 +168,7 @@ constexpr char kFadeOp[] = "FadeOp";
constexpr char kFlangerOp[] = "FlangerOp";
constexpr char kFrequencyMaskingOp[] = "FrequencyMaskingOp";
constexpr char kGainOp[] = "GainOp";
constexpr char kGriffinLimOp[] = "GriffinLimOp";
constexpr char kHighpassBiquadOp[] = "HighpassBiquadOp";
constexpr char kLFilterOp[] = "LFilterOp";
constexpr char kLowpassBiquadOp[] = "LowpassBiquadOp";

View File

@ -28,11 +28,11 @@ from .utils import BorderType, DensityFunction, FadeShape, GainType, Interpolati
from .validators import check_allpass_biquad, check_amplitude_to_db, check_band_biquad, check_bandpass_biquad, \
check_bandreject_biquad, check_bass_biquad, check_biquad, check_complex_norm, check_compute_deltas, \
check_contrast, check_db_to_amplitude, check_dc_shift, check_deemph_biquad, check_detect_pitch_frequency, \
check_dither, check_equalizer_biquad, check_fade, check_flanger, check_gain, check_highpass_biquad, \
check_lfilter, check_lowpass_biquad, check_magphase, check_mask_along_axis, check_mask_along_axis_iid, \
check_masking, check_mel_scale, check_mu_law_coding, check_overdrive, check_phase_vocoder, check_phaser, \
check_riaa_biquad, check_sliding_window_cmn, check_spectral_centroid, check_spectrogram, check_time_stretch, \
check_treble_biquad, check_vol
check_dither, check_equalizer_biquad, check_fade, check_flanger, check_gain, check_griffin_lim, \
check_highpass_biquad, check_lfilter, check_lowpass_biquad, check_magphase, check_mask_along_axis, \
check_mask_along_axis_iid, check_masking, check_mel_scale, check_mu_law_coding, check_overdrive, \
check_phase_vocoder, check_phaser, check_riaa_biquad, check_sliding_window_cmn, check_spectral_centroid, \
check_spectrogram, check_time_stretch, check_treble_biquad, check_vol
class AudioTensorOperation(TensorOperation):
@ -929,6 +929,59 @@ class Gain(AudioTensorOperation):
return cde.GainOperation(self.gain_db)
class GriffinLim(AudioTensorOperation):
r"""
Approximate magnitude spectrogram inversion using the GriffinLim algorithm.
.. math::
x(n)=\frac{\sum_{m=-\infty}^{\infty} w(m S-n) y_{w}(m S, n)}{\sum_{m=-\infty}^{\infty} w^{2}(m S-n)}
where w represents the window function, y represents the reconstructed signal of each frame and x represents the
whole signal.
Args:
n_fft (int, optional): Size of FFT (default=400).
n_iter (int, optional): Number of iteration for phase recovery (default=32).
win_length (int, optional): Window size for GriffinLim (default=None, will be set to n_fft).
hop_length (int, optional): Length of hop between STFT windows (default=None, will be set to win_length // 2).
window_type (WindowType, optional): Window type for GriffinLim, which can be WindowType.BARTLETT,
WindowType.BLACKMAN, WindowType.HAMMING, WindowType.HANN or WindowType.KAISER (default=WindowType.HANN).
Currently kaiser window is not supported on macOS.
power (float, optional): Exponent for the magnitude spectrogram (default=2.0).
momentum (float, optional): The momentum for fast Griffin-Lim (default=0.99).
length (int, optional): Length of the expected output waveform (default=None, will be set to the value of last
dimension of the stft matrix).
rand_init (bool, optional): Flag for random phase initialization or all-zero phase initialization
(default=True).
Examples:
>>> import numpy as np
>>>
>>> waveform = np.random.random([201, 6])
>>> numpy_slices_dataset = ds.NumpySlicesDataset(data=waveform, column_names=["audio"])
>>> transforms = [audio.GriffinLim(n_fft=400)]
>>> numpy_slices_dataset = numpy_slices_dataset.map(operations=transforms, input_columns=["audio"])
"""
@check_griffin_lim
def __init__(self, n_fft=400, n_iter=32, win_length=None, hop_length=None, window_type=WindowType.HANN,
power=2, momentum=0.99, length=None, rand_init=True):
self.n_fft = n_fft
self.n_iter = n_iter
self.win_length = win_length if win_length else self.n_fft
self.hop_length = hop_length if hop_length else self.win_length // 2
self.window_type = window_type
self.power = power
self.momentum = momentum
self.length = length if length else 0
self.rand_init = rand_init
def parse(self):
return cde.GriffinLimOperation(self.n_fft, self.n_iter, self.win_length, self.hop_length,
DE_C_WINDOW_TYPE.get(self.window_type), self.power, self.momentum, self.length,
self.rand_init)
class HighpassBiquad(AudioTensorOperation):
"""
Design biquad highpass filter and perform filtering. Similar to SoX implementation.

View File

@ -621,6 +621,42 @@ def check_fade(method):
return new_method
def check_griffin_lim(method):
"""Wrapper method to check the parameters of GriffinLim."""
@wraps(method)
def new_method(self, *args, **kwargs):
[n_fft, n_iter, win_length, hop_length, window_type, power, momentum, length,
rand_init], _ = parse_user_args(method, *args, **kwargs)
type_check(n_fft, (int,), "n_fft")
check_pos_int32(n_fft, "n_fft")
type_check(n_iter, (int,), "n_iter")
check_pos_int32(n_iter, "n_iter")
if win_length is not None:
type_check(win_length, (int,), "win_length")
check_non_negative_int32(win_length, "win_length")
if win_length > n_fft:
raise ValueError(
"Input win_length should be no more than n_fft, but got win_length: {0} and n_fft: {1}.".format(
win_length, n_fft))
if hop_length is not None:
type_check(hop_length, (int,), "hop_length")
check_non_negative_int32(hop_length, "hop_length")
type_check(window_type, (WindowType,), "window_type")
type_check(power, (int, float), "power")
check_pos_float32(power, "power")
type_check(momentum, (int, float), "momentum")
check_non_negative_float32(momentum, "momentum")
if length is not None:
type_check(length, (int,), "length")
check_non_negative_int32(length, "length")
type_check(rand_init, (bool,), "rand_init")
return method(self, *args, **kwargs)
return new_method
def check_vol(method):
"""Wrapper method to check the parameters of Vol."""

View File

@ -1007,6 +1007,143 @@ TEST_F(MindDataTestPipeline, TestTrebleBiquadWrongArg) {
EXPECT_EQ(iter02, nullptr);
}
/// Feature: GriffinLim.
/// Description: test pipeline.
/// Expectation: success.
TEST_F(MindDataTestPipeline, TestGriffinLimPipeline) {
MS_LOG(INFO) << "Doing MindDataTestPipeline-TestGriffinLimPipeline.";
// Original waveform
std::shared_ptr<SchemaObj> schema = Schema();
ASSERT_OK(schema->add_column("waveform", mindspore::DataType::kNumberTypeFloat32, {201, 6}));
std::shared_ptr<Dataset> ds = RandomData(50, schema);
EXPECT_NE(ds, nullptr);
ds = ds->SetNumWorkers(4);
EXPECT_NE(ds, nullptr);
auto griffin_lim = audio::GriffinLim(400, 32, 0, 0, WindowType::kHann, 2.0, 0.99, 0, true);
ds = ds->Map({griffin_lim});
EXPECT_NE(ds, nullptr);
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 = {1000};
int i = 0;
while (row.size() != 0) {
auto col = row["waveform"];
ASSERT_EQ(col.Shape(), expected);
ASSERT_EQ(col.Shape().size(), 1);
ASSERT_EQ(col.DataType(), mindspore::DataType::kNumberTypeFloat32);
ASSERT_OK(iter->GetNextRow(&row));
i++;
}
EXPECT_EQ(i, 50);
iter->Stop();
// Original waveform
std::shared_ptr<SchemaObj> schema2 = Schema();
ASSERT_OK(schema2->add_column("waveform", mindspore::DataType::kNumberTypeFloat64, {2, 301, 6}));
std::shared_ptr<Dataset> ds2 = RandomData(50, schema2);
EXPECT_NE(ds2, nullptr);
ds2 = ds2->SetNumWorkers(4);
EXPECT_NE(ds2, nullptr);
auto griffin_lim2 = audio::GriffinLim(600, 10, 0, 300, WindowType::kHann, 1.0, 0.99, 0, false);
ds2 = ds2->Map({griffin_lim2});
EXPECT_NE(ds2, nullptr);
std::shared_ptr<Iterator> iter2 = ds2->CreateIterator();
EXPECT_NE(ds2, nullptr);
std::unordered_map<std::string, mindspore::MSTensor> row2;
ASSERT_OK(iter2->GetNextRow(&row2));
std::vector<int64_t> expected2 = {2, 1500};
i = 0;
while (row2.size() != 0) {
auto col = row2["waveform"];
ASSERT_EQ(col.Shape(), expected2);
ASSERT_EQ(col.Shape().size(), 2);
ASSERT_EQ(col.DataType(), mindspore::DataType::kNumberTypeFloat64);
ASSERT_OK(iter2->GetNextRow(&row2));
i++;
}
EXPECT_EQ(i, 50);
iter->Stop();
}
/// Feature: GriffinLim.
/// Description: test some invalid parameters.
/// Expectation: success.
TEST_F(MindDataTestPipeline, TestGriffinLimWrongArgs) {
MS_LOG(INFO) << "Doing MindDataTestPipeline-TestGriffinLimWrongArgs.";
// Original waveform
std::shared_ptr<SchemaObj> schema = Schema();
ASSERT_OK(schema->add_column("waveform", mindspore::DataType::kNumberTypeFloat32, {201, 6}));
std::shared_ptr<Dataset> ds = RandomData(50, schema);
EXPECT_NE(ds, nullptr);
ds = ds->SetNumWorkers(4);
EXPECT_NE(ds, nullptr);
// invalid n_fft
auto griffin_lim_op = audio::GriffinLim(-10);
ds = ds->Map({griffin_lim_op});
EXPECT_NE(ds, nullptr);
std::shared_ptr<Iterator> iter = ds->CreateIterator();
// Expect failure
EXPECT_EQ(iter, nullptr);
// invalid n_iter
griffin_lim_op = audio::GriffinLim(400, -10);
ds = ds->Map({griffin_lim_op});
EXPECT_NE(ds, nullptr);
iter = ds->CreateIterator();
// Expect failure
EXPECT_EQ(iter, nullptr);
// invalid win_length
griffin_lim_op = audio::GriffinLim(400, 10, -2);
ds = ds->Map({griffin_lim_op});
EXPECT_NE(ds, nullptr);
iter = ds->CreateIterator();
// Expect failure
EXPECT_EQ(iter, nullptr);
griffin_lim_op = audio::GriffinLim(400, 10, 500);
ds = ds->Map({griffin_lim_op});
EXPECT_NE(ds, nullptr);
iter = ds->CreateIterator();
// Expect failure
EXPECT_EQ(iter, nullptr);
// invalid hop_length
griffin_lim_op = audio::GriffinLim(400, 10, 0, -10);
ds = ds->Map({griffin_lim_op});
EXPECT_NE(ds, nullptr);
iter = ds->CreateIterator();
// Expect failure
EXPECT_EQ(iter, nullptr);
// invalid power
griffin_lim_op = audio::GriffinLim(400, 10, 0, 0, WindowType::kHann, -2);
ds = ds->Map({griffin_lim_op});
EXPECT_NE(ds, nullptr);
iter = ds->CreateIterator();
// Expect failure
EXPECT_EQ(iter, nullptr);
// invalid momentum
griffin_lim_op = audio::GriffinLim(400, 10, 0, 0, WindowType::kHann, 2, -10);
ds = ds->Map({griffin_lim_op});
EXPECT_NE(ds, nullptr);
iter = ds->CreateIterator();
// Expect failure
EXPECT_EQ(iter, nullptr);
// invalid length
griffin_lim_op = audio::GriffinLim(400, 10, 0, 0, WindowType::kHann, 2, 0.9, -3);
ds = ds->Map({griffin_lim_op});
EXPECT_NE(ds, nullptr);
iter = ds->CreateIterator();
// Expect failure
EXPECT_EQ(iter, nullptr);
}
TEST_F(MindDataTestPipeline, TestVolPipeline) {
MS_LOG(INFO) << "Doing MindDataTestPipeline-TestVolPipeline.";
// Original waveform

View File

@ -1435,6 +1435,30 @@ TEST_F(MindDataTestExecute, TestFadeWithBool) {
EXPECT_TRUE(s01.IsOk());
}
/// Feature: GriffinLim
/// Description: test basic usage of GriffinLim
/// Expectation: success
TEST_F(MindDataTestExecute, TestGriffinLimDefaultValue) {
MS_LOG(INFO) << "Doing MindDataTestExecute-TestGriffinLimDefaultValue.";
// Random waveform
std::mt19937 gen;
std::normal_distribution<float> distribution(1.0, 0.5);
std::vector<float> vec;
for (int i = 0; i < 1206; ++i) {
vec.push_back(distribution(gen));
}
std::shared_ptr<Tensor> input;
ASSERT_OK(Tensor::CreateFromVector(vec, TensorShape({1, 201, 6}), &input));
auto input_ms = mindspore::MSTensor(std::make_shared<mindspore::dataset::DETensor>(input));
std::shared_ptr<TensorTransform> griffin_lim_op = std::make_shared<audio::GriffinLim>();
// apply griffinlim
mindspore::dataset::Execute trans({griffin_lim_op});
Status status = trans(input_ms, &input_ms);
EXPECT_TRUE(status.IsOk());
}
TEST_F(MindDataTestExecute, TestVolDefalutValue) {
MS_LOG(INFO) << "Doing MindDataTestExecute-TestVolDefalutValue.";
std::shared_ptr<Tensor> input_tensor_;

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,245 @@
# Copyright 2022 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 GriffinLim op in DE
"""
import numpy as np
import pytest
import mindspore.dataset as ds
import mindspore.dataset.audio.transforms as c_audio
from mindspore import log as logger
DATA_DIR = "../data/dataset/audiorecord/"
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 allclose_nparray(data_expected, data_me, rtol, atol, equal_nan=True):
if np.any(np.isnan(data_expected)):
assert np.allclose(data_me, data_expected, rtol, atol, equal_nan=equal_nan)
elif not np.allclose(data_me, data_expected, rtol, atol, equal_nan=equal_nan):
count_unequal_element(data_expected, data_me, rtol, atol)
def test_griffin_lim_pipeline():
"""
Feature: GriffinLim
Description: test GriffinLim cpp op in pipeline
Expectation: equal results from Mindspore and benchmark
"""
# <101, 6>
in_data = np.load(DATA_DIR + "griffinlim_101x6.npy")[np.newaxis, :]
out_expect = np.load(DATA_DIR + "griffinlim_101x6_out.npy")
dataset = ds.NumpySlicesDataset(in_data, column_names=["multi_dimensional_data"], shuffle=False)
transforms = [c_audio.GriffinLim(n_fft=200, rand_init=False)]
dataset = dataset.map(operations=transforms, input_columns=["multi_dimensional_data"])
for item in dataset.create_dict_iterator(num_epochs=1, output_numpy=True):
out_put = item["multi_dimensional_data"]
allclose_nparray(out_put, out_expect, 0.001, 0.001)
# <151, 8>
in_data = np.load(DATA_DIR + "griffinlim_151x8.npy")[np.newaxis, :]
out_expect = np.load(DATA_DIR + "griffinlim_151x8_out.npy")
dataset = ds.NumpySlicesDataset(in_data, column_names=["multi_dimensional_data"], shuffle=False)
transforms = [c_audio.GriffinLim(n_fft=300, n_iter=20, win_length=240, hop_length=120, rand_init=False, power=1.2)]
dataset = dataset.map(operations=transforms, input_columns=["multi_dimensional_data"])
for item in dataset.create_dict_iterator(num_epochs=1, output_numpy=True):
out_put = item["multi_dimensional_data"]
allclose_nparray(out_put, out_expect, 0.001, 0.001)
# <2, 301, 4> hop_length greater than half of win_length
in_data = np.load(DATA_DIR + "griffinlim_2x301x4.npy")[np.newaxis, :]
out_expect = np.load(DATA_DIR + "griffinlim_2x301x4_out.npy")
dataset = ds.NumpySlicesDataset(in_data, column_names=["multi_dimensional_data"], shuffle=False)
transforms = [c_audio.GriffinLim(n_fft=600, n_iter=10, win_length=240, hop_length=130, rand_init=False)]
dataset = dataset.map(operations=transforms, input_columns=["multi_dimensional_data"])
for item in dataset.create_dict_iterator(num_epochs=1, output_numpy=True):
out_put = item["multi_dimensional_data"]
allclose_nparray(out_put, out_expect, 0.001, 0.001)
def test_griffin_lim_pipeline_invalid_param_range():
"""
Feature: GriffinLim
Description: test GriffinLim with invalid input parameters
Expectation: throw ValueError
"""
logger.info("test GriffinLim op with default values")
in_data = np.load(DATA_DIR + "griffinlim_151x8.npy")[np.newaxis, :]
data1 = ds.NumpySlicesDataset(in_data, column_names=["multi_dimensional_data"], shuffle=False)
with pytest.raises(ValueError, match=r"Input n_fft is not within the required interval of \[1, 2147483647\]."):
transforms = [c_audio.GriffinLim(n_fft=-10)]
data1 = data1.map(operations=transforms, input_columns=["multi_dimensional_data"])
for item in data1.create_dict_iterator(num_epochs=1, output_numpy=True):
_ = item["multi_dimensional_data"]
with pytest.raises(ValueError, match=r"Input n_iter is not within the required interval of \[1, 2147483647\]."):
transforms = [c_audio.GriffinLim(n_fft=300, n_iter=-10)]
data1 = data1.map(operations=transforms, input_columns=["multi_dimensional_data"])
for item in data1.create_dict_iterator(num_epochs=1, output_numpy=True):
_ = item["multi_dimensional_data"]
with pytest.raises(ValueError, match=r"Input win_length is not within the required interval of \[0, 2147483647\]."):
transforms = [c_audio.GriffinLim(n_fft=300, n_iter=10, win_length=-10)]
data1 = data1.map(operations=transforms, input_columns=["multi_dimensional_data"])
for item in data1.create_dict_iterator(num_epochs=1, output_numpy=True):
_ = item["multi_dimensional_data"]
with pytest.raises(ValueError,
match=r"Input win_length should be no more than n_fft, but got win_length: 400 " +
r"and n_fft: 300."):
transforms = [c_audio.GriffinLim(n_fft=300, n_iter=10, win_length=400)]
data1 = data1.map(operations=transforms, input_columns=["multi_dimensional_data"])
for item in data1.create_dict_iterator(num_epochs=1, output_numpy=True):
_ = item["multi_dimensional_data"]
with pytest.raises(ValueError, match=r"Input hop_length is not within the required interval of \[0, 2147483647\]."):
transforms = [c_audio.GriffinLim(n_fft=300, n_iter=10, win_length=0, hop_length=-10)]
data1 = data1.map(operations=transforms, input_columns=["multi_dimensional_data"])
for item in data1.create_dict_iterator(num_epochs=1, output_numpy=True):
_ = item["multi_dimensional_data"]
with pytest.raises(ValueError, match=r"Input power is not within the required interval of \(0, 16777216\]."):
transforms = [c_audio.GriffinLim(n_fft=300, n_iter=10, win_length=0, hop_length=0, power=-3)]
data1 = data1.map(operations=transforms, input_columns=["multi_dimensional_data"])
for item in data1.create_dict_iterator(num_epochs=1, output_numpy=True):
_ = item["multi_dimensional_data"]
with pytest.raises(ValueError, match=r"Input momentum is not within the required interval of \[0, 16777216\]."):
transforms = [c_audio.GriffinLim(n_fft=300, n_iter=10, win_length=0, hop_length=0, power=2, momentum=-10)]
data1 = data1.map(operations=transforms, input_columns=["multi_dimensional_data"])
for item in data1.create_dict_iterator(num_epochs=1, output_numpy=True):
_ = item["multi_dimensional_data"]
with pytest.raises(ValueError, match=r"Input length is not within the required interval of \[0, 2147483647\]."):
transforms = [
c_audio.GriffinLim(n_fft=300, n_iter=10, win_length=0, hop_length=0, power=2, momentum=0.9, length=-2)
]
data1 = data1.map(operations=transforms, input_columns=["multi_dimensional_data"])
for item in data1.create_dict_iterator(num_epochs=1, output_numpy=True):
_ = item["multi_dimensional_data"]
def test_griffin_lim_pipeline_invalid_param_constraint():
"""
Feature: GriffinLim
Description: test GriffinLim with invalid input parameters
Expectation: throw RuntimeError
"""
logger.info("test GriffinLim op with default values")
in_data = np.load(DATA_DIR + "griffinlim_151x8.npy")[np.newaxis, :]
data1 = ds.NumpySlicesDataset(in_data, column_names=["multi_dimensional_data"], shuffle=False)
with pytest.raises(RuntimeError,
match=r"Unexpected error. map operation: \[GriffinLim\] failed. " +
r"GriffinLim: the frequency of the input should equal to n_fft / 2 \+ 1"):
transforms = [c_audio.GriffinLim(n_fft=100)]
data1 = data1.map(operations=transforms, input_columns=["multi_dimensional_data"])
for item in data1.create_dict_iterator(num_epochs=1, output_numpy=True):
_ = item["multi_dimensional_data"]
with pytest.raises(RuntimeError,
match=r"Unexpected error. map operation: \[GriffinLim\] failed. " +
r"GriffinLim: the frequency of the input should equal to n_fft / 2 \+ 1"):
transforms = [c_audio.GriffinLim(n_fft=300, n_iter=10, win_length=0, hop_length=120)]
data1 = data1.map(operations=transforms, input_columns=["multi_dimensional_data"])
for item in data1.create_dict_iterator(num_epochs=1, output_numpy=True):
_ = item["multi_dimensional_data"]
with pytest.raises(RuntimeError,
match=r"Syntax error. GriffinLim: momentum equal to or greater than 1 can be unstable, " +
"but got: 1.000000"):
transforms = [c_audio.GriffinLim(n_fft=300, n_iter=10, win_length=0, hop_length=0, power=2, momentum=1)]
data1 = data1.map(operations=transforms, input_columns=["multi_dimensional_data"])
for item in data1.create_dict_iterator(num_epochs=1, output_numpy=True):
_ = item["multi_dimensional_data"]
def test_griffin_lim_pipeline_invalid_param_type():
"""
Feature: GriffinLim
Description: test GriffinLim with invalid input parameters
Expectation: throw TypeError
"""
logger.info("test GriffinLim op with default values")
in_data = np.load(DATA_DIR + "griffinlim_151x8.npy")[np.newaxis, :]
data1 = ds.NumpySlicesDataset(in_data, column_names=["multi_dimensional_data"], shuffle=False)
with pytest.raises(TypeError,
match=r"Argument window_type with value type is not of type " +
r"\[<enum \'WindowType\'>\], but got <class \'str\'>."):
transforms = [c_audio.GriffinLim(n_fft=300, n_iter=10, win_length=0, hop_length=0, window_type="type")]
data1 = data1.map(operations=transforms, input_columns=["multi_dimensional_data"])
for item in data1.create_dict_iterator(num_epochs=1, output_numpy=True):
_ = item["multi_dimensional_data"]
with pytest.raises(TypeError,
match=r"Argument rand_init with value true is not of type \[<class \'bool\'>\], " +
r"but got <class \'str\'>."):
transforms = [
c_audio.GriffinLim(n_fft=300,
n_iter=10,
win_length=0,
hop_length=0,
power=2,
momentum=0.9,
length=0,
rand_init='true')
]
data1 = data1.map(operations=transforms, input_columns=["multi_dimensional_data"])
for item in data1.create_dict_iterator(num_epochs=1, output_numpy=True):
_ = item["multi_dimensional_data"]
def test_griffin_lim_eager():
"""
Feature: GriffinLim
Description: test GriffinLim cpp op with eager mode
Expectation: equal results from Mindspore and benchmark
"""
# <freq, time>
spectrogram = np.load(DATA_DIR + "griffinlim_101x6.npy").astype(np.float64)
out_expect = np.load(DATA_DIR + "griffinlim_101x6_out.npy").astype(np.float64)
out_ms = c_audio.GriffinLim(n_fft=200, rand_init=False)(spectrogram)
allclose_nparray(out_ms, out_expect, 0.001, 0.001)
# <1, freq, time>
spectrogram = np.load(DATA_DIR + "griffinlim_1x201x6.npy").astype(np.float64)
out_expect = np.load(DATA_DIR + "griffinlim_1x201x6_out.npy").astype(np.float64)
out_ms = c_audio.GriffinLim(rand_init=False)(spectrogram)
allclose_nparray(out_ms, out_expect, 0.001, 0.001)
# <2, freq, time>
spectrogram = np.load(DATA_DIR + "griffinlim_2x301x6.npy").astype(np.float64)
out_expect = np.load(DATA_DIR + "griffinlim_2x301x6_out.npy").astype(np.float64)
out_ms = c_audio.GriffinLim(n_fft=600, rand_init=False)(spectrogram)
allclose_nparray(out_ms, out_expect, 0.001, 0.001)
if __name__ == "__main__":
test_griffin_lim_pipeline()
test_griffin_lim_pipeline_invalid_param_range()
test_griffin_lim_pipeline_invalid_param_constraint()
test_griffin_lim_pipeline_invalid_param_type()
test_griffin_lim_eager()