Skip to content

Commit f799703

Browse files
committed
[tmva][sofie] Drop NumPy C API dependency from SOFIE parsers
The PyTorch parser and the parser unit tests included `<numpy/arrayobject.h>` and linked against `Python3::NumPy` purely to read tensor shapes and data pointers (`PyArray_NDIM`/`PyArray_DIM`/`PyArray_DATA`). This coupled SOFIE to a specific NumPy ABI at build/link time, even though NumPy is only ever needed at runtime to produce the arrays on the Python side. This commit repaces these uses with the generic CPython API.
1 parent 149cca4 commit f799703

6 files changed

Lines changed: 71 additions & 93 deletions

File tree

cmake/modules/SearchInstalledSoftware.cmake

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,7 @@ if(pyroot AND NOT (tpython OR tmva-pymva))
407407
elseif(tpython OR tmva-pymva)
408408
list(APPEND python_components Development)
409409
endif()
410-
if(tmva-pymva OR tmva-sofie)
410+
if(tmva-pymva)
411411
list(APPEND python_components NumPy)
412412
endif()
413413
find_package(Python3 3.10 COMPONENTS ${python_components})
@@ -1188,7 +1188,7 @@ if(tmva)
11881188
endif()
11891189
endif()
11901190
endif()
1191-
if(tmva-pymva OR tmva-sofie)
1191+
if(tmva-pymva)
11921192
if(fail-on-missing AND (NOT Python3_NumPy_FOUND OR NOT Python3_Development_FOUND))
11931193
message(SEND_ERROR "TMVA: numpy python package or Python development package not found and tmva-pymva component required"
11941194
" (python executable: ${Python3_EXECUTABLE})")

tmva/sofie/test/CMakeLists.txt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,6 @@ if (tpython AND ROOT_TORCH_FOUND AND ROOT_ONNX_FOUND AND BLAS_FOUND AND NOT brok
146146
LIBRARIES
147147
ROOTTMVASofie
148148
TMVA
149-
Python3::NumPy
150149
Python3::Python
151150
BLAS::BLAS
152151
INCLUDE_DIRS
@@ -165,7 +164,6 @@ if (tpython AND ROOT_KERAS_FOUND AND BLAS_FOUND)
165164
ROOT_ADD_GTEST(TestRModelParserKeras TestRModelParserKeras.C
166165
LIBRARIES
167166
ROOTTMVASofie
168-
Python3::NumPy
169167
Python3::Python
170168
BLAS::BLAS
171169
INCLUDE_DIRS

tmva/sofie/test/TestRModelParserKeras.C

Lines changed: 37 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
#include <Python.h>
2-
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
3-
#include <numpy/arrayobject.h>
42

53
#include "gtest/gtest.h"
64
#include <cmath>
5+
#include <vector>
76

87
#include "TSystem.h"
98
#include "TMVA/RSofieReader.hxx"
@@ -21,6 +20,20 @@ const char *PyStringAsString(PyObject *string)
2120
return cstring;
2221
}
2322

23+
// Read a NumPy array bound in the Python namespace into a std::vector<float>.
24+
// The array is flattened to a Python list and read through the generic CPython
25+
// API, so this avoids any dependency on the NumPy C API (arrayobject.h).
26+
std::vector<float> GetTensorValues(PyObject *globalNS, PyObject *localNS, const char *name)
27+
{
28+
std::string code = std::string("outputFlat=") + name + ".flatten().tolist()";
29+
PyRun_String(code.c_str(), Py_single_input, globalNS, localNS);
30+
PyObject *list = PyDict_GetItemString(localNS, "outputFlat");
31+
std::vector<float> values(PyList_Size(list));
32+
for (std::size_t i = 0; i < values.size(); ++i)
33+
values[i] = (float)PyFloat_AsDouble(PyList_GetItem(list, i));
34+
return values;
35+
}
36+
2437
} // namespace
2538

