Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor libtorchaudio example #1486

Merged
merged 1 commit into from
May 4, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 1 addition & 4 deletions examples/libtorchaudio/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,4 @@ message("libtorchaudio CMakeLists: ${TORCH_CXX_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${TORCH_CXX_FLAGS}")

add_subdirectory(../.. libtorchaudio)

add_executable(main main.cpp)
target_link_libraries(main "${TORCH_LIBRARIES}" "${TORCHAUDIO_LIBRARY}")
set_property(TARGET main PROPERTY CXX_STANDARD 14)
add_subdirectory(augmentation)
30 changes: 23 additions & 7 deletions examples/libtorchaudio/README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,27 @@
# Example usage: libtorchaudio
# Libtorchaudio Examples

This example demonstrates how you can use torchaudio's I/O features in C++ application, in addition to PyTorch's operations.
* [Augmentation](./augmentation)

To try this example, simply run `./run.sh`. This script will
## Build

1. Create an audio preprocessing pipeline with TorchScript and dump it to a file.
2. Build the application using `libtorch` and `libtorchaudio`.
3. Execute the preprocessing pipeline on an example audio.
The example applications in this directory depend on `libtorch` and `libtorchaudio`.
If you have a working `PyTorch`, you already have `libtorch`.
Please refer to [this tutorial](https://pytorch.org/tutorials/advanced/torch_script_custom_classes.html) for the use of `libtorch` and TorchScript.

The detail of the preprocessing pipeline can be found in [`create_jittable_pipeline.py`](./create_jittable_pipeline.py).
`libtorchaudio` is the library of torchaudio's C++ components without Python component.
It is currently not distributed, and it will be built alongside with the applications.

The following commands will build `libtorchaudio` and applications.

```bash
mkdir build
cd build
cmake -GNinja \
-DCMAKE_PREFIX_PATH="$(python -c 'import torch;print(torch.utils.cmake_prefix_path)')" \
-DBUILD_SOX=ON \
-DBUILD_KALDI=OFF \
..
cmake --build .
```

For the usages of each application, refer to the corresponding application directory.
3 changes: 3 additions & 0 deletions examples/libtorchaudio/augmentation/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
add_executable(augment main.cpp)
target_link_libraries(augment "${TORCH_LIBRARIES}" "${TORCHAUDIO_LIBRARY}")
set_property(TARGET augment PROPERTY CXX_STANDARD 14)
36 changes: 36 additions & 0 deletions examples/libtorchaudio/augmentation/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Augmentation

This example demonstrates how you can use torchaudio's I/O features and augmentations in C++ application.

**NOTE**
This example uses `"sox_io"` backend, thus does not work on Windows.

## Steps
### 1. Create augmentation pipeline TorchScript file.

First, we implement our data process pipeline as a regular Python, and save it as a TorchScript object.
We will load and execute it in our C++ application. The C++ code is found in [`main.cpp`](./main.cpp).

```python
python create_jittable_pipeline.py \
--rir-path "../data/rir.wav" \
--output-path "./pipeline.zip"
```

### 2. Build the application

Please refer to [the top level README.md](../README.md)

### 3. Run the application

Now we run the C++ application `augment`, with the TorchScript object we created in Step.1 and an input audio file.

In [the top level directory](../)

```bash
input_audio_file="./data/input.wav"
./build/augmentation/augment ./augmentation/pipeline.zip "${input_audio_file}" "output.wav"
```

When you give a clean speech file, the output audio sounds like it's a phone conversation.

Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ class Pipeline(torch.nn.Module):

This example load waveform from a file then apply effects and save it to a file.
"""
def __init__(self):
def __init__(self, rir_path: str):
super().__init__()
rir, sample_rate = _load_rir()
rir, sample_rate = torchaudio.load(rir_path)
self.register_buffer('rir', rir)
self.rir_sample_rate: int = sample_rate

Expand Down Expand Up @@ -44,8 +44,8 @@ def forward(self, input_path: str, output_path: str):
torchaudio.save(output_path, waveform, sample_rate)


def _create_jit_pipeline(output_path):
module = torch.jit.script(Pipeline())
def _create_jit_pipeline(rir_path, output_path):
module = torch.jit.script(Pipeline(rir_path))
print("*" * 40)
print("* Pipeline code")
print("*" * 40)
Expand All @@ -59,24 +59,24 @@ def _get_path(*paths):
return os.path.join(os.path.dirname(__file__), *paths)


def _load_rir():
path = _get_path("data", "rir.wav")
return torchaudio.load(path)


def _parse_args():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument(
"--rir-path",
default=_get_path("..", "data", "rir.wav"),
help="Audio dara for room impulse response."
)
parser.add_argument(
"--output-path",
default=_get_path("data", "pipeline.zip"),
default=_get_path("pipeline.zip"),
help="Output JIT file."
)
return parser.parse_args()


def _main():
args = _parse_args()
_create_jit_pipeline(args.output_path)
_create_jit_pipeline(args.rir_path, args.output_path)


if __name__ == '__main__':
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ int main(int argc, char* argv[]) {
}

torch::jit::script::Module module;
std::cout << "Loading module from: " << argv[0] << std::endl;
std::cout << "Loading module from: " << argv[1] << std::endl;
try {
module = torch::jit::load(argv[1]);
} catch (const c10::Error &error) {
Expand Down
12 changes: 2 additions & 10 deletions examples/libtorchaudio/run.sh → examples/libtorchaudio/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,14 @@
set -eux

this_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"

build_dir="${this_dir}/build"
data_dir="${this_dir}/data"
jit_file="${data_dir}/pipeline.zip"
input_file="${data_dir}/input.wav"
output_file="${data_dir}/output.wav"

cd "${this_dir}"
python create_jittable_pipeline.py

mkdir -p "${build_dir}"
cd "${build_dir}"

cmake -GNinja \
-DCMAKE_PREFIX_PATH="$(python -c 'import torch;print(torch.utils.cmake_prefix_path)')" \
-DBUILD_SOX=ON \
-DBUILD_KALDI=OFF \
..
cmake --build . --target main
./main "${jit_file}" "${input_file}" "${output_file}"
cmake --build .