## @package device_checker # Module caffe2.python.device_checker import numpy as np import copy from caffe2.python import workspace from caffe2.python.core import InferOpBlobDevicesAsDict from future.utils import viewitems class DeviceChecker(object): """A device checker in Python to check consistency across multiple devices. This is not the most efficient way to check devices, as the Python interface will involve a lot of copies back and forth operations. Use at your own risk. """ def __init__(self, threshold, device_options): self._threshold = threshold self._device_options = device_options def CheckSimple(self, op, inputs, outputs_to_check, input_device_options=None): """Checks the operator with different device implementations. Inputs: op: the operator to be checked. inputs: the input data in numpy arrays. outputs_to_check: the outputs to check between devices. input_device_options: a mapping from input name to a device to use (instead of self._device_options) Outputs: boolean: True if it passes, False if it does not pass. """ op = copy.deepcopy(op) # Entering the checker workspace old_ws_name = workspace.CurrentWorkspace() results = [] workspace.SwitchWorkspace("_device_check_", True) for i, device_option in enumerate(self._device_options): op.device_option.CopyFrom(device_option) _input_device_options = input_device_options or \ InferOpBlobDevicesAsDict(op)[0] print(_input_device_options) for i, arr in enumerate(inputs): workspace.FeedBlob( op.input[i], np.array(arr), _input_device_options.get(op.input[i], device_option) ) workspace.RunOperatorOnce(op) results.append( [workspace.FetchBlob(op.output[idx]) for idx in outputs_to_check]) # Everything is done, reset the workspace. workspace.ResetWorkspace() # After running on all devices, check correctness success = True for i in range(1, len(self._device_options)): for j in range(len(outputs_to_check)): x = results[i][j] y = results[0][j] if not np.allclose(x, y, atol=self._threshold, rtol=self._threshold): print('Failure in checking device option {}' ' and output {}. The outputs are:' .format(i, op.output[outputs_to_check[j]])) print(x.flatten()) print(y.flatten()) print(np.max(np.abs(x - y))) success = False # else: # print ('Passed device pair (0, %d), %s %s' % # (i, outputs_to_check[j], y.shape)) workspace.SwitchWorkspace(old_ws_name) return success def CheckNet(self, net, inputs=None, blobs_to_check=None, ignore=None): """Checks a network by inspecting all of its intermediate results, and see if things match. """ if inputs is None: inputs = {} if ignore is None: ignore = set() old_ws_name = workspace.CurrentWorkspace() results = [] if blobs_to_check is None: blobs_to_check = sum([list(op.output) for op in net.op], []) blobs_to_check = [b for b in blobs_to_check if b not in ignore] workspace.SwitchWorkspace("_device_check_", True) for device_option in self._device_options: for name, arr in viewitems(inputs): # print 'feeding', name workspace.FeedBlob(name, arr, device_option) for op in net.op: op.device_option.CopyFrom(device_option) workspace.RunNetOnce(net) results.append( [workspace.FetchBlob(name) for name in blobs_to_check] ) # After running on all devices, check correctness success = True for i in range(1, len(results)): for j in range(len(blobs_to_check)): x = results[i][j] y = results[0][j] if not np.allclose(x, y, atol=self._threshold, rtol=self._threshold): print('Failure in checking device option {}' ' and output {}. The outputs are:' .format(i, blobs_to_check[j])) print(x.flatten()) print(y.flatten()) print(np.max(np.abs(x - y))) success = False # else: # print ('Passed device pair (%d, %d), %s %s: %s' % # (i, j, blobs_to_check[j], y.shape, # str(y.flatten()))) workspace.SwitchWorkspace(old_ws_name) return success