From baa5bc993358d1155cdc640676f7bd768eae00a0 Mon Sep 17 00:00:00 2001 From: Davide Valsecchi Date: Fri, 1 Dec 2023 17:49:01 +0100 Subject: [PATCH] Added package for PyTorch. Tests for TorchScript inference CPU and CUDA --- PhysicsTools/PyTorch/BuildFile.xml | 8 ++ PhysicsTools/PyTorch/test/BuildFile.xml | 24 +++++ PhysicsTools/PyTorch/test/simple_dnn.pt | Bin 0 -> 4356 bytes PhysicsTools/PyTorch/test/testBase.h | 52 +++++++++++ PhysicsTools/PyTorch/test/testBaseCUDA.h | 65 ++++++++++++++ PhysicsTools/PyTorch/test/testRunner.cc | 1 + .../PyTorch/test/testTorchSimpleDnn.cc | 56 ++++++++++++ .../PyTorch/test/testTorchSimpleDnnCUDA.cc | 82 ++++++++++++++++++ .../PyTorch/test/testTorchSimpleDnnCuda.cc | 82 ++++++++++++++++++ 9 files changed, 370 insertions(+) create mode 100644 PhysicsTools/PyTorch/BuildFile.xml create mode 100644 PhysicsTools/PyTorch/test/BuildFile.xml create mode 100644 PhysicsTools/PyTorch/test/simple_dnn.pt create mode 100644 PhysicsTools/PyTorch/test/testBase.h create mode 100644 PhysicsTools/PyTorch/test/testBaseCUDA.h create mode 100644 PhysicsTools/PyTorch/test/testRunner.cc create mode 100644 PhysicsTools/PyTorch/test/testTorchSimpleDnn.cc create mode 100644 PhysicsTools/PyTorch/test/testTorchSimpleDnnCUDA.cc create mode 100644 PhysicsTools/PyTorch/test/testTorchSimpleDnnCuda.cc diff --git a/PhysicsTools/PyTorch/BuildFile.xml b/PhysicsTools/PyTorch/BuildFile.xml new file mode 100644 index 0000000000000..511f4697bbabe --- /dev/null +++ b/PhysicsTools/PyTorch/BuildFile.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/PhysicsTools/PyTorch/test/BuildFile.xml b/PhysicsTools/PyTorch/test/BuildFile.xml new file mode 100644 index 0000000000000..01aeb83b73738 --- /dev/null +++ b/PhysicsTools/PyTorch/test/BuildFile.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/PhysicsTools/PyTorch/test/simple_dnn.pt b/PhysicsTools/PyTorch/test/simple_dnn.pt new file mode 100644 index 0000000000000000000000000000000000000000..d4f602ea0b07c68442d91445e981d474e8060539 GIT binary patch literal 4356 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 IKd*WAUwhmq@&Et; literal 0 HcmV?d00001 diff --git a/PhysicsTools/PyTorch/test/testBase.h b/PhysicsTools/PyTorch/test/testBase.h new file mode 100644 index 0000000000000..cb325db68e306 --- /dev/null +++ b/PhysicsTools/PyTorch/test/testBase.h @@ -0,0 +1,52 @@ +/* + * Base class for tests. + * + */ + +#ifndef PHYSICSTOOLS_PYTORCH_TEST_TESTBASE_H +#define PHYSICSTOOLS_PYTORCH_TEST_TESTBASE_H + +#include +#include +#include +#include + +class testBasePyTorch : public CppUnit::TestFixture { +public: + std::string dataPath_; + std::string testPath_; + + void setUp(); + void tearDown(); + std::string cmsswPath(std::string path); + + virtual void test() = 0; + +}; + +void testBasePyTorch::setUp() { + dataPath_ = + cmsswPath("/test/" + std::string(std::getenv("SCRAM_ARCH")) + "/" + boost::filesystem::unique_path().string()); + + // create the graph + testPath_ = cmsswPath("/src/PhysicsTools/PyTorch/test"); +} + +void testBasePyTorch::tearDown() { + if (std::filesystem::exists(dataPath_)) { + std::filesystem::remove_all(dataPath_); + } +} + +std::string testBasePyTorch::cmsswPath(std::string path) { + if (path.size() > 0 && path.substr(0, 1) != "/") { + path = "/" + path; + } + + std::string base = std::string(std::getenv("CMSSW_BASE")); + std::string releaseBase = std::string(std::getenv("CMSSW_RELEASE_BASE")); + + return (std::filesystem::exists(base.c_str()) ? base : releaseBase) + path; +} + +#endif // PHYSICSTOOLS_PYTORCH_TEST_TESTBASE_H diff --git a/PhysicsTools/PyTorch/test/testBaseCUDA.h b/PhysicsTools/PyTorch/test/testBaseCUDA.h new file mode 100644 index 0000000000000..cb8d496dd1eb2 --- /dev/null +++ b/PhysicsTools/PyTorch/test/testBaseCUDA.h @@ -0,0 +1,65 @@ +/* + * Base class for tests. + * + */ + +#ifndef PHYSICSTOOLS_PYTORCH_TEST_TESTBASECUDA_H +#define PHYSICSTOOLS_PYTORCH_TEST_TESTBASECUDA_H + +#include +#include +#include +#include + +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h" +#include "FWCore/ParameterSetReader/interface/ParameterSetReader.h" +#include "FWCore/PluginManager/interface/PluginManager.h" +#include "FWCore/PluginManager/interface/standard.h" +#include "FWCore/ServiceRegistry/interface/Service.h" +#include "FWCore/ServiceRegistry/interface/ServiceRegistry.h" +#include "FWCore/ServiceRegistry/interface/ServiceToken.h" +#include "FWCore/Utilities/interface/Exception.h" +#include "FWCore/Utilities/interface/ResourceInformation.h" +#include "HeterogeneousCore/CUDAServices/interface/CUDAInterface.h" +#include "HeterogeneousCore/CUDAUtilities/interface/requireDevices.h" + +class testBasePyTorchCUDA : public CppUnit::TestFixture { +public: + std::string dataPath_; + std::string testPath_; + + void setUp(); + void tearDown(); + std::string cmsswPath(std::string path); + + virtual void test() = 0; + +}; + +void testBasePyTorchCUDA::setUp() { + dataPath_ = + cmsswPath("/test/" + std::string(std::getenv("SCRAM_ARCH")) + "/" + boost::filesystem::unique_path().string()); + + // create the graph + testPath_ = cmsswPath("/src/PhysicsTools/PyTorch/test"); +} + +void testBasePyTorchCUDA::tearDown() { + if (std::filesystem::exists(dataPath_)) { + std::filesystem::remove_all(dataPath_); + } +} + +std::string testBasePyTorchCUDA::cmsswPath(std::string path) { + if (path.size() > 0 && path.substr(0, 1) != "/") { + path = "/" + path; + } + + std::string base = std::string(std::getenv("CMSSW_BASE")); + std::string releaseBase = std::string(std::getenv("CMSSW_RELEASE_BASE")); + + return (std::filesystem::exists(base.c_str()) ? base : releaseBase) + path; +} + +#endif // PHYSICSTOOLS_PYTORCH_TEST_TESTBASE_H diff --git a/PhysicsTools/PyTorch/test/testRunner.cc b/PhysicsTools/PyTorch/test/testRunner.cc new file mode 100644 index 0000000000000..1482cf9a9ce85 --- /dev/null +++ b/PhysicsTools/PyTorch/test/testRunner.cc @@ -0,0 +1 @@ +#include diff --git a/PhysicsTools/PyTorch/test/testTorchSimpleDnn.cc b/PhysicsTools/PyTorch/test/testTorchSimpleDnn.cc new file mode 100644 index 0000000000000..28da1f2a1f73c --- /dev/null +++ b/PhysicsTools/PyTorch/test/testTorchSimpleDnn.cc @@ -0,0 +1,56 @@ +#include +#include "testBase.h" +#include +#include +#include + + +class testSimpleDNN : public testBasePyTorch { + CPPUNIT_TEST_SUITE(testSimpleDNN); + CPPUNIT_TEST(test); + CPPUNIT_TEST_SUITE_END(); + +public: + void test() override; +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(testSimpleDNN); + +void testSimpleDNN::test() { + std::string model_path = testPath_ + "/simple_dnn.pt"; + torch::Device device(torch::kCPU); + torch::jit::script::Module module; + try { + // Deserialize the ScriptModule from a file using torch::jit::load(). + module = torch::jit::load(model_path); + module.to(device); + } + catch (const c10::Error& e) { + + std::cerr << "error loading the model\n" << e.what() << std::endl; + } + // Create a vector of inputs. + std::vector inputs; + inputs.push_back(torch::ones(10, device)); + + + // Execute the model and turn its output into a tensor. + at::Tensor output = module.forward(inputs).toTensor(); + std::cout << "output: "<< output << '\n'; + CPPUNIT_ASSERT(output.item() == 110.); + std::cout << "ok\n"; +} + + + +// int main(int argc, const char* argv[]) { +// std::cout << "Running model on CPU" << std::endl; +// torch::Device cpu(torch::kCPU); +// runModel("/data/user/dvalsecc/simple_dnn.pt", cpu); + +// std::cout << "Running model on CUDA" << std::endl; +// torch::Device cuda(torch::kCUDA); +// runModel("/data/user/dvalsecc/simple_dnn.pt", cuda); + +// return 0; +// } diff --git a/PhysicsTools/PyTorch/test/testTorchSimpleDnnCUDA.cc b/PhysicsTools/PyTorch/test/testTorchSimpleDnnCUDA.cc new file mode 100644 index 0000000000000..da6bc028c90be --- /dev/null +++ b/PhysicsTools/PyTorch/test/testTorchSimpleDnnCUDA.cc @@ -0,0 +1,82 @@ +#include +#include "testBaseCUDA.h" +#include +#include +#include + + +class testSimpleDNNCUDA : public testBasePyTorchCUDA { + CPPUNIT_TEST_SUITE(testSimpleDNNCUDA); + CPPUNIT_TEST(test); + CPPUNIT_TEST_SUITE_END(); + +public: + void test() override; +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(testSimpleDNNCUDA); + +void testSimpleDNNCUDA::test() { + if (!cms::cudatest::testDevices()) + return; + + std::vector psets; + edm::ServiceToken serviceToken = edm::ServiceRegistry::createSet(psets); + edm::ServiceRegistry::Operate operate(serviceToken); + + // Setup the CUDA Service + edmplugin::PluginManager::configure(edmplugin::standard::config()); + + std::string const config = R"_(import FWCore.ParameterSet.Config as cms +process = cms.Process('Test') +process.add_(cms.Service('ResourceInformationService')) +process.add_(cms.Service('CUDAService')) +)_"; + std::unique_ptr params; + edm::makeParameterSets(config, params); + edm::ServiceToken tempToken(edm::ServiceRegistry::createServicesFromConfig(std::move(params))); + edm::ServiceRegistry::Operate operate2(tempToken); + edm::Service cuda; + std::cout << "CUDA service enabled: " << cuda->enabled() << std::endl; + + std::cout << "Testing CUDA backend" << std::endl; + + + + std::string model_path = testPath_ + "/simple_dnn.pt"; + torch::Device device(torch::kCUDA ); + torch::jit::script::Module module; + try { + // Deserialize the ScriptModule from a file using torch::jit::load(). + module = torch::jit::load(model_path); + module.to(device); + } + catch (const c10::Error& e) { + + std::cerr << "error loading the model\n" << e.what() << std::endl; + } + // Create a vector of inputs. + std::vector inputs; + inputs.push_back(torch::ones(10, device)); + + + // Execute the model and turn its output into a tensor. + at::Tensor output = module.forward(inputs).toTensor(); + std::cout << "output: "<< output << '\n'; + CPPUNIT_ASSERT(output.item() == 110.); + std::cout << "ok\n"; +} + + + +// int main(int argc, const char* argv[]) { +// std::cout << "Running model on CPU" << std::endl; +// torch::Device cpu(torch::kCPU); +// runModel("/data/user/dvalsecc/simple_dnn.pt", cpu); + +// std::cout << "Running model on CUDA" << std::endl; +// torch::Device cuda(torch::kCUDA); +// runModel("/data/user/dvalsecc/simple_dnn.pt", cuda); + +// return 0; +// } diff --git a/PhysicsTools/PyTorch/test/testTorchSimpleDnnCuda.cc b/PhysicsTools/PyTorch/test/testTorchSimpleDnnCuda.cc new file mode 100644 index 0000000000000..da6bc028c90be --- /dev/null +++ b/PhysicsTools/PyTorch/test/testTorchSimpleDnnCuda.cc @@ -0,0 +1,82 @@ +#include +#include "testBaseCUDA.h" +#include +#include +#include + + +class testSimpleDNNCUDA : public testBasePyTorchCUDA { + CPPUNIT_TEST_SUITE(testSimpleDNNCUDA); + CPPUNIT_TEST(test); + CPPUNIT_TEST_SUITE_END(); + +public: + void test() override; +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(testSimpleDNNCUDA); + +void testSimpleDNNCUDA::test() { + if (!cms::cudatest::testDevices()) + return; + + std::vector psets; + edm::ServiceToken serviceToken = edm::ServiceRegistry::createSet(psets); + edm::ServiceRegistry::Operate operate(serviceToken); + + // Setup the CUDA Service + edmplugin::PluginManager::configure(edmplugin::standard::config()); + + std::string const config = R"_(import FWCore.ParameterSet.Config as cms +process = cms.Process('Test') +process.add_(cms.Service('ResourceInformationService')) +process.add_(cms.Service('CUDAService')) +)_"; + std::unique_ptr params; + edm::makeParameterSets(config, params); + edm::ServiceToken tempToken(edm::ServiceRegistry::createServicesFromConfig(std::move(params))); + edm::ServiceRegistry::Operate operate2(tempToken); + edm::Service cuda; + std::cout << "CUDA service enabled: " << cuda->enabled() << std::endl; + + std::cout << "Testing CUDA backend" << std::endl; + + + + std::string model_path = testPath_ + "/simple_dnn.pt"; + torch::Device device(torch::kCUDA ); + torch::jit::script::Module module; + try { + // Deserialize the ScriptModule from a file using torch::jit::load(). + module = torch::jit::load(model_path); + module.to(device); + } + catch (const c10::Error& e) { + + std::cerr << "error loading the model\n" << e.what() << std::endl; + } + // Create a vector of inputs. + std::vector inputs; + inputs.push_back(torch::ones(10, device)); + + + // Execute the model and turn its output into a tensor. + at::Tensor output = module.forward(inputs).toTensor(); + std::cout << "output: "<< output << '\n'; + CPPUNIT_ASSERT(output.item() == 110.); + std::cout << "ok\n"; +} + + + +// int main(int argc, const char* argv[]) { +// std::cout << "Running model on CPU" << std::endl; +// torch::Device cpu(torch::kCPU); +// runModel("/data/user/dvalsecc/simple_dnn.pt", cpu); + +// std::cout << "Running model on CUDA" << std::endl; +// torch::Device cuda(torch::kCUDA); +// runModel("/data/user/dvalsecc/simple_dnn.pt", cuda); + +// return 0; +// }