#ifndef CAFFE2_UTILS_TEST_UTILS_H_ #define CAFFE2_UTILS_TEST_UTILS_H_ #include "caffe2/core/tensor.h" #include "caffe2/core/workspace.h" #include "caffe2/utils/proto_utils.h" #include #include #include #include // Utilities that make it easier to write caffe2 C++ unit tests. // These utils are designed to be concise and easy to use. They may sacrifice // performance and should only be used in tests/non production code. namespace caffe2 { namespace testing { // Asserts that the values of two tensors are the same. CAFFE2_API void assertTensorEquals(const TensorCPU& tensor1, const TensorCPU& tensor2); // Asserts that two float values are close within epsilon. CAFFE2_API void assertNear(float value1, float value2, float epsilon); // Asserts that the numeric values of a tensor is equal to a data vector. template void assertTensorEquals( const TensorCPU& tensor, const std::vector& data, float epsilon = 0.1f) { CAFFE_ENFORCE(tensor.IsType()); CAFFE_ENFORCE_EQ(tensor.numel(), data.size()); for (auto idx = 0; idx < tensor.numel(); ++idx) { if (tensor.IsType()) { assertNear(tensor.data()[idx], data[idx], epsilon); } else { CAFFE_ENFORCE_EQ(tensor.data()[idx], data[idx]); } } } // Assertion for tensor sizes and values. template void assertTensor( const TensorCPU& tensor, const std::vector& sizes, const std::vector& data, float epsilon = 0.1f) { CAFFE_ENFORCE_EQ(tensor.sizes(), sizes); assertTensorEquals(tensor, data, epsilon); } // Asserts a list of tensors presented in two workspaces are equal. CAFFE2_API void assertTensorListEquals( const std::vector& tensorNames, const Workspace& workspace1, const Workspace& workspace2); // Read a tensor from the workspace. CAFFE2_API const caffe2::Tensor& getTensor( const caffe2::Workspace& workspace, const std::string& name); // Create a new tensor in the workspace. CAFFE2_API caffe2::Tensor* createTensor( const std::string& name, caffe2::Workspace* workspace); // Create a new operator in the net. CAFFE2_API caffe2::OperatorDef* createOperator( const std::string& type, const std::vector& inputs, const std::vector& outputs, caffe2::NetDef* net); // Fill data from a vector to a tensor. template void fillTensor( const std::vector& shape, const std::vector& data, TensorCPU* tensor) { tensor->Resize(shape); CAFFE_ENFORCE_EQ(data.size(), tensor->numel()); auto ptr = tensor->mutable_data(); for (int i = 0; i < tensor->numel(); ++i) { ptr[i] = data[i]; } } // Create a tensor and fill data. template caffe2::Tensor* createTensorAndFill( const std::string& name, const std::vector& shape, const std::vector& data, Workspace* workspace) { auto* tensor = createTensor(name, workspace); fillTensor(shape, data, tensor); return tensor; } template caffe2::Tensor createTensorAndFill( const std::vector& shape, const std::vector& data) { Tensor tensor(caffe2::CPU); fillTensor(shape, data, &tensor); return tensor; } // Fill a constant to a tensor. template void constantFillTensor( const vector& shape, const T& data, TensorCPU* tensor) { tensor->Resize(shape); auto ptr = tensor->mutable_data(); for (int i = 0; i < tensor->numel(); ++i) { ptr[i] = data; } } // Create a tensor and fill a constant. template caffe2::Tensor* createTensorAndConstantFill( const std::string& name, const std::vector& shape, const T& data, Workspace* workspace) { auto* tensor = createTensor(name, workspace); constantFillTensor(shape, data, tensor); return tensor; } // Concise util class to mutate a net in a chaining fashion. class CAFFE2_API NetMutator { public: explicit NetMutator(caffe2::NetDef* net) : net_(net) {} NetMutator& newOp( const std::string& type, const std::vector& inputs, const std::vector& outputs); NetMutator& externalInputs(const std::vector& externalInputs); NetMutator& externalOutputs(const std::vector& externalOutputs); // Add argument to the last created op. template NetMutator& addArgument(const std::string& name, const T& value) { CAFFE_ENFORCE(lastCreatedOp_ != nullptr); AddArgument(name, value, lastCreatedOp_); return *this; } // Set device name for the last created op. NetMutator& setDeviceOptionName(const std::string& name); private: caffe2::NetDef* net_; caffe2::OperatorDef* lastCreatedOp_; }; // Concise util class to mutate a workspace in a chaining fashion. class CAFFE2_API WorkspaceMutator { public: explicit WorkspaceMutator(caffe2::Workspace* workspace) : workspace_(workspace) {} // New tensor filled by a data vector. template WorkspaceMutator& newTensor( const std::string& name, const std::vector& shape, const std::vector& data) { createTensorAndFill(name, shape, data, workspace_); return *this; } // New tensor filled by a constant. template WorkspaceMutator& newTensorConst( const std::string& name, const std::vector& shape, const T& data) { createTensorAndConstantFill(name, shape, data, workspace_); return *this; } private: caffe2::Workspace* workspace_; }; } // namespace testing } // namespace caffe2 #endif // CAFFE2_UTILS_TEST_UTILS_H_