3
import caffe2.python.fakelowp.init_shared_libs # noqa
5
from hypothesis import given, settings
6
from hypothesis import strategies as st
7
from caffe2.proto import caffe2_pb2
8
from caffe2.python import core
9
from caffe2.python import workspace
10
from caffe2.python.onnx.onnxifi import onnxifi_caffe2_net
11
from caffe2.python.fakelowp.test_utils import print_test_debug_info
12
from caffe2.python.fakelowp.test_utils import compute_ulp_error
13
import caffe2.python.serialized_test.serialized_test_util as serial
15
core.GlobalInit(["caffe2", "--caffe2_log_level=-3", "--glow_global_fp16=1"])
20
class ArithmeticOpsTest(serial.SerializedTestCase):
21
def _test_binary_op_graph(self, name, seed):
23
workspace.ResetWorkspace()
24
# First dimension is the batch size
25
dims = np.concatenate((np.array([1]), np.random.randint(1, 20, size=3)))
26
A = np.random.uniform(low=-100.0, high=100.0, size=dims).astype(np.float32)
27
B = np.random.uniform(low=-100.0, high=100.0, size=dims).astype(np.float32)
29
B[np.abs(B) < 1e-3] = 1e-3
30
print(A.shape, B.shape)
31
pred_net = caffe2_pb2.NetDef()
32
pred_net.name = "pred"
33
pred_net.external_input.extend(["A", "B"])
34
pred_net.external_output.append("C")
35
pred_net.op.add().CopyFrom(
42
pred_net_ref = caffe2_pb2.NetDef()
43
pred_net_ref.name = "ref"
44
pred_net_ref.external_input.extend(["A", "B"])
45
pred_net_ref.external_output.append("C_ref")
46
pred_net_ref.op.add().CopyFrom(
54
shape_hints = {"A": A.shape, "B": B.shape}
55
pred_net_onnxified = onnxifi_caffe2_net(pred_net,
60
print(pred_net_onnxified)
61
num_onnxified_ops = sum(
62
1 if o.type == "Onnxifi" else 0 for o in pred_net_onnxified.op)
63
np.testing.assert_equal(num_onnxified_ops, 1)
64
workspace.SwitchWorkspace("glow_test_ws", True)
65
workspace.FeedBlob("A", A)
66
workspace.FeedBlob("B", B)
68
workspace.CreateNet(pred_net_ref)
69
workspace.CreateNet(pred_net_onnxified)
71
for _ in range(num_iterations):
72
A = np.random.uniform(low=-100.0, high=100.0, size=dims).astype(np.float32)
73
B = np.random.uniform(low=-100.0, high=100.0, size=dims).astype(np.float32)
75
B[np.abs(B) < 1e-3] = 1e-3
77
workspace.FeedBlob("A", A)
78
workspace.FeedBlob("B", B)
80
workspace.RunNet(pred_net_ref.name)
81
Y_c2 = workspace.FetchBlob("C_ref")
84
workspace.RunNet(pred_net_onnxified.name)
85
Y_glow = workspace.FetchBlob("C")
87
Y_glow[Y_glow == np.Inf] = np.finfo(np.float16).max
88
Y_glow[Y_glow == np.NINF] = np.finfo(np.float16).min
90
# Ignore mismatches solely due to difference in precision
91
fp16_finite = np.isfinite(A.astype(np.float16) / B.astype(np.float16))
93
# Results should be identical since we are comparing with the C2 emulation
94
if not np.allclose(Y_c2[fp16_finite], Y_glow[fp16_finite]):
95
diff = np.abs((Y_glow - Y_c2) / (Y_c2 + kEpsilon))
96
print_test_debug_info(name, {
97
"dims": dims, "iter": _, "seed": seed, "A": A, "B": B,
98
"Y_glow": Y_glow, "Y_c2": Y_c2, "diff": diff})
101
@given(seed=st.integers(0, 65534))
102
@settings(deadline=datetime.timedelta(seconds=10))
103
def test_add_graph(self, seed):
104
self._test_binary_op_graph("Add", seed)
106
@given(seed=st.integers(0, 65534))
107
@settings(deadline=datetime.timedelta(seconds=10))
108
def test_sub_graph(self, seed):
109
self._test_binary_op_graph("Sub", seed)
111
@given(seed=st.integers(0, 65534))
112
@settings(deadline=datetime.timedelta(seconds=10))
113
def test_mul_graph(self, seed):
114
self._test_binary_op_graph("Mul", seed)
116
@given(seed=st.integers(0, 65534))
117
@settings(deadline=datetime.timedelta(seconds=10))
118
def test_div_graph(self, seed):
119
self._test_binary_op_graph("Div", seed)
122
class UnaryOpTest(serial.SerializedTestCase):
123
def _test_unary_op(self, opname, X, rtol=1e-5, atol=1e-8):
124
workspace.ResetWorkspace()
126
pred_net = caffe2_pb2.NetDef()
127
pred_net.name = "pred"
128
pred_net.external_input.append("X")
129
pred_net.external_output.append("Y")
130
pred_net.op.add().CopyFrom(
136
ref_net = caffe2_pb2.NetDef()
138
ref_net.external_input.append("X")
139
ref_net.external_output.append("Y")
140
ref_net.op.add().CopyFrom(
142
opname + 'FakeFp16NNPI',
146
print("REF NET = {}".format(ref_net))
148
shape_hints = {"X": X.shape}
149
pred_net_onnxified = onnxifi_caffe2_net(pred_net,
154
num_onnxified_ops = sum(
155
1 if o.type == "Onnxifi" else 0 for o in pred_net_onnxified.op)
156
np.testing.assert_equal(num_onnxified_ops, 1)
157
workspace.SwitchWorkspace("glow_test_ws", True)
158
workspace.FeedBlob("X", X)
159
workspace.CreateNet(ref_net)
160
workspace.CreateNet(pred_net_onnxified)
162
workspace.RunNet(pred_net_onnxified.name)
163
Y_glow = workspace.FetchBlob('Y')
164
# Run caffe2 reference net
165
workspace.RunNet(ref_net.name)
166
Y_c2 = workspace.FetchBlob('Y')
168
if not np.allclose(Y_c2, Y_glow, rtol=atol, atol=atol):
169
diff = np.abs(Y_c2 - Y_glow)
170
np.save('/tmp/' + opname + 'diff', diff)
171
np.save('/tmp/' + opname + 'result', Y_c2)
172
print_test_debug_info(opname, {
182
def _test_op_w_ulp_error(self, seed, opname, regions, atol=0, err_threshold=2):
184
for x0, x1 in regions:
185
X = np.linspace(x0, x1, num=1025, dtype=np.float16).astype(np.float32)
186
Y_glow = self._test_unary_op(opname, X, atol=atol)
187
region_err = compute_ulp_error(opname, X, Y_glow)
188
ulp_err = max(np.max(np.abs(region_err)), ulp_err)
189
if (ulp_err > err_threshold):
190
print(r'{} Op detected ulp_err={}'.format(opname, ulp_err))
193
# These tests doesn't need to run multiple times given that it is a
194
# linear sweep and it is deterministic.
195
# Once hypothesis.testing version is updated, we can re-enable
196
# testing with different hypothesis examples.
197
@given(seed=st.integers(0, 65534))
198
@settings(deadline=datetime.timedelta(seconds=20))
199
def test_sigmoid(self, seed):
202
regions = [[-8., -4.], [-4., -2.], [-2., -1.], [-1., -.5], [-.5, -.25],
203
[-.25, .25], [.25, .5], [.5, 1.], [1., 2.], [2., 4.],
205
self._test_op_w_ulp_error(seed, opname, regions, atol=0, err_threshold=2.5)
207
# These tests doesn't need to run multiple times given that it is a
208
# linear sweep and it is deterministic.
209
# Once hypothesis.testing version is updated, we can re-enable
210
# testing with different hypothesis examples.
211
@given(seed=st.integers(0, 65534))
212
@settings(deadline=datetime.timedelta(seconds=20))
213
def test_tanh(self, seed):
216
regions = [[2.**(-9), 2.**(-8)], [2.**(-8), 2.**(-7)],
217
[2.**(-7), 2.**(-6)], [2.**(-6), 2.**(-5)],
218
[2.**(-5), 2.**(-4)], [2.**(-4), 2.**(-3)],
219
[2.**(-3), 2.**(-2)], [2.**(-2), 2.**(-1)],
220
[2.**(-1), 1.], [1., 2.], [2., 4.], [4., 8.]]
221
self._test_op_w_ulp_error(seed, opname, regions, atol=0, err_threshold=2)
223
# These tests doesn't need to run multiple times given that it is a
224
# linear sweep and it is deterministic.
225
# Once hypothesis.testing version is updated, we can re-enable
226
# testing with different hypothesis examples.
227
# TODO: move atol to 1e-8 once we get a non-lowered swish implementation
228
@given(seed=st.integers(0, 65534))
229
@settings(deadline=datetime.timedelta(seconds=10))
230
def test_swish(self, seed):
233
regions = [[-20.5, -11.], [-11., -8.], [-8., -1.], [-1., -0.1],
234
[-1. / 8., 1. / 8.], [1. / 8, 5.], [5., 8.]]
235
self._test_op_w_ulp_error(seed, opname, regions, atol=0.008, err_threshold=384)
237
# These tests doesn't need to run multiple times given that it is a
238
# linear sweep and it is deterministic.
239
# Once hypothesis.testing version is updated, we can re-enable
240
# testing with different hypothesis examples.
241
@given(seed=st.integers(0, 65534))
242
@settings(deadline=datetime.timedelta(seconds=10))
243
def test_logit(self, seed):
245
workspace.ResetWorkspace()
248
X = np.linspace(0, 1, num=m, dtype=np.float32)
250
pred_net = caffe2_pb2.NetDef()
251
pred_net.name = "pred"
252
pred_net.external_input.append("X")
253
pred_net.external_output.append("Y")
254
pred_net.op.add().CopyFrom(
261
ref_net = caffe2_pb2.NetDef()
263
ref_net.external_input.append("X")
264
ref_net.external_output.append("Y")
265
ref_net.op.add().CopyFrom(
272
print("REF NET = {}".format(ref_net))
274
shape_hints = {"X": (n, m)}
275
pred_net_onnxified = onnxifi_caffe2_net(pred_net,
280
num_onnxified_ops = sum(
281
1 if o.type == "Onnxifi" else 0 for o in pred_net_onnxified.op)
282
np.testing.assert_equal(num_onnxified_ops, 1)
283
workspace.SwitchWorkspace("glow_test_ws", True)
284
workspace.FeedBlob("X", X)
285
workspace.CreateNet(ref_net)
286
workspace.CreateNet(pred_net_onnxified)
288
workspace.RunNet(pred_net_onnxified.name)
289
Y_glow = workspace.FetchBlob('Y')
290
# Run caffe2 reference net
291
workspace.RunNet(ref_net.name)
292
Y_c2 = workspace.FetchBlob('Y')
294
diff = np.abs(Y_c2 - Y_glow)
295
if np.nanmax(diff) > 9e-3:
296
np.save('/tmp/logit_diff', diff)
297
np.save('/tmp/logit_result', Y_c2)
298
print_test_debug_info('Logit', {
306
class ReluTest(serial.SerializedTestCase):
307
@given(seed=st.integers(0, 65534))
308
@settings(deadline=datetime.timedelta(seconds=10))
309
def relu_test(self, inputs, gc, dc, seed):
311
inputs = np.random.rand(1).astype(np.float32)
313
# First dimension is the batch size
315
pred_net = caffe2_pb2.NetDef()
316
pred_net.name = "pred"
317
pred_net.external_input.extend(["X"])
318
pred_net.external_output.append("Y")
319
pred_net.op.add().CopyFrom(
326
pred_net_ref = caffe2_pb2.NetDef()
327
pred_net_ref.name = "ref"
328
pred_net_ref.external_input.extend(["X"])
329
pred_net_ref.external_output.append("Y_ref")
330
pred_net_ref.op.add().CopyFrom(
338
shape_hints = {"X": X.shape}
339
pred_net_onnxified = onnxifi_caffe2_net(pred_net,
344
print(pred_net_onnxified)
345
num_onnxified_ops = sum(
346
1 if o.type == "Onnxifi" else 0 for o in pred_net_onnxified.op)
347
np.testing.assert_equal(num_onnxified_ops, 1)
348
workspace.SwitchWorkspace("glow_test_ws", True)
349
workspace.FeedBlob("X", X)
351
workspace.CreateNet(pred_net_ref)
352
workspace.CreateNet(pred_net_onnxified)
353
workspace.FeedBlob("X", X)
355
workspace.RunNet(pred_net_ref.name)
356
Y_c2 = workspace.FetchBlob("Y_ref")
359
workspace.RunNet(pred_net_onnxified.name)
360
Y_glow = workspace.FetchBlob("Y")
362
# Results should be identical since we are comparing with the C2 emulation
363
if not np.allclose(Y_c2, Y_glow):
364
diff = np.abs((Y_glow - Y_c2) / (Y_c2 + kEpsilon))
365
print_test_debug_info("Relu", {
366
"seed": seed, "X": X,
367
"Y_glow": Y_glow, "Y_c2": Y_c2, "diff": diff})