Skip to content

Commit d3fd066

Browse files
committed
Silence TMVA SOFIE tutorial warnings from third party libraries
Keras and PyTorch still cause some warnings in a few places where they use deprecated features from their dependencies. We need a mechanism to silence these warnings to that our tests will run with warnings as errors, while also making sure we catch when the warnings don't happen anymore, so we can remove the boilerplate code for warnings silencing.
1 parent 5760f78 commit d3fd066

4 files changed

Lines changed: 119 additions & 5 deletions

File tree

tutorials/machine_learning/TMVA_SOFIE_Keras.py

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,37 @@
99
### \author Sanjiban Sengupta and Lorenzo Moneta
1010

1111

12+
import contextlib
13+
import warnings
14+
1215
import ROOT
1316

1417
# Enable ROOT in batch mode (same effect as -nodraw)
1518
ROOT.gROOT.SetBatch(True)
1619

20+
21+
@contextlib.contextmanager
22+
def expect_warning(category, message):
23+
"""Silence a known third-party warning and raise if it stops firing.
24+
25+
Notifies us to drop the workaround once the upstream library is fixed.
26+
"""
27+
with warnings.catch_warnings(record=True) as caught:
28+
warnings.simplefilter("always")
29+
yield
30+
seen = False
31+
for w in caught:
32+
if issubclass(w.category, category) and message in str(w.message):
33+
seen = True
34+
else:
35+
warnings.warn_explicit(w.message, w.category, w.filename, w.lineno)
36+
if not seen:
37+
raise RuntimeError(
38+
f"Expected {category.__name__} containing {message!r} was not "
39+
"emitted. This tutorial's workaround can probably be removed."
40+
)
41+
42+
1743
# -----------------------------------------------------------------------------
1844
# Step 1: Create and train a simple Keras model (via embedded Python)
1945
# -----------------------------------------------------------------------------
@@ -37,7 +63,13 @@
3763

3864
model.compile(loss="mse", optimizer="adam")
3965
model.fit(x_train, y_train, epochs=3, batch_size=2)
40-
model.save("KerasModel.keras")
66+
67+
# Keras' internal ``np.array(x)`` (TensorFlow backend) does not yet implement
68+
# the NumPy 2.0 ``__array__(copy=...)`` signature, so saving the model emits a
69+
# DeprecationWarning that we cannot fix from user code.
70+
with expect_warning(DeprecationWarning, "__array__ implementation doesn't accept a copy keyword"):
71+
model.save("KerasModel.keras")
72+
4173
model.summary()
4274

4375
# -----------------------------------------------------------------------------

tutorials/machine_learning/TMVA_SOFIE_Keras_HiggsModel.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
### \author Lorenzo Moneta
99

1010

11+
import contextlib
12+
import warnings
1113
from os.path import exists
1214

1315
import numpy as np
@@ -16,6 +18,28 @@
1618
from sklearn.model_selection import train_test_split
1719

1820

21+
@contextlib.contextmanager
22+
def expect_warning(category, message):
23+
"""Silence a known third-party warning and raise if it stops firing.
24+
25+
Notifies us to drop the workaround once the upstream library is fixed.
26+
"""
27+
with warnings.catch_warnings(record=True) as caught:
28+
warnings.simplefilter("always")
29+
yield
30+
seen = False
31+
for w in caught:
32+
if issubclass(w.category, category) and message in str(w.message):
33+
seen = True
34+
else:
35+
warnings.warn_explicit(w.message, w.category, w.filename, w.lineno)
36+
if not seen:
37+
raise RuntimeError(
38+
f"Expected {category.__name__} containing {message!r} was not "
39+
"emitted. This tutorial's workaround can probably be removed."
40+
)
41+
42+
1943
def CreateModel(nlayers=4, nunits=64):
2044
input = layers.Input(shape=(7,))
2145
x = input

tutorials/machine_learning/TMVA_SOFIE_Models.py

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,47 @@
1313
### \macro_output
1414
### \author Lorenzo Moneta
1515

16+
import contextlib
1617
import os
18+
import warnings
1719

1820
import numpy as np
1921
import ROOT
2022
from sklearn.model_selection import train_test_split
21-
from tensorflow.keras.layers import Dense
23+
from tensorflow.keras.layers import Dense, Input
2224
from tensorflow.keras.models import Sequential
2325
from tensorflow.keras.optimizers import Adam
2426

