|
|
1. 영상분류 코드분석
(1) dataset 로드 결과 확인
vision/references/classification/train.py 코드의 main함수에서 다음처럼 테스트 코드 추가하여 결과확인
...
train_dir = os.path.join(args.data_path, "train")
val_dir = os.path.join(args.data_path, "val")
dataset, dataset_test, train_sampler, test_sampler = load_data(train_dir, val_dir, args)
# display dataset
print(dataset.classes)
print(dataset.class_to_idx)
print(dataset.imgs)
# 이후 주석처리 후 실행
중략
클래스는 cat, dog으로 출력되었고 클래스 id는 각각 0,1이 할당되었음
dataset 객체는 리스트형식으로서 원소는 (영상파일의 경로, 클래스 id) 형태로 저장되어 있음을 확인
('D:\\Users\\2sungryul\\Dropbox\\Work\\PyTorch\\dataset1\\train\\cat\\0.jpg', 0)
('D:\\Users\\2sungryul\\Dropbox\\Work\\PyTorch\\dataset1\\train\\dog\\998.jpg', 1)
(2) dataloader 및 증식결과 확인
vision/references/classification/train.py 코드의 main함수에서 다음처럼 테스트 코드 추가하여 결과확인
...
data_loader = torch.utils.data.DataLoader(
dataset,
batch_size=args.batch_size,
sampler=train_sampler,
num_workers=args.workers,
pin_memory=True,
collate_fn=collate_fn,
)
# Display image and label.
import matplotlib.pyplot as plt
from torchvision.transforms.functional import to_pil_image
print(len(data_loader))
train_img, train_labels = next(iter(data_loader))
print(f"Feature batch shape: {train_img.size()}")
print(f"Labels batch shape: {train_labels.size()}")
img = train_img[0].squeeze()
label = train_labels[0]
print(f"Label: {label}")
plt.imshow(to_pil_image(img))
plt.show()
# 이후 주석처리 후 실행
12는 배치데이터의 갯수를 의미함
배치사이즈가 32이므로 32개의 영상이 하나의 배치데이터가 되고 이런 배치데이터가 12개 있다는 의미
[32, 3, 224, 224] -> 32는 배치사이즈, 3은 3채널컬러영상, 224,224은 영상의 해상도 전처리를 통해 모델에 입력되는 사이즈
첫번째 훈련데이터의 영상과 레이블을 출력하면 개사진이 증식되어 있음을 확인할수 있고 label은 1이 출력되어 있음
2. 객체검출 코드분석
(1) dataset 로드 결과 확인
vision/references/detection/train.py 코드의 main함수에서 다음처럼 테스트 코드 추가하여 결과확인
...
dataset, num_classes = get_dataset(is_train=True, args=args)
dataset_test, _ = get_dataset(is_train=False, args=args)
# display dataset
print(num_classes)
print(len(dataset))
print(dataset[0])
#print(dataset[0][0])
#print(dataset[0][1])
#print(dataset[0][1]['masks'])
import matplotlib.pyplot as plt
from torchvision.transforms.functional import to_pil_image
plt.imshow(to_pil_image(dataset[0][0]))
plt.show()
plt.subplot(121), plt.imshow(to_pil_image(dataset[0][1]['masks'][0]))
plt.subplot(122), plt.imshow(to_pil_image(dataset[0][1]['masks'][1]))
plt.show()
# 이후 주석처리 후 실행
3 -> 클래스의 갯수
160 -> 데이터(영상)의 갯수
첫번째 원소 dataset[0]는 2개의 원소로 구성됨 -> 영상 텐서, taget정보(boxes, labels, masks, image_id, area, iscrowd)
영상과 마스크를 출력한결과
마스크 : 객체의 바운딩박스 영역과 배경영역의 2가지 상태만 갖는 이진영상
dataset[0][0] -> 영상
dataset[0][1]['masks'][0] -> 첫번째 마스크
dataset[0][1]['masks'][1] -> 두번째 마스크
마스크는 영상에서 객체의 위치를 표시한 영상을 의미함
객체가 2개이고 좌측마스크는 클래스 id가 1인 객체(big robot)의 위치를 나타내고 우측마스크는 클래스 id가 2인 객체(small robot)의 위치를 나타냄
레이블링 파일(json)로 부터 마스크영상을 만들어주는 코드는 아래를 참고할것
vision/references/detection/coco_utils.py 파일안에서
convert_coco_poly_to_mask 함수
ConvertCocoPolysToMask 클래스
get_coco 함수
(2) dataloader 및 증식결과 확인
vision/references/detection/train.py 코드의 main함수에서 다음처럼 테스트 코드 추가하여 결과확인
...
data_loader = torch.utils.data.DataLoader(
dataset, batch_sampler=train_batch_sampler, num_workers=args.workers, collate_fn=train_collate_fn
)
# Display image and label.
import matplotlib.pyplot as plt
from torchvision.transforms.functional import to_pil_image
print(len(data_loader))
train_img, train_labels = next(iter(data_loader))
print(len(train_img))
print(len(train_labels))
print(train_img[0])
plt.imshow(to_pil_image(train_img[0]))
plt.show()
print(train_labels[0])
plt.subplot(131), plt.imshow(to_pil_image(train_labels[0]['masks'][0]))
plt.subplot(132), plt.imshow(to_pil_image(train_labels[0]['masks'][1]))
plt.subplot(133), plt.imshow(to_pil_image(train_labels[0]['masks'][2]))
plt.show()
# 이후 주석처리 후 실행
80은 배치데이터의 갯수
배치사이즈가 2이고 영상이 160개이므로 80개가 나옴
첫번째 영상데이터와 target 정보
검출예제에서는 증식지정이 없음 따라서 원본그대로 출력됨
위 입력영상에 대한 마스크영상
3. 영상분할 코드분석
(1) dataset 로드 결과 확인
vision/references/segmentation/train.py 코드의 main함수에서 다음처럼 테스트 코드 추가하여 결과확인
...
dataset, num_classes = get_dataset(args, is_train=True)
dataset_test, _ = get_dataset(args, is_train=False)
# display dataset
import numpy as np
def decode_segmap(image, nc=21):
label_colors = np.array([(0, 0, 0), # 0=background
# 1=aeroplane, 2=bicycle, 3=bird, 4=boat, 5=bottle
(128, 0, 0), (0, 128, 0), (128, 128, 0), (0, 0, 128), (128, 0, 128),
# 6=bus, 7=car, 8=cat, 9=chair, 10=cow
(0, 128, 128), (128, 128, 128), (64, 0, 0), (192, 0, 0), (64, 128, 0),
# 11=dining table, 12=dog, 13=horse, 14=motorbike, 15=person
(192, 128, 0), (64, 0, 128), (192, 0, 128), (64, 128, 128), (192, 128, 128),
# 16=potted plant, 17=sheep, 18=sofa, 19=train, 20=tv/monitor
(0, 64, 0), (128, 64, 0), (0, 192, 0), (128, 192, 0), (0, 64, 128)])
r = np.zeros_like(image).astype(np.uint8)
g = np.zeros_like(image).astype(np.uint8)
b = np.zeros_like(image).astype(np.uint8)
for l in range(0, nc):
idx = image == l
r[idx] = label_colors[l, 0]
g[idx] = label_colors[l, 1]
b[idx] = label_colors[l, 2]
rgb = np.stack([r, g, b], axis=2)
return rgb
print(num_classes)
print(len(dataset))
print(dataset[0])
print(dataset[0][1].size())
import matplotlib.pyplot as plt
from torchvision.transforms.functional import to_pil_image
plt.subplot(121), plt.imshow(to_pil_image(dataset[0][0]))
plt.subplot(122), plt.imshow(decode_segmap(dataset[0][1]))
plt.show()
# 이후 주석처리 후 실행
9 -> 클래스 갯수
160 -> 데이터셋 크기
2개의 tensor -> 입력영상(3채널 컬러), 마스크영상(1채널, 클래스id인 0~8사이 값만 가짐)
[480,480] -> 입력영상은 전처리변환과정에서 480x480 으로 resize
왼쪽은 훈련영상에 증식변환 적용된 영상(480x480), 오른쪽은 480x480 마스크영상(파란색->floor, 흰색->wall, 갈색->window)
(2) dataloader 및 증식결과 확인
vision/references/segmentation/train.py 코드의 main함수에서 다음처럼 테스트 코드 추가하여 결과확인
....
data_loader_test = torch.utils.data.DataLoader(
dataset_test, batch_size=1, sampler=test_sampler, num_workers=args.workers, collate_fn=utils.collate_fn
)
# Display image and label.
import matplotlib.pyplot as plt
from torchvision.transforms.functional import to_pil_image
import numpy as np
def decode_segmap(image, nc=21):
label_colors = np.array([(0, 0, 0), # 0=background
# 1=aeroplane, 2=bicycle, 3=bird, 4=boat, 5=bottle
(128, 0, 0), (0, 128, 0), (128, 128, 0), (0, 0, 128), (128, 0, 128),
# 6=bus, 7=car, 8=cat, 9=chair, 10=cow
(0, 128, 128), (128, 128, 128), (64, 0, 0), (192, 0, 0), (64, 128, 0),
# 11=dining table, 12=dog, 13=horse, 14=motorbike, 15=person
(192, 128, 0), (64, 0, 128), (192, 0, 128), (64, 128, 128), (192, 128, 128),
# 16=potted plant, 17=sheep, 18=sofa, 19=train, 20=tv/monitor
(0, 64, 0), (128, 64, 0), (0, 192, 0), (128, 192, 0), (0, 64, 128)])
r = np.zeros_like(image).astype(np.uint8)
g = np.zeros_like(image).astype(np.uint8)
b = np.zeros_like(image).astype(np.uint8)
for l in range(0, nc):
idx = image == l
r[idx] = label_colors[l, 0]
g[idx] = label_colors[l, 1]
b[idx] = label_colors[l, 2]
rgb = np.stack([r, g, b], axis=2)
return rgb
print(len(data_loader))
train_img, train_labels = next(iter(data_loader))
print(len(train_img))
print(len(train_labels))
print(train_img[0])
print(train_labels[0])
plt.subplot(121),plt.imshow(to_pil_image(train_img[0]))
plt.subplot(122),plt.imshow(decode_segmap(train_labels[0]))
plt.show()
# 이후 주석처리 후 실행
40 -> 배치데이터의 크기, 배치사이즈가 4이므로 160/4=4
4-> 1개의 배치데이터의 영상의 크기
4-> 1개의 배치데이터의 레이블(마스크영상)의 크기
2개의 tensor -> 입력영상 3채널 480x480, 마스크영상 1채널 480x480
왼쪽은 훈련영상에 증식변환이 적용된 영상(480x480), 오른쪽은 480x480 마스크영상(빨간색->ceiling, 흰색->wall, 갈색->window, 검정-> 레이블링하지 않는 영역)
dataloader 객체에 저장된 입력영상과 마스크영상이 훈련과정에서 실제로 사용되는 데이터임
4. 명령행 인자 처리코드 분석
(1) argparse 클래스 : 명령행 인자를 처리하는 파이썬 클래스
https://docs.python.org/3/library/argparse.html
argparse 객체 생성후 원하는 명령행 인자를 argparse 객체의 멤버변수로 add하고 명령행 실행시 전달된 인자를 받아서 객체에 add된 멤버를 초기화
(2) argparse 객체 생성 -> train.py 파일의 def get_args_parser(add_help=True): 함수를 참고
parser = argparse.ArgumentParser(description="PyTorch Classification Training", add_help=add_help)
인자의 설명, 도움말 기능 정의
(3) 인자 등록 -> train.py 파일의 def get_args_parser(add_help=True): 함수에서 수행
parser.add_argument("--data-path", default="/datasets01/imagenet_full_size/061417/", type=str, help="dataset path")
parser 객체에 data-path 라는 이름의 멤버변수가 추가됨, default 값은 명령행에서 인자를 입력하지 않는 경우 초기값
(4) 명령행 인자를 객체 멤버에 저장하는과정 -> train.py 파일에서 명령행 인자를 args 객체에 저장후 main 함수 호출
if __name__ == "__main__":
args = get_args_parser().parse_args() -> 명령행 인자를 받아서 parser객체의 멤버에 대입하고 리턴해서 args에 저장
main(args) -> args에 저장된 명령행 인자를 받아서 실행
명령행에서 다음처럼 입력
> python train.py --data-path C:\dataset ....
args = get_args_parser().parse_args()
-> args.data-path = "C:\dataset" 와 동일함
-> args.data-path 라는 멤버변수에 " C:\dataset" 값이 저장되어 main함수에 전달됨
5. 영상분할 예제에서 증식변환 코드분석
(1) 영상분할 증식은 references/segmentation/presets.py 코드에서 증식변환용 클래스가 정의되어 있음
SegmentationPresetTrain, SegmentationPresetEval 클래스에 각각 훈련용 증식, 검증용증식방법이 정의되어 있음
위 2개의 클래스 내부에 생성자 __init__안에 원하는 변환(증식)을 추가해주면 됨
get_modules함수를 보면 use_v2 인자가 정의되어 있으면 torchvision.transforms.v2 의 변환(v2버전)을 사용하고 그렇지 않으면 torchvision.transforms의 변환(v1버전)을 사용함
v1을 사용하는 경우 import transforms 을 수행하면 references/segmentation/transforms.py 모듈이 임포트됨
따라서 transforms.py 에 정의된 기능만 사용가능, 근데 몇가지 v1 api를 이용한 기능만 구현되어 있음
v1에서 제공하는 더 많은 변환을 사용하려면 transforms.py 에 추가해줘야함 아니면 torchvision.transforms (v1)에 포함된 기능을 직접호출해서 사용하면됨
v1라이브러리 -> torchvision.transforms
v2라이브러리 -> torchvision.transforms.v2
V1 API Reference
https://pytorch.org/vision/stable/transforms.html#v1-api-referencehttps://pytorch.org/vision/0.9/transforms.html
V2 API reference
https://pytorch.org/vision/stable/transforms.html#v2-api-reference-recommended
Transforming and augmenting images -> 변환및 증식 예제
https://pytorch.org/vision/stable/transforms.html
Getting started with transforms v2 -> v2 변환이용하는 튜토리얼
https://pytorch.org/vision/main/auto_examples/transforms/plot_transforms_getting_started.html
(2) references/segmentation/train.py 코드의 get_transform함수에서 SegmentationPresetTrain, SegmentationPresetEval 객체를 생성하여 리턴함
(3) references/segmentation/train.py 코드의 get_dataset함수에서 get_transform함수 호출하여 변환적용된 데이터셋 생성
(4) references/segmentation/train.py 코드의 main함수에서 get_dataset함수를 호출함
6. 하이퍼파라미터
대부분의 하이퍼파라미터를 명령행인자로 입력받아서 초기화 하도록 되어있음
명령행 인자를 파싱하는 부분을 이해해야함
7. 모델저장
8. 실습 과제
1) 영상분류 코드에서 증식옵션을 완전히 제거해보고 dataloader에 저장된 영상을 출력해보라
2) 객체검출 코드에서 증식옵션(resize, 회전 등)을 추가하여 마스크영상도 같이 증식이 되는지 dataloader에 저장된 영상을 확인하라
3) 영상분할 코드에서 증식옵션중에 480x480 resize만 남기고 나머지는 제거하고 실행하여 마스크영상도 같이 증식이 되는지 dataloader에 저장된 영상을 확인하라
|
|
