class ModelOpenVINO(object):
    def __init__(self,
                 xml_file_path,
                 bin_file_path=None,
                 mapping_file_path=None,
                 device='CPU',
                 required_inputs=None,
                 required_outputs=None,
                 max_num_requests=1,
                 collect_perf_counters=False,
                 cfg=None,
                 classes=None):

        from openvino.inference_engine import IENetwork

        ie = IECore()
        logging.info('Reading network from IR...')
        if bin_file_path is None:
            bin_file_path = osp.splitext(xml_file_path)[0] + '.bin'
        if mapping_file_path is None:
            mapping_file_path = osp.splitext(xml_file_path)[0] + '.mapping'

        self.net = IENetwork(model=xml_file_path, weights=bin_file_path)

        self.orig_ir_mapping = self.get_mapping(mapping_file_path)
        self.ir_orig_mapping = {v: k for k, v in self.orig_ir_mapping.items()}

        self.net_inputs_mapping = OrderedDict({})
        self.net_outputs_mapping = OrderedDict({})
        self.configure_inputs(required_inputs)
        self.configure_outputs(required_outputs)

        if 'CPU' in device:
            self.check_cpu_support(ie, self.net)

        logging.info('Loading network to plugin...')
        self.max_num_requests = max_num_requests
        self.exec_net = ie.load_network(network=self.net,
                                        device_name=device,
                                        num_requests=max_num_requests)

        self.perf_counters = None
        if collect_perf_counters:
            self.perf_counters = PerformanceCounters()

        self.pt_model = None
        if cfg is not None:
            self.pt_model = build_detector(cfg.model,
                                           train_cfg=None,
                                           test_cfg=cfg.test_cfg)
            if classes is not None:
                self.pt_model.CLASSES = classes

    @staticmethod
    def check_cpu_support(ie, net):
        logging.info('Check that all layers are supported...')
        supported_layers = ie.query_network(net, 'CPU')
        not_supported_layers = [
            l for l in net.layers.keys() if l not in supported_layers
        ]
        if len(not_supported_layers) != 0:
            unsupported_info = '\n\t'.join(
                '{} ({} with params {})'.format(
                    layer_id, net.layers[layer_id].type,
                    str(net.layers[layer_id].params))
                for layer_id in not_supported_layers)
            logging.warning(
                'Following layers are not supported '
                'by the CPU plugin:\n\t{}'.format(unsupported_info))
            logging.warning(
                'Please try to specify cpu extensions library path.')
            raise ValueError('Some of the layers are not supported.')

    def get_mapping(self, mapping_file_path=None):
        mapping = {}
        if mapping_file_path is not None:
            logging.info('Loading mapping file...')
            root = etree.parse(mapping_file_path).getroot()
            for m in root:
                if m.tag != 'map':
                    continue
                framework = m.find('framework')
                ir = m.find('IR')
                framework_name = framework.get('name')
                ir_name = ir.get('name')
                mapping[framework_name] = ir_name
                if framework_name != ir_name:
                    # FIXME. This may not be correct for all operations.
                    mapping[framework_name] += '.0'
        return mapping

    def try_add_extra_outputs(self, extra_outputs):
        if extra_outputs is None:
            return
        for extra_output in extra_outputs:
            if extra_output not in self.orig_ir_mapping:
                continue
            ir_name = self.orig_ir_mapping[extra_output]
            try:
                self.net.add_outputs(ir_name)
            except RuntimeError:
                pass

    def configure_inputs(self, required):
        self.net_inputs_mapping = OrderedDict(
            (i, i) for i in self.net.inputs.keys())
        self.check_required(self.net_inputs_mapping.keys(), required)

    def configure_outputs(self, required):
        self.try_add_extra_outputs(required)
        self.net_outputs_mapping = OrderedDict(
            (i, self.ir_orig_mapping[i]) for i in self.net.outputs.keys())
        self.check_required(self.orig_ir_mapping.keys(), required)

    def set_outputs(self, outputs):
        self.check_required(self.orig_ir_mapping.keys(), outputs)
        self.net_outputs_mapping = OrderedDict(
            (self.orig_ir_mapping[i], i) for i in outputs)

    @staticmethod
    def check_required(available, required):
        if required is None:
            return
        for x in required:
            if x not in available:
                raise ValueError(
                    f'Failed to identify data blob with name "{x}"')

    def rename_outputs(self, outputs):
        return {
            self.net_outputs_mapping[k]: v
            for k, v in outputs.items() if k in self.net_outputs_mapping
        }

    def unify_inputs(self, inputs):
        if not isinstance(inputs, dict):
            if len(self.net_inputs_mapping) == 1 and not isinstance(
                    inputs, (list, tuple)):
                inputs = [inputs]
            inputs = {
                k: v
                for (k, _), v in zip(self.net_inputs_mapping.items(), inputs)
            }
        inputs = {self.net_inputs_mapping[k]: v for k, v in inputs.items()}
        return inputs

    def __call__(self, inputs):
        inputs = self.unify_inputs(inputs)
        outputs = self.exec_net.infer(inputs)
        if self.perf_counters:
            perf_counters = self.exec_net.requests[0].get_perf_counts()
            self.perf_counters.update(perf_counters)
        return self.rename_outputs(outputs)

    def print_performance_counters(self):
        if self.perf_counters:
            self.perf_counters.print()

    def show(self, data, result, dataset=None, score_thr=0.3, wait_time=0):
        if self.pt_model is not None:
            self.pt_model.show_result(data,
                                      result,
                                      dataset=dataset,
                                      score_thr=score_thr,
                                      wait_time=wait_time)