27+
28+
@contextlib.contextmanager
29+
def expect_warning(category, message):
30+
"""Silence a known third-party warning. Raise if it stops firing.
31+
32+
Notifies us to drop the workaround once the upstream library is fixed.
33+
"""
34+
with warnings.catch_warnings(record=True) as caught:
35+
warnings.simplefilter("always")
36+
yield
37+
seen = False
38+
for w in caught:
39+
if issubclass(w.category, category) and message in str(w.message):
40+
seen = True
41+
else:
42+
warnings.warn_explicit(w.message, w.category, w.filename, w.lineno)
43+
if not seen:
44+
raise RuntimeError(
45+
f"Expected {category.__name__} containing {message!r} was not "
46+
"emitted. This tutorial's workaround can probably be removed."
47+
)
48+
49+
2550
## generate and train Keras models with different architectures
2651

2752

2853
def CreateModel(nlayers=4, nunits=64):
2954
model = Sequential()
30-
model.add(Dense(nunits, activation="relu", input_dim=7))
55+
model.add(Input(shape=(7,)))
56+
model.add(Dense(nunits, activation="relu"))
3157
for i in range(1, nlayers):
3258
model.add(Dense(nunits, activation="relu"))
3359

@@ -71,7 +97,11 @@ def PrepareData():
7197
def TrainModel(model, x, y, name):
7298
model.fit(x, y, epochs=5, batch_size=50)
7399
modelFile = name + ".keras"
74-
model.save(modelFile)
100+
# Keras' internal ``np.array(x)`` (TensorFlow backend) does not yet
101+
# implement the NumPy 2.0 ``__array__(copy=...)`` signature, so saving
102+
# emits a DeprecationWarning that we cannot fix from user code.
103+
with expect_warning(DeprecationWarning, "__array__ implementation doesn't accept a copy keyword"):
104+
model.save(modelFile)
75105
return modelFile
76106

77107

tutorials/machine_learning/TMVA_SOFIE_ONNX.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,38 @@
1313
## \author Lorenzo Moneta
1414

1515

16+
import contextlib
1617
import inspect
18+
import warnings
1719

1820
import numpy as np
1921
import ROOT
2022
import torch
2123
import torch.nn as nn
2224

2325

26+
@contextlib.contextmanager
27+
def expect_warning(category, message):
28+
"""Silence a known third-party warning and raise if it stops firing.
29+
30+
Notifies us to drop the workaround once the upstream library is fixed.
31+
"""
32+
with warnings.catch_warnings(record=True) as caught:
33+
warnings.simplefilter("always")
34+
yield
35+
seen = False
36+
for w in caught:
37+
if issubclass(w.category, category) and message in str(w.message):
38+
seen = True
39+
else:
40+
warnings.warn_explicit(w.message, w.category, w.filename, w.lineno)
41+
if not seen:
42+
raise RuntimeError(
43+
f"Expected {category.__name__} containing {message!r} was not "
44+
"emitted. This tutorial's workaround can probably be removed."
45+
)
46+
47+
2448
def CreateAndTrainModel(modelName):
2549

2650
model = nn.Sequential(nn.Linear(32, 16), nn.ReLU(), nn.Linear(16, 8), nn.ReLU(), nn.Linear(8, 2), nn.Softmax(dim=1))
@@ -64,7 +88,11 @@ def filtered_kwargs(func, **candidate_kwargs):
6488
print("calling torch.onnx.export with parameters", kwargs)
6589

6690
try:
67-
torch.onnx.export(model, dummy_x, modelFile, **kwargs)
91+
# torch.onnx.export (dynamo path) pickles its export program through
92+
# copyreg, which still references the deprecated LeafSpec. The warning
93+
# is emitted from inside PyTorch and cannot be avoided from user code.
94+
with expect_warning(FutureWarning, "isinstance(treespec, LeafSpec)"):
95+
torch.onnx.export(model, dummy_x, modelFile, **kwargs)
6896
print("model exported to ONNX as", modelFile)
6997
return modelFile
7098
except TypeError:

0 commit comments

Comments
 (0)