|
|
■ jetson-inference segmetation (SUN RGB-D)
jetson-inference에서는 SUN RGB-D를 따로 훈련 해줄 필요없이 이미 pretraining되어진 모델을 가져와서 예제에서 사용하는것으로 보인다.
SUN RGB-D데이터셋은 실내 전용 데이터셋으로 보인다. 실내에서 AI기술을 사용할 것이므로 이 모델을 사용하는것이 좋아보인다.
■ jetson-inference segmetation 출력 영상 분석
위 영상을 출력하는 코드를 자세히 보면
출력 영상을 버퍼에 저장하는 함수인데 첫번째로는 OverlayImg를 받는다. OverlayImg는 실제 카메라 영상에 마스크 이미지를 투영한 것으로 마스크가 얼마나 정확하게 분할을 하고 있는지 시각적으로 확인 할 수 있도록 하기위해서 출력하는 영상이고, 두번째로 받는영상은 클래스 정보를 3채널 영상으로 분할한 마스크 이미지를 받는다. 마스크 이미지가 실제로 우리가 써야하는 데이터이다.
위 함수에서 가장 마지막에 출력하는 output은 imgcomposite인데 앞서서 받은 두개의 이미지를 사이즈만 달리해서 합쳐놓은것이 imgComposite이다. 그래서 위에 출력된이미지 왼쪽은 overlay 이미지이고 오른쪽은 mask 이미지이다.
내가 원하는 출력 데이터는 mask 이미지이므로 mask 이미지만 출력하도록 하는 옵션을 찾아야한다.
위 코드를 보면 뒷단에 overlay|mask 라는 값이 들어가 있는데 이걸 mask로 수정한다면 mask 이미지만 출력할것 같아서 mask로 값을 바꿔봤다.
옵션을 mask로 바꿔주니 mask 영상만 출력되었다.
■ jetson-inference segmetation fcn-resnet50
fcn-resnet18의 출력물이 너무 각지고 클레스별로 구분하는것이 명확하지 않아서 fcn-resnet18 모델의 입력과 출력을 보기 위해서 opencv라이브러리를 사용했다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 | import os import cv2 import numpy as np import torch import torch.onnx from torch.autograd import Variable from torchvision import models def get_pytorch_onnx_model(original_model): # define the directory for further converted model save onnx_model_path = "models" # define the name of further converted model onnx_model_name = "fcn_resnet18.onnx" # create directory for further converted model os.makedirs(onnx_model_path, exist_ok=True) # get full path to the converted model full_model_path = os.path.join(onnx_model_path, onnx_model_name) # generate model input generated_input = Variable( torch.randn(1, 3, 500, 500) ) # model export into ONNX format torch.onnx.export( original_model, generated_input, full_model_path, verbose=True, input_names=["input"], output_names=["output"], opset_version=11 ) return full_model_path #segmentation data processing def get_preprocessed_img(img_path): # read the image input_img = cv2.imread(img_path, cv2.IMREAD_COLOR) input_img = input_img.astype(np.float32) # target image sizes img_height = input_img.shape[0] img_width = input_img.shape[1] print(img_height) print(img_width) # define preprocess parameters mean = np.array([0.485, 0.456, 0.406]) * 255.0 scale = 1 / 255.0 std = [0.229, 0.224, 0.225] # prepare input blob to fit the model input: # 1. subtract mean # 2. scale to set pixel values from 0 to 1 input_blob = cv2.dnn.blobFromImage( image=input_img, scalefactor=scale, size=(img_width, img_height), # img target size mean=mean, swapRB=True, # BGR -> RGB crop=False # center crop ) # 3. divide by std input_blob[0] /= np.asarray(std, dtype=np.float32).reshape(3, 1, 1) return input_blob def get_imagenet_labels(labels_path): with open(labels_path) as f: imagenet_labels = [line.strip() for line in f.readlines()] print(imagenet_labels) return imagenet_labels def get_opencv_dnn_prediction(opencv_net, preproc_img, imagenet_labels): # set OpenCV DNN input # set OpenCV DNN input opencv_net.setInput(preproc_img) print(opencv_net) # OpenCV DNN inference out = opencv_net.forward() print("OpenCV DNN segmentation prediction: \n") print("* shape: ", out.shape) # get IDs of predicted classes out_predictions = np.argmax(out[0], axis=0) print(out_predictions) # get confidence # confidence = out[0][out_predictions] # print("* class ID: {}, label: {}".format(out_predictions, imagenet_labels[out_predictions])) # print("* confidence: {:.4f}".format(confidence)) def get_pytorch_dnn_prediction(original_net, preproc_img, imagenet_labels): original_net.eval() preproc_img = torch.FloatTensor(preproc_img) with torch.no_grad(): # obtaining unnormalized probabilities for each class out = original_net(preproc_img)['out'] print("\nPyTorch segmentation model prediction: \n") print("* shape: ", out.shape) # get IDs of predicted classes out_predictions = out[0].argmax(dim=0) def main(): full_model_path = "./models/fcn_resnet18.onnx" # read converted .onnx model with OpenCV API opencv_net = cv2.dnn.readNetFromONNX(full_model_path) print("OpenCV model was successfully read. Layer IDs: \n", opencv_net.getLayerNames()) #print("OpenCV model was successfully read. Layer shapes: \n", opencv_net.getLayerShapes()) # get preprocessed image input_img = get_preprocessed_img("./000054.jpg") input_shape=opencv_net.getLayersShapes(input_img.shape) print(input_shape) # # get ImageNet labels imagenet_labels = get_imagenet_labels("./classes.txt") # # obtain OpenCV DNN predictions get_opencv_dnn_prediction(opencv_net, input_img, imagenet_labels) # # obtain original PyTorch ResNet50 predictions # get_pytorch_dnn_prediction(original_model, input_img, imagenet_labels) if __name__ == "__main__": main() | cs |
출력 해상도가 16x12로 나오는것을 확인했다.
출력 해상도가 너무 작아서 그것을 640x480으로 늘리는 과정에서 클래스와 클래스의 구분이 불분명하게 되어질 수 있겠다고 판단했다. 그래서 그보다 큰모델인 fcn-resnet50을 훈련해보기로 결정했다.
모델을 바꿔서 훈련시킨후에 fcn-resnet50모델을 .pth에서 onnx으로 변환했다.
# model의 input, output을 출력하는 opencv 라이브러리 함수
model resolution을 500x500으로 fcn-resnet50모델을 voc데이터셋으로 훈련시켜봤다.
입력과 출력값이 동일한 size로 출력되었다. 그 다음으로는 jetson-inference training Code를 가지고 fcn-resnet50모델을 SUN-RGBD(실내데이터셋)으로 훈련해보겠다.
■ jetson-inference segmetation fcn-resnet50 Using SUN-RGBD
# SUNRGBD데이터셋으로 훈련한 결과
■ Opencv 라이브러리를 활용하여 모델의 출력 구하기
# 소스코드
https://github.com/downy25/Using_Opencv_segmentation
# Using CUDA
# Using CPU
# opencv라이브러리에서 jetson-inference와는 색이 다르게 나오는이유
jetson inference는 3채널 컬러를 텍스트 파일에 입력해주면 스스로 뒤에 255를 더 추가해서 4개의 채널로 바꾼다.
jetson inference와는 다르게 opencv라이브러리는 3채널영상을 입력해주면 3채널 그대로가 들어간다. 그이유 때문에 차이가
나는 거같음
그리고 위의 jetson inference 출력과는 다르게 클래스의 갯수를 38개로 늘려서 다시 학습했다. 나는 댓글에 링크 걸어둔 곳의 데이터셋을 받아서 훈련했는데 그곳은 클래스의 갯수를 38개로 늘려서 학습하라고 권장했기 때문
그래서 이전의 jetson inference 21개의 클래스로 학습한것과는 출력이 다를 수 있음
# PC Gpu를 사용했을때 걸리는 시간 비교
#GTX 1660 super
# RTX 3070
■ Pytorch training 예제를 활용하여 SUNRGBD 데이터셋 훈련(fcn_resnet50)
■ Custom data(학교 실내영상)을 레이블링해서 training
# Semantic segmentation 레이블링 데이터의 특징
1. 레이블링 파일 포맷이 .png형식의 확장자로 저장된다.
꼭 png형식으로 저장되어야하는 이유는 이미지를 압축했을때 손실이 없다는것과 색상의 깊이가 8비트에서 최대 16비트까지 다양한 색상의 깊이를 지원하는 장점을 가지고있기 때문에 semantic label영상은 png포맷으로 해야한다.
# 레이블링을 할때 주의사항
하나의 객체를 지정하고싶을때는 레이블링 형태가 폐곡선 형태여야만 class를 지정해줄 수 있음.
# 레이블링을 할때 궁금했던점
벽을 레이블링 한후에 폐곡선 안에 있는 창문을 레이블링을 하면 결과가 어떻게 될지 궁금했었는데
위 방식으로 레이블링 해도 마스크 영상은 두개가 구별된 클래스로 출력되는것으로 확인되었다.
# 내가 한 레이블링 데이터셋이 파이토치 예제의 함수와 호환이 되는지 확인
레이블링 데이터를 많이 해두어도 훈련할 때 쓸 수 없으면 시간낭비이므로 소량의 데이터 (30장정도)를 레이블링해서 훈련하는 코드에 데이터셋이 잘불러와지는지 확인해봤다.
# 학교 실내데이터 200장을 가지고 이전에 SUNRGBD 데이터셋으로 훈련시킨 모델을 재학습

