This message was deleted.
# ask-for-help
s
This message was deleted.
j
my run code docker run --gpus ‘“device=0”’ -it --rm -p 3000:3000 <my_bento> serve --production --api-workers=1
c
Hi @Jin Heo - could you share a bit more about the model and your service/runner code?
j
yes, 3 files below. (service.py, image_basic_processing.py, segment_anything.py) -------------service.py--------------- import numpy as np import bentoml from bentoml.io import JSON, Multipart from pathlib import Path import time from runners.image_basic_processing import BasicPreprocessingRunnable from runners.segment_anything import SegmentAnythingRunner # Setting runner, service basic_preprocessing_runner = bentoml.Runner(BasicPreprocessingRunnable, name=‘basic_preprocessor’) segment_anything_runner = bentoml.Runner(SegmentAnythingRunner, name=‘segment_anything_runner’) svc = bentoml.Service(“embryo_segment”, runners=[segment_anything_runner, basic_preprocessing_runner]) @svc.api(input=JSON(), output=JSON()) async def predict(input_data: JSON()): “”" url : 이미지 url embryo_num : 요청 바운딩 박스 개수 (or 배아 개수) “”" with bentoml.monitor(“embryo_segment”) as mon: ### 이미지 데이터 처리 url = input_data.get(“url”, None) image = await basic_preprocessing_runner.processing.async_run(url) # cropped_image_list = await microscope_processing_runner.img_cropping.async_run(image) ## rule-based cropping start = time.time() masks = await segment_anything_runner.segment.async_run(image) # embryo_num = 1 # embryo_num embryo_num = input_data.get(“embryo_num”, None) mon.log(url, name=‘url’, role=‘image_path’, data_type=“str”) mon.log(embryo_num, name=‘embryo_num’, role=‘request bbox count’, data_type=“numerical”) if embryo_num is None or embryo_num == 0: return ‘request bbox count is fault... required bbox count >= 1’ if type(embryo_num) is not int: embryo_num = int(embryo_num) if embryo_num > 4: embryo_num = 4 # max bbox_from_sam = await segment_anything_runner.find_the_segmentation.async_run(embryo_num, masks) ### cropped image save for test # await basic_preprocessing_runner.save_cropped_image.async_run(url, image, bbox_from_sam) end = time.time() print(‘segmentation time: ’,end - start) predict_result = { # ‘preg’: output_tensor.tolist()[0][0] ‘bbox_coordinates’: bbox_from_sam } print(‘predict_result:’, predict_result) mon.log(bbox_from_sam, name=“pred”, role=“prediction”, data_type=“list”) # print(‘predict_result: ’, predict_result) return predict_result -------------segment_anything.py----------- import bentoml import numpy as np import cv2 from segment_anything import sam_model_registry, SamAutomaticMaskGenerator class SegmentAnythingRunner(bentoml.Runnable): SUPPORTED_RESOURCES = (“cpu”,“nvidia.com/gpu”,) SUPPORTS_CPU_MULTI_THREADING = True def __init__(self): # SegmentAnythingRunner는 서버를 띄울 때, 1회만 호출 됨 self.device = “cuda:0” self.sam_checkpoint = “./SAM_weights” self.model_type = “vit_h” self.sam = sam_model_registry[self.model_type](checkpoint=self.sam_checkpoint) self.sam.to(self.device) self.kernel = np.ones((5,5), np.uint8) self.mask_generator = SamAutomaticMaskGenerator( model=self.sam, points_per_side=10, pred_iou_thresh=0.90, stability_score_thresh=0.90, crop_n_layers=1, crop_n_points_downscale_factor=2, min_mask_region_area=100000, # Requires open-cv to run post-processing ) @bentoml.Runnable.method(batchable=False) def segment(self, input_tensor: np.ndarray): # arr = np.asarray(input_tensor, dtype=np.uint8) # return self.mask_generator.generate(input_tensor) @bentoml.Runnable.method(batchable=False) def find_the_segmentation(self, embryo_num, masks): “”" CASE 1. 당장 배포, 단일 배아 전제, 크롭하기 - 1인 경우 1번 인덱스만 리턴함. CASE 2. 멀티 배아인 경우 크롭하기 (소프트웨어팀 화면개발이 완료되면) - 아래 embryo_num if else 구문은 필요 없어짐 - embryo 개수를 입력으로 받고, 그때는 embryo_num + 1 로 리턴한다. “”" def make_bbox(index_): sorted_anns = sorted(masks, key=(lambda x: x[‘area’]), reverse=True) # print(‘the segmentation area has {} pixels’.format(sorted_anns[index_][‘area’])) mask = np.expand_dims(sorted_anns[index_][‘segmentation’],axis=-1) mask = mask.astype(‘uint8’).copy() # dilate = cv2.dilate(mask, kernel, iterations=20) dilate = cv2.dilate(mask, self.kernel, iterations=3) cnts,_ = cv2.findContours(dilate, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) #print(cnts[0]) h,w = dilate.shape[:2] for c in cnts: x,y,w,h = cv2.boundingRect(c) # ROI = image[y:y+h, x:x+w] # 이미지 Cropping # bbox_list.append([x,y,x+w,y+h]) return [x,y,x+w,y+h] #### 실행 로직 #### # if embryo_num == 1: # index_list = [1] # else: # index_list = [x for x in range(embryo_num + 1)] index_list = [x for x in range(embryo_num + 1)] bbox_list = [] for index_ in index_list: try: bbox_coordinate = make_bbox(index_) bbox_list.append(bbox_coordinate) except IndexError: # index_: 0 은 무조건 있다고 가정함 # 추후 소프트웨어 개발팀에서 배아 선택 화면이 개발이 되면 indexError가 났을 때, 바로 bbox_list를 return 해도 됨. # 왜냐하면 0 index 부터 반복되고 0인 항상 있기 때문에 if len(bbox_list) == 0: print(‘embryo_num가 1인경우 index error’) bbox_coordinate = make_bbox(0) bbox_list.append(bbox_coordinate) return bbox_list return bbox_list return bbox_list --------------image_basic_processing.py-------- import cv2 import numpy as np import bentoml from urllib.request import urlopen from urllib.error import URLError, HTTPError import os from datetime import datetime class BasicPreprocessingRunnable(bentoml.Runnable): # SUPPORTED_RESOURCES = (“nvidia.com/gpu”,) SUPPORTED_RESOURCES = (“cpu”) SUPPORTS_CPU_MULTI_THREADING = True @bentoml.Runnable.method(batchable=False) def processing(self, url) -> np.ndarray: try: resp = urlopen(url) encoded_img = np.fromstring(resp.read(), dtype = np.uint8) img = cv2.imdecode(encoded_img, cv2.IMREAD_COLOR) # img = PILImage.open(urlopen(url)).convert(‘RGB’) # img.size 로 찍으면 (w,h) 로만 나옴 (channel 정보가 안보임) # img = img.resize((224,224), PILImage.BICUBIC) if len(img.shape) == 3: h, w, c = img.shape if c == 4: img = img[,,:-1] if len(img.shape) == 4: # img = img[,,:-1] img = img[,,:,0] rgb_img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) ### cropping 알고리즘에서 원본영상으로 처리해서 여기서 resize 안함 # img = cv2.resize(img, (224,224)) # print(‘ulr processing: ’, type(img), img.shape) return rgb_img except URLError as e: print(e.reason) return e