def __init__(self, service_name, engine, comm_config, pipeline_config_path=None, disable_engine=False, disable_warmup=False, warmup_size=(480, 640, 3), output_broker_ip="localhost", output_mqtt_topic='berrynet/engine/pipeline/result'): super().__init__(service_name, engine, comm_config) self.pipeline_config_path = pipeline_config_path self.trainer_config_path = '' self.warmup_size = warmup_size self.disable_engine = disable_engine self.output_broker_ip = output_broker_ip self.output_mqtt_topic = output_mqtt_topic if not os.path.exists('/tmp/dlbox-pipeline'): os.mkdir('/tmp/dlbox-pipeline') self.counter = 0 logger.debug('Pipeline result topic: {}'.format( self.output_mqtt_topic))
def main(): # Test TensorFlow engine args = parse_args() if args['debug']: logger.setLevel(logging.DEBUG) else: logger.setLevel(logging.INFO) logger.debug('model filepath: ' + args['model']) logger.debug('label filepath: ' + args['label']) model = 'berrynet/engine/inception_v3_2016_08_28_frozen.pb' label = 'berrynet/engine/imagenet_slim_labels.txt' jpg_filepath = 'berrynet/engine/grace_hopper.jpg' input_layer = 'input:0' output_layer = 'InceptionV3/Predictions/Reshape_1:0' tfe = TensorFlowEngine(model, label, input_layer, output_layer) comm_config = { 'subscribe': {}, 'broker': { 'address': 'localhost', 'port': 1883 } } engine_service = TensorFlowService(args['service_name'], tfe, comm_config) engine_service.run(args)
def main(): args = parse_args() if args['debug']: logger.setLevel(logging.DEBUG) else: logger.setLevel(logging.INFO) if args['model_package'] != '': dlmm = DLModelManager() meta = dlmm.get_model_meta(args['model_package']) args['model'] = meta['model'] args['label'] = meta['label'] logger.debug('model filepath: ' + args['model']) logger.debug('label filepath: ' + args['label']) engine = DarknetEngine(config=meta['config']['config'].encode('utf-8'), model=args['model'].encode('utf-8'), meta=meta['config']['meta'].encode('utf-8')) comm_config = { 'subscribe': {}, 'broker': { 'address': 'localhost', 'port': 1883 } } engine_service = DarknetService(args['service_name'], engine, comm_config, args['draw']) engine_service.run(args)
def detect_np(net, meta, np_img, thresh=.5, hier_thresh=.5, nms=.45): im = nparray_to_image(np_img) boxes = make_boxes(net) probs = make_probs(net) num = num_boxes(net) t_start = time.time() network_detect(net, im, thresh, hier_thresh, nms, boxes, probs) t_end = time.time() logger.debug('inference time: {} s'.format(t_end - t_start)) res = [] for j in range(num): for i in range(meta.classes): if probs[j][i] > 0: res.append({ 'type': 'detection', 'label': meta.names[i].decode('utf-8'), 'confidence': probs[j][i], 'left': boxes[j].x, 'top': boxes[j].y, 'right': boxes[j].x + boxes[j].w, 'bottom': boxes[j].y + boxes[j].h, 'id': -1 }) free_image(im) free_ptrs(cast(probs, POINTER(c_void_p)), num) return res
def handler_shot(self, update, context): logger.info("Received command `shot`, chat id: %s" % update.message.chat_id) # Register the chat-id for receiving images self.shot = True self.single_shot_chat_id = update.message.chat_id logger.debug('Enable single shot.')
def main(): # Test OpenVINO classifier engine args = parse_args() if args['debug']: logger.setLevel(logging.DEBUG) else: logger.setLevel(logging.INFO) if args['model_package'] != '': dlmm = DLModelManager() meta = dlmm.get_model_meta(args['model_package']) args['model'] = meta['model'] args['label'] = meta['label'] logger.debug('model filepath: ' + args['model']) logger.debug('label filepath: ' + args['label']) comm_config = { 'subscribe': {}, 'broker': { 'address': 'localhost', 'port': 1883 } } engine = OpenVINOClassifierEngine( model = args['model'], device = args['device'], labels = args['label'], top_k = args['num_top_predictions']) service_functor = OpenVINOClassifierService engine_service = service_functor(args['service_name'], engine, comm_config, draw=args['draw']) engine_service.run(args)
def warmup(self, shape=(480, 640, 3), iteration=5): """Warmup pipeline engine Use all-zero numpy array as input to warmup pipeline engine. Args: meta: Metadata of image data shape: Warmup image shape in (w, h, c) format iteration: How many times to feed in warmup image Returns: N/A """ logger.debug('Warmup shape: {}'.format(shape)) input_data = [np.zeros(shape=shape, dtype=np.uint8)] * iteration # FIXME: get engines programmatically dl_comp_config = self.get_dl_component_config(self.pipeline_config) for comp_config in dl_comp_config: t_start = time.time() comp_name = comp_config['name'] inst = self.launcher.pipeline.pipeline[comp_name]['instance'] inst.input_data = input_data inst.main_process() t_duration = time.time() - t_start logger.debug('Warmup {0} costs {1} sec'.format( comp_name, t_duration))
def single_shot(self, pl): """Capture an image from camera client and send to the client. """ if self.shot is True: try: payload_json = payload.deserialize_payload(pl.decode('utf-8')) # WORKAROUND: Support customized camera client. # # Original camera client sends an `obj` in payload, # Customized camera client sends an `[obj]` in payload. # # We are unifying the rules. Before that, checking the type # as workaround. if type(payload_json) is list: logger.debug('WORDAROUND: receive and unpack [obj]') payload_json = payload_json[0] jpg_bytes = payload.destringify_jpg(payload_json["bytes"]) jpg_file_descriptor = io.BytesIO(jpg_bytes) logger.info('Send single shot') self.updater.bot.send_photo(chat_id=self.single_shot_chat_id, photo=jpg_file_descriptor) except Exception as e: logger.info(e) self.shot = False else: logger.debug('Single shot is disabled, do nothing.')
def main(): # Test Movidius engine args = parse_args() if args['debug']: logger.setLevel(logging.DEBUG) else: logger.setLevel(logging.INFO) if args['model_package'] != '': dlmm = DLModelManager() meta = dlmm.get_model_meta(args['model_package']) args['model'] = meta['model'] args['label'] = meta['label'] logger.debug('model filepath: ' + args['model']) logger.debug('label filepath: ' + args['label']) comm_config = { 'subscribe': {}, 'broker': { 'address': 'localhost', 'port': 1883 } } if args['service_name'] == 'Classification': mvng = MovidiusEngine(args['model'], args['label']) service_functor = MovidiusClassificationService elif args['service_name'] == 'MobileNetSSD': mvng = MovidiusMobileNetSSDEngine(args['model'], args['label']) service_functor = MovidiusMobileNetSSDService else: logger.critical('Legal service names are Classification, MobileNetSSD') engine_service = service_functor(args['service_name'], mvng, comm_config) engine_service.run(args)
def update(self, pl): if not os.path.exists(self.data_dirpath): try: os.mkdir(self.data_dirpath) except Exception as e: logger.warn('Failed to create {}'.format(self.data_dirpath)) raise (e) payload_json = payload.deserialize_payload(pl.decode('utf-8')) if 'bytes' in payload_json.keys(): img_k = 'bytes' elif 'image_blob' in payload_json.keys(): img_k = 'image_blob' else: raise Exception('No image data in MQTT payload') jpg_bytes = payload.destringify_jpg(payload_json[img_k]) payload_json.pop(img_k) logger.debug('inference text result: {}'.format(payload_json)) img = payload.jpg2rgb(jpg_bytes) try: res = payload_json['annotations'] except KeyError: res = [{ 'label': 'hello', 'confidence': 0.42, 'left': random.randint(50, 60), 'top': random.randint(50, 60), 'right': random.randint(300, 400), 'bottom': random.randint(300, 400) }] self.frame = overlay_on_image(img, res)
def update(self, pl): try: payload_json = payload.deserialize_payload(pl.decode('utf-8')) jpg_bytes = payload.destringify_jpg(payload_json["bytes"]) jpg_file_descriptor = io.BytesIO(jpg_bytes) for u in self.cameraHandlers: if self.updater is None: continue if self.target_label == '': if len(payload_json['annotations']) > 0: logger.debug("Send photo to %s" % u) self.updater.bot.send_photo(chat_id=u, photo=jpg_file_descriptor) else: logger.debug("Does not detect any object, no action") elif self.match_target_label(self.target_label, payload_json): logger.info("Send notification photo with result to %s" % u) self.updater.bot.send_photo(chat_id=u, photo=jpg_file_descriptor) else: pass except Exception as e: logger.info(e)
def inference(self, tensor): inf_start = time() if self.is_async_mode: self.exec_net.start_async(request_id=self.next_request_id, inputs={self.input_blob: tensor}) else: self.exec_net.start_async(request_id=self.cur_request_id, inputs={self.input_blob: tensor}) if self.exec_net.requests[self.cur_request_id].wait(-1) == 0: inf_end = time() det_time = inf_end - inf_start if self.is_async_mode: logger.debug('Inference time: N\A for async mode') else: logger.debug("Inference time: {:.3f} ms".format(det_time * 1000)) # Parse detection results of the current request res = self.exec_net.requests[self.cur_request_id].outputs[self.out_blob] else: res = None return res # FIXME: async mode does not work currently. # process_input needs to provide two input tensors for async. if self.is_async_mode: self.cur_request_id, self.next_request_id = self.next_request_id, self.cur_request_id frame = next_frame
def result_hook(self, generalized_result): gr = generalized_result jpg_bytes = payload.destringify_jpg(gr.pop('bytes')) logger.debug('generalized result (readable only): {}'.format(gr)) with open('/tmp/mockup/{}.jpg'.format(gr['timestamp']), 'wb') as f: f.write(jpg_bytes) with open('/tmp/mockup/{}.json'.format(gr['timestamp']), 'w') as f: f.write(json.dumps(gr, indent=4))
def match_target_label(self, target_label, bn_result): labels = [r['label'] for r in bn_result['annotations']] if target_label in labels: logger.debug('Find {0} in inference result {1}'.format( target_label, labels)) return True else: logger.debug('Not find {0} in inference result {1}'.format( target_label, labels)) return False
def get_distribution_info(): """Get Debuan or Ubuntu distribution information. """ info = {} with open('/etc/lsb-release') as f: info_l = [i.strip().split('=') for i in f.readlines()] for i in info_l: info[i[0]] = i[1] logger.debug('Distribution info: {}'.format(info)) return info
def generalize_result(self, eng_input, eng_output): # Pipeline returns None if any error happened if eng_output is None: eng_output = {} # If pipeline generate multiple outputs simultaneously # # In this case, the format of engine output is # # { # 'annotations': {...}, # 'bytes': '...' # } if all(key in eng_output.keys() for key in ['annotations', 'bytes']): logger.debug('Pipeline output type: multiple') logger.debug('eng_input type = {0}, len = {1}'.format( type(eng_input), len(eng_input))) # FIXME: Re-cap why eng_input is a list and only contains 1 item. eng_input = eng_input[0] try: eng_input['annotations'] = eng_output['annotations'] logger.debug('output image type: {0}, len: {1}'.format( type(eng_output['bytes']), len(eng_output['bytes']))) pipeline_img = eng_output['bytes'][0] retval, jpg_bytes = cv2.imencode('.jpg', pipeline_img) eng_input['bytes'] = payload.stringify_jpg(jpg_bytes) except Exception as e: logger.critical(e) else: logger.debug('Pipeline output type: simple') # FIXME: Workaround for spec incompatibility # DLBox spec use 'image_blob', but BerryNet use 'bytes', so we have to # do a convert here if isinstance(eng_output, list): inf_output = eng_output[0] else: inf_output = eng_output if len(eng_input) > 1: for i in range(len(eng_input)): try: retval, jpg_bytes = cv2.imencode('.jpg', inf_output) eng_input[i]['bytes'] = payload.stringify_jpg( jpg_bytes) #eng_input[i].pop('bytes') except Exception as e: print(e) else: try: eng_input, = eng_input retval, jpg_bytes = cv2.imencode('.jpg', inf_output) eng_input['bytes'] = payload.stringify_jpg(jpg_bytes) #eng_input.pop('bytes') except Exception as e: print(e) return eng_input
def send_email_text(sender_address, sender_password, receiver_address, body='', subject='BerryNet mail client notification', attachments=None): # instance of MIMEMultipart msg = MIMEMultipart() msg['From'] = sender_address msg['To'] = receiver_address msg['Subject'] = subject logger.debug('Sender: {}'.format(msg['From'])) logger.debug('Receiver: {}'.format(msg['To'])) logger.debug('Subject: {}'.format(msg['Subject'])) # attach the body with the msg instance msg.attach(MIMEText(body, 'plain')) for fpath in attachments: logger.debug('Attachment: {}'.format(fpath)) msg.attach(create_mime_attachment(fpath)) # creates SMTP session s = smtplib.SMTP('smtp.gmail.com', 587) # start TLS for security s.starttls() # Authentication s.login(sender_address, sender_password) # Converts the Multipart msg into a string text = msg.as_string() # sending the mail s.sendmail(sender_address, receiver_address, text) # terminating the session s.quit()
def update(self, pl): payload_json = payload.deserialize_payload(pl.decode('utf-8')) jpg_bytes = payload.destringify_jpg(payload_json['bytes']) inference_result = [ '{0}: {1}<br>'.format(anno['label'], anno['confidence']) for anno in payload_json['annotations'] ] logger.debug('inference results: {}'.format(inference_result)) with open(pjoin(self.basedir, 'snapshot.jpg'), 'wb') as f: f.write(jpg_bytes) self.comm.send('berrynet/dashboard/snapshot', 'snapshot.jpg') self.comm.send('berrynet/dashboard/inferenceResult', json.dumps(inference_result))
def check_param_keys(self): """ Check if any default key is missing in the self.param. """ default_keys = [ "model_file", "model_description", "label_file", "device" ] for _key in default_keys: if _key not in self.param.keys(): logger.error("%s missing in self.param" % _key) self.terminate_flag = True else: continue logger.debug("keys of self.param are checked")
def main(): # Example command # $ python3 tflite_engine.py -e detector \ # -m detect.tflite --labels labels.txt -i dog.jpg --debug args = parse_argsr() if args.debug: logger.setLevel(logging.DEBUG) else: logger.setLevel(logging.INFO) if args.engine == 'classifier': #engine = TFLiteClassifierEngine( # model = args.model, # device = args.device, # labels = args.labels, # top_k = args.number_top) import sys sys.exit(0) elif args.engine == 'detector': engine = TFLiteDetectorEngine(model=args.model, labels=args.labels) else: raise Exception('Illegal engine {}, it should be ' 'classifier or detector'.format(args.engine)) for i in range(5): bgr_array = cv2.imread(args.input) t = time.time() image_data = engine.process_input(bgr_array) output = engine.inference(image_data) model_outputs = engine.process_output(output) # Reference result # input: # darknet/data/dog.jpg # output: # Inference takes 0.7533011436462402 s # Inference takes 0.5741658210754395 s # Inference takes 0.6120760440826416 s # Inference takes 0.6191139221191406 s # Inference takes 0.5809791088104248 s # label: bicycle conf: 0.9563907980918884 (139, 116) (567, 429) # label: car conf: 0.8757821917533875 (459, 80) (690, 172) # label: dog conf: 0.869189441204071 (131, 218) (314, 539) # label: car conf: 0.40003547072410583 (698, 122) (724, 152) logger.debug('Inference takes {} s'.format(time.time() - t)) for r in model_outputs['annotations']: logger.debug('label: {0} conf: {1} ({2}, {3}) ({4}, {5})'.format( r['label'], r['confidence'], r['left'], r['top'], r['right'], r['bottom']))
def process_output(self, output): processed_output = {'annotations': []} decimal_digits = 2 predictions = np.squeeze(output) top_k_index = predictions.argsort()[-self.top_k:][::-1] for node_id in top_k_index: human_string = self.labels[node_id] score = round(float(predictions[node_id]), decimal_digits) anno = { 'type': 'classification', 'label': human_string, 'confidence': score } processed_output['annotations'].append(anno) logger.debug('%s (score = %.5f)' % (human_string, score)) return processed_output
def send_result(self, generalized_result, topic='berrynet/engine/pipeline/result'): # NOTE: There are numpy float in pipeline output, so we use # tools.dump_json instead of payload.serialize_payload for r in generalized_result: try: c_id = r.get('channel', None) or r['meta']['channel_id'] topic += '/{}'.format(c_id) except KeyError: logger.warn( 'No channel id found, set topic to {}'.format(topic)) logger.debug('output topic: {}'.format(topic)) publish.single(topic, payload=tools.dump_json(generalized_result), hostname=self.output_broker_ip)
def main(): args = parse_args() comm_config = { 'subscribe': {}, 'broker': { 'address': args['broker_ip'], 'port': args['broker_port'] } } comm = Communicator(comm_config, debug=True) duration = lambda t: (datetime.now() - t).microseconds / 1000 if args['mode'] == 'stream': counter = 0 capture = cv2.VideoCapture(0) while True: status, im = capture.read() if (status is False): logger.warn('ERROR: Failure happened when reading frame') t = datetime.now() retval, jpg_bytes = cv2.imencode('.jpg', im) mqtt_payload = payload.serialize_jpg(jpg_bytes) comm.send('berrynet/data/rgbimage', mqtt_payload) logger.debug('send: {} ms'.format(duration(t))) time.sleep(1.0 / args['fps']) elif args['mode'] == 'file': # Prepare MQTT payload im = cv2.imread(args['filepath']) retval, jpg_bytes = cv2.imencode('.jpg', im) t = datetime.now() mqtt_payload = payload.serialize_jpg(jpg_bytes) logger.debug('payload: {} ms'.format(duration(t))) logger.debug('payload size: {}'.format(len(mqtt_payload))) # Client publishes payload t = datetime.now() comm.send('berrynet/data/rgbimage', mqtt_payload) logger.debug('mqtt.publish: {} ms'.format(duration(t))) logger.debug('publish at {}'.format(datetime.now().isoformat())) else: logger.error('User assigned unknown mode {}'.format(args['mode']))
def main(): args = parse_argsr() if args.debug: logger.setLevel(logging.DEBUG) else: logger.setLevel(logging.INFO) if args.engine == 'classifier': engine = OpenVINOClassifierEngine( model = args.model, device = args.device, labels = args.labels, top_k = args.number_top) elif args.engine == 'detector': engine = OpenVINODetectorEngine( model = args.model, device = args.device, labels = args.labels) else: raise Exception('Illegal engine {}, it should be ' 'classifier or detector'.format(args.engine)) #set_openvino_environment() #if args.debug: # logger.debug('OpenVINO environment vars') # target_vars = ['INSTALLDIR', # 'INTEL_CVSDK_DIR', # 'LD_LIBRARY_PATH', # 'InferenceEngine_DIR', # 'IE_PLUGINS_PATH', # 'PATH', # 'PYTHONPATH'] # for i in target_vars: # logger.debug('\t{var}: {val}'.format( # var = i, # val = os.environ.get(i))) bgr_array = cv2.imread(args.input) t = time() image_data = engine.process_input(bgr_array) output = engine.inference(image_data) model_outputs = engine.process_output(output) logger.debug('Result: {}'.format(model_outputs)) logger.debug('Classification takes {} s'.format(time() - t))
def main(): # Test TFLite engines args = parse_args() if args['debug']: logger.setLevel(logging.DEBUG) else: logger.setLevel(logging.INFO) if args['model_package'] != '': dlmm = DLModelManager() meta = dlmm.get_model_meta(args['model_package']) args['model'] = meta['model'] args['label'] = meta['label'] logger.debug('model filepath: ' + args['model']) logger.debug('label filepath: ' + args['label']) comm_config = { 'subscribe': {}, 'broker': { 'address': 'localhost', 'port': 1883 } } if args['service'] == 'classifier': engine = TFLiteClassifierEngine( model = args['model'], labels = args['label'], top_k = args['top_k'], num_threads = args['num_threads']) service_functor = TFLiteClassifierService elif args['service'] == 'detector': engine = TFLiteDetectorEngine( model = args['model'], labels = args['label'], num_threads = args['num_threads']) service_functor = TFLiteDetectorService else: raise Exception('Illegal service {}, it should be ' 'classifier or detector'.format(args['service'])) engine_service = service_functor(args['service_name'], engine, comm_config, draw=args['draw']) engine_service.run(args)
def update(self, pl): payload_json = payload.deserialize_payload(pl.decode('utf-8')) if 'bytes' in payload_json.keys(): img_k = 'bytes' elif 'image_blob' in payload_json.keys(): img_k = 'image_blob' else: raise Exception('No image data in MQTT payload') jpg_bytes = payload.destringify_jpg(payload_json[img_k]) payload_json.pop(img_k) logger.debug('inference text result: {}'.format(payload_json)) img = payload.jpg2rgb(jpg_bytes) if self.no_decoration: self.frame = img else: try: res = payload_json['annotations'] except KeyError: res = [{ 'label': 'hello', 'confidence': 0.42, 'left': random.randint(50, 60), 'top': random.randint(50, 60), 'right': random.randint(300, 400), 'bottom': random.randint(300, 400) }] self.frame = overlay_on_image(img, res) # Save frames for analysis or debugging if self.debug and self.save_frame: if not os.path.exists(self.data_dirpath): try: os.mkdir(self.data_dirpath) except Exception as e: logger.warn('Failed to create {}'.format( self.data_dirpath)) raise (e) timestamp = datetime.now().isoformat() with open(pjoin(self.data_dirpath, timestamp + '.jpg'), 'wb') as f: f.write(jpg_bytes) with open(pjoin(self.data_dirpath, timestamp + '.json'), 'w') as f: f.write(json.dumps(payload_json, indent=4))
def update(self, pl): if not os.path.exists(self.data_dirpath): try: os.mkdir(self.data_dirpath) except Exception as e: logger.warn('Failed to create {}'.format(self.data_dirpath)) raise (e) payload_json = payload.deserialize_payload(pl.decode('utf-8')) jpg_bytes = payload.destringify_jpg(payload_json['bytes']) payload_json.pop('bytes') logger.debug('inference text result: {}'.format(payload_json)) timestamp = datetime.now().isoformat() with open(pjoin(self.data_dirpath, timestamp + '.jpg'), 'wb') as f: f.write(jpg_bytes) with open(pjoin(self.data_dirpath, timestamp + '.json'), 'w') as f: f.write(json.dumps(payload_json, indent=4))
def update(self, pl): payload_json = payload.deserialize_payload(pl.decode('utf-8')) if self.pipeline_compatible: b64img_key = 'image_blob' else: b64img_key = 'bytes' jpg_bytes = payload.destringify_jpg(payload_json[b64img_key]) payload_json.pop(b64img_key) logger.debug('inference text result: {}'.format(payload_json)) match_target_label = self.find_target_label(self.target_label, payload_json) logger.debug('Find target label {0}: {1}'.format( self.target_label, match_target_label)) if match_target_label: timestamp = datetime.now().isoformat() notification_image = pjoin('/tmp', timestamp + '.jpg') notification_text = pjoin('/tmp', timestamp + '.json') with open(notification_image, 'wb') as f: f.write(jpg_bytes) with open(notification_text, 'w') as f: f.write(json.dumps(payload_json, indent=4)) try: send_email_text(self.email['sender_address'], self.email['sender_password'], self.email['receiver_address'], body=('Target label {} is found. ' 'Please check the attachments.' ''.format(self.target_label)), subject='BerryNet mail client notification', attachments=set( [notification_image, notification_text])) except Exception as e: logger.warn(e) os.remove(notification_image) os.remove(notification_text) else: # target label is not in generalized result, do nothing pass
def process_output(self, output): logger.debug("Processing output blob") logger.debug("Threshold: {} ".format(self.threshold)) annotations = [] for obj in output[0][0]: # Collect objects when probability more than specified threshold if obj[2] > self.threshold: xmin = int(obj[3] * self.img_w) ymin = int(obj[4] * self.img_h) xmax = int(obj[5] * self.img_w) ymax = int(obj[6] * self.img_h) class_id = int(obj[1]) if self.labels_map: det_label = self.labels_map[class_id] else: str(class_id) annotations.append({ 'label': det_label, 'confidence': float(obj[2]), 'left': xmin, 'top': ymin, 'right': xmax, 'bottom': ymax }) logger.debug('process_output return: {}'.format(annotations)) return annotations
def __init__(self, service_name, engine, comm_config, pid=None, pipeline_config_path=None, disable_engine=False, disable_warmup=False, warmup_size=(480, 640, 3)): super().__init__(service_name, engine, comm_config) self.pipeline_config_path = pipeline_config_path self.dyda_config_path = '' self.warmup_size = warmup_size self.disable_engine = disable_engine if not os.path.exists('/tmp/dlbox-pipeline'): os.mkdir('/tmp/dlbox-pipeline') self.counter = 0 self.pid = pid logger.debug('Pipeline result topic: berrynet/engine/pipeline/result')