Skip to content

Commit

Permalink
Refactor libtorchaudio example (#1486)
Browse files Browse the repository at this point in the history
  • Loading branch information
mthrok committed May 4, 2021
1 parent 7fd5fce commit 3ab521f
Show file tree
Hide file tree
Showing 7 changed files with 77 additions and 33 deletions.
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 .

0 comments on commit 3ab521f

Please sign in to comment.