Exemple #2
0
def main():
    colormap = 'viridis'
    job_id = os.environ['PBS_JOBID']
    job_id = job_id.rstrip().split('.')[0]
    log.basicConfig(format="[ %(levelname)s ] %(message)s",
                    level=log.INFO,
                    stream=sys.stdout)
    args = build_argparser().parse_args()
    model_xml = args.model
    model_bin = os.path.splitext(model_xml)[0] + ".bin"
    log.info("Loading network files:\n\t{}\n\t{}".format(model_xml, model_bin))
    device = args.device

    fp16 = True
    if device == "CPU":
        fp16 = False

    # Plugin initialization for specified device and load extensions library if specified
    plugin = IEPlugin(device=device)

    # Read IR
    net = IENetwork(model=model_xml, weights=model_bin)

    assert len(
        net.inputs.keys()) == 1, "Sample supports only single input topologies"

    bn = "relu_1/Relu"
    print(bn)
    # add the last convolutional layer as output
    net.add_outputs(bn)
    fc = "predictions_1/MatMul"

    # name of the inputs and outputs
    input_blob = next(iter(net.inputs))
    out_blob = "predictions_1/Sigmoid"

    net.batch_size = 1

    exec_net = plugin.load(network=net)

    n, c, h, w = net.inputs[input_blob].shape
    print("Current Directory:", os.getcwd())
    files = glob.glob(os.getcwd() + args.input[0])

    if not os.path.isdir(args.output_dir):
        os.makedirs(args.output_dir, exist_ok=True)
    f = open(os.path.join(args.output_dir, job_id, 'result.txt'), 'w')
    progress_file_path = os.path.join(args.output_dir, job_id,
                                      "i_progress.txt")
    print(progress_file_path)
    time_images = []
    tstart = time.time()
    for index_f, file in enumerate(files):
        [image1, image] = read_image(file)
        t0 = time.time()
        for i in range(args.number_iter):
            res = exec_net.infer(inputs={input_blob: image1})
            #infer_time.append((time()-t0)*1000)
        infer_time = (time.time() - t0) * 1000
        log.info("Average running time of one iteration: {} ms".format(
            np.average(np.asarray(infer_time))))
        if args.perf_counts:
            perf_counts = exec_net.requests[0].get_perf_counts()
            log.info("Performance counters:")
            print("{:<70} {:<15} {:<15} {:<15} {:<10}".format(
                'name', 'layer_type', 'exet_type', 'status', 'real_time, us'))
            for layer, stats in perf_counts.items():
                print("{:<70} {:<15} {:<15} {:<15} {:<10}".format(
                    layer, stats['layer_type'], stats['exec_type'],
                    stats['status'], stats['real_time']))
        res_pb = res[out_blob]
        probs = res_pb[0][0]
        print("Probability of having disease= " + str(probs) +
              ", performed in " + str(np.average(np.asarray(infer_time))) +
              " ms")

        # Class Activation Map
        t0 = time.time()
        cam = class_activation_map_openvino(res, bn, fc, net, fp16)
        cam_time = (time.time() - t0) * 1000
        print("Time for CAM: {} ms".format(cam_time))

        fig, ax = plt.subplots(1, 2)
        # Visualize the CAM heatmap
        cam = (cam - np.min(cam)) / (np.max(cam) - np.min(cam))
        im = ax[0].imshow(cam, cmap=colormap)
        ax[0].axis('off')
        plt.colorbar(im, ax=ax[0], fraction=0.046, pad=0.04)

        # Visualize the CAM overlaid over the X-ray image
        colormap_val = cm.get_cmap(colormap)
        imss = np.uint8(colormap_val(cam) * 255)
        im = Image.fromarray(imss)
        width, height = image.size
        cam1 = resize_image(im, (height, width))
        heatmap = np.asarray(cam1)
        img1 = heatmap[:, :, :3] * 0.3 + image
        ax[1].imshow(np.uint16(img1))
        plt.xticks([]), plt.yticks([])  # to hide tick values on X and Y axis
        plt.savefig(os.path.join(args.output_dir, job_id,
                                 'result' + str(index_f) + '.png'),
                    bbox_inches='tight',
                    pad_inches=0,
                    dpi=300)

        avg_time = round((infer_time / args.number_iter), 1)
        #f.write(res + "\n Inference performed in " + str(np.average(np.asarray(infer_time))) + "ms")
        f.write("Pneumonia probability: " + str(probs) +
                ", Inference performed in " + str(avg_time) + "ms \n")
        time_images.append(avg_time)
        progressUpdate(progress_file_path, index_f * avg_time, index_f + 1,
                       len(files))

    total_time = round(time.time() - tstart, 2)
    stats = {}
    stats['time'] = str(total_time)
    stats['frames'] = str(len(files))
    stats['fps'] = str(round(len(files) / total_time, 2))
    with open(os.path.join(args.output_dir, job_id, 'stats.json'),
              'w') as json_file:
        json.dump(stats, json_file)