첫댓글 SUN-RGBD 데이터셋 다운로드 https://github.com/ankurhanda/sunrgbd-meta-data
1. SUN RGB-D 클래스 정보에 있는 색상과 출력영상의 색상이 안맞는거 같은데?
2. 비행기영상 추론하는데 걸린시간도 캡쳐해서 추가할것
3. opencv cpp로 추론해볼것, 아래 코드 참고할것
https://github.com/opencv/opencv/blob/4.x/samples/dnn/segmentation.cpp
opencv segmentation inference python example
https://docs.opencv.org/5.x/d7/d9a/pytorch_segm_tutorial_dnn_conversion.html
opencv segmentation inference cpp example
https://github.com/opencv/opencv/blob/4.x/samples/dnn/segmentation.cpp
1. CommandLine을 줄때 사용자가 label 텍스트 파일과 color 텍스트 파일을 주지 않으면 임의로 색을 배정해서 맞지 않는것 같습니다. 텍스트 파일의 경로를 줘서 위에 있는 클레스 정보와 색을 맞추도록 하겠습니다.
2. 캡쳐해서 추가 하겠습니다
3. 알겠습니다
<Convert gstCamera float to OpenCV Mat>
https://github.com/dusty-nv/jetson-inference/issues/1346
<opencv 소스코드 빌드하는법>
https://www.youtube.com/watch?v=ac75cFPYlOQ&t=1654s
PLAY
1. 처리시간이 cPU, gpu 바뀐거 같은데
2. 파이토치 라이브러리로 학습 -> onnx모델변환 ->opencv라이브러리로 젯슨보드에서 실행 -> 젯슨라이브러리 사용하지 말고 파이토치 라이브러리로만 학습하고 opencv코드로 추론하는게 관리하기 가장 쉬움
3. PC에서 GPU로 돌려볼것 더 나아지는지 확인필요, C++라이브러리 쓰면 opencv를 다시 빌드해야되니까 파이썬 opencv를 사용해서 Gpu모드로 돌리는게 가능한지 해봐라
4. 시간단축방법 : 젯슨agx보드 쓰는거 or 성능좋은 PC에서 받아서 처리하는 방법 or 더작은 모델쓰는거