From 8d339ccfeae7e214d1a3eed12a5f2ca4a7d5d21c Mon Sep 17 00:00:00 2001 From: ZJM <782473006@qq.com> Date: Fri, 21 Jan 2022 17:34:42 +0800 Subject: [PATCH] [assistant][ops][22736] Add new dataset operator LibriTTSDataset --- .../ccsrc/minddata/dataset/api/datasets.cc | 23 ++ .../engine/ir/datasetops/source/bindings.cc | 13 + .../engine/datasetops/source/CMakeLists.txt | 1 + .../engine/datasetops/source/libri_tts_op.cc | 234 +++++++++++++ .../engine/datasetops/source/libri_tts_op.h | 120 +++++++ .../engine/ir/datasetops/dataset_node.h | 1 + .../ir/datasetops/source/CMakeLists.txt | 1 + .../ir/datasetops/source/libri_tts_node.cc | 121 +++++++ .../ir/datasetops/source/libri_tts_node.h | 95 ++++++ .../dataset/include/dataset/datasets.h | 97 ++++++ .../dataset/include/dataset/samplers.h | 1 + .../mindspore/dataset/engine/__init__.py | 1 + .../dataset/engine/datasets_audio.py | 154 ++++++++- .../mindspore/dataset/engine/validators.py | 29 ++ tests/ut/cpp/dataset/CMakeLists.txt | 1 + .../dataset/c_api_dataset_libri_tts_test.cc | 311 ++++++++++++++++++ .../2506/11267/2506_11267.trans.tsv | 3 + .../2506/11267/2506_11267_000001_000000.wav | Bin 0 -> 4844 bytes .../2506/11267/2506_11267_000002_000000.wav | Bin 0 -> 4844 bytes .../2506/11267/2506_11267_000003_000001.wav | Bin 0 -> 4844 bytes .../python/dataset/test_datasets_libri_tts.py | 235 +++++++++++++ 21 files changed, 1439 insertions(+), 2 deletions(-) create mode 100644 mindspore/ccsrc/minddata/dataset/engine/datasetops/source/libri_tts_op.cc create mode 100644 mindspore/ccsrc/minddata/dataset/engine/datasetops/source/libri_tts_op.h create mode 100644 mindspore/ccsrc/minddata/dataset/engine/ir/datasetops/source/libri_tts_node.cc create mode 100644 mindspore/ccsrc/minddata/dataset/engine/ir/datasetops/source/libri_tts_node.h create mode 100644 tests/ut/cpp/dataset/c_api_dataset_libri_tts_test.cc create mode 100644 tests/ut/data/dataset/testLibriTTSData/train-clean-100/2506/11267/2506_11267.trans.tsv create mode 100644 tests/ut/data/dataset/testLibriTTSData/train-clean-100/2506/11267/2506_11267_000001_000000.wav create mode 100644 tests/ut/data/dataset/testLibriTTSData/train-clean-100/2506/11267/2506_11267_000002_000000.wav create mode 100644 tests/ut/data/dataset/testLibriTTSData/train-clean-100/2506/11267/2506_11267_000003_000001.wav create mode 100644 tests/ut/python/dataset/test_datasets_libri_tts.py diff --git a/mindspore/ccsrc/minddata/dataset/api/datasets.cc b/mindspore/ccsrc/minddata/dataset/api/datasets.cc index d1462235bd..4e09714a69 100644 --- a/mindspore/ccsrc/minddata/dataset/api/datasets.cc +++ b/mindspore/ccsrc/minddata/dataset/api/datasets.cc @@ -99,6 +99,7 @@ #include "minddata/dataset/engine/ir/datasetops/source/iwslt2016_node.h" #include "minddata/dataset/engine/ir/datasetops/source/iwslt2017_node.h" #include "minddata/dataset/engine/ir/datasetops/source/kmnist_node.h" +#include "minddata/dataset/engine/ir/datasetops/source/libri_tts_node.h" #include "minddata/dataset/engine/ir/datasetops/source/lj_speech_node.h" #include "minddata/dataset/engine/ir/datasetops/source/manifest_node.h" #include "minddata/dataset/engine/ir/datasetops/source/minddata_node.h" @@ -1393,6 +1394,28 @@ KMnistDataset::KMnistDataset(const std::vector &dataset_dir, const std::ve ir_node_ = std::static_pointer_cast(ds); } +LibriTTSDataset::LibriTTSDataset(const std::vector &dataset_dir, const std::vector &usage, + const std::shared_ptr &sampler, const std::shared_ptr &cache) { + auto sampler_obj = sampler ? sampler->Parse() : nullptr; + auto ds = std::make_shared(CharToString(dataset_dir), CharToString(usage), sampler_obj, cache); + ir_node_ = std::static_pointer_cast(ds); +} + +LibriTTSDataset::LibriTTSDataset(const std::vector &dataset_dir, const std::vector &usage, + const Sampler *sampler, const std::shared_ptr &cache) { + auto sampler_obj = sampler ? sampler->Parse() : nullptr; + auto ds = std::make_shared(CharToString(dataset_dir), CharToString(usage), sampler_obj, cache); + ir_node_ = std::static_pointer_cast(ds); +} + +LibriTTSDataset::LibriTTSDataset(const std::vector &dataset_dir, const std::vector &usage, + const std::reference_wrapper &sampler, + const std::shared_ptr &cache) { + auto sampler_obj = sampler.get().Parse(); + auto ds = std::make_shared(CharToString(dataset_dir), CharToString(usage), sampler_obj, cache); + ir_node_ = std::static_pointer_cast(ds); +} + LJSpeechDataset::LJSpeechDataset(const std::vector &dataset_dir, const std::shared_ptr &sampler, const std::shared_ptr &cache) { auto sampler_obj = sampler ? sampler->Parse() : nullptr; diff --git a/mindspore/ccsrc/minddata/dataset/api/python/bindings/dataset/engine/ir/datasetops/source/bindings.cc b/mindspore/ccsrc/minddata/dataset/api/python/bindings/dataset/engine/ir/datasetops/source/bindings.cc index b1f7238046..6de8dd7875 100644 --- a/mindspore/ccsrc/minddata/dataset/api/python/bindings/dataset/engine/ir/datasetops/source/bindings.cc +++ b/mindspore/ccsrc/minddata/dataset/api/python/bindings/dataset/engine/ir/datasetops/source/bindings.cc @@ -50,6 +50,7 @@ #include "minddata/dataset/engine/ir/datasetops/source/iwslt2016_node.h" #include "minddata/dataset/engine/ir/datasetops/source/iwslt2017_node.h" #include "minddata/dataset/engine/ir/datasetops/source/kmnist_node.h" +#include "minddata/dataset/engine/ir/datasetops/source/libri_tts_node.h" #include "minddata/dataset/engine/ir/datasetops/source/mnist_node.h" #include "minddata/dataset/engine/ir/datasetops/source/penn_treebank_node.h" #include "minddata/dataset/engine/ir/datasetops/source/random_node.h" @@ -415,6 +416,18 @@ PYBIND_REGISTER(KMnistNode, 2, ([](const py::module *m) { })); })); +PYBIND_REGISTER(LibriTTSNode, 2, ([](const py::module *m) { + (void)py::class_>(*m, "LibriTTSNode", + "to create a LibriTTSNode") + .def( + py::init([](const std::string &dataset_dir, const std::string &usage, const py::handle &sampler) { + std::shared_ptr libri_tts = + std::make_shared(dataset_dir, usage, toSamplerObj(sampler), nullptr); + THROW_IF_ERROR(libri_tts->ValidateParams()); + return libri_tts; + })); + })); + PYBIND_REGISTER(LJSpeechNode, 2, ([](const py::module *m) { (void)py::class_>(*m, "LJSpeechNode", "to create a LJSpeechNode") diff --git a/mindspore/ccsrc/minddata/dataset/engine/datasetops/source/CMakeLists.txt b/mindspore/ccsrc/minddata/dataset/engine/datasetops/source/CMakeLists.txt index dedcd6604f..d7f2839720 100644 --- a/mindspore/ccsrc/minddata/dataset/engine/datasetops/source/CMakeLists.txt +++ b/mindspore/ccsrc/minddata/dataset/engine/datasetops/source/CMakeLists.txt @@ -28,6 +28,7 @@ set(DATASET_ENGINE_DATASETOPS_SOURCE_SRC_FILES iwslt_op.cc io_block.cc kmnist_op.cc + libri_tts_op.cc lj_speech_op.cc mappable_leaf_op.cc mnist_op.cc diff --git a/mindspore/ccsrc/minddata/dataset/engine/datasetops/source/libri_tts_op.cc b/mindspore/ccsrc/minddata/dataset/engine/datasetops/source/libri_tts_op.cc new file mode 100644 index 0000000000..cd6c5f6cce --- /dev/null +++ b/mindspore/ccsrc/minddata/dataset/engine/datasetops/source/libri_tts_op.cc @@ -0,0 +1,234 @@ +/** + * 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/engine/datasetops/source/libri_tts_op.h" + +#include +#include +#include + +#include "minddata/dataset/audio/kernels/audio_utils.h" +#include "minddata/dataset/core/config_manager.h" +#include "minddata/dataset/core/tensor_shape.h" +#include "minddata/dataset/engine/datasetops/source/sampler/sequential_sampler.h" +#include "minddata/dataset/engine/execution_tree.h" +#include "utils/file_utils.h" + +namespace mindspore { +namespace dataset { +const int32_t label_file_suffix_len = 10; +const char label_file_suffix[] = ".trans.tsv"; +const char audio_file_suffix[] = ".wav"; +const std::vector usage_list = {"dev-clean", "dev-other", "test-clean", "test-other", + "train-clean-100", "train-clean-360", "train-other-500"}; + +LibriTTSOp::LibriTTSOp(const std::string &dataset_dir, const std::string &usage, int32_t num_workers, + int32_t queue_size, std::unique_ptr data_schema, std::shared_ptr sampler) + : MappableLeafOp(num_workers, queue_size, std::move(sampler)), + dataset_dir_(dataset_dir), + usage_(usage), + data_schema_(std::move(data_schema)) {} + +Status LibriTTSOp::LoadTensorRow(row_id_type row_id, TensorRow *trow) { + RETURN_UNEXPECTED_IF_NULL(trow); + LibriTTSLabelTuple audio_tuple = audio_label_tuples_[row_id]; + const uint32_t rate = 24000; + std::shared_ptr waveform, sample_rate, original_text, normalized_text, speaker_id, chapter_id, utterance_id; + Path dir(real_path_); + std::string file_name = audio_tuple.utterance_id + audio_file_suffix; + Path full_dir = dir / audio_tuple.usage / std::to_string(audio_tuple.speaker_id) / + std::to_string(audio_tuple.chapter_id) / file_name; + RETURN_IF_NOT_OK(ReadAudio(full_dir.ToString(), &waveform)); + RETURN_IF_NOT_OK(Tensor::CreateScalar(rate, &sample_rate)); + RETURN_IF_NOT_OK(Tensor::CreateScalar(audio_tuple.original_text, &original_text)); + RETURN_IF_NOT_OK(Tensor::CreateScalar(audio_tuple.normalized_text, &normalized_text)); + RETURN_IF_NOT_OK(Tensor::CreateScalar(audio_tuple.speaker_id, &speaker_id)); + RETURN_IF_NOT_OK(Tensor::CreateScalar(audio_tuple.chapter_id, &chapter_id)); + RETURN_IF_NOT_OK(Tensor::CreateScalar(audio_tuple.utterance_id, &utterance_id)); + (*trow) = TensorRow( + row_id, {std::move(waveform), std::move(sample_rate), std::move(original_text), std::move(normalized_text), + std::move(speaker_id), std::move(chapter_id), std::move(utterance_id)}); + std::string label_path = audio_tuple.label_path; + trow->setPath({full_dir.ToString(), full_dir.ToString(), label_path, label_path, label_path, label_path, label_path}); + return Status::OK(); +} + +void LibriTTSOp::Print(std::ostream &out, bool show_all) const { + if (!show_all) { + ParallelOp::Print(out, show_all); + out << "\n"; + } else { + ParallelOp::Print(out, show_all); + out << "\nNumber of rows: " << num_rows_ << "\nLibriTTS directory: " << dataset_dir_ << "\n\n"; + } +} + +Status LibriTTSOp::CountTotalRows(const std::string &dir, const std::string &usage, int64_t *count) { + RETURN_UNEXPECTED_IF_NULL(count); + *count = 0; + const int64_t num_samples = 0; + const int64_t start_index = 0; + auto sampler = std::make_shared(start_index, num_samples); + auto schema = std::make_unique(); + + RETURN_IF_NOT_OK(schema->AddColumn(ColDescriptor("waveform", DataType(DataType::DE_FLOAT32), TensorImpl::kCv, 1))); + TensorShape scalar_rate = TensorShape::CreateScalar(); + RETURN_IF_NOT_OK(schema->AddColumn( + ColDescriptor("sample_rate", DataType(DataType::DE_UINT32), TensorImpl::kFlexible, 0, &scalar_rate))); + TensorShape scalar_original_text = TensorShape::CreateScalar(); + RETURN_IF_NOT_OK(schema->AddColumn( + ColDescriptor("original_text", DataType(DataType::DE_STRING), TensorImpl::kFlexible, 0, &scalar_original_text))); + TensorShape scalar_normalized_text = TensorShape::CreateScalar(); + RETURN_IF_NOT_OK(schema->AddColumn(ColDescriptor("normalized_text", DataType(DataType::DE_STRING), + TensorImpl::kFlexible, 0, &scalar_normalized_text))); + TensorShape scalar_speaker_id = TensorShape::CreateScalar(); + RETURN_IF_NOT_OK(schema->AddColumn( + ColDescriptor("speaker_id", DataType(DataType::DE_UINT32), TensorImpl::kFlexible, 0, &scalar_speaker_id))); + TensorShape scalar_chapter_id = TensorShape::CreateScalar(); + RETURN_IF_NOT_OK(schema->AddColumn( + ColDescriptor("chapter_id", DataType(DataType::DE_UINT32), TensorImpl::kFlexible, 0, &scalar_chapter_id))); + TensorShape scalar_utterance_id = TensorShape::CreateScalar(); + RETURN_IF_NOT_OK(schema->AddColumn( + ColDescriptor("utterance_id", DataType(DataType::DE_STRING), TensorImpl::kFlexible, 0, &scalar_utterance_id))); + std::shared_ptr cfg = GlobalContext::config_manager(); + int32_t num_workers = cfg->num_parallel_workers(); + int32_t op_connect_size = cfg->op_connector_size(); + auto op = + std::make_shared(dir, usage, num_workers, op_connect_size, std::move(schema), std::move(sampler)); + RETURN_IF_NOT_OK(op->PrepareData()); + *count = op->audio_label_tuples_.size(); + return Status::OK(); +} + +Status LibriTTSOp::ComputeColMap() { + if (column_name_id_map_.empty()) { + for (int32_t i = 0; i < data_schema_->NumColumns(); ++i) { + column_name_id_map_[data_schema_->Column(i).Name()] = i; + } + } else { + MS_LOG(WARNING) << "Column name map is already set!"; + } + return Status::OK(); +} + +Status LibriTTSOp::ReadAudio(const std::string &audio_dir, std::shared_ptr *waveform) { + RETURN_UNEXPECTED_IF_NULL(waveform); + const int32_t kWavFileSampleRate = 24000; + int32_t sample_rate = 0; + std::vector waveform_vec; + RETURN_IF_NOT_OK(ReadWaveFile(audio_dir, &waveform_vec, &sample_rate)); + CHECK_FAIL_RETURN_UNEXPECTED( + sample_rate == kWavFileSampleRate, + "Invalid file, sampling rate of LibriTTS wav file must be 24000, file path: " + audio_dir); + RETURN_IF_NOT_OK(Tensor::CreateFromVector(waveform_vec, waveform)); + RETURN_IF_NOT_OK((*waveform)->ExpandDim(0)); + return Status::OK(); +} + +Status LibriTTSOp::PrepareData() { + auto realpath = FileUtils::GetRealPath(dataset_dir_.data()); + if (!realpath.has_value()) { + MS_LOG(ERROR) << "Invalid file path, LibriTTS dataset dir: " << dataset_dir_ << " does not exist."; + RETURN_STATUS_UNEXPECTED("Invalid file path, LibriTTS dataset dir: " + dataset_dir_ + " does not exist."); + } + real_path_ = realpath.value(); + Path dir(real_path_); + if (usage_ != "all") { + Path full_dir = dir / usage_; + cur_usage_ = usage_; + RETURN_IF_NOT_OK(GetPaths(&full_dir)); + RETURN_IF_NOT_OK(GetLabels()); + } else { + for (std::string usage_iter : usage_list) { + cur_usage_ = usage_iter; + Path full_dir = dir / cur_usage_; + RETURN_IF_NOT_OK(GetPaths(&full_dir)); + RETURN_IF_NOT_OK(GetLabels()); + } + } + num_rows_ = audio_label_tuples_.size(); + CHECK_FAIL_RETURN_UNEXPECTED(num_rows_ > 0, + "Invalid data, no valid data matching the dataset API LibriTTSDataset. " + "Please check dataset API or file path: " + + dataset_dir_ + "."); + return Status::OK(); +} + +Status LibriTTSOp::GetPaths(Path *dir) { + RETURN_UNEXPECTED_IF_NULL(dir); + auto iter = Path::DirIterator::OpenDirectory(dir); + if (iter == nullptr) { + MS_LOG(WARNING) << "Invalid file path, unable to open directory: " << dir->ToString() << "."; + } else { + while (iter->HasNext()) { + Path sub_dir = iter->Next(); + if (sub_dir.IsDirectory()) { + RETURN_IF_NOT_OK(GetPaths(&sub_dir)); + } else { + Path file_path = sub_dir; + std::string file_name = file_path.Basename(); + int32_t length = file_name.size(); + if (length > label_file_suffix_len && file_name.substr(length - label_file_suffix_len) == label_file_suffix) { + label_files_.push_back(sub_dir.ToString()); + return Status::OK(); + } + } + } + } + return Status::OK(); +} + +Status LibriTTSOp::GetLabels() { + std::string utterance_id_body = ""; + std::string original_text_body = ""; + std::string normalized_text_body = ""; + const uint32_t base = 10; + const uint32_t ascii_zero = 48; + const size_t underline_exact = 3; + for (std::string label_file : label_files_) { + std::ifstream label_reader(label_file); + while (getline(label_reader, utterance_id_body, '\t')) { + getline(label_reader, original_text_body, '\t'); + getline(label_reader, normalized_text_body, '\n'); + uint32_t speaker_id = 0; + uint32_t chapter_id = 0; + size_t underline_num = 0; + size_t underline_inx[4] = {0}; + for (size_t i = 0; i < utterance_id_body.size() && underline_num <= underline_exact; i++) { + if (utterance_id_body[i] == '_') { + underline_inx[underline_num++] = i; + } + } + if (underline_num != underline_exact) { + label_reader.close(); + RETURN_STATUS_UNEXPECTED("Invalid file, the file may not be a LibriTTS dataset file: " + label_file); + } + for (size_t i = 0; i < underline_inx[0]; i++) { + speaker_id = speaker_id * base + utterance_id_body[i] - ascii_zero; + } + for (size_t i = underline_inx[0] + 1; i < underline_inx[1]; i++) { + chapter_id = chapter_id * base + utterance_id_body[i] - ascii_zero; + } + audio_label_tuples_.push_back( + {cur_usage_, utterance_id_body, original_text_body, normalized_text_body, speaker_id, chapter_id, label_file}); + } + label_reader.close(); + } + label_files_.clear(); + return Status::OK(); +} +} // namespace dataset. +} // namespace mindspore. diff --git a/mindspore/ccsrc/minddata/dataset/engine/datasetops/source/libri_tts_op.h b/mindspore/ccsrc/minddata/dataset/engine/datasetops/source/libri_tts_op.h new file mode 100644 index 0000000000..143827b342 --- /dev/null +++ b/mindspore/ccsrc/minddata/dataset/engine/datasetops/source/libri_tts_op.h @@ -0,0 +1,120 @@ +/** + * 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_ENGINE_DATASETOPS_SOURCE_LIBRI_TTS_OP_H_ +#define MINDSPORE_CCSRC_MINDDATA_DATASET_ENGINE_DATASETOPS_SOURCE_LIBRI_TTS_OP_H_ + +#include +#include +#include +#include +#include +#include + +#include "minddata/dataset/core/tensor.h" +#include "minddata/dataset/engine/data_schema.h" +#include "minddata/dataset/engine/datasetops/parallel_op.h" +#include "minddata/dataset/engine/datasetops/source/mappable_leaf_op.h" +#include "minddata/dataset/engine/datasetops/source/sampler/sampler.h" +#include "minddata/dataset/util/path.h" +#include "minddata/dataset/util/queue.h" +#include "minddata/dataset/util/status.h" +#include "minddata/dataset/util/wait_post.h" + +namespace mindspore { +namespace dataset { +struct LibriTTSLabelTuple { + std::string usage; + std::string utterance_id; + std::string original_text; + std::string normalized_text; + uint32_t speaker_id; + uint32_t chapter_id; + std::string label_path; +}; + +class LibriTTSOp : public MappableLeafOp { + public: + /// \brief Constructor. + /// \param[in] dataset_dir Dir directory of LibriTTS. + /// \param[in] usage usage of this dataset, can be "dev-clean", "dev-other", "test-clean", "test-other", + /// "train-clean-100", "train-clean-360", "train-other-500", or "all". + /// \param[in] num_workers Number of workers reading audios in parallel. + /// \param[in] queue_size Connector queue size. + /// \param[in] data_schema The schema of the LibriTTS dataset. + /// \param[in] sampler Sampler tells LibriSpeechOp what to read. + LibriTTSOp(const std::string &dataset_dir, const std::string &usage, int32_t num_workers, int32_t queue_size, + std::unique_ptr data_schema, std::shared_ptr sampler); + + /// \brief Destructor. + ~LibriTTSOp() = default; + + /// \brief A print method typically used for debugging. + /// \param[out] out Output stream. + /// \param[in] show_all Whether to show all information. + void Print(std::ostream &out, bool show_all) const override; + + /// \brief Function to count the number of samples in the LibriTTS dataset. + /// \param[in] dir Path to the LibriTTS directory. + /// \param[in] usage Select the data set section. + /// \param[out] count Output arg that will hold the minimum of the actual dataset size and numSamples. + /// \return Status The status code returned. + static Status CountTotalRows(const std::string &dir, const std::string &usage, int64_t *count); + + /// \brief Op name getter. + /// \return Name of the current Op. + std::string Name() const override { return "LibriTTSOp"; } + + private: + /// \brief Load a tensor row according to a pair. + /// \param[in] row_id Id for this tensor row. + /// \param[out] row Audio & label read into this tensor row. + /// \return Status The status code returned. + Status LoadTensorRow(row_id_type row_id, TensorRow *row) override; + + /// \brief Read all paths in the directory. + /// \param[in] dir File path to be traversed. + /// \return Status The status code returned. + Status GetPaths(Path *dir); + + /// \brief Read all label files. + /// \return Status The status code returned. + Status GetLabels(); + + /// \brief Parse a single wav file. + /// \param[in] audio_dir Audio file path. + /// \param[out] waveform The output waveform tensor. + /// \return Status The status code returned. + Status ReadAudio(const std::string &audio_dir, std::shared_ptr *waveform); + + /// \brief Prepare all data in the directory. + /// \return Status The status code returned. + Status PrepareData(); + + /// \brief Private function for computing the assignment of the column name map. + /// \return Status The status code returned. + Status ComputeColMap() override; + + const std::string usage_; + std::string cur_usage_; + std::string real_path_; + std::string dataset_dir_; + std::unique_ptr data_schema_; + std::vector audio_label_tuples_; + std::vector label_files_; +}; +} // namespace dataset +} // namespace mindspore +#endif // MINDSPORE_CCSRC_MINDDATA_DATASET_ENGINE_DATASETOPS_SOURCE_LIBRI_TTS_OP_H_ diff --git a/mindspore/ccsrc/minddata/dataset/engine/ir/datasetops/dataset_node.h b/mindspore/ccsrc/minddata/dataset/engine/ir/datasetops/dataset_node.h index c96f84897c..4f04b39139 100644 --- a/mindspore/ccsrc/minddata/dataset/engine/ir/datasetops/dataset_node.h +++ b/mindspore/ccsrc/minddata/dataset/engine/ir/datasetops/dataset_node.h @@ -103,6 +103,7 @@ constexpr char kIMDBNode[] = "IMDBDataset"; constexpr char kIWSLT2016Node[] = "IWSLT2016Dataset"; constexpr char kIWSLT2017Node[] = "IWSLT2017Dataset"; constexpr char kKMnistNode[] = "KMnistDataset"; +constexpr char kLibriTTSNode[] = "LibriTTSDataset"; constexpr char kLJSpeechNode[] = "LJSpeechDataset"; constexpr char kManifestNode[] = "ManifestDataset"; constexpr char kMindDataNode[] = "MindDataDataset"; diff --git a/mindspore/ccsrc/minddata/dataset/engine/ir/datasetops/source/CMakeLists.txt b/mindspore/ccsrc/minddata/dataset/engine/ir/datasetops/source/CMakeLists.txt index 721b04677a..fbc7a6f7b0 100644 --- a/mindspore/ccsrc/minddata/dataset/engine/ir/datasetops/source/CMakeLists.txt +++ b/mindspore/ccsrc/minddata/dataset/engine/ir/datasetops/source/CMakeLists.txt @@ -29,6 +29,7 @@ set(DATASET_ENGINE_IR_DATASETOPS_SOURCE_SRC_FILES iwslt2016_node.cc iwslt2017_node.cc kmnist_node.cc + libri_tts_node.cc lj_speech_node.cc manifest_node.cc minddata_node.cc diff --git a/mindspore/ccsrc/minddata/dataset/engine/ir/datasetops/source/libri_tts_node.cc b/mindspore/ccsrc/minddata/dataset/engine/ir/datasetops/source/libri_tts_node.cc new file mode 100644 index 0000000000..4b7d6bd782 --- /dev/null +++ b/mindspore/ccsrc/minddata/dataset/engine/ir/datasetops/source/libri_tts_node.cc @@ -0,0 +1,121 @@ +/** + * 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/engine/ir/datasetops/source/libri_tts_node.h" + +#include +#include +#include +#include + +#include "minddata/dataset/engine/datasetops/source/libri_tts_op.h" +#include "minddata/dataset/util/status.h" + +namespace mindspore { +namespace dataset { +LibriTTSNode::LibriTTSNode(const std::string &dataset_dir, const std::string &usage, + std::shared_ptr sampler, std::shared_ptr cache) + : MappableSourceNode(std::move(cache)), dataset_dir_(dataset_dir), usage_(usage), sampler_(sampler) {} + +void LibriTTSNode::Print(std::ostream &out) const { out << Name(); } + +std::shared_ptr LibriTTSNode::Copy() { + std::shared_ptr sampler = (sampler_ == nullptr) ? nullptr : sampler_->SamplerCopy(); + auto node = std::make_shared(dataset_dir_, usage_, sampler, cache_); + return node; +} + +Status LibriTTSNode::ValidateParams() { + RETURN_IF_NOT_OK(DatasetNode::ValidateParams()); + RETURN_IF_NOT_OK(ValidateDatasetDirParam("LibriTTSDataset", dataset_dir_)); + RETURN_IF_NOT_OK(ValidateDatasetSampler("LibriTTSDataset", sampler_)); + RETURN_IF_NOT_OK(ValidateStringValue("LibriTTSDataset", usage_, + {"dev-clean", "dev-other", "test-clean", "test-other", "train-clean-100", + "train-clean-360", "train-other-500", "all"})); + return Status::OK(); +} + +Status LibriTTSNode::GetShardId(int32_t *shard_id) { + *shard_id = sampler_->ShardId(); + return Status::OK(); +} + +Status LibriTTSNode::GetDatasetSize(const std::shared_ptr &size_getter, bool estimate, + int64_t *dataset_size) { + if (dataset_size_ > 0) { + *dataset_size = dataset_size_; + return Status::OK(); + } + int64_t num_rows, sample_size; + RETURN_IF_NOT_OK(LibriTTSOp::CountTotalRows(dataset_dir_, usage_, &num_rows)); + std::shared_ptr sampler_rt = nullptr; + RETURN_IF_NOT_OK(sampler_->SamplerBuild(&sampler_rt)); + sample_size = sampler_rt->CalculateNumSamples(num_rows); + if (sample_size == -1) { + RETURN_IF_NOT_OK(size_getter->DryRun(shared_from_this(), &sample_size)); + } + *dataset_size = sample_size; + dataset_size_ = *dataset_size; + return Status::OK(); +} + +Status LibriTTSNode::Build(std::vector> *const node_ops) { + auto schema = std::make_unique(); + RETURN_IF_NOT_OK(schema->AddColumn(ColDescriptor("waveform", DataType(DataType::DE_FLOAT32), TensorImpl::kCv, 1))); + TensorShape scalar_rate = TensorShape::CreateScalar(); + RETURN_IF_NOT_OK(schema->AddColumn( + ColDescriptor("sample_rate", DataType(DataType::DE_UINT32), TensorImpl::kFlexible, 0, &scalar_rate))); + TensorShape scalar_original_text = TensorShape::CreateScalar(); + RETURN_IF_NOT_OK(schema->AddColumn( + ColDescriptor("original_text", DataType(DataType::DE_STRING), TensorImpl::kFlexible, 0, &scalar_original_text))); + TensorShape scalar_normalized_text = TensorShape::CreateScalar(); + RETURN_IF_NOT_OK(schema->AddColumn(ColDescriptor("normalized_text", DataType(DataType::DE_STRING), + TensorImpl::kFlexible, 0, &scalar_normalized_text))); + TensorShape scalar_speaker_id = TensorShape::CreateScalar(); + RETURN_IF_NOT_OK(schema->AddColumn( + ColDescriptor("speaker_id", DataType(DataType::DE_UINT32), TensorImpl::kFlexible, 0, &scalar_speaker_id))); + TensorShape scalar_chapter_id = TensorShape::CreateScalar(); + RETURN_IF_NOT_OK(schema->AddColumn( + ColDescriptor("chapter_id", DataType(DataType::DE_UINT32), TensorImpl::kFlexible, 0, &scalar_chapter_id))); + TensorShape scalar_utterance_id = TensorShape::CreateScalar(); + RETURN_IF_NOT_OK(schema->AddColumn( + ColDescriptor("utterance_id", DataType(DataType::DE_STRING), TensorImpl::kFlexible, 0, &scalar_utterance_id))); + std::shared_ptr sampler_rt = nullptr; + RETURN_IF_NOT_OK(sampler_->SamplerBuild(&sampler_rt)); + auto op = std::make_shared(dataset_dir_, usage_, num_workers_, connector_que_size_, std::move(schema), + std::move(sampler_rt)); + op->SetTotalRepeats(GetTotalRepeats()); + op->SetNumRepeatsPerEpoch(GetNumRepeatsPerEpoch()); + node_ops->push_back(op); + return Status::OK(); +} + +Status LibriTTSNode::to_json(nlohmann::json *out_json) { + nlohmann::json args, sampler_args; + RETURN_IF_NOT_OK(sampler_->to_json(&sampler_args)); + args["sampler"] = sampler_args; + args["num_parallel_workers"] = num_workers_; + args["dataset_dir"] = dataset_dir_; + args["usage"] = usage_; + if (cache_ != nullptr) { + nlohmann::json cache_args; + RETURN_IF_NOT_OK(cache_->to_json(&cache_args)); + args["cache"] = cache_args; + } + *out_json = args; + return Status::OK(); +} +} // namespace dataset +} // namespace mindspore diff --git a/mindspore/ccsrc/minddata/dataset/engine/ir/datasetops/source/libri_tts_node.h b/mindspore/ccsrc/minddata/dataset/engine/ir/datasetops/source/libri_tts_node.h new file mode 100644 index 0000000000..812a5b8e29 --- /dev/null +++ b/mindspore/ccsrc/minddata/dataset/engine/ir/datasetops/source/libri_tts_node.h @@ -0,0 +1,95 @@ +/** + * 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_ENGINE_IR_DATASETOPS_SOURCE_LIBRI_TTS_NODE_H_ +#define MINDSPORE_CCSRC_MINDDATA_DATASET_ENGINE_IR_DATASETOPS_SOURCE_LIBRI_TTS_NODE_H_ + +#include +#include +#include + +#include "minddata/dataset/engine/ir/datasetops/dataset_node.h" + +namespace mindspore { +namespace dataset { +class LibriTTSNode : public MappableSourceNode { + public: + /// \brief Constructor. + LibriTTSNode(const std::string &dataset_dir, const std::string &usage, std::shared_ptr sampler, + std::shared_ptr cache); + + /// \brief Destructor. + ~LibriTTSNode() = default; + + /// \brief Node name getter. + /// \return Name of the current node. + std::string Name() const override { return kLibriTTSNode; } + + /// \brief Print the description. + /// \param out The output stream to write output to. + void Print(std::ostream &out) const override; + + /// \brief Copy the node to a new object. + /// \return A shared pointer to the new copy. + std::shared_ptr Copy() override; + + /// \brief a base class override function to create the required runtime dataset op objects for this class. + /// \param node_ops A vector containing shared pointer to the Dataset Ops that this object will create. + /// \return Status Status::OK() if build successfully. + Status Build(std::vector> *const node_ops) override; + + /// \brief Parameters validation. + /// \return Status Status::OK() if all the parameters are valid. + Status ValidateParams() override; + + /// \brief Get the shard id of node. + /// \param[in] shard_id The shard ID within num_shards. + /// \return Status Status::OK() if get shard id successfully. + Status GetShardId(int32_t *shard_id) override; + + /// \brief Base-class override for GetDatasetSize. + /// \param[in] size_getter Shared pointer to DatasetSizeGetter. + /// \param[in] estimate This is only supported by some of the ops and it's used to speed up the process of getting + /// dataset size at the expense of accuracy. + /// \param[out] dataset_size the size of the dataset. + /// \return Status of the function. + Status GetDatasetSize(const std::shared_ptr &size_getter, bool estimate, + int64_t *dataset_size) override; + + /// \brief Getter functions. + const std::string &DatasetDir() const { return dataset_dir_; } + const std::string &usage() const { return usage_; } + + /// \brief Get the arguments of node. + /// \param[out] out_json JSON string of all attributes. + /// \return Status of the function. + Status to_json(nlohmann::json *out_json) override; + + /// \brief Sampler getter. + /// \return SamplerObj of the current node. + std::shared_ptr Sampler() override { return sampler_; } + + /// \brief Sampler setter. + /// \param[in] sampler Tells LibriTTSOp what to read. + void SetSampler(std::shared_ptr sampler) override { sampler_ = sampler; } + + private: + std::string dataset_dir_; + std::string usage_; + std::shared_ptr sampler_; +}; +} // namespace dataset +} // namespace mindspore +#endif // MINDSPORE_CCSRC_MINDDATA_DATASET_ENGINE_IR_DATASETOPS_SOURCE_LIBRI_TTS_NODE_H_ diff --git a/mindspore/ccsrc/minddata/dataset/include/dataset/datasets.h b/mindspore/ccsrc/minddata/dataset/include/dataset/datasets.h index 104c5dcfa5..8720f65c73 100644 --- a/mindspore/ccsrc/minddata/dataset/include/dataset/datasets.h +++ b/mindspore/ccsrc/minddata/dataset/include/dataset/datasets.h @@ -3230,6 +3230,103 @@ inline std::shared_ptr MS_API KMnist(const std::string &dataset_d return std::make_shared(StringToChar(dataset_dir), StringToChar(usage), sampler, cache); } +/// \class LibriTTSDataset +/// \brief A source dataset for reading and parsing LibriTTSDataset dataset. +class MS_API LibriTTSDataset : public Dataset { + public: + /// \brief Constructor of LibriTTSDataset. + /// \param[in] dataset_dir Path to the root directory that contains the dataset. + /// \param[in] usage Part of dataset of LibriTTS, can be "dev-clean", "dev-other", "test-clean", + /// "test-other", "train-clean-100", "train-clean-360", "train-other-500" or "all". + /// \param[in] sampler Shared pointer to a sampler object used to choose samples from the dataset. + /// \param[in] cache Tensor cache to use. + LibriTTSDataset(const std::vector &dataset_dir, const std::vector &usage, + const std::shared_ptr &sampler, const std::shared_ptr &cache); + + /// \brief Constructor of LibriTTSDataset. + /// \param[in] dataset_dir Path to the root directory that contains the dataset. + /// \param[in] usage Part of dataset of LibriTTS, can be "dev-clean", "dev-other", "test-clean", + /// "test-other", "train-clean-100", "train-clean-360", "train-other-500" or "all". + /// \param[in] sampler Raw pointer to a sampler object used to choose samples from the dataset. + /// \param[in] cache Tensor cache to use. + LibriTTSDataset(const std::vector &dataset_dir, const std::vector &usage, const Sampler *sampler, + const std::shared_ptr &cache); + + /// \brief Constructor of LibriTTSDataset. + /// \param[in] dataset_dir Path to the root directory that contains the dataset. + /// \param[in] usage Part of dataset of LibriTTS, can be "dev-clean", "dev-other", "test-clean", + /// "test-other", "train-clean-100", "train-clean-360", "train-other-500" or "all". + /// \param[in] sampler Sampler object used to choose samples from the dataset. + /// \param[in] cache Tensor cache to use. + LibriTTSDataset(const std::vector &dataset_dir, const std::vector &usage, + const std::reference_wrapper &sampler, const std::shared_ptr &cache); + + /// \brief Destructor of LibriTTSDataset. + ~LibriTTSDataset() = default; +}; + +/// \brief Function to create a LibriTTSDataset. +/// \note The generated dataset has seven columns ['waveform', 'sample_rate', 'original_text', 'normalized_text', +/// 'speaker_id', 'chapter_id', 'utterance_id']. +/// \param[in] dataset_dir Path to the root directory that contains the dataset. +/// \param[in] usage Part of dataset of LibriTTS, can be "dev-clean", "dev-other", "test-clean", "test-other", +/// "train-clean-100", "train-clean-360", "train-other-500", or "all" (default = "all"). +/// \param[in] sampler Shared pointer to a sampler object used to choose samples from the dataset. If sampler is not +/// given, a `RandomSampler` will be used to randomly iterate the entire dataset (default = RandomSampler()). +/// \param[in] cache Tensor cache to use (default=nullptr, which means no cache is used). +/// \return Shared pointer to the LibriTTSDataset. +/// \par Example +/// \code +/// /* Define dataset path and LibriTTS object */ +/// std::string folder_path = "/path/to/libri_tts_dataset_directory"; +/// std::shared_ptr ds = LibriTTS(folder_path); +/// +/// /* Create iterator to read dataset */ +/// std::shared_ptr iter = ds->CreateIterator(); +/// std::unordered_map row; +/// iter->GetNextRow(&row); +/// +/// /* Note: In LibriTTS dataset, each data dictionary has seven columns ["waveform", "sample_rate", +/// "original_text", "normalized_text", "speaker_id", "chapter_id", "utterance_id"].*/ +/// auto waveform = row["waveform"]; +/// \endcode +inline std::shared_ptr MS_API +LibriTTS(const std::string &dataset_dir, const std::string &usage = "all", + const std::shared_ptr &sampler = std::make_shared(), + const std::shared_ptr &cache = nullptr) { + return std::make_shared(StringToChar(dataset_dir), StringToChar(usage), sampler, cache); +} + +/// \brief Function to create a LibriTTSDataset. +/// \note The generated dataset has seven columns ['waveform', 'sample_rate', 'original_text', 'normalized_text', +/// 'speaker_id', 'chapter_id', 'utterance_id']. +/// \param[in] dataset_dir Path to the root directory that contains the dataset. +/// \param[in] usage Part of dataset of LibriTTS, can be "dev-clean", "dev-other", "test-clean", "test-other", +/// "train-clean-100", "train-clean-360", "train-other-500", or "all". +/// \param[in] sampler Raw pointer to a sampler object used to choose samples from the dataset. +/// \param[in] cache Tensor cache to use (default=nullptr, which means no cache is used). +/// \return Shared pointer to the LibriTTSDataset. +inline std::shared_ptr MS_API LibriTTS(const std::string &dataset_dir, const std::string &usage, + const Sampler *sampler, + const std::shared_ptr &cache = nullptr) { + return std::make_shared(StringToChar(dataset_dir), StringToChar(usage), sampler, cache); +} + +/// \brief Function to create a LibriTTSDataset. +/// \note The generated dataset has seven columns ['waveform', 'sample_rate', 'original_text', 'normalized_text', +/// 'speaker_id', 'chapter_id', 'utterance_id']. +/// \param[in] dataset_dir Path to the root directory that contains the dataset. +/// \param[in] usage Part of dataset of LibriTTS, can be "dev-clean", "dev-other", "test-clean", "test-other", +/// "train-clean-100", "train-clean-360", "train-other-500", or "all". +/// \param[in] sampler Sampler object used to choose samples from the dataset. +/// \param[in] cache Tensor cache to use (default=nullptr, which means no cache is used). +/// \return Shared pointer to the LibriTTSDataset. +inline std::shared_ptr MS_API LibriTTS(const std::string &dataset_dir, const std::string &usage, + const std::reference_wrapper &sampler, + const std::shared_ptr &cache = nullptr) { + return std::make_shared(StringToChar(dataset_dir), StringToChar(usage), sampler, cache); +} + /// \class LJSpeechDataset /// \brief A source dataset for reading and parsing LJSpeech dataset. class MS_API LJSpeechDataset : public Dataset { diff --git a/mindspore/ccsrc/minddata/dataset/include/dataset/samplers.h b/mindspore/ccsrc/minddata/dataset/include/dataset/samplers.h index 05681a6f97..9da88422d1 100644 --- a/mindspore/ccsrc/minddata/dataset/include/dataset/samplers.h +++ b/mindspore/ccsrc/minddata/dataset/include/dataset/samplers.h @@ -50,6 +50,7 @@ class MS_API Sampler : std::enable_shared_from_this { friend class ImageFolderDataset; friend class IMDBDataset; friend class KMnistDataset; + friend class LibriTTSDataset; friend class LJSpeechDataset; friend class ManifestDataset; friend class MindDataDataset; diff --git a/mindspore/python/mindspore/dataset/engine/__init__.py b/mindspore/python/mindspore/dataset/engine/__init__.py index 9fd368d642..87291dfab0 100644 --- a/mindspore/python/mindspore/dataset/engine/__init__.py +++ b/mindspore/python/mindspore/dataset/engine/__init__.py @@ -84,6 +84,7 @@ __all__ = ["Caltech101Dataset", # Vision "YelpReviewDataset", # Text "CMUArcticDataset", # Audio "GTZANDataset", # Audio + "LibriTTSDataset", # Audio "LJSpeechDataset", # Audio "SpeechCommandsDataset", # Audio "TedliumDataset", # Audio diff --git a/mindspore/python/mindspore/dataset/engine/datasets_audio.py b/mindspore/python/mindspore/dataset/engine/datasets_audio.py index 24bca9178e..b42599386a 100644 --- a/mindspore/python/mindspore/dataset/engine/datasets_audio.py +++ b/mindspore/python/mindspore/dataset/engine/datasets_audio.py @@ -26,8 +26,8 @@ After declaring the dataset object, you can further apply dataset operations import mindspore._c_dataengine as cde from .datasets import AudioBaseDataset, MappableDataset -from .validators import check_cmu_arctic_dataset, check_gtzan_dataset, check_lj_speech_dataset, check_speech_commands_dataset, \ - check_tedlium_dataset, check_yes_no_dataset +from .validators import check_cmu_arctic_dataset, check_gtzan_dataset, check_libri_tts_dataset, check_lj_speech_dataset, \ + check_speech_commands_dataset, check_tedlium_dataset, check_yes_no_dataset from ..core.validator_helpers import replace_none @@ -299,6 +299,156 @@ class GTZANDataset(MappableDataset, AudioBaseDataset): return cde.GTZANNode(self.dataset_dir, self.usage, self.sampler) +class LibriTTSDataset(MappableDataset, AudioBaseDataset): + """ + A source dataset that reads and parses the LibriTTS dataset. + + The generated dataset has seven columns :py:obj:`['waveform', 'sample_rate', 'original_text', 'normalized_text', + 'speaker_id', 'chapter_id', 'utterance_id']`. + The tensor of column :py:obj:`waveform` is of the float32 type. + The tensor of column :py:obj:`sample_rate` is of a scalar of uint32 type. + The tensor of column :py:obj:`original_text` is of a scalar of string type. + The tensor of column :py:obj:`normalized_text` is of a scalar of string type. + The tensor of column :py:obj:`speaker_id` is of a scalar of uint32 type. + The tensor of column :py:obj:`chapter_id` is of a scalar of uint32 type. + The tensor of column :py:obj:`utterance_id` is of a scalar of string type. + + Args: + dataset_dir (str): Path to the root directory that contains the dataset. + usage (str, optional): Part of this dataset, can be ""dev-clean", "dev-other", "test-clean", "test-other", + "train-clean-100", "train-clean-360", "train-other-500", or "all" (default=None, equal "all"). + num_samples (int, optional): The number of images to be included in the dataset + (default=None, will read all audio). + num_parallel_workers (int, optional): Number of workers to read the data + (default=None, will use value set in the config). + shuffle (bool, optional): Whether or not to perform shuffle on the dataset + (default=None, expected order behavior shown in the table). + sampler (Sampler, optional): Object used to choose samples from the + dataset (default=None, expected order behavior shown in the table). + num_shards (int, optional): Number of shards that the dataset will be divided into (default=None). + When this argument is specified, `num_samples` reflects the max sample number of per shard. + shard_id (int, optional): The shard ID within `num_shards` (default=None). This + argument can only be specified when `num_shards` is also specified. + cache (DatasetCache, optional): Use tensor caching service to speed up dataset processing + (default=None, which means no cache is used). + + Raises: + RuntimeError: If source raises an exception during execution. + RuntimeError: If dataset_dir does not contain data files. + RuntimeError: If num_parallel_workers exceeds the max thread numbers. + RuntimeError: If sampler and shuffle are specified at the same time. + RuntimeError: If sampler and sharding are specified at the same time. + RuntimeError: If num_shards is specified but shard_id is None. + RuntimeError: If shard_id is specified but num_shards is None. + ValueError: If shard_id is invalid (< 0 or >= num_shards). + + Note: + - LibriTTS dataset doesn't support PKSampler. + - This dataset can take in a `sampler`. `sampler` and `shuffle` are mutually exclusive. + The table below shows what input arguments are allowed and their expected behavior. + + .. list-table:: Expected Order Behavior of Using 'sampler' and 'shuffle' + :widths: 25 25 50 + :header-rows: 1 + + * - Parameter `sampler` + - Parameter `shuffle` + - Expected Order Behavior + * - None + - None + - random order + * - None + - True + - random order + * - None + - False + - sequential order + * - Sampler object + - None + - order defined by sampler + * - Sampler object + - True + - not allowed + * - Sampler object + - False + - not allowed + + Examples: + >>> libri_tts_dataset_dir = "/path/to/libri_tts_dataset_directory" + >>> + >>> # 1) Read 500 samples (audio files) in libri_tts_dataset_directory + >>> dataset = ds.LibriTTSDataset(libri_tts_dataset_dir, usage="train-clean-100", num_samples=500) + >>> + >>> # 2) Read all samples (audio files) in libri_tts_dataset_directory + >>> dataset = ds.LibriTTSDataset(libri_tts_dataset_dir) + + About LibriTTS dataset: + + LibriTTS is a multi-speaker English corpus of approximately 585 hours of read English speech at 24kHz + sampling rate, prepared by Heiga Zen with the assistance of Google Speech and Google Brain team members. + The LibriTTS corpus is designed for TTS research. It is derived from the original materials (mp3 audio + files from LibriVox and text files from Project Gutenberg) of the LibriSpeech corpus. + + You can construct the following directory structure from LibriTTS dataset and read by MindSpore's API. + + .. code-block:: + + . + └── libri_tts_dataset_directory + ├── dev-clean + │ ├── 116 + │ │ ├── 288045 + | | | ├── 116_288045.trans.tsv + │ │ │ ├── 116_288045_000003_000000.wav + │ │ │ └──... + │ │ ├── 288046 + | | | ├── 116_288046.trans.tsv + | | | ├── 116_288046_000003_000000.wav + │ | | └── ... + | | └── ... + │ ├── 1255 + │ │ ├── 138279 + | | | ├── 1255_138279.trans.tsv + │ │ │ ├── 1255_138279_000001_000000.wav + │ │ │ └── ... + │ │ ├── 74899 + | | | ├── 1255_74899.trans.tsv + | | | ├── 1255_74899_000001_000000.wav + │ | | └── ... + | | └── ... + | └── ... + └── ... + + Citation: + + .. code-block:: + + @article{lecun2010mnist, + title = {LIBRITTS handwritten digit database}, + author = {zpw, NBU}, + journal = {ATT Labs [Online]}, + volume = {2}, + year = {2010}, + howpublished = {http://www.openslr.org/resources/60/}, + description = {The LibriSpeech ASR corpus (http://www.openslr.org/12/) [1] has been used in + various research projects. However, as it was originally designed for ASR research, + there are some undesired properties when using for TTS research} + } + """ + + @check_libri_tts_dataset + def __init__(self, dataset_dir, usage=None, num_samples=None, num_parallel_workers=None, shuffle=None, + sampler=None, num_shards=None, shard_id=None, cache=None): + super().__init__(num_parallel_workers=num_parallel_workers, sampler=sampler, num_samples=num_samples, + shuffle=shuffle, num_shards=num_shards, shard_id=shard_id, cache=cache) + + self.dataset_dir = dataset_dir + self.usage = replace_none(usage, "all") + + def parse(self, children=None): + return cde.LibriTTSNode(self.dataset_dir, self.usage, self.sampler) + + class LJSpeechDataset(MappableDataset, AudioBaseDataset): """ A source dataset that reads and parses LJSpeech dataset. diff --git a/mindspore/python/mindspore/dataset/engine/validators.py b/mindspore/python/mindspore/dataset/engine/validators.py index c62fa3495d..d89b22e2ec 100644 --- a/mindspore/python/mindspore/dataset/engine/validators.py +++ b/mindspore/python/mindspore/dataset/engine/validators.py @@ -729,6 +729,35 @@ def check_celebadataset(method): return new_method +def check_libri_tts_dataset(method): + """A wrapper that wraps a parameter checker around the original Dataset(LibriTTSDataset).""" + + @wraps(method) + def new_method(self, *args, **kwargs): + _, param_dict = parse_user_args(method, *args, **kwargs) + + nreq_param_int = ['num_samples', 'num_parallel_workers', 'num_shards', 'shard_id'] + nreq_param_bool = ['shuffle'] + + dataset_dir = param_dict.get('dataset_dir') + check_dir(dataset_dir) + + usage = param_dict.get('usage') + if usage is not None: + check_valid_str(usage, ["dev-clean", "dev-other", "test-clean", "test-other", "train-clean-100", + "train-clean-360", "train-other-500", "all"], "usage") + validate_dataset_param_value(nreq_param_int, param_dict, int) + validate_dataset_param_value(nreq_param_bool, param_dict, bool) + + check_sampler_shuffle_shard_options(param_dict) + cache = param_dict.get('cache') + check_cache_option(cache) + + return method(self, *args, **kwargs) + + return new_method + + def check_lj_speech_dataset(method): """A wrapper that wraps a parameter checker around the original Dataset(LJSpeechDataset).""" diff --git a/tests/ut/cpp/dataset/CMakeLists.txt b/tests/ut/cpp/dataset/CMakeLists.txt index 2aa7da196d..e327b4e73b 100644 --- a/tests/ut/cpp/dataset/CMakeLists.txt +++ b/tests/ut/cpp/dataset/CMakeLists.txt @@ -38,6 +38,7 @@ SET(DE_UT_SRCS c_api_dataset_iterator_test.cc c_api_dataset_iwslt_test.cc c_api_dataset_kmnist_test.cc + c_api_dataset_libri_tts.cc c_api_dataset_lj_speech_test.cc c_api_dataset_manifest_test.cc c_api_dataset_minddata_test.cc diff --git a/tests/ut/cpp/dataset/c_api_dataset_libri_tts_test.cc b/tests/ut/cpp/dataset/c_api_dataset_libri_tts_test.cc new file mode 100644 index 0000000000..69825d61ea --- /dev/null +++ b/tests/ut/cpp/dataset/c_api_dataset_libri_tts_test.cc @@ -0,0 +1,311 @@ +/** + * 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 "common/common.h" +#include "minddata/dataset/include/dataset/datasets.h" +#include "include/dataset/transforms.h" + +using namespace mindspore::dataset; +using mindspore::dataset::Tensor; + +class MindDataTestPipeline : public UT::DatasetOpTesting { + protected: +}; + +/// Feature: LibriTTSDataset +/// Description: test LibriTTS +/// Expectation: get correct LibriTTS dataset +TEST_F(MindDataTestPipeline, TestLibriTTSBasic) { + MS_LOG(INFO) << "Doing MindDataTestPipeline-TestLibriTTSBasic."; + + std::string folder_path = datasets_root_path_ + "/testLibriTTSData"; + std::shared_ptr ds = LibriTTS(folder_path); + EXPECT_NE(ds, nullptr); + + // Create an iterator over the result of the above dataset. + // This will trigger the creation of the Execution Tree and launch it. + std::shared_ptr iter = ds->CreateIterator(); + EXPECT_NE(iter, nullptr); + + // Iterate the dataset and get each row. + std::unordered_map row; + ASSERT_OK(iter->GetNextRow(&row)); + uint64_t i = 0; + + while (row.size() != 0) { + auto waveform = row["waveform"]; + auto sample_rate = row["sample_rate"]; + auto original_text = row["original_text"]; + auto normalized_text = row["normalized_text"]; + auto speaker_id = row["speaker_id"]; + auto chapter_id = row["chapter_id"]; + auto utterance_id = row["utterance_id"]; + i++; + ASSERT_OK(iter->GetNextRow(&row)); + } + EXPECT_EQ(i, 3); + iter->Stop(); +} + +/// Feature: LibriTTSDataset +/// Description: test LibriTTS with Pipeline +/// Expectation: get correct LibriTTS dataset +TEST_F(MindDataTestPipeline, TestLibriTTSBasicWithPipeline) { + MS_LOG(INFO) << "Doing DataSetOpBatchTest-TestLibriTTSBasicWithPipeline."; + + // Create a LibriTTSDataset Dataset + std::string folder_path = datasets_root_path_ + "/testLibriTTSData"; + std::shared_ptr ds = LibriTTS(folder_path, "train-clean-100", std::make_shared(0, 2)); + EXPECT_NE(ds, nullptr); + auto op = transforms::PadEnd({1, 500000}); + std::vector input_columns = {"waveform"}; + std::vector output_columns = {"waveform"}; + std::vector project_columns = {"sample_rate", "original_text", "normalized_text", "speaker_id", + "chapter_id", "utterance_id", "waveform"}; + ds = ds->Map({op}, input_columns, output_columns, project_columns); + EXPECT_NE(ds, nullptr); + ds = ds->Repeat(5); + EXPECT_NE(ds, nullptr); + ds = ds->Batch(2); + EXPECT_NE(ds, nullptr); + // Create an iterator over the result of the above dataset. + // This will trigger the creation of the Execution Tree and launch it. + std::shared_ptr iter = ds->CreateIterator(); + EXPECT_NE(iter, nullptr); + // Iterate the dataset and get each row. + std::unordered_map row; + iter->GetNextRow(&row); + std::vector expected_original_text = {"good morning", "good afternoon"}; + std::vector expected_normalized_text = {"Good morning", "Good afternoon"}; + std::vector expected_speaker_id = {2506, 2506}; + std::vector expected_chapter_id = {11267, 11267}; + std::vector expected_utterance_id = {"2506_11267_000001_000000", "2506_11267_000002_000000"}; + uint64_t i = 0; + while (row.size() != 0) { + i++; + auto waveform = row["waveform"]; + auto original_text = row["original_text"]; + auto normalized_text = row["normalized_text"]; + auto sample_rate = row["sample_rate"]; + auto speaker_id = row["speaker_id"]; + auto chapter_id = row["chapter_id"]; + auto utterance_id = row["utterance_id"]; + + std::shared_ptr de_original_text; + ASSERT_OK(Tensor::CreateFromVector(expected_original_text, &de_original_text)); + mindspore::MSTensor fix_original_text = + mindspore::MSTensor(std::make_shared(de_original_text)); + EXPECT_MSTENSOR_EQ(original_text, fix_original_text); + + std::shared_ptr de_normalized_text; + ASSERT_OK(Tensor::CreateFromVector(expected_normalized_text, &de_normalized_text)); + mindspore::MSTensor fix_normalized_text = + mindspore::MSTensor(std::make_shared(de_normalized_text)); + EXPECT_MSTENSOR_EQ(normalized_text, fix_normalized_text); + + std::shared_ptr de_expected_speaker_id; + ASSERT_OK(Tensor::CreateFromVector(expected_speaker_id, &de_expected_speaker_id)); + mindspore::MSTensor fix_expected_speaker_id = + mindspore::MSTensor(std::make_shared(de_expected_speaker_id)); + EXPECT_MSTENSOR_EQ(speaker_id, fix_expected_speaker_id); + + std::shared_ptr de_expected_chapter_id; + ASSERT_OK(Tensor::CreateFromVector(expected_chapter_id, &de_expected_chapter_id)); + mindspore::MSTensor fix_expected_chapter_id = + mindspore::MSTensor(std::make_shared(de_expected_chapter_id)); + EXPECT_MSTENSOR_EQ(chapter_id, fix_expected_chapter_id); + + std::shared_ptr de_expected_utterance_id; + ASSERT_OK(Tensor::CreateFromVector(expected_utterance_id, &de_expected_utterance_id)); + mindspore::MSTensor fix_expected_utterance_id = + mindspore::MSTensor(std::make_shared(de_expected_utterance_id)); + EXPECT_MSTENSOR_EQ(utterance_id, fix_expected_utterance_id); + + ASSERT_OK(iter->GetNextRow(&row)); + } + + EXPECT_EQ(i, 5); + iter->Stop(); +} + +/// Feature: LibriTTSDataset +/// Description: test LibriTTS with invalid directory +/// Expectation: get correct LibriTTS dataset +TEST_F(MindDataTestPipeline, TestLibriTTSError) { + MS_LOG(INFO) << "Doing MindDataTestPipeline-TestLibriTTSError."; + + // Create a LibriTTS Dataset with non-existing dataset dir + std::shared_ptr ds0 = LibriTTS("NotExistFile"); + EXPECT_NE(ds0, nullptr); + + // Create an iterator over the result of the above dataset + std::shared_ptr iter0 = ds0->CreateIterator(); + // Expect failure: invalid LibriTTS input + EXPECT_EQ(iter0, nullptr); + + // Create a LibriTTS Dataset with invalid string of dataset dir + std::shared_ptr ds1 = LibriTTS(":*?\"<>|`&;'"); + EXPECT_NE(ds1, nullptr); + + // Create an iterator over the result of the above dataset + std::shared_ptr iter1 = ds1->CreateIterator(); + // Expect failure: invalid LibriTTS input + EXPECT_EQ(iter1, nullptr); +} + +/// Feature: LibriTTSDataset +/// Description: test LibriTTS with Getters +/// Expectation: dataset is null +TEST_F(MindDataTestPipeline, TestLibriTTSGetters) { + MS_LOG(INFO) << "Doing MindDataTestPipeline-TestLibriTTSGetters."; + + std::string folder_path = datasets_root_path_ + "/testLibriTTSData"; + // Create a LibriTTS Dataset. + std::shared_ptr ds1 = LibriTTS(folder_path); + std::shared_ptr ds2 = LibriTTS(folder_path, "train-clean-100"); + + std::vector column_names = {"waveform", "sample_rate", "original_text", "normalized_text", + "speaker_id", "chapter_id", "utterance_id"}; + + EXPECT_NE(ds1, nullptr); + EXPECT_EQ(ds1->GetDatasetSize(), 3); + EXPECT_EQ(ds1->GetColumnNames(), column_names); + + EXPECT_NE(ds2, nullptr); + EXPECT_EQ(ds2->GetDatasetSize(), 3); + EXPECT_EQ(ds2->GetColumnNames(), column_names); +} + +/// Feature: LibriTTSDataset +/// Description: test LibriTTS dataset with invalid type +/// Expectation: dataset is null +TEST_F(MindDataTestPipeline, TestLibriTTSWithInvalidUsageError) { + MS_LOG(INFO) << "Doing MindDataTestPipeline-TestLibriTTSWithInvalidUsageError."; + + std::string folder_path = datasets_root_path_ + "/testLibriTTSData"; + // Create a LibriTTS Dataset. + std::shared_ptr ds1 = LibriTTS(folder_path, "----"); + EXPECT_NE(ds1, nullptr); + + // Create an iterator over the result of the above dataset + std::shared_ptr iter1 = ds1->CreateIterator(); + // Expect failure: invalid LibriTTS input, sampler cannot be nullptr + EXPECT_EQ(iter1, nullptr); + + std::shared_ptr ds2 = LibriTTS(folder_path, "csacs"); + EXPECT_NE(ds2, nullptr); + + // Create an iterator over the result of the above dataset + std::shared_ptr iter2 = ds2->CreateIterator(); + // Expect failure: invalid LibriTTS input, sampler cannot be nullptr + EXPECT_EQ(iter2, nullptr); +} + +/// Feature: LibriTTSDataset +/// Description: test LibriTTS dataset with null sampler +/// Expectation: dataset is null +TEST_F(MindDataTestPipeline, TestLibriTTSWithNullSamplerError) { + MS_LOG(INFO) << "Doing MindDataTestPipeline-TestLibriTTSWithNullSamplerError."; + + std::string folder_path = datasets_root_path_ + "/testLibriTTSData"; + // Create a LibriTTS Dataset. + std::shared_ptr ds = LibriTTS(folder_path, "all", nullptr); + EXPECT_NE(ds, nullptr); + + // Create an iterator over the result of the above dataset + std::shared_ptr iter = ds->CreateIterator(); + // Expect failure: invalid LibriTTS input, sampler cannot be nullptr + EXPECT_EQ(iter, nullptr); +} + +/// Feature: LibriTTSDataset +/// Description: test LibriTTS with sequential sampler +/// Expectation: get correct LibriTTS dataset +TEST_F(MindDataTestPipeline, TestLibriTTSSequentialSamplers) { + MS_LOG(INFO) << "Doing MindDataTestPipeline-TestLibriTTSSequentialSamplers."; + + std::string folder_path = datasets_root_path_ + "/testLibriTTSData"; + std::shared_ptr ds = LibriTTS(folder_path, "all", std::make_shared(0, 2)); + EXPECT_NE(ds, nullptr); + + // Create an iterator over the result of the above dataset. + // This will trigger the creation of the Execution Tree and launch it. + std::shared_ptr iter = ds->CreateIterator(); + EXPECT_NE(iter, nullptr); + + // Iterate the dataset and get each row. + std::unordered_map row; + ASSERT_OK(iter->GetNextRow(&row)); + std::string_view original_text_idx, normalized_text_idx, utterance_id_idx; + uint32_t speaker_idx_id = 0, chapter_idx_id = 0; + std::vector expected_original_text = {"good morning", "good afternoon"}; + std::vector expected_normalized_text = {"Good morning", "Good afternoon"}; + std::vector expected_speaker_id = {2506, 2506}; + std::vector expected_chapter_id = {11267, 11267}; + std::vector expected_utterance_id = {"2506_11267_000001_000000", "2506_11267_000002_000000"}; + uint32_t rate = 0; + uint64_t i = 0; + while (row.size() != 0) { + auto waveform = row["waveform"]; + auto sample_rate = row["sample_rate"]; + auto original_text = row["original_text"]; + auto normalized_text = row["normalized_text"]; + auto speaker_id = row["speaker_id"]; + auto chapter_id = row["chapter_id"]; + auto utterance_id = row["utterance_id"]; + + MS_LOG(INFO) << "Tensor waveform shape: " << waveform.Shape(); + + std::shared_ptr trate; + ASSERT_OK(Tensor::CreateFromMSTensor(sample_rate, &trate)); + ASSERT_OK(trate->GetItemAt(&rate, {})); + EXPECT_EQ(rate, 24000); + + std::shared_ptr de_original_text; + ASSERT_OK(Tensor::CreateFromMSTensor(original_text, &de_original_text)); + ASSERT_OK(de_original_text->GetItemAt(&original_text_idx, {})); + std::string s_original_text(original_text_idx); + EXPECT_STREQ(s_original_text.c_str(), expected_original_text[i].c_str()); + + std::shared_ptr de_normalized_text; + ASSERT_OK(Tensor::CreateFromMSTensor(normalized_text, &de_normalized_text)); + ASSERT_OK(de_normalized_text->GetItemAt(&normalized_text_idx, {})); + std::string s_normalized_text(normalized_text_idx); + EXPECT_STREQ(s_normalized_text.c_str(), expected_normalized_text[i].c_str()); + + std::shared_ptr de_speaker_id; + ASSERT_OK(Tensor::CreateFromMSTensor(speaker_id, &de_speaker_id)); + ASSERT_OK(de_speaker_id->GetItemAt(&speaker_idx_id, {})); + EXPECT_EQ(speaker_idx_id, expected_speaker_id[i]); + + std::shared_ptr de_chapter_id; + ASSERT_OK(Tensor::CreateFromMSTensor(chapter_id, &de_chapter_id)); + ASSERT_OK(de_chapter_id->GetItemAt(&chapter_idx_id, {})); + EXPECT_EQ(chapter_idx_id, expected_chapter_id[i]); + + std::shared_ptr de_utterance_id; + ASSERT_OK(Tensor::CreateFromMSTensor(utterance_id, &de_utterance_id)); + ASSERT_OK(de_utterance_id->GetItemAt(&utterance_id_idx, {})); + std::string s_utterance_id(utterance_id_idx); + EXPECT_STREQ(s_utterance_id.c_str(), expected_utterance_id[i].c_str()); + + i++; + ASSERT_OK(iter->GetNextRow(&row)); + } + + EXPECT_EQ(i, 2); + + iter->Stop(); +} \ No newline at end of file diff --git a/tests/ut/data/dataset/testLibriTTSData/train-clean-100/2506/11267/2506_11267.trans.tsv b/tests/ut/data/dataset/testLibriTTSData/train-clean-100/2506/11267/2506_11267.trans.tsv new file mode 100644 index 0000000000..39924daaf6 --- /dev/null +++ b/tests/ut/data/dataset/testLibriTTSData/train-clean-100/2506/11267/2506_11267.trans.tsv @@ -0,0 +1,3 @@ +2506_11267_000001_000000 good morning Good morning +2506_11267_000002_000000 good afternoon Good afternoon +2506_11267_000003_000001 good evening Good evening diff --git a/tests/ut/data/dataset/testLibriTTSData/train-clean-100/2506/11267/2506_11267_000001_000000.wav b/tests/ut/data/dataset/testLibriTTSData/train-clean-100/2506/11267/2506_11267_000001_000000.wav new file mode 100644 index 0000000000000000000000000000000000000000..8041fc48b63302ff54a0a669afe81d3d97601314 GIT binary patch literal 4844 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 egHLR=X%VSSH_2QcRhqQ6*h-0}ssvG5wX`L+ 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 literal 0 HcmV?d00001 diff --git a/tests/ut/python/dataset/test_datasets_libri_tts.py b/tests/ut/python/dataset/test_datasets_libri_tts.py new file mode 100644 index 0000000000..5e34bd22e6 --- /dev/null +++ b/tests/ut/python/dataset/test_datasets_libri_tts.py @@ -0,0 +1,235 @@ +# 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 foNtest_resr the specific language governing permissions and +# limitations under the License. +# ============================================================================== +""" +Test LibriTTS dataset operators +""" +import numpy as np +import pytest + +import mindspore.dataset as ds +from mindspore import log as logger + +DATA_DIR = "../data/dataset/testLibriTTSData" + + +def test_libri_tts_basic(): + """ + Feature: LibriTTSDataset + Description: test basic usage of LibriTTS + Expectation: the dataset is as expected + """ + logger.info("Test LibriTTSDataset Op") + + # case 1: test loading fault dataset. + data1 = ds.LibriTTSDataset(DATA_DIR) + num_iter1 = 0 + for _ in data1.create_dict_iterator(output_numpy=True, num_epochs=1): + num_iter1 += 1 + assert num_iter1 == 3 + + # case 2: test num_samples. + data2 = ds.LibriTTSDataset(DATA_DIR, num_samples=1) + num_iter2 = 0 + for _ in data2.create_dict_iterator(output_numpy=True, num_epochs=1): + num_iter2 += 1 + assert num_iter2 == 1 + + # case 3: test repeat. + data3 = ds.LibriTTSDataset(DATA_DIR, usage="all", num_samples=3) + data3 = data3.repeat(3) + num_iter3 = 0 + for _ in data3.create_dict_iterator(output_numpy=True, num_epochs=1): + num_iter3 += 1 + assert num_iter3 == 9 + + # case 4: test batch with drop_remainder=False. + data4 = ds.LibriTTSDataset(DATA_DIR, usage="train-clean-100", num_samples=3) + assert data4.get_dataset_size() == 3 + assert data4.get_batch_size() == 1 + data4 = data4.batch(batch_size=2) # drop_remainder is default to be False. + assert data4.get_dataset_size() == 2 + assert data4.get_batch_size() == 2 + + # case 5: test batch with drop_remainder=True. + data5 = ds.LibriTTSDataset(DATA_DIR, usage="train-clean-100", num_samples=3) + assert data5.get_dataset_size() == 3 + assert data5.get_batch_size() == 1 + # the rest of incomplete batch will be dropped. + data5 = data5.batch(batch_size=2, drop_remainder=True) + assert data5.get_dataset_size() == 1 + assert data5.get_batch_size() == 2 + + +def test_libri_tts_distribute_sampler(): + """ + Feature: LibriTTSDataset + Description: test LibriTTS dataset with DisributeSampler + Expectation: the results are as expected + """ + logger.info("Test LibriTTS with sharding") + + list1, list2 = [], [] + num_shards = 3 + shard_id = 0 + + data1 = ds.LibriTTSDataset(DATA_DIR, usage="all", num_shards=num_shards, shard_id=shard_id) + count = 0 + for item1 in data1.create_dict_iterator(output_numpy=True, num_epochs=1): + list1.append(item1["original_text"]) + count = count + 1 + assert count == 1 + + num_shards = 3 + shard_id = 0 + sampler = ds.DistributedSampler(num_shards, shard_id) + data2 = ds.LibriTTSDataset(DATA_DIR, usage="train-clean-100", sampler=sampler) + count = 0 + for item2 in data2.create_dict_iterator(output_numpy=True, num_epochs=1): + list2.append(item2["original_text"]) + count = count + 1 + assert count == 1 + + +def test_libri_tts_exception(): + """ + Feature: LibriTTSDataset + Description: test error cases for LibriTTSDataset + Expectation: the results are as expected + """ + logger.info("Test error cases for LibriTTSDataset") + + error_msg_1 = "sampler and shuffle cannot be specified at the same time" + with pytest.raises(RuntimeError, match=error_msg_1): + ds.LibriTTSDataset(DATA_DIR, shuffle=False, sampler=ds.PKSampler(3)) + + error_msg_2 = "sampler and sharding cannot be specified at the same time" + with pytest.raises(RuntimeError, match=error_msg_2): + ds.LibriTTSDataset(DATA_DIR, sampler=ds.PKSampler(3), num_shards=2, shard_id=0) + + error_msg_3 = "num_shards is specified and currently requires shard_id as well" + with pytest.raises(RuntimeError, match=error_msg_3): + ds.LibriTTSDataset(DATA_DIR, num_shards=10) + + error_msg_4 = "shard_id is specified but num_shards is not" + with pytest.raises(RuntimeError, match=error_msg_4): + ds.LibriTTSDataset(DATA_DIR, shard_id=0) + + error_msg_5 = "Input shard_id is not within the required interval" + with pytest.raises(ValueError, match=error_msg_5): + ds.LibriTTSDataset(DATA_DIR, num_shards=5, shard_id=-1) + with pytest.raises(ValueError, match=error_msg_5): + ds.LibriTTSDataset(DATA_DIR, num_shards=5, shard_id=5) + with pytest.raises(ValueError, match=error_msg_5): + ds.LibriTTSDataset(DATA_DIR, num_shards=2, shard_id=5) + + error_msg_6 = "num_parallel_workers exceeds" + with pytest.raises(ValueError, match=error_msg_6): + ds.LibriTTSDataset(DATA_DIR, shuffle=False, num_parallel_workers=0) + with pytest.raises(ValueError, match=error_msg_6): + ds.LibriTTSDataset(DATA_DIR, shuffle=False, num_parallel_workers=256) + with pytest.raises(ValueError, match=error_msg_6): + ds.LibriTTSDataset(DATA_DIR, shuffle=False, num_parallel_workers=-2) + + error_msg_7 = "Argument shard_id" + with pytest.raises(TypeError, match=error_msg_7): + ds.LibriTTSDataset(DATA_DIR, num_shards=2, shard_id="0") + + def exception_func(item): + raise Exception("Error occur!") + + error_msg_8 = "The corresponding data files" + with pytest.raises(RuntimeError, match=error_msg_8): + data = ds.LibriTTSDataset(DATA_DIR) + data = data.map(operations=exception_func, input_columns=["waveform"], num_parallel_workers=1) + for _ in data.create_dict_iterator(output_numpy=True, num_epochs=1): + pass + + +def test_libri_tts_sequential_sampler(): + """ + Feature: LibriTTSDataset + Description: test LibriTTSDataset with SequentialSampler + Expectation: the results are as expected + """ + logger.info("Test LibriTTSDataset Op with SequentialSampler") + + num_samples = 2 + sampler = ds.SequentialSampler(num_samples=num_samples) + data1 = ds.LibriTTSDataset(DATA_DIR, usage="train-clean-100", sampler=sampler) + data2 = ds.LibriTTSDataset(DATA_DIR, usage="train-clean-100", shuffle=False, num_samples=num_samples) + list1, list2 = [], [] + list_expected = [24000, b'good morning', b'Good morning', 2506, 11267, b'2506_11267_000001_000000', + 24000, b'good afternoon', b'Good afternoon', 2506, 11267, b'2506_11267_000002_000000'] + + num_iter = 0 + for item1, item2 in zip(data1.create_dict_iterator(output_numpy=True, num_epochs=1), + data2.create_dict_iterator(output_numpy=True, num_epochs=1)): + list1.append(item1["sample_rate"]) + list2.append(item2["sample_rate"]) + list1.append(item1["original_text"]) + list2.append(item2["original_text"]) + list1.append(item1["normalized_text"]) + list2.append(item2["normalized_text"]) + list1.append(item1["speaker_id"]) + list2.append(item2["speaker_id"]) + list1.append(item1["chapter_id"]) + list2.append(item2["chapter_id"]) + list1.append(item1["utterance_id"]) + list2.append(item2["utterance_id"]) + num_iter += 1 + np.testing.assert_array_equal(list1, list_expected) + np.testing.assert_array_equal(list2, list_expected) + assert num_iter == num_samples + + +def test_libri_tts_usage(): + """ + Feature: LibriTTSDataset + Description: test LibriTTSDataset usage + Expectation: the results are as expected + """ + logger.info("Test LibriTTSDataset usage") + + def test_config(usage, libri_tts_path=None): + libri_tts_path = DATA_DIR if libri_tts_path is None else libri_tts_path + try: + data = ds.LibriTTSDataset(libri_tts_path, usage=usage, shuffle=False) + num_rows = 0 + for _ in data.create_dict_iterator(num_epochs=1, output_numpy=True): + num_rows += 1 + except (ValueError, TypeError, RuntimeError) as e: + return str(e) + return num_rows + + assert test_config("all") == 3 + assert test_config("train-clean-100") == 3 + assert "Input usage is not within the valid set of ['dev-clean', 'dev-other', 'test-clean', 'test-other', " \ + "'train-clean-100', 'train-clean-360', 'train-other-500', 'all']." in test_config("invalid") + assert "Argument usage with value ['list'] is not of type []" in test_config(["list"]) + + all_files_path = None + if all_files_path is not None: + assert test_config("train-clean-100", all_files_path) == 3 + assert ds.LibriTTSDataset(all_files_path, usage="train-clean-100").get_dataset_size() == 3 + assert test_config("all", all_files_path) == 3 + assert ds.LibriTTSDataset(all_files_path, usage="all").get_dataset_size() == 3 + + +if __name__ == '__main__': + test_libri_tts_basic() + test_libri_tts_distribute_sampler() + test_libri_tts_exception() + test_libri_tts_sequential_sampler() + test_libri_tts_usage()