20
20
21
21
import numpy as np
22
22
import pytest
23
+ from unittest .mock import patch
23
24
24
25
from art .attacks .poisoning .one_pixel_shortcut_attack import OnePixelShortcutAttack
25
- from unittest .mock import patch
26
26
from tests .utils import ARTTestException
27
27
28
28
logger = logging .getLogger (__name__ )
29
29
30
30
31
+ @pytest .mark .framework_agnostic
31
32
def test_one_pixel_per_image_and_label_preservation ():
32
33
try :
33
34
x = np .zeros ((4 , 3 , 3 ))
@@ -49,6 +50,7 @@ def test_one_pixel_per_image_and_label_preservation():
49
50
raise ARTTestException ("Pixel change or label consistency check failed" ) from e
50
51
51
52
53
+ @pytest .mark .framework_agnostic
52
54
def test_missing_labels_raises_error ():
53
55
try :
54
56
x = np .zeros ((3 , 5 , 5 ))
@@ -59,6 +61,7 @@ def test_missing_labels_raises_error():
59
61
raise ARTTestException ("Expected error not raised for missing labels" ) from e
60
62
61
63
64
+ @pytest .mark .framework_agnostic
62
65
def test_multi_channel_consistency ():
63
66
try :
64
67
x = np .zeros ((2 , 2 , 2 , 3 ))
@@ -82,6 +85,7 @@ def test_multi_channel_consistency():
82
85
raise ARTTestException ("Multi-channel image consistency check failed" ) from e
83
86
84
87
88
+ @pytest .mark .only_with_platform ("pytorch" )
85
89
def test_one_pixel_effect_with_pytorchclassifier ():
86
90
try :
87
91
import torch
@@ -92,11 +96,11 @@ def test_one_pixel_effect_with_pytorchclassifier():
92
96
np .random .seed (0 )
93
97
94
98
# Create a toy dataset: 2x2 grayscale images, 2 classes
95
- X = np .zeros ((8 , 1 , 2 , 2 ), dtype = np .float32 )
99
+ x = np .zeros ((8 , 1 , 2 , 2 ), dtype = np .float32 )
96
100
for i in range (4 ):
97
- X [i , 0 , 0 , 0 ] = i * 0.25 # class 0
101
+ x [i , 0 , 0 , 0 ] = i * 0.25 # class 0
98
102
for i in range (4 , 8 ):
99
- X [i , 0 , 0 , 1 ] = (i - 4 ) * 0.25 # class 1
103
+ x [i , 0 , 0 , 1 ] = (i - 4 ) * 0.25 # class 1
100
104
y = np .array ([0 , 0 , 0 , 0 , 1 , 1 , 1 , 1 ])
101
105
102
106
model_clean = nn .Sequential (nn .Flatten (), nn .Linear (4 , 2 ))
@@ -114,7 +118,7 @@ def test_one_pixel_effect_with_pytorchclassifier():
114
118
acc_clean = np .mean (preds_clean .argmax (axis = 1 ) == y )
115
119
116
120
ops_attack = OnePixelShortcutAttack ()
117
- X_poison , y_poison = ops_attack .poison (X .copy (), y .copy ())
121
+ x_poison , y_poison = ops_attack .poison (X .copy (), y .copy ())
118
122
119
123
model_poisoned = nn .Sequential (nn .Flatten (), nn .Linear (4 , 2 ))
120
124
classifier_poisoned = PyTorchClassifier (
@@ -125,24 +129,25 @@ def test_one_pixel_effect_with_pytorchclassifier():
125
129
nb_classes = 2 ,
126
130
)
127
131
classifier_poisoned .fit (
128
- X_poison ,
132
+ x_poison ,
129
133
y_poison ,
130
134
nb_epochs = 10 ,
131
135
batch_size = 4 ,
132
136
verbose = 0 ,
133
137
)
134
- preds_poisoned = classifier_poisoned .predict (X_poison )
138
+ preds_poisoned = classifier_poisoned .predict (x_poison )
135
139
acc_poisoned = np .mean (preds_poisoned .argmax (axis = 1 ) == y_poison )
136
140
137
141
# Adjusted assertions for robustness
138
- assert acc_poisoned > = 1.0 , f"Expected 100% poisoned accuracy, got { acc_poisoned :.3f} "
142
+ assert acc_poisoned = = 1.0 , f"Expected 100% poisoned accuracy, got { acc_poisoned :.3f} "
139
143
assert acc_clean < 0.95 , f"Expected clean accuracy < 95%, got { acc_clean :.3f} "
140
144
141
145
except Exception as e :
142
146
logger .warning ("test_one_pixel_effect_with_pytorchclassifier failed: %s" , e )
143
147
raise ARTTestException ("PyTorchClassifier integration with OPS attack failed" ) from e
144
148
145
149
150
+ @pytest .mark .framework_agnostic
146
151
def test_check_params_noop ():
147
152
try :
148
153
attack = OnePixelShortcutAttack ()
@@ -154,6 +159,7 @@ def test_check_params_noop():
154
159
raise ARTTestException ("Parameter check method failed unexpectedly" ) from e
155
160
156
161
162
+ @pytest .mark .framework_agnostic
157
163
def test_ambiguous_layout_nhwc ():
158
164
try :
159
165
# Shape (N=1, H=3, W=2, C=3) - ambiguous, both 3 could be channels
@@ -173,6 +179,7 @@ def test_ambiguous_layout_nhwc():
173
179
raise ARTTestException ("Ambiguous NHWC layout handling failed" ) from e
174
180
175
181
182
+ @pytest .mark .framework_agnostic
176
183
def test_ambiguous_layout_nchw ():
177
184
try :
178
185
# Shape (N=1, C=2, H=3, W=2) - ambiguous, no dim equals 1/3/4
@@ -192,6 +199,7 @@ def test_ambiguous_layout_nchw():
192
199
raise ARTTestException ("Ambiguous NCHW layout handling failed" ) from e
193
200
194
201
202
+ @pytest .mark .framework_agnostic
195
203
def test_unsupported_input_shape_raises_error ():
196
204
try :
197
205
x = np .zeros ((5 , 5 ), dtype = np .float32 ) # 2D input (unsupported)
@@ -203,6 +211,7 @@ def test_unsupported_input_shape_raises_error():
203
211
raise ARTTestException ("ValueError not raised for unsupported input shape" ) from e
204
212
205
213
214
+ @pytest .mark .framework_agnostic
206
215
def test_one_hot_labels_preserve_format ():
207
216
try :
208
217
# Two 2x2 grayscale images, with one-hot labels for classes 0 and 1
@@ -221,6 +230,7 @@ def test_one_hot_labels_preserve_format():
221
230
raise ARTTestException ("One-hot label handling failed" ) from e
222
231
223
232
233
+ @pytest .mark .framework_agnostic
224
234
def test_class_skipping_when_no_samples ():
225
235
try :
226
236
# Small dataset: 1 image 2x2, class 0
0 commit comments