2639
void GenerateModels() {
@@ -78,15 +91,12 @@ TEST(RModelParser_Keras, SEQUENTIAL)
7891
"0.63637339, 0.94483464, 0.11032887, 0.22424818,"
7992
"0.50972592, 0.04671024, 0.39230661, 0.80500943]).reshape(4,8)",Py_single_input,fGlobalNS,fLocalNS);
8093
PyRun_String("output=model(input).numpy()",Py_single_input,fGlobalNS,fLocalNS);
81-
PyRun_String("outputSize=output.size",Py_single_input,fGlobalNS,fLocalNS);
82-
std::size_t pOutputSequentialSize=(std::size_t)PyLong_AsLong(PyDict_GetItemString(fLocalNS,"outputSize"));
94+
std::vector<float> pOutputSequential=GetTensorValues(fGlobalNS,fLocalNS,"output");
95+
std::size_t pOutputSequentialSize=pOutputSequential.size();
8396

8497
//Testing the actual and expected output tensor sizes
8598
EXPECT_EQ(outputSequential.size(), pOutputSequentialSize);
8699

87-
PyArrayObject* pSequentialValues=(PyArrayObject*)PyDict_GetItemString(fLocalNS,"output");
88-
float* pOutputSequential=(float*)PyArray_DATA(pSequentialValues);
89-
90100
//Testing the actual and expected output tensor values
91101
for (size_t i = 0; i < outputSequential.size(); ++i) {
92102
EXPECT_LE(std::abs(outputSequential[i] - pOutputSequential[i]), TOLERANCE);
@@ -124,15 +134,12 @@ TEST(RModelParser_Keras, FUNCTIONAL)
124134
PyRun_String("input=numpy.array([0.60828574, 0.50069386, 0.75186709, 0.14968806, 0.7692464 ,0.77027585, 0.75095316, 0.96651197,"
125135
"0.38536308, 0.95565917, 0.62796356, 0.13818375, 0.65484891,0.89220363, 0.23879365, 0.00635323]).reshape(2,8)",Py_single_input,fGlobalNS,fLocalNS);
126136
PyRun_String("output=model(input).numpy()",Py_single_input,fGlobalNS,fLocalNS);
127-
PyRun_String("outputSize=output.size",Py_single_input,fGlobalNS,fLocalNS);
128-
std::size_t pOutputFunctionalSize=(std::size_t)PyLong_AsLong(PyDict_GetItemString(fLocalNS,"outputSize"));
137+
std::vector<float> pOutputFunctional=GetTensorValues(fGlobalNS,fLocalNS,"output");
138+
std::size_t pOutputFunctionalSize=pOutputFunctional.size();
129139

130140
//Testing the actual and expected output tensor sizes
131141
EXPECT_EQ(outputFunctional.size(), pOutputFunctionalSize);
132142

133-
PyArrayObject* pFunctionalValues=(PyArrayObject*)PyDict_GetItemString(fLocalNS,"output");
134-
float* pOutputFunctional=(float*)PyArray_DATA(pFunctionalValues);
135-
136143
//Testing the actual and expected output tensor values
137144
for (size_t i = 0; i < outputFunctional.size(); ++i) {
138145
EXPECT_LE(std::abs(outputFunctional[i] - pOutputFunctional[i]), TOLERANCE);
@@ -169,15 +176,12 @@ TEST(RModelParser_Keras, BATCH_NORM)
169176
PyRun_String("input=numpy.array([0.22308163, 0.95274901, 0.44712538, 0.84640867,"
170177
"0.69947928, 0.29743695, 0.81379782, 0.39650574]).reshape(2,4)",Py_single_input,fGlobalNS,fLocalNS);
171178
PyRun_String("output=model(input).numpy()",Py_single_input,fGlobalNS,fLocalNS);
172-
PyRun_String("outputSize=output.size",Py_single_input,fGlobalNS,fLocalNS);
173-
std::size_t pOutputBatchNormSize=(std::size_t)PyLong_AsLong(PyDict_GetItemString(fLocalNS,"outputSize"));
179+
std::vector<float> pOutputBatchNorm=GetTensorValues(fGlobalNS,fLocalNS,"output");
180+
std::size_t pOutputBatchNormSize=pOutputBatchNorm.size();
174181

175182
//Testing the actual and expected output tensor sizes
176183
EXPECT_EQ(outputBatchNorm.size(), pOutputBatchNormSize);
177184

178-
PyArrayObject* pBatchNormValues=(PyArrayObject*)PyDict_GetItemString(fLocalNS,"output");
179-
float* pOutputBatchNorm=(float*)PyArray_DATA(pBatchNormValues);
180-
181185
//Testing the actual and expected output tensor values
182186
for (size_t i = 0; i < outputBatchNorm.size(); ++i) {
183187
EXPECT_LE(std::abs(outputBatchNorm[i] - pOutputBatchNorm[i]), TOLERANCE);
@@ -218,15 +222,12 @@ TEST(DISABLED_RModelParser_Keras, CONV_VALID)
218222
PyRun_String("model=load_model('KerasModelConv2D_Valid.keras')",Py_single_input,fGlobalNS,fLocalNS);
219223
PyRun_String("input=numpy.ones((1,4,4,1))",Py_single_input,fGlobalNS,fLocalNS);
220224
PyRun_String("output=model(input).numpy()",Py_single_input,fGlobalNS,fLocalNS);
221-
PyRun_String("outputSize=output.size",Py_single_input,fGlobalNS,fLocalNS);
222-
std::size_t pOutputConv2DValidSize=(std::size_t)PyLong_AsLong(PyDict_GetItemString(fLocalNS,"outputSize"));
225+
std::vector<float> pOutputConv2DValid=GetTensorValues(fGlobalNS,fLocalNS,"output");
226+
std::size_t pOutputConv2DValidSize=pOutputConv2DValid.size();
223227

224228
//Testing the actual and expected output tensor sizes
225229
EXPECT_EQ(outputConv2D_Valid.size(), pOutputConv2DValidSize);
226230

227-
PyArrayObject* pConv2DValidValues=(PyArrayObject*)PyDict_GetItemString(fLocalNS,"output");
228-
float* pOutputConv2DValid=(float*)PyArray_DATA(pConv2DValidValues);
229-
230231
//Testing the actual and expected output tensor values
231232
for (size_t i = 0; i < outputConv2D_Valid.size(); ++i) {
232233
EXPECT_LE(std::abs(outputConv2D_Valid[i] - pOutputConv2DValid[i]), TOLERANCE);
@@ -268,15 +269,12 @@ TEST(DISABLED_RModelParser_Keras, CONV_SAME)
268269
PyRun_String("model=load_model('KerasModelConv2D_Same.keras')",Py_single_input,fGlobalNS,fLocalNS);
269270
PyRun_String("input=numpy.ones((1,4,4,1))",Py_single_input,fGlobalNS,fLocalNS);
270271
PyRun_String("output=model(input).numpy()",Py_single_input,fGlobalNS,fLocalNS);
271-
PyRun_String("outputSize=output.size",Py_single_input,fGlobalNS,fLocalNS);
272-
std::size_t pOutputConv2DSameSize=(std::size_t)PyLong_AsLong(PyDict_GetItemString(fLocalNS,"outputSize"));
272+
std::vector<float> pOutputConv2DSame=GetTensorValues(fGlobalNS,fLocalNS,"output");
273+
std::size_t pOutputConv2DSameSize=pOutputConv2DSame.size();
273274

274275
//Testing the actual and expected output tensor sizes
275276
EXPECT_EQ(outputConv2D_Same.size(), pOutputConv2DSameSize);
276277

277-
PyArrayObject* pConv2DSameValues=(PyArrayObject*)PyDict_GetItemString(fLocalNS,"output");
278-
float* pOutputConv2DSame=(float*)PyArray_DATA(pConv2DSameValues);
279-
280278
//Testing the actual and expected output tensor values
281279
for (size_t i = 0; i < outputConv2D_Same.size(); ++i) {
282280
EXPECT_LE(std::abs(outputConv2D_Same[i] - pOutputConv2DSame[i]), TOLERANCE);
@@ -314,15 +312,12 @@ TEST(RModelParser_Keras, RESHAPE)
314312
PyRun_String("model=load_model('KerasModelReshape.keras')",Py_single_input,fGlobalNS,fLocalNS);
315313
PyRun_String("input=numpy.ones((1,4,4,1))",Py_single_input,fGlobalNS,fLocalNS);
316314
PyRun_String("output=model(input).numpy()",Py_single_input,fGlobalNS,fLocalNS);
317-
PyRun_String("outputSize=output.size",Py_single_input,fGlobalNS,fLocalNS);
318-
std::size_t pOutputReshapeSize=(std::size_t)PyLong_AsLong(PyDict_GetItemString(fLocalNS,"outputSize"));
315+
std::vector<float> pOutputReshape=GetTensorValues(fGlobalNS,fLocalNS,"output");
316+
std::size_t pOutputReshapeSize=pOutputReshape.size();
319317

320318
//Testing the actual and expected output tensor sizes
321319
EXPECT_EQ(outputReshape.size(), pOutputReshapeSize);
322320

323-
PyArrayObject* pReshapeValues=(PyArrayObject*)PyDict_GetItemString(fLocalNS,"output");
324-
float* pOutputReshape=(float*)PyArray_DATA(pReshapeValues);
325-
326321
//Testing the actual and expected output tensor values
327322
for (size_t i = 0; i < outputReshape.size(); ++i) {
328323
EXPECT_LE(std::abs(outputReshape[i] - pOutputReshape[i]), TOLERANCE);
@@ -359,14 +354,12 @@ TEST(RModelParser_Keras, CONCATENATE)
359354
PyRun_String("input_1=numpy.ones((1,2))",Py_single_input,fGlobalNS,fLocalNS);
360355
PyRun_String("input_2=numpy.ones((1,2))",Py_single_input,fGlobalNS,fLocalNS);
361356
PyRun_String("output=model([input_1,input_2]).numpy()",Py_single_input,fGlobalNS,fLocalNS);
362-
PyRun_String("outputSize=output.size",Py_single_input,fGlobalNS,fLocalNS);
363-
long pOutputConcatenateSize=PyLong_AsLong(PyDict_GetItemString(fLocalNS,"outputSize"));
357+
std::vector<float> pOutputConcatenate=GetTensorValues(fGlobalNS,fLocalNS,"output");
358+
long pOutputConcatenateSize=(long)pOutputConcatenate.size();
364359

365360
//Testing the actual and expected output tensor sizes (can fail if an error eccoured and returns a -1 from Python)
366361
EXPECT_EQ((long) outputConcatenate.size(), pOutputConcatenateSize);
367362

368-
PyArrayObject* pConcatenateValues=(PyArrayObject*)PyDict_GetItemString(fLocalNS,"output");
369-
float* pOutputConcatenate=(float*)PyArray_DATA(pConcatenateValues);
370363

371364
//Testing the actual and expected output tensor values
372365
for (size_t i = 0; i < outputConcatenate.size(); ++i) {
@@ -405,14 +398,12 @@ TEST(RModelParser_Keras, BINARY_OP)
405398
PyRun_String("input1=numpy.array([[1,2],[3,4]],dtype='float32')",Py_single_input,fGlobalNS,fLocalNS);
406399
PyRun_String("input2=numpy.array([[5,6],[7,8]],dtype='float32')",Py_single_input,fGlobalNS,fLocalNS);
407400
PyRun_String("output=model([input1,input2]).numpy()",Py_single_input,fGlobalNS,fLocalNS);
408-
PyRun_String("outputSize=output.size",Py_single_input,fGlobalNS,fLocalNS);
409-
long pOutputBinaryOpSize=PyLong_AsLong(PyDict_GetItemString(fLocalNS,"outputSize"));
401+
std::vector<float> pOutputBinaryOp=GetTensorValues(fGlobalNS,fLocalNS,"output");
402+
long pOutputBinaryOpSize=(long)pOutputBinaryOp.size();
410403

411404
//Testing the actual and expected output tensor sizes
412405
EXPECT_EQ((long) outputBinaryOp.size(), pOutputBinaryOpSize);
413406

414-
PyArrayObject* pBinaryOpValues=(PyArrayObject*)PyDict_GetItemString(fLocalNS,"output");
415-
float* pOutputBinaryOp=(float*)PyArray_DATA(pBinaryOpValues);
416407

417408
//Testing the actual and expected output tensor values
418409
for (size_t i = 0; i < outputBinaryOp.size(); ++i) {
@@ -448,15 +439,12 @@ TEST(RModelParser_Keras, ACTIVATIONS)
448439
PyRun_String("model=load_model('KerasModelActivations.keras')",Py_single_input,fGlobalNS,fLocalNS);
449440
PyRun_String("input=numpy.ones((1,8))",Py_single_input,fGlobalNS,fLocalNS);
450441
PyRun_String("output=model(input).numpy()",Py_single_input,fGlobalNS,fLocalNS);
451-
PyRun_String("outputSize=output.size",Py_single_input,fGlobalNS,fLocalNS);
452-
std::size_t pOutputActivationsSize=(std::size_t)PyLong_AsLong(PyDict_GetItemString(fLocalNS,"outputSize"));
442+
std::vector<float> pOutputActivations=GetTensorValues(fGlobalNS,fLocalNS,"output");
443+
std::size_t pOutputActivationsSize=pOutputActivations.size();
453444

454445
//Testing the actual and expected output tensor sizes
455446
EXPECT_EQ(outputActivations.size(), pOutputActivationsSize);
456447

457-
PyArrayObject* pActivationsValues=(PyArrayObject*)PyDict_GetItemString(fLocalNS,"output");
458-
float* pOutputActivations=(float*)PyArray_DATA(pActivationsValues);
459-
460448
//Testing the actual and expected output tensor values
461449
for (size_t i = 0; i < outputActivations.size(); ++i) {
462450
EXPECT_LE(std::abs(outputActivations[i] - pOutputActivations[i]), TOLERANCE);
@@ -491,15 +479,12 @@ TEST(RModelParser_Keras, SWISH)
491479
PyRun_String("model=load_model('KerasModelSwish.keras')",Py_single_input,fGlobalNS,fLocalNS);
492480
PyRun_String("input=numpy.ones((1,8))",Py_single_input,fGlobalNS,fLocalNS);
493481
PyRun_String("output=model(input).numpy()",Py_single_input,fGlobalNS,fLocalNS);
494-
PyRun_String("outputSize=output.size",Py_single_input,fGlobalNS,fLocalNS);
495-
std::size_t pOutputSize=(std::size_t)PyLong_AsLong(PyDict_GetItemString(fLocalNS,"outputSize"));
482+
std::vector<float> pOutput=GetTensorValues(fGlobalNS,fLocalNS,"output");
483+
std::size_t pOutputSize=pOutput.size();
496484

497485
//Testing the actual and expected output tensor sizes
498486
EXPECT_EQ(output.size(), pOutputSize);
499487

500-
PyArrayObject* pValues=(PyArrayObject*)PyDict_GetItemString(fLocalNS,"output");
501-
float* pOutput=(float*)PyArray_DATA(pValues);
502-
503488
//Testing the actual and expected output tensor values
504489
for (size_t i = 0; i < output.size(); ++i) {
505490
EXPECT_LE(std::abs(output[i] - pOutput[i]), TOLERANCE);
@@ -537,8 +522,8 @@ TEST(RModel, CUSTOM_OP)
537522
PyRun_String("model.add(Lambda(lambda x: x * 2))",Py_single_input,fGlobalNS,fLocalNS);
538523
PyRun_String("input=numpy.array([1,1,1,1,1,1,1,1]).reshape(1,8)",Py_single_input,fGlobalNS,fLocalNS);
539524
PyRun_String("output=model(input).numpy()",Py_single_input,fGlobalNS,fLocalNS);
540-
PyRun_String("outputSize=output.size",Py_single_input,fGlobalNS,fLocalNS);
541-
std::size_t pOutputCustomOpSize=(std::size_t)PyLong_AsLong(PyDict_GetItemString(fLocalNS,"outputSize"));
525+
std::vector<float> pOutputCustomOp=GetTensorValues(fGlobalNS,fLocalNS,"output");
526+
std::size_t pOutputCustomOpSize=pOutputCustomOp.size();
542527

543528
// get input name for custom (it is output of one before last)
544529
PyRun_String("outputName = model.get_layer(index=len(model.layers)-2).output.name",Py_single_input,fGlobalNS,fLocalNS);
@@ -557,9 +542,6 @@ TEST(RModel, CUSTOM_OP)
557542
//Testing the actual and expected output tensor sizes
558543
EXPECT_EQ(outputCustomOp.size(), pOutputCustomOpSize);
559544

560-
PyArrayObject* pCustomOpValues=(PyArrayObject*)PyDict_GetItemString(fLocalNS,"output");
561-
float* pOutputCustomOp=(float*)PyArray_DATA(pCustomOpValues);
562-
563545
//Testing the actual and expected output tensor values
564546
for (size_t i = 0; i < outputCustomOp.size(); ++i) {
565547
EXPECT_LE(std::abs(outputCustomOp[i] - pOutputCustomOp[i]), TOLERANCE);

tmva/sofie/test/TestRModelParserPyTorch.C

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44

55
#include <Python.h>
66
#include "TSystem.h"
7-
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
8-
#include <numpy/arrayobject.h>
97

108
#include "gtest/gtest.h"
119
#include <cmath>
@@ -60,18 +58,17 @@ TEST(RModelParser_PyTorch, SEQUENTIAL_MODEL)
6058
"-0.7750, -1.6701,"
6159
" 0.8171, -0.2858]),(2,4))",Py_single_input,fGlobalNS,fLocalNS);
6260
PyRun_String("output=model(input).detach().numpy().reshape(2,6)",Py_single_input,fGlobalNS,fLocalNS);
63-
PyRun_String("outputSize=output.size",Py_single_input,fGlobalNS,fLocalNS);
64-
std::size_t pOutputSequentialSize=(std::size_t)PyLong_AsLong(PyDict_GetItemString(fLocalNS,"outputSize"));
61+
PyRun_String("outputFlat=output.flatten().tolist()",Py_single_input,fGlobalNS,fLocalNS);
62+
PyObject* pSequentialValues=PyDict_GetItemString(fLocalNS,"outputFlat");
63+
std::size_t pOutputSequentialSize=(std::size_t)PyList_Size(pSequentialValues);
6564

6665
//Testing the actual and expected output tensor sizes
6766
EXPECT_EQ(outputSequential.size(), pOutputSequentialSize);
6867

69-
PyArrayObject* pSequentialValues=(PyArrayObject*)PyDict_GetItemString(fLocalNS,"output");
70-
float* pOutputSequential=(float*)PyArray_DATA(pSequentialValues);
71-
7268
//Testing the actual and expected output tensor values
7369
for (size_t i = 0; i < outputSequential.size(); ++i) {
74-
EXPECT_LE(std::abs(outputSequential[i] - pOutputSequential[i]), TOLERANCE);
70+
float pOutputSequential=(float)PyFloat_AsDouble(PyList_GetItem(pSequentialValues, i));
71+
EXPECT_LE(std::abs(outputSequential[i] - pOutputSequential), TOLERANCE);
7572
}
7673

7774
}
@@ -114,18 +111,17 @@ TEST(RModelParser_PyTorch, MODULE_MODEL)
114111
"-1.8818, 0.4736,"
115112
" 1.1102, 1.8694]),(2,6))",Py_single_input,fGlobalNS,fLocalNS);
116113
PyRun_String("output=model(input).detach().numpy().reshape(2,12)",Py_single_input,fGlobalNS,fLocalNS);
117-
PyRun_String("outputSize=output.size",Py_single_input,fGlobalNS,fLocalNS);
118-
std::size_t pOutputModuleSize=(std::size_t)PyLong_AsLong(PyDict_GetItemString(fLocalNS,"outputSize"));
114+
PyRun_String("outputFlat=output.flatten().tolist()",Py_single_input,fGlobalNS,fLocalNS);
115+
PyObject* pModuleValues=PyDict_GetItemString(fLocalNS,"outputFlat");
116+
std::size_t pOutputModuleSize=(std::size_t)PyList_Size(pModuleValues);
119117

120118
//Testing the actual and expected output tensor sizes
121119
EXPECT_EQ(outputModule.size(), pOutputModuleSize);
122120

123-
PyArrayObject* pModuleValues=(PyArrayObject*)PyDict_GetItemString(fLocalNS,"output");
124-
float* pOutputModule=(float*)PyArray_DATA(pModuleValues);
125-
126121
//Testing the actual and expected output tensor values
127122
for (size_t i = 0; i < outputModule.size(); ++i) {
128-
EXPECT_LE(std::abs(outputModule[i] - pOutputModule[i]), TOLERANCE);
123+
float pOutputModule=(float)PyFloat_AsDouble(PyList_GetItem(pModuleValues, i));
124+
EXPECT_LE(std::abs(outputModule[i] - pOutputModule), TOLERANCE);
129125
}
130126
}
131127

@@ -158,17 +154,16 @@ TEST(RModelParser_PyTorch, CONVOLUTION_MODEL)
158154
PyRun_String("model=torch.jit.load('PyTorchModelConvolution.pt')",Py_single_input,fGlobalNS,fLocalNS);
159155
PyRun_String("input=torch.arange(1,751,dtype=torch.float).reshape(5,6,5,5)",Py_single_input,fGlobalNS,fLocalNS);
160156
PyRun_String("output=model(input).detach().numpy().reshape(5,5,2,2)",Py_single_input,fGlobalNS,fLocalNS);
161-
PyRun_String("outputSize=output.size",Py_single_input,fGlobalNS,fLocalNS);
162-
std::size_t pOutputConvSize=(std::size_t)PyLong_AsLong(PyDict_GetItemString(fLocalNS,"outputSize"));
157+
PyRun_String("outputFlat=output.flatten().tolist()",Py_single_input,fGlobalNS,fLocalNS);
158+
PyObject* pConvValues=PyDict_GetItemString(fLocalNS,"outputFlat");
159+
std::size_t pOutputConvSize=(std::size_t)PyList_Size(pConvValues);
163160

164161
//Testing the actual and expected output tensor sizes
165162
EXPECT_EQ(outputConv.size(), pOutputConvSize);
166163

167-
PyArrayObject* pConvValues=(PyArrayObject*)PyDict_GetItemString(fLocalNS,"output");
168-
float* pOutputConv=(float*)PyArray_DATA(pConvValues);
169-
170164
//Testing the actual and expected output tensor values
171165
for (size_t i = 0; i < outputConv.size(); ++i) {
172-
EXPECT_LE(std::abs(outputConv[i] - pOutputConv[i]), TOLERANCE);
166+
float pOutputConv=(float)PyFloat_AsDouble(PyList_GetItem(pConvValues, i));
167+
EXPECT_LE(std::abs(outputConv[i] - pOutputConv), TOLERANCE);
173168
}
174169
}

tmva/sofie_parsers/CMakeLists.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,6 @@ ROOT_LINKER_LIBRARY(ROOTTMVASofiePyParsers
9494
src/RModelParser_Keras.cxx
9595
src/RModelParser_PyTorch.cxx
9696
LIBRARIES
97-
Python3::NumPy
9897
Python3::Python
9998
ROOTTMVASofie
10099
)

0 commit comments

Comments
 (0)