Skip to content

Commit 6c3b5c3

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. (cherry picked from commit f799703)
1 parent efe3e59 commit 6c3b5c3

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
@@ -413,7 +413,7 @@ if(pyroot AND NOT (tpython OR tmva-pymva))
413413
elseif(tpython OR tmva-pymva)
414414
list(APPEND python_components Development)
415415
endif()
416-
if(tmva-pymva OR tmva-sofie)
416+
if(tmva-pymva)
417417
list(APPEND python_components NumPy)
418418
endif()
419419
find_package(Python3 3.10 COMPONENTS ${python_components})
@@ -1378,7 +1378,7 @@ if(tmva)
13781378
endif()
13791379
endif()
13801380
endif()
1381-
if(tmva-pymva OR tmva-sofie)
1381+
if(tmva-pymva)
13821382
if(fail-on-missing AND (NOT Python3_NumPy_FOUND OR NOT Python3_Development_FOUND))
13831383
message(SEND_ERROR "TMVA: numpy python package or Python development package not found and tmva-pymva component required"
13841384
" (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)