|
|
1. 객체검출(object detection)
영상에서 객체의 클래스와 위치를 동시에 구해주는 기술
영상에 여러개의 객체가 존재할때 객체별로 분류와 위치를 동시에 구해줌
객체의 클래스를 구하는 걸 classification(영상분류)
객체의 위치를 구하는 걸 localization(위치추정)
객체의 위치는 바운딩박스로 그려줌
객체가 존재할 확률이 큰 사각형 영역을 먼저 찾고 찾은 사각형안에서 영상분류를 수행함
객체검출모델의 입력은 영상이고 출력은 클래스별 확률과 객체의 위치(바운딩박스정보)임
영상에 여러개의 객체가 존재할수 있으므로 객체 갯수만큼의 바운딩박스와 각 박스안에 객체의 확률을 출력해줌
따라서 훈련데이터의 레이블정보(정답)는 클래스정보와 바운딩박스정보로 구성됨
https://pytorch.org/tutorials/intermediate/torchvision_tutorial.html
https://learnopencv.com/faster-r-cnn-object-detection-with-pytorch/
2. 참고사이트
파이토치 깃허브 사이트(vision)
https://github.com/pytorch/vision
3. 파이토치 비전 깃허브 객체검출 예제
아래 사이트에 접속하면 영상분류(classification), 객체검출(detection), 영상분할(segmentation) 예제들이 저장되어 있음
https://github.com/pytorch/vision/tree/main/references
객체검출예제는 detection 폴더에 저장되어 있고 아래 주소에 접속해보면 소스코드와 코드 실행방법이 나와있음
https://github.com/pytorch/vision/tree/main/references/detection
위 객체검출 예제는 COCO dataset을 훈련하는 예제임, 커스텀 데이터로 훈련할때는 코드를 적절하게 수정해서 사용해야함
4. anaconda 가상환경 활성화
파이토치 프레임워크를 이용한 모든 실습은 가상환경 pytorch 에서 실행한다.
먼저 생성된 가상환경 리스트 확인
> conda env list
가상환경 pytorch 활성화
> conda activate pytorch
파이썬(3.11), pip(24.0), 파이토치(2.3.1) 버전 확인
파이토치 예제코드 실행 확인
이후의 모든 실습은 언급하지 않아도 가상환경 pytorch에서 진행한다.
5. 훈련데이터 준비
깃허브에는 소스코드만 있고 훈련데이터는 없으므로 훈련 영상은 직접 만들어야 함
문제 : 영상에서 2종류의 로봇인 big robot, small robot을 검출하는 예제
class : big robot, small robot
클래스수 : 2개
먼저 적당한 <사용자작업폴더>로 이동 후 아래구조로 훈련, 검증, 테스트용 폴더를 작성하고 훈련영상 저장
훈련용 데이터셋
<사용자작업폴더>/dataset2/train/JPEGImages -> 영상파일 폴더, 이폴더 아래에 jpg파일들을 저장
<사용자작업폴더>/dataset2/train/annotations.json -> json 레이블파일, labelme를 이용하여 1개로 통합해야함
검증용 데이터셋
<사용자작업폴더>/dataset2/val/JPEGImages -> 영상파일 폴더, 이폴더 아래에 jpg파일들을 저장
<사용자작업폴더>/dataset2/val/annotations.json -> json 레이블파일, labelme를 이용하여 1개로 통합해야함
훈련,검증영상은 모두 달라야하고 중복되는게 있으면 안됨, 전체데이터셋을 8:2로 분할
영상의 해상도는 달라도 되고 훈련이나 테스트할때 전처리과정에서 모델 입력사이즈에 맞게 변환됨
훈련데이터 폴더생성 확인방법
> cd <사용자작업폴더> -> 사용자작업폴더는 d:\users\2sungryul\dropbox\work\Pytorch, 각자 컴퓨터의 작업폴더를 적어주면 됨
> tree dataset2 -> 폴더를 트리구조로 출력해줌 -> 설명안한것들은 무시하라
train아래에 폴더구조는 labelme를 이용하여 자동생성됨
JPEGImages 에는 영상파일이 저장됨
Visualization 폴더는 레이블링의 결과를 확인하는 영상이 저장되어 있음
annotations.json -> 1개로 통합된 레이블파일
훈련용 영상 갯수 : 160개
val 아래에 폴더구조는 labelme를 이용하여 자동생성됨
JPEGImages 에는 영상파일이 저장됨
Visualization 폴더는 레이블링의 결과를 확인하는 영상이 저장되어 있음
annotations.json -> 1개로 통합된 레이블파일
검증용 영상 갯수 : 40개
6. 소스코드 다운로드
파이토치 예제 소스를 저장할 <사용자작업폴더>로 이동
git clone 명령어로 pytorch vision 레포지토리를 다운로드
<사용자작업폴더> 아래에 vision 폴더 생성 확인
> cd <사용자작업폴더>
> git clone https://github.com/pytorch/vision.git
소스코드수정사항
1) <사용자작업폴더>\vision\references\detection\train.py의 45번 라인의 코드를 다음처럼 수정
#num_classes, mode = {"coco": (91, "instances"), "coco_kp": (2, "person_keypoints")}[args.dataset]
num_classes, mode = {"coco": (3, "instances"), "coco_kp": (2, "person_keypoints")}[args.dataset]
위의 예제코드에서 91은 coco데이터셋의 클래스수를 의미함 -> coco dataset 형식을 사용하는 경우는 객체검출시 배경도 하나의 클래스로 보기때문에 클래스수는 실제클래스수(90)+1으로 계산해줘야함
여기서는 실제 클래스의 갯수가 2이므로 2+1=3으로 설정해야함
2) <사용자작업폴더>\vision\references\detection\train.py의 247번 라인 아래에 다음 코드를 추가
#print(model)
for param in model.backbone.parameters():
param.requires_grad = False
for name, param in model.named_parameters():
print(name, param.requires_grad)
백본모델의 파라미터를 freeze(고정) 시킴, ImageNet으로 선행학습한 값으로 초기화했으므로 다시 훈련할 필요없고 훈련속도 증가함
3) <사용자작업폴더>\vision\references\detection\coco_utils.py의 201-206번 라인의 코드를 다음처럼 수정
#anno_file_template = "{}_{}2017.json"
#PATHS = {
# "train": ("train2017", os.path.join("annotations", anno_file_template.format(mode, "train"))),
# "val": ("val2017", os.path.join("annotations", anno_file_template.format(mode, "val"))),
# # "train": ("val2017", os.path.join("annotations", anno_file_template.format(mode, "val")))
#}
anno_file_template = "annotations.json"
PATHS = {
"train": ("train", os.path.join("train", anno_file_template)),
"val": ("val", os.path.join("val", anno_file_template)),
# "train": ("val2017", os.path.join("annotations", anno_file_template.format(mode, "val")))
}
예제에서는 coco dataset의 폴더구조와 파일명을 이용하는데 우리는 labelme에서 만들어주는 데이터셋 폴더구조에 맞게 수정함 -> labelme를 이용한 객체검출용 레이블링에서 생성한 폴더구조를 이용
4) <사용자작업폴더>\vision\references\detection \train.py의 323라인 아래에 아래처럼 코드추가할것
모델의 구조와 가중치 모두를 저장하는 코드임
322,323라인의 checkpoint.pth, model_x.pth 는 모델의 가중치와 훈련파라미터 정보만 저장함
utils.save_on_master(checkpoint, os.path.join(args.output_dir, f"model_{epoch}.pth"))
utils.save_on_master(checkpoint, os.path.join(args.output_dir, "checkpoint.pth"))
# added by 2sungryul, save the full model with its structure and weight
torch.save(model_without_ddp, os.path.join(args.output_dir, "model.pth"))
7. 훈련
객체검출 훈련 소스코드 위치
<사용자작업폴더>\vision\references\detection\train.py
D:\Users\2sungryul\Dropbox\Work\PyTorch\vision\references\detection\train.py
객체검출 훈련데이터 위치
<사용자작업폴더>\dataset2
D:\Users\2sungryul\Dropbox\Work\PyTorch\dataset2
훈련코드 실행
훈련코드 train.py가 존재하는 경로 <사용자작업폴더>\vision\references\detection 로 이동
여기서 <사용자작업폴더>는 D:\Users\2sungryul\Dropbox\Work\PyTorch 임, 각자 컴퓨터의 작업폴더를 적어주면 됨
명령행 인자를 지정하여 train.py 실행
파이토치 깃허브에서는 분산처리를 위하여 torchrun 명령어를 사용하고 있는데 분산처리 안하면 다음처럼 실행하면 됨
> cd <사용자작업폴더>\vision\references\detection
> python train.py --data-path D:\Users\2sungryul\Dropbox\Work\PyTorch\dataset2 --dataset coco --model fasterrcnn_resnet50_fpn --device cpu --epochs 26 --lr-steps 16 22 --aspect-ratio-group-factor 3 --weights-backbone ResNet50_Weights.IMAGENET1K_V1 --output-dir D:\Users\2sungryul\Dropbox\Work\PyTorch\dataset2\output
명령행 인자 설명
--data-path D:\Users\2sungryul\Dropbox\Work\PyTorch\dataset2
-> 훈련데이터의 경로, 지정된 경로아래에 train, val 경로가 있어야하고 그 아래에 레이블파일과 영상파일이 있어야함
--dataset coco
-> 예제는 coco데이터셋을 기준으로 만들어져 있어 객체검출시 항상 coco로 설정해야함
--model asterrcnn_resnet50_fpn
-> 훈련할 모델명
--device cpu
-> cpu or cuda, gpu 있으면 cuda으로 설정
--epochs 26
-> 훈련할 에퍽의 숫자, 결과 분석후 조절해야 함
--lr-steps 16 22
->
--aspect-ratio-group-factor 3
->
--weights-backbone ResNet50_Weights.IMAGENET1K_V1
->
--output-dir D:\Users\2sungryul\Dropbox\Work\PyTorch\dataset2\output
-> 훈련결과로 생성되는 모델파일(확장자 pth, 모델 구조, 가중치 포함)의 저장경로, 각 에퍽마다 별도 파일로 생성됨
실행 결과 해석
Epoch : train 폴더의 데이터 이용하여 훈련한 결과
Test ; 1에퍽을 훈련한 후 val 폴더의 데이터를 이용하여 훈련한 가중치를 이용하여 검증한 결과
Epoch: [0] [ 0/80] -> [0] : 에퍽횟수, [0/80] : 80는 총배치횟수, 0은 현재 배치횟수, 배치가 10회때마다 출력
Test: [ 0/4] -> [0/4] : 4는 총배치횟수, 0은 현재 배치횟수
eta(estimated time of arrival) -> 1epoch을 훈련하는데 걸리는 추정시간
lr -> learning rate
loss -> training loss
loss_classifier ->
loss_box_reg ->
loss_objectness ->
loss_rpn_box_reg ->
AP ->
IoU ->
maxDets ->
훈련 종료시 화면 -> 총 8시간 10분 걸림, Epoch =26이므로 0->25
모델파일 확인
--output-dir D:\Users\2sungryul\Dropbox\Work\PyTorch\dataset2\output 에서 설정한 폴더에 모델파일이 에퍽때마다 저장됨
마지막 파일은 model_25.pth 이고 이것을 예측시 사용하면 됨
3종류의 파일이 생성됨
checkpoint.pth -> 가장 최근의 훈련결과(가중치, 하이퍼파라미터, 코드에서 확인할것)를 저장, 마지막 model_X.pth와 같음
model_X.pth -> 각 에퍽마다 훈련결과 (가중치, 하이퍼파라미터, 코드에서 확인할것) 를 저장함, X : 에퍽횟수
-> 저장한 pth파일의 가중치와 파라미터를 불러와서 다시 훈련할 수 있음, 명령행 인자중 resume 옵션이용
model.pth -> 모델전체정보, 모델구조와 가중치를 포함하는 파일, 위의 2개파일과 저장되는 내용이 다름
8. pth파일을 onnx파일로 변환
작성중...
pth파일은 opencv에서 지원하지않으므로 onnx파일로 변환하여 opencv에서 사용함
pth형식을 onnx로 변환하는 소스코드는 아래 주소를 참고할것
https://github.com/pytorch/vision/pull/1555
먼저 onnx패키지 설치해야함
> pip install onnx
아래코드는 model.pth 파일을 frcnn_resnet50.onnx 파일로 변환하는 예제임
각자의 상황에 맞게 수정하여 사용할것
입력파일 model.pth는 모델구조와 가중치를 모두 포함하도록 저장해야함
input_names, output_names는 모델의 입력층과 출력층의 이름을 의미하고 model 정보를 출력해보면 알수있음
dummy_input은 실제로 사용할 입력의 크기와 동일하게 생성해야함, 여기서는 입력영상이 3채널, 256x256 해상도임를 의미
현재 작업폴더에 입력파일 model.pth가 존재해야하고 출력파일 resnet50.onnx이 현재 폴더에 생성됨
> python pth2onnx.py
9. 테스트
테스트는 훈련, 검증에 사용되지 않은 새로운 영상으로 진행해야함
1) 파이토치 라이브러리를 이용하여 테스트 코드작성
model.pth 파일을 불러와서 테스트 영상으로 추론(inference) 또는 예측(prediction) 실행
참고사이트
https://pytorch.org/tutorials/intermediate/torchvision_tutorial.html
https://www.kaggle.com/code/mtszkw/inference-with-pretrained-faster-r-cnn-pytorch
https://github.com/spmallick/learnopencv/blob/master/PyTorch-faster-RCNN/PyTorch_faster_RCNN.ipynb
https://learnopencv.com/faster-r-cnn-object-detection-with-pytorch/
파이토치 소스코드 -> 추론부분은 파이토치라이브러리를 사용했고 영상출력은 opencv-python, matplotlib을 사용했음
import torch
from PIL import Image
import matplotlib.pyplot as plt
import torchvision.transforms as T
import numpy as np
import cv2
COCO_INSTANCE_CATEGORY_NAMES = [
'__background__', 'big robot', 'small robot'
]
# load pth model
model = torch.load('model.pth')
# set model to inference mode
model.eval()
#print(model)
# prediction
img_path = 'robot2.jpg'
threshold=0.5
img = Image.open(img_path)
transform = T.Compose([T.ToTensor()])
img = transform(img)
pred = model([img])
pred_class = [COCO_INSTANCE_CATEGORY_NAMES[i] for i in list(pred[0]['labels'].numpy())]
pred_boxes = [[(i[0], i[1]), (i[2], i[3])] for i in list(pred[0]['boxes'].detach().numpy())]
pred_score = list(pred[0]['scores'].detach().numpy())
pred_t = [pred_score.index(x) for x in pred_score if x>threshold][-1]
pred_boxes = pred_boxes[:pred_t+1]
pred_class = pred_class[:pred_t+1]
# Get predictions
img = cv2.imread(img_path)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
for i in range(len(pred_boxes)):
cv2.rectangle(img, (int(pred_boxes[i][0][0]),int(pred_boxes[i][0][1])), (int(pred_boxes[i][1][0]),int(pred_boxes[i][1][1])), (0, 255, 0), thickness=3)
cv2.putText(img,pred_class[i]+':'+f'{pred_score[i]:.4f}',(int(pred_boxes[i][0][0]),int(pred_boxes[i][0][1])), cv2.FONT_HERSHEY_SIMPLEX, 3, (0,255,0),thickness=3)
plt.figure(figsize=(10,10))
plt.imshow(img)
plt.xticks([])
plt.yticks([])
plt.show()
실행결과 -> 훈련,모델저장, 모델로드, 예측(추론)까지 전과정이 정상적으로 동작했음을 확인
pred = model([img])
print(pred)
[{'boxes': tensor([[2045.9016, 383.3862, 2728.3586, 1168.2094],
[ 305.1040, 349.7833, 1694.6129, 1533.6274]], grad_fn=StackBackward0>),
'labels': tensor([2, 1]),
'scores': tensor([0.9992, 0.9991], grad_fn=<IndexBackward0>)}]
| key | value : 1st bounding box | value : 2nd bounding box |
| 'boxes' | [2045.9016, 383.3862, 2728.3586, 1168.2094] | [ 305.1040, 349.7833, 1694.6129, 1533.6274] |
| 'labels' | 2 -> small robot | 1 -> big robot |
| 'scores' | 0.9992 | 0.9991 |
출력텐서 pred -> 자료형이 리스트이고 첫번째 원소 pred[0]는 딕셔너리이고, 키값 'boxes', labels', 'scores'를 가짐
키값이 'boxes'인 경우 바운딩박스별로 좌표(x,y,width, height), 1행 -> 첫번째바운딩박스정보, 2행 -> 두번째바운딩박스 정보
키값이 'labels'인 경우 바운딩박스별로 클래스id, 2 -> 첫번째바운딩박스의 클래스 id는 2번(small robot), 1->두번째 바운딩박스의 클래스 id는 1( big robot)
키값이 'scores'인 경우 확률값저장, 바운딩박스별로 객체가 존재할 확률, 0.9992 -> 첫번째 바운딩박스에 2번 객체가 존재할확률, 0.9991 -> 두번째 바운딩박스에 1번 객체가 존재할 확률
클래스 id는 0번 배경, 1번, big robot, 2번 small robot임
2) python opencv 라이브러리를 이용하여 테스트 코드작성
onnx파일을 불러와서 테스트 영상으로 추론실행
https://velog.io/@kyungmin1029/CV-Faster-R-CNN-Object-Detection-%EC%8B%A4%EC%8A%B5
3) C++ opencv 라이브러리를 이용하여 테스트 코드작성
onnx파일을 불러와서 테스트 영상으로 추론실행
https://github.com/opencv/opencv/tree/4.x/samples/dnn
10. 실습과제
1) faster r-cnn 모델의 구조와 원리를 조사하라
https://arxiv.org/pdf/1506.01497
https://junha1125.github.io/blog/artificial-intelligence/2020-08-15-1FastRCNN/
2) 다음 2가지 방식으로 훈련결과를 실시간으로 시각화하시오.
- 원본은 건드리지 말고 새로운 소스파일 my_train.py 생성하여 원본을 복사하여 작업하고 시각화 코드를 적당한 위치에 추가할것
- 훈련로스, 정확도, 검증로스, 검증정확도 데이터를 예제 코드 어떤 부분에서 가져올수 있는지 설명하시오.
- 훈련로스, 정확도, 검증로스, 검증정확도 그래프 출력기능을 다음 2가지 방법으로 구현 -> matplotlib을 이용하는 방법, 텐서보드를 사용하여 시각화하는 방법
- 매 에퍽마다 실시간으로 그래프를 업데이트하도록 할것(동영상으로 저장) -> 훈련하는 동안 시간에 따라 로스의 변화를 확인가능하도록 할것 -> 손실이 더이상 감소하지 않거나 감소하다가 다시 증가한다면 훈련중단해야함
그래프 예제 -> https://youtu.be/m2gqcl06UeM
3) 최종 모델파일을 이용하여 테스트하는 파이토치 코드 my_test.py를 작성하시오.
테스트영상은 로봇사진을 각각 10장씩 새로 찍어서 사용하라
파일을 개별적으로 오픈하지 말고 파이썬 os 패키지는 이용하여 폴더명을 주면 폴더에 저장된 영상파일을 모두 검색하여 불러와서 테스트하도록 할것
영상 1장의 추론(예측)시간을 측정하여 출력하시오.
참고 : https://learnopencv.com/faster-r-cnn-object-detection-with-pytorch/
4) 최종 모델파일을 이용하여 테스트하는 opencv C++ 코드 my_test.cpp를 작성하시오.
테스트영상은 로봇사진을 각각 10장씩 새로 찍어서 사용하라
파일을 개별적으로 오픈하지 말고 C++ filesystem 라이브러리를 이용하여 폴더명을 주면 폴더에 저장된 영상파일을 모두 검색하여 불러와 서 테스트하도록 할것
영상 1장의 추론(예측)시간을 측정하여 출력하시오.
참고 : https://modoocode.com/306
5) 훈련 성능을 평가하는 아래의 지표들의 의미를 설명하시오.
loss, loss_classifier, loss_box_reg, loss_objectness, loss_rpn_box_reg, AP, IoU, maxDets,
6) 아래 표의 의미를 설명하라.
7) 전이학습에서 훈련하는 웨이트는 컨벌루션레이어와 완전연결레이어중 어느것인가?
8) 백본모델을 resnet101 모델로 변경하여 훈련을 실행하고 resnet50과 성능을 비교하시오.
9) 훈련결과를 이용하여 과적합을 판단하는 방법을 설명하라.
10) 파이토치 예제에서 사용한 증식적용에 대하여 다음 사항을 설명하라.
- 파이토치 예제에서 사용한 증식방법이 무엇인지 소스코드를 찾아서 자세히 설명하라.
- 증식 전후 영상을 비교하여 적용여부를 확인하라. -> 증식변환이 영상파일과 레이블정보에 모두 적용되었는지 확인할것, 예를 들어 영상을 회전변환을 적용했다면 레이블정보도 똑같은 회전변환이 적용되어 좌표값이 수정되어어야함
- 증식을 추가하려면 어떤 소스파일의 어느 부분을 수정해야 하는지 설명하라
- 원하는 증식방법을 추가하여 훈련을 진행해보라.
- 원본소스는 건드리지 말고 새로운 파일 my_train.py를 만들어서 테스트코드를 추가하여 실행할것
참고 : https://cafe.daum.net/SmartRobot/W2or/159
11) Yolo모델을 이용하여 객체검출을 수행하라.
- 최신 Yolo 모델을 이용하여 예제의 로봇 데이터셋을 분류하는 과제를 수행하라.
- Yolo 모델 훈련시 사용하는 레이블 파일의 형식을 조사하시오.
- 로봇영상의 레이블파일(json)을 Yolo 레이블 형식(txt)으로 변환하시오.
- 울트라리틱스에서 제공하는 라이브러리를 설치하여 사용할것 https://www.ultralytics.com/ko
- 예제에서 사용한 Faster RCNN모델과 추론(예측)시간, 정확도를 비교하시오.
- 2번에서 사용한 그래프 기능을 Yolo 코드에 추가하여 그래프를 그려보시오.
- Yolo에서 훈련시 저장해주는 그래프를 첨부하시오.
- Yolo 백본의 가중치는 고정하고 전이학습을 수행하라.
https://learnopencv.com/fine-tuning-yolov10/
- 참고자료 -> https://youtu.be/uXulsX-7DIg
|
|
