Skip to content

Commit

Permalink
Merge pull request #103 from Cambridge-ICCS/add-eval-no-grad-options
Browse files Browse the repository at this point in the history
 Add options for eval and gradient required - Rebase of #78

Allows users to enable/disable gradient calculations on Torch objects for efficiency, and set models to evaluation mode.
Defaults are gradients off and eval mode on.
  • Loading branch information
jatkinson1000 authored Apr 8, 2024
2 parents ccb655e + 48978b9 commit 4b451d7
Show file tree
Hide file tree
Showing 5 changed files with 661 additions and 307 deletions.
14 changes: 11 additions & 3 deletions pages/troubleshooting.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@ In this case you must install
You will then need to load the intel Fortran compilers using `setvars.bat`
which is found in the Intel compiler install directory (see the
[intel docs](https://www.intel.com/content/www/us/en/docs/oneapi/programming-guide/2023-2/use-the-setvars-script-with-windows.html))
for more details.\
for more details.<br>
From CMD this can be done with:
```
"C:\Program Files (x86)\Intel\oneAPI\setvars.bat"
```

Finally you will need to add `-G "NMake Makefiles"` to the `cmake` command in the
[regular install instructions](doc/page/cmake.html).\
[regular install instructions](doc/page/cmake.html).<br>
So the basic command to build from CMD becomes:
```
cmake -G "NMake Makefiles" -DCMAKE_PREFIX_PATH="C:\Users\melt\Downloads\libtorch-win-shared-with-deps-2.1.0+cpu\libtorch" -DCMAKE_BUILD_TYPE=Release ..
Expand Down Expand Up @@ -67,11 +67,19 @@ on locating Torch within a virtual environment (venv) for CMake.

The reason input tensors to [[torch_module_forward(subroutine)]] are contained in an
array is because it is possible to pass multiple input tensors to the `forward()`
method of a torch net.\
method of a torch net.<br>
The nature of Fortran means that it is not possible to set an arbitrary number
of inputs to the `torch_module_forward` subroutine, so instead we use an single array
of input tensors which _can_ have an arbitrary length of `n_inputs`.

Note that this does not refer to batching data.
This should be done in the same way as in Torch; by extending the dimensionality of
the input tensors.

### Do I need to set torch.no_grad() or torch.eval() somewhere like in PyTorch?

By default we disable gradient calculations for tensors and models and place models in
evaluation mode for efficiency.
These can be adjusted using the `requires_grad` and `is_training` optional arguments
in the Fortran interface. See the [API procedures documentation](lists/procedures.html)
for details.
36 changes: 30 additions & 6 deletions src/ctorch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,22 @@ const auto get_device(torch_device_t device_type, int device_index)
}
}

void set_is_training(torch_jit_script_module_t module,
const bool is_training=false)
{
auto model = static_cast<torch::jit::script::Module*>(module);
if (is_training) {
model->train();
} else {
model->eval();
}
}

torch_tensor_t torch_zeros(int ndim, const int64_t* shape, torch_data_t dtype,
torch_device_t device_type, int device_index = -1)
torch_device_t device_type, int device_index = -1,
const bool requires_grad=false)
{
torch::AutoGradMode enable_grad(requires_grad);
torch::Tensor* tensor = nullptr;
try {
// This doesn't throw if shape and dimensions are incompatible
Expand All @@ -82,8 +95,10 @@ torch_tensor_t torch_zeros(int ndim, const int64_t* shape, torch_data_t dtype,
}

torch_tensor_t torch_ones(int ndim, const int64_t* shape, torch_data_t dtype,
torch_device_t device_type, int device_index = -1)
torch_device_t device_type, int device_index = -1,
const bool requires_grad=false)
{
torch::AutoGradMode enable_grad(requires_grad);
torch::Tensor* tensor = nullptr;
try {
// This doesn't throw if shape and dimensions are incompatible
Expand All @@ -104,8 +119,10 @@ torch_tensor_t torch_ones(int ndim, const int64_t* shape, torch_data_t dtype,
}

torch_tensor_t torch_empty(int ndim, const int64_t* shape, torch_data_t dtype,
torch_device_t device_type, int device_index = -1)
torch_device_t device_type, int device_index = -1,
const bool requires_grad=false)
{
torch::AutoGradMode enable_grad(requires_grad);
torch::Tensor* tensor = nullptr;
try {
// This doesn't throw if shape and dimensions are incompatible
Expand All @@ -129,8 +146,10 @@ torch_tensor_t torch_empty(int ndim, const int64_t* shape, torch_data_t dtype,
// data
torch_tensor_t torch_from_blob(void* data, int ndim, const int64_t* shape,
const int64_t* strides, torch_data_t dtype,
torch_device_t device_type, int device_index = -1)
torch_device_t device_type, int device_index = -1,
const bool requires_grad=false)
{
torch::AutoGradMode enable_grad(requires_grad);
torch::Tensor* tensor = nullptr;

try {
Expand Down Expand Up @@ -174,8 +193,11 @@ void torch_tensor_delete(torch_tensor_t tensor)

torch_jit_script_module_t torch_jit_load(const char* filename,
const torch_device_t device_type = torch_kCPU,
const int device_index = -1)
const int device_index = -1,
const bool requires_grad=false,
const bool is_training=false)
{
torch::AutoGradMode enable_grad(requires_grad);
torch::jit::script::Module* module = nullptr;
try {
module = new torch::jit::script::Module;
Expand All @@ -189,14 +211,16 @@ torch_jit_script_module_t torch_jit_load(const char* filename,
delete module;
exit(EXIT_FAILURE);
}
set_is_training(module, is_training);

return module;
}

void torch_jit_module_forward(const torch_jit_script_module_t module,
const torch_tensor_t *inputs, const int nin,
torch_tensor_t output)
torch_tensor_t output, const bool requires_grad=false)
{
torch::AutoGradMode enable_grad(requires_grad);
// Here we cast the pointers we recieved in to Tensor objects
auto model = static_cast<torch::jit::script::Module*>(module);
auto in = reinterpret_cast<torch::Tensor* const*>(inputs);
Expand Down
22 changes: 16 additions & 6 deletions src/ctorch.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,11 @@ typedef enum { torch_kCPU, torch_kCUDA } torch_device_t;
* @param data type of the elements of the Tensor
* @param device type used (cpu, CUDA, etc.)
* @param device index for the CUDA case
* @param whether gradient is required
*/
EXPORT_C torch_tensor_t torch_zeros(int ndim, const int64_t* shape,
torch_data_t dtype, torch_device_t device_type,
int device_index);
int device_index, const bool requires_grad);

/**
* Function to generate a Torch Tensor of ones
Expand All @@ -51,10 +52,11 @@ EXPORT_C torch_tensor_t torch_zeros(int ndim, const int64_t* shape,
* @param data type of the elements of the Tensor
* @param device type used (cpu, CUDA, etc.)
* @param device index for the CUDA case
* @param whether gradient is required
*/
EXPORT_C torch_tensor_t torch_ones(int ndim, const int64_t* shape,
torch_data_t dtype, torch_device_t device_type,
int device_index);
int device_index, const bool requires_grad);

/**
* Function to generate an empty Torch Tensor
Expand All @@ -63,10 +65,11 @@ EXPORT_C torch_tensor_t torch_ones(int ndim, const int64_t* shape,
* @param data type of the elements of the Tensor
* @param device type used (cpu, CUDA, etc.)
* @param device index for the CUDA case
* @param whether gradient is required
*/
EXPORT_C torch_tensor_t torch_empty(int ndim, const int64_t* shape,
torch_data_t dtype, torch_device_t device_type,
int device_index);
int device_index, const bool requires_grad);

/**
* Function to create a Torch Tensor from memory location given extra information
Expand All @@ -77,14 +80,16 @@ EXPORT_C torch_tensor_t torch_empty(int ndim, const int64_t* shape,
* @param data type of the elements of the Tensor
* @param device type used (cpu, CUDA, etc.)
* @param device index for the CUDA case
* @param whether gradient is required
* @return Torch Tensor interpretation of the data pointed at
*/
EXPORT_C torch_tensor_t torch_from_blob(void* data, int ndim,
const int64_t* shape,
const int64_t* strides,
torch_data_t dtype,
torch_device_t device_type,
int device_index);
int device_index,
const bool requires_grad);

/**
* Function to print out a Torch Tensor
Expand Down Expand Up @@ -114,22 +119,27 @@ EXPORT_C void torch_tensor_delete(torch_tensor_t tensor);
* @param filename where TorchScript description of model is stored
* @param device type used (cpu, CUDA, etc.)
* @param device index for the CUDA case
* @param whether gradient is required
* @param whether model is being trained
* @return Torch Module loaded in from file
*/
EXPORT_C torch_jit_script_module_t torch_jit_load(const char* filename,
const torch_device_t device_type,
const int device_index);
const int device_index,
const bool requires_grad,
const bool is_training);

/**
* Function to run the `forward` method of a Torch Module
* @param Torch Module containing the model
* @param vector of Torch Tensors as inputs to the model
* @param number of input Tensors in the input vector
* @param the output Tensor from running the model
* @param whether gradient is required
*/
EXPORT_C void torch_jit_module_forward(const torch_jit_script_module_t module,
const torch_tensor_t *inputs, const int nin,
torch_tensor_t output);
torch_tensor_t output, const bool requires_grad);

/**
* Function to delete a Torch Module to clean up
Expand Down
Loading

0 comments on commit 4b451d7

Please sign in to comment.