class Network:
    """
    Load and configure inference plugins for the specified target devices 
    and performs synchronous and asynchronous modes for the specified infer requests.
    """
    def __init__(self):
        ### TODO: Initialize any class variables desired ###
        self.plugin = IECore()
        self.network = None
        self.exec_network = None
        self.input_blob = None
        self.output_blob = None
        self.input_info = None

    def load_model(self, model, cpu_extension):
        model_xml = model
        model_bin = os.path.splitext(model_xml)[0] + ".bin"

        if cpu_extension:
            self.plugin.add_extension(cpu_extension, "CPU")

        ### TODO: Load the model ###
        self.network = IENetwork(model=model_xml, weights=model_bin)
        self.network.add_outputs(['detection_output'])
        self.exec_network = self.plugin.load_network(self.network, "CPU")

        ### TODO: Check for supported layers ###
        supported_layers = self.plugin.query_network(network=self.network,
                                                     device_name="CPU")
        #print(supported_layers)

        unsupported_layers = [
            l for l in self.network.layers.keys() if l not in supported_layers
        ]
        if len(unsupported_layers) != 0:
            print("Unsupported layers found: {}".format(unsupported_layers))
            print("Check whether extensions are available to add to IECore.")
            exit(1)

        ### TODO: Add any necessary extensions ###
        ### TODO: Return the loaded inference plugin ###
        ### Note: You may need to update the function parameters. ###
        #I understood the input form of the model thanks to:
        #https://knowledge.udacity.com/questions/196315
        #https://knowledge.udacity.com/questions/157050
        #https://knowledge.udacity.com/questions/137114
        inputs = iter(self.network.inputs)
        self.input_info = "image_info"
        self.input_blob = "image_tensor"
        self.output_blob = next(iter(self.network.outputs))
        return

    def get_input_shape(self):
        ### TODO: Return the shape of the input layer ###
        #print(self.input_blob)
        #print(self.network.inputs[self.input_info].shape)
        #print(self.network.inputs)
        return self.network.inputs[self.input_blob].shape

    def exec_net(self, image):
        ### TODO: Start an asynchronous request ###
        #print(self.network.inputs[self.input_info])
        #print(image.shape[1:])
        self.exec_network.requests[0].async_infer({
            self.input_info: [800, 800, 1],
            self.input_blob:
            image
        })
        #self.exec_network.start_async(request_id=0, inputs={self.input_blob: image})
        ### TODO: Return any necessary information ###
        ### Note: You may need to update the function parameters. ###
        return

    def wait(self):
        ### TODO: Wait for the request to be complete. ###
        ### TODO: Return any necessary information ###
        ### Note: You may need to update the function parameters. ###
        status = self.exec_network.requests[0].wait(-1)
        return status

    def get_output(self):
        ### TODO: Extract and return the output results
        ### Note: You may need to update the function parameters. ###
        return self.exec_network.requests[0].outputs[
            'detection_output']  #[self.output_blob]