{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Pytorch starter - FasterRCNN Train\nIn this notebook I enabled the GPU and the Internet access (needed for the pre-trained weights). We can not use Internet during inference, so I'll create another notebook for commiting. Stay tuned!\n\nYou can find the [inference notebook here](https://www.kaggle.com/pestipeti/pytorch-starter-fasterrcnn-inference)\n\n- FasterRCNN from torchvision\n- Use Resnet50 backbone\n- Albumentation enabled (simple flip for now)\n","metadata":{}},{"cell_type":"markdown","source":"## 참고 사이트\n- [PyTorch](https://pytorch.org/)\n- [PyTorch로 시작하는 딥러닝 입문](https://wikidocs.net/book/2788)\n- [파이토치 한국 사용자 모임](https://pytorch.kr/)\n","metadata":{}},{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport cv2\nimport os\nimport re\n\nfrom PIL import Image\n\nimport albumentations as A\nfrom albumentations.pytorch.transforms import ToTensorV2\n\nimport torch\nimport torchvision\n\nfrom torchvision.models.detection.faster_rcnn import FastRCNNPredictor\nfrom torchvision.models.detection import FasterRCNN\nfrom torchvision.models.detection.rpn import AnchorGenerator\n\nfrom torch.utils.data import DataLoader, Dataset\nfrom torch.utils.data.sampler import SequentialSampler\n\nfrom matplotlib import pyplot as plt\n\n# Path\nDIR_INPUT = '/kaggle/input/global-wheat-detection'\nDIR_TRAIN = f'{DIR_INPUT}/train'\nDIR_TEST = f'{DIR_INPUT}/test'","metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","execution":{"iopub.status.busy":"2022-01-04T08:01:28.939049Z","iopub.execute_input":"2022-01-04T08:01:28.939448Z","iopub.status.idle":"2022-01-04T08:01:31.401188Z","shell.execute_reply.started":"2022-01-04T08:01:28.939397Z","shell.execute_reply":"2022-01-04T08:01:31.400378Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# train data 불러오기\ntrain_df = pd.read_csv(f'{DIR_INPUT}/train.csv')\ntrain_df.shape","metadata":{"execution":{"iopub.status.busy":"2022-01-04T08:01:31.403147Z","iopub.execute_input":"2022-01-04T08:01:31.403738Z","iopub.status.idle":"2022-01-04T08:01:31.657714Z","shell.execute_reply.started":"2022-01-04T08:01:31.403685Z","shell.execute_reply":"2022-01-04T08:01:31.656957Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df.head()","metadata":{"execution":{"iopub.status.busy":"2022-01-04T08:01:58.832293Z","iopub.execute_input":"2022-01-04T08:01:58.832637Z","iopub.status.idle":"2022-01-04T08:01:58.850452Z","shell.execute_reply.started":"2022-01-04T08:01:58.832588Z","shell.execute_reply":"2022-01-04T08:01:58.849533Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# BBOX 컬럼을 X, Y, W, H 컬럼으로 분할(?)\n# 위치 초기화\ntrain_df['x'] = -1\ntrain_df['y'] = -1\ntrain_df['w'] = -1\ntrain_df['h'] = -1\n\ndef expand_bbox(x):\n    # 정규식 [0-9]: 숫자, + : 1번 이상 반복, [.]? : .이 있어도 되고 없어도 됨, *: 0번이상 반복\n    r = np.array(re.findall(\"([0-9]+[.]?[0-9]*)\", x))\n    # r에 값이 없을 경우 : 충족X\n    if len(r) == 0:\n        r = [-1, -1, -1, -1]\n    return r\n\n# bbox리스트의 각각의 위치를 x, y, w, h로 할당 (stack 형식)\ntrain_df[['x', 'y', 'w', 'h']] = np.stack(train_df['bbox'].apply(lambda x: expand_bbox(x)))\ntrain_df.drop(columns=['bbox'], inplace=True) # bbox 컬럼 제거\n# 타입 변경 to float\ntrain_df['x'] = train_df['x'].astype(np.float)\ntrain_df['y'] = train_df['y'].astype(np.float)\ntrain_df['w'] = train_df['w'].astype(np.float)\ntrain_df['h'] = train_df['h'].astype(np.float)","metadata":{"execution":{"iopub.status.busy":"2022-01-04T08:01:59.437264Z","iopub.execute_input":"2022-01-04T08:01:59.4376Z","iopub.status.idle":"2022-01-04T08:02:01.313544Z","shell.execute_reply.started":"2022-01-04T08:01:59.437548Z","shell.execute_reply":"2022-01-04T08:02:01.312756Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df.head()","metadata":{"execution":{"iopub.status.busy":"2022-01-04T08:02:02.682741Z","iopub.execute_input":"2022-01-04T08:02:02.683119Z","iopub.status.idle":"2022-01-04T08:02:02.700217Z","shell.execute_reply.started":"2022-01-04T08:02:02.683068Z","shell.execute_reply":"2022-01-04T08:02:02.699511Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"image_ids = train_df['image_id'].unique()\nprint(\"Image 개수 :\", len(image_ids) )\n# train, valid로 분할\nvalid_ids = image_ids[-665:]\ntrain_ids = image_ids[:-665]","metadata":{"execution":{"iopub.status.busy":"2022-01-04T08:02:04.383464Z","iopub.execute_input":"2022-01-04T08:02:04.383824Z","iopub.status.idle":"2022-01-04T08:02:04.39918Z","shell.execute_reply.started":"2022-01-04T08:02:04.383752Z","shell.execute_reply":"2022-01-04T08:02:04.398196Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# id를 가지고 데이터프레임 분할\nvalid_df = train_df[train_df['image_id'].isin(valid_ids)]\ntrain_df = train_df[train_df['image_id'].isin(train_ids)]","metadata":{"execution":{"iopub.status.busy":"2022-01-04T08:02:04.977825Z","iopub.execute_input":"2022-01-04T08:02:04.978161Z","iopub.status.idle":"2022-01-04T08:02:05.015412Z","shell.execute_reply.started":"2022-01-04T08:02:04.978112Z","shell.execute_reply":"2022-01-04T08:02:05.014649Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"valid_df.shape, train_df.shape","metadata":{"execution":{"iopub.status.busy":"2022-01-04T08:02:06.407411Z","iopub.execute_input":"2022-01-04T08:02:06.407742Z","iopub.status.idle":"2022-01-04T08:02:06.413742Z","shell.execute_reply.started":"2022-01-04T08:02:06.407692Z","shell.execute_reply":"2022-01-04T08:02:06.412856Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df['image_id']","metadata":{"execution":{"iopub.status.busy":"2022-01-04T08:02:06.879278Z","iopub.execute_input":"2022-01-04T08:02:06.879634Z","iopub.status.idle":"2022-01-04T08:02:06.888402Z","shell.execute_reply.started":"2022-01-04T08:02:06.879577Z","shell.execute_reply":"2022-01-04T08:02:06.886316Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"index = 0\nimage_id = train_df['image_id'][0]\nrecords = train_df[train_df['image_id'] == image_id] \n# 이미지 id가 같은 데이터프레임 가져오기\n\n# 이미지 불러오기 cv2(OpenCV) 사용\nimage = cv2.imread(f'{self.image_dir}/{image_id}.jpg', cv2.IMREAD_COLOR)\n# OpenCV가 컬러를 저장하는 방식인 BGR을 RGB로 변환\nimage = cv2.cvtColor(image, cv2.COLOR_BGR2RGB).astype(np.float32)\nimage /= 255.0 # 0 ~ 1로 스케일링\n\nboxes = records[['x', 'y', 'w', 'h']].values\n# x2, y2값 찾기\nboxes[:, 2] = boxes[:, 0] + boxes[:, 2]\nboxes[:, 3] = boxes[:, 1] + boxes[:, 3]\n        \narea = (boxes[:, 3] - boxes[:, 1]) * (boxes[:, 2] - boxes[:, 0])\n\n# tensor 값으로 변환\narea = torch.as_tensor(area, dtype=torch.float32)\n# there is only one class => 객체는 한 종류만 존재\nlabels = torch.ones((records.shape[0],), dtype=torch.int64)\nprint(records.shape)\nprint(labels)\n\n# 모든 인스턴스는 crowd 상태가 아님을 가정\niscrowd = torch.zeros((records.shape[0],), dtype=torch.int64)\n        \n","metadata":{"execution":{"iopub.status.busy":"2022-01-04T08:02:33.731734Z","iopub.execute_input":"2022-01-04T08:02:33.732167Z","iopub.status.idle":"2022-01-04T08:02:33.807623Z","shell.execute_reply.started":"2022-01-04T08:02:33.73211Z","shell.execute_reply":"2022-01-04T08:02:33.806368Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## [Pytorch 데이터셋 정의하기](https://tutorials.pytorch.kr/intermediate/torchvision_tutorial.html#id1)\n객체 검출, 인스턴스 분할 및 사용자 키포인트(Keypoint) 검출을 학습하기 위한 참조 스크립트를 통해 새로운 사용자 정의 데이터셋 추가를 쉽게 진행해 볼 수 있습니다. 데이터셋은 표준 torch.utils.data.Dataset 클래스를 상속 받아야 하며, \\_\\_len__ 와 \\_\\_getitem__ 메소드를 구현해 주어야 합니다.\n\n데이터셋에서 필요한 유일한 특성은 \\_\\_getitem__ 메소드가 다음을 반환 해야 하는 것입니다:\n\n- 이미지 : PIL(Python Image Library) 이미지의 크기 (H, W)\n- 대상: 다음의 필드를 포함하는 사전 타입\n- **boxes** (FloatTensor[N, 4]): N 개의 바운딩 박스(Bounding box)의 좌표를 **[x0, y0, x1, y1]** 형태로 가집니다. x와 관련된 값 범위는 0 부터 W 이고 y와 관련된 값의 범위는 0 부터 H 까지입니다.\n\n![image.png](attachment:80cfbea7-dc33-404a-8627-ad95a9588986.png)\n- labels (Int64Tensor[N]): 바운딩 박스 마다의 라벨 정보입니다. 0 은 항상 배경의 클래스를 표현합니다.\n- image_id (Int64Tensor[1]): 이미지 구분자입니다. 데이터셋의 모든 이미지 간에 고유한 값이어야 하며 평가 중에도 사용됩니다.\n- area (Tensor[N]): 바운딩 박스의 면적입니다. 면적은 평가 시 작음,중간,큰 박스 간의 점수를 내기 위한 기준이며 COCO 평가를 기준으로 합니다.\n- iscrowd (UInt8Tensor[N]): 이 값이 참일 경우 평가에서 제외합니다.\n- (선택적) masks (UInt8Tensor[N, H, W]): N 개의 객체 마다의 분할 마스크 정보입니다.\n- (선택적) keypoints (FloatTensor[N, K, 3]): N 개의 객체마다의 키포인트 정보입니다. 키포인트는 [x, y, visibility] 형태의 값입니다. visibility 값이 0인 경우 키포인트는 보이지 않음을 의미합니다. 데이터 증강(Data augmentation)의 경우 키포인트 좌우 반전의 개념은 데이터 표현에 따라 달라지며, 새로운 키포인트 표현에 대해 “references/detection/transforms.py” 코드 부분을 수정 해야 할 수도 있습니다","metadata":{},"attachments":{"80cfbea7-dc33-404a-8627-ad95a9588986.png":{"image/png":"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"}}},{"cell_type":"code","source":"class WheatDataset(Dataset):\n\n    def __init__(self, dataframe, image_dir, transforms=None):\n        super().__init__()\n        \n        self.image_ids = dataframe['image_id'].unique() # 이미지 고유 ID\n        self.df = dataframe\n        self.image_dir = image_dir\n        self.transforms = transforms\n\n    def __getitem__(self, index: int):\n        # 이미지 index로 아이템 불러오기\n\n        image_id = self.image_ids[index]\n        records = self.df[self.df['image_id'] == image_id] \n        # 이미지 id가 같은 데이터프레임 가져오기\n\n        # 이미지 불러오기 cv2(OpenCV) 사용\n        image = cv2.imread(f'{self.image_dir}/{image_id}.jpg', cv2.IMREAD_COLOR)\n        # OpenCV가 컬러를 저장하는 방식인 BGR을 RGB로 변환\n        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB).astype(np.float32)\n        image /= 255.0 # 0 ~ 1로 스케일링\n\n        boxes = records[['x', 'y', 'w', 'h']].values\n        # x2, y2값 찾기\n        boxes[:, 2] = boxes[:, 0] + boxes[:, 2]\n        boxes[:, 3] = boxes[:, 1] + boxes[:, 3]\n        \n        area = (boxes[:, 3] - boxes[:, 1]) * (boxes[:, 2] - boxes[:, 0])\n\n        # tensor 값으로 변환\n        area = torch.as_tensor(area, dtype=torch.float32)\n        # there is only one class => 객체는 한 종류만 존재\n        labels = torch.ones((records.shape[0],), dtype=torch.int64)\n        # 모든 인스턴스는 crowd 상태가 아님을 가정\n        iscrowd = torch.zeros((records.shape[0],), dtype=torch.int64)\n        \n        target = {}\n        target['boxes'] = boxes\n        target['labels'] = labels\n        # target['masks'] = None\n        target['image_id'] = torch.tensor([index])\n        target['area'] = area\n        target['iscrowd'] = iscrowd\n\n        if self.transforms:\n            sample = {\n                'image': image,\n                'bboxes': target['boxes'],\n                'labels': labels\n            }\n            # ** : 딕셔너리형태로 전달 가능\n            sample = self.transforms(**sample)\n            image = sample['image']\n            #permute : 차원변경?/ bboxes = (x1,y1,x2,y2) / zip *로 풀어서 각 값을 tensor로 바꾸고 다시 튜플로 묶는다.\n            target['boxes'] = torch.stack(tuple(map(torch.tensor, zip(*sample['bboxes'])))).permute(1, 0)\n\n        return image, target, image_id\n\n    def __len__(self) -> int:\n        return self.image_ids.shape[0]","metadata":{"execution":{"iopub.status.busy":"2021-12-30T06:34:00.07638Z","iopub.execute_input":"2021-12-30T06:34:00.076932Z","iopub.status.idle":"2021-12-30T06:34:00.095292Z","shell.execute_reply.started":"2021-12-30T06:34:00.076769Z","shell.execute_reply":"2021-12-30T06:34:00.094389Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**iscrowd**\nThe segmentation format depends on whether the instance represents a single object (iscrowd=0 in which case polygons are used) or a collection of objects (iscrowd=1 in which case RLE is used). Note that a single object (iscrowd=0) may require multiple polygons, for example if occluded. Crowd annotations (iscrowd=1) are used to label large groups of objects (e.g. a crowd of people).","metadata":{}},{"cell_type":"code","source":"# Albumentations\ndef get_train_transform():\n    return A.Compose([\n        # 이미지 뒤집기\n        A.Flip(0.5),\n        # ToTensor의 역할 = 텐서자료형으로 바꾸기\n        ToTensorV2(p=1.0)\n    ], bbox_params={'format': 'pascal_voc', 'label_fields': ['labels']})\n\ndef get_valid_transform():\n    return A.Compose([\n        ToTensorV2(p=1.0)\n    ], bbox_params={'format': 'pascal_voc', 'label_fields': ['labels']})\n","metadata":{"execution":{"iopub.status.busy":"2021-12-30T06:34:00.09658Z","iopub.execute_input":"2021-12-30T06:34:00.097173Z","iopub.status.idle":"2021-12-30T06:34:00.107572Z","shell.execute_reply.started":"2021-12-30T06:34:00.097123Z","shell.execute_reply":"2021-12-30T06:34:00.106637Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### [Albumentations](https://albumentations.readthedocs.io/en/latest/)\n### [Albumentation Tutorial 한글](https://hoya012.github.io/blog/albumentation_tutorial/)\nimage의 형태를 변환\n\n[ToTensorV2](https://albumentations.ai/docs/api_reference/pytorch/transforms/)","metadata":{}},{"cell_type":"markdown","source":"# Create the model","metadata":{}},{"cell_type":"code","source":"# load a model; pre-trained on COCO\nmodel = torchvision.models.detection.fasterrcnn_resnet50_fpn(pretrained=True)","metadata":{"execution":{"iopub.status.busy":"2021-12-30T06:34:00.109375Z","iopub.execute_input":"2021-12-30T06:34:00.109951Z","iopub.status.idle":"2021-12-30T06:34:06.752086Z","shell.execute_reply.started":"2021-12-30T06:34:00.109901Z","shell.execute_reply":"2021-12-30T06:34:06.751163Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"[fasterrcnn_resnet50_fpn](https://pytorch.org/vision/main/generated/torchvision.models.detection.fasterrcnn_resnet50_fpn.html)\n- pretrained : If True, returns a model pre-trained on COCO train2017","metadata":{}},{"cell_type":"code","source":"num_classes = 2  # 1 class (wheat) + background\n\n# 모델의 차원 정보 얻기\nin_features = model.roi_heads.box_predictor.cls_score.in_features\n\n# 모델의 차원, 새로 정의한 클래스 개수로 헤드 교체\nmodel.roi_heads.box_predictor = FastRCNNPredictor(in_features, num_classes)","metadata":{"execution":{"iopub.status.busy":"2021-12-30T06:34:06.753482Z","iopub.execute_input":"2021-12-30T06:34:06.753999Z","iopub.status.idle":"2021-12-30T06:34:06.763355Z","shell.execute_reply.started":"2021-12-30T06:34:06.753947Z","shell.execute_reply":"2021-12-30T06:34:06.762618Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def collate_fn(batch):\n    return tuple(zip(*batch)) # unzip\n\ntrain_dataset = WheatDataset(train_df, DIR_TRAIN, get_train_transform())\nvalid_dataset = WheatDataset(valid_df, DIR_TRAIN, get_valid_transform())\n\n\n# split the dataset in train and test set\nindices = torch.randperm(len(train_dataset)).tolist() # 개수만큼 난수 순열\n\ntrain_data_loader = DataLoader(\n    train_dataset,\n    batch_size=16,\n    shuffle=False,\n    num_workers=4,# 멀티프로세싱\n    collate_fn=collate_fn\n)\n\nvalid_data_loader = DataLoader(\n    valid_dataset,\n    batch_size=8,\n    shuffle=False,\n    num_workers=4,\n    collate_fn=collate_fn\n)","metadata":{"execution":{"iopub.status.busy":"2021-12-30T06:34:06.775471Z","iopub.execute_input":"2021-12-30T06:34:06.776063Z","iopub.status.idle":"2021-12-30T06:34:06.799568Z","shell.execute_reply.started":"2021-12-30T06:34:06.775989Z","shell.execute_reply":"2021-12-30T06:34:06.798874Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 디바이스 cuda -> 없으면 cpu\ndevice = torch.device('cuda') if torch.cuda.is_available() else torch.device('cpu')","metadata":{"execution":{"iopub.status.busy":"2021-12-30T06:34:06.802271Z","iopub.execute_input":"2021-12-30T06:34:06.802543Z","iopub.status.idle":"2021-12-30T06:34:06.824297Z","shell.execute_reply.started":"2021-12-30T06:34:06.802501Z","shell.execute_reply":"2021-12-30T06:34:06.823398Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Sample","metadata":{}},{"cell_type":"code","source":"print(train_data_loader)\n# data 처음부터 읽어오기\nimages, targets, image_ids = next(iter(train_data_loader))\nprint(images[0])\n# 모든 모듈의 매개변수와 버퍼를 CUDA tensor로 변경\nimages = list(image.to(device) for image in images)\ntargets = [{k: v.to(device) for k, v in t.items()} for t in targets]\nprint(images[0],'\\n\\n')","metadata":{"execution":{"iopub.status.busy":"2021-12-30T06:34:06.825605Z","iopub.execute_input":"2021-12-30T06:34:06.82609Z","iopub.status.idle":"2021-12-30T06:34:14.841889Z","shell.execute_reply.started":"2021-12-30T06:34:06.826039Z","shell.execute_reply":"2021-12-30T06:34:14.840417Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Image[2] 표시","metadata":{}},{"cell_type":"code","source":"# 박스 좌표값 int형으로 변경\nboxes = targets[2]['boxes'].cpu().numpy().astype(np.int32)\n# 차원 변경\nprint(images[2].shape)\nsample = images[2].permute(1,2,0).cpu().numpy()\nprint(sample.shape)","metadata":{"execution":{"iopub.status.busy":"2021-12-30T06:34:14.844146Z","iopub.execute_input":"2021-12-30T06:34:14.844521Z","iopub.status.idle":"2021-12-30T06:34:14.857953Z","shell.execute_reply.started":"2021-12-30T06:34:14.844467Z","shell.execute_reply":"2021-12-30T06:34:14.857252Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 이미지에 박스 표시\nfig, ax = plt.subplots(1, 1, figsize=(16, 8))\n\nfor box in boxes:\n    cv2.rectangle(sample,\n                  (box[0], box[1]),\n                  (box[2], box[3]),\n                  (220, 0, 0), 3)\n    \nax.set_axis_off()\nax.imshow(sample)","metadata":{"execution":{"iopub.status.busy":"2021-12-30T06:34:14.860368Z","iopub.execute_input":"2021-12-30T06:34:14.860732Z","iopub.status.idle":"2021-12-30T06:34:15.420389Z","shell.execute_reply.started":"2021-12-30T06:34:14.860681Z","shell.execute_reply":"2021-12-30T06:34:15.4195Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Train","metadata":{}},{"cell_type":"code","source":"# model=>cuda\nmodel.to(device)\n# 파라미터 받아서 전달\nparams = [p for p in model.parameters() if p.requires_grad]\n\n# 확률적 경사 하강법\noptimizer = torch.optim.SGD(params, lr=0.005, momentum=0.9, weight_decay=0.0005)\n\n# 매 step_size epoch 마다 감마로 각 매개변수 그룹의 학습률을 감소\n# lr_scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=3, gamma=0.1) \nlr_scheduler = None\n\nnum_epochs = 2","metadata":{"execution":{"iopub.status.busy":"2021-12-30T06:42:20.19695Z","iopub.execute_input":"2021-12-30T06:42:20.197315Z","iopub.status.idle":"2021-12-30T06:42:20.20761Z","shell.execute_reply.started":"2021-12-30T06:42:20.19726Z","shell.execute_reply":"2021-12-30T06:42:20.206835Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"requires_grad : keeps track of how it was created\n\n[모델 파라미터](https://easy-going-programming.tistory.com/11)\n\n[파이토치 옵티마이저 torch.optim](https://pytorch.org/docs/stable/optim.html)","metadata":{}},{"cell_type":"code","source":"# 평균 <= loss 결과의 평균값을 내기 위한 클래스 (굳이 클래스 안써도 될 듯)\nclass Averager:\n    def __init__(self):\n        self.current_total = 0.0\n        self.iterations = 0.0\n\n    def send(self, value):\n        self.current_total += value\n        self.iterations += 1\n\n    @property\n    def value(self):\n        if self.iterations == 0:\n            return 0\n        else:\n            return 1.0 * self.current_total / self.iterations\n\n    def reset(self):\n        self.current_total = 0.0\n        self.iterations = 0.0","metadata":{"execution":{"iopub.status.busy":"2021-12-30T06:34:06.766566Z","iopub.execute_input":"2021-12-30T06:34:06.767049Z","iopub.status.idle":"2021-12-30T06:34:06.773785Z","shell.execute_reply.started":"2021-12-30T06:34:06.766869Z","shell.execute_reply":"2021-12-30T06:34:06.772711Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 손실함수 => 평균값\nloss_hist = Averager()\nitr = 1\n\n# 데이터셋에 대한 훈련\nfor epoch in range(num_epochs):\n    loss_hist.reset()\n    \n    for images, targets, image_ids in train_data_loader:\n        \n        images = list(image.to(device) for image in images)\n        targets = [{k: v.to(device) for k, v in t.items()} for t in targets]\n\n        loss_dict = model(images, targets)\n\n        losses = sum(loss for loss in loss_dict.values())\n        loss_value = losses.item()\n\n        loss_hist.send(loss_value)\n\n        optimizer.zero_grad()\n        losses.backward()\n        optimizer.step() # 매개변수 업데이트\n\n        if itr % 50 == 0:\n            print(f\"Iteration #{itr} loss: {loss_value}\")\n\n        itr += 1\n    \n    # update the learning rate\n    if lr_scheduler is not None:\n        lr_scheduler.step()\n\n    print(f\"Epoch #{epoch} loss: {loss_hist.value}\")   ","metadata":{"execution":{"iopub.status.busy":"2021-12-30T06:57:11.569225Z","iopub.execute_input":"2021-12-30T06:57:11.56993Z","iopub.status.idle":"2021-12-30T07:07:34.931336Z","shell.execute_reply.started":"2021-12-30T06:57:11.569675Z","shell.execute_reply":"2021-12-30T07:07:34.930148Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### 검증 - 사진 하나만 출력","metadata":{}},{"cell_type":"code","source":"images, targets, image_ids = next(iter(valid_data_loader))","metadata":{"execution":{"iopub.status.busy":"2021-12-30T07:29:11.760297Z","iopub.execute_input":"2021-12-30T07:29:11.760651Z","iopub.status.idle":"2021-12-30T07:29:13.597729Z","shell.execute_reply.started":"2021-12-30T07:29:11.760596Z","shell.execute_reply":"2021-12-30T07:29:13.596371Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"images = list(img.to(device) for img in images)\ntargets = [{k: v.to(device) for k, v in t.items()} for t in targets]","metadata":{"execution":{"iopub.status.busy":"2021-12-30T07:29:13.599901Z","iopub.execute_input":"2021-12-30T07:29:13.600214Z","iopub.status.idle":"2021-12-30T07:29:13.68172Z","shell.execute_reply.started":"2021-12-30T07:29:13.600167Z","shell.execute_reply":"2021-12-30T07:29:13.680565Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"boxes = targets[1]['boxes'].cpu().numpy().astype(np.int32)\nsample = images[1].permute(1,2,0).cpu().numpy()","metadata":{"execution":{"iopub.status.busy":"2021-12-30T07:29:13.683332Z","iopub.execute_input":"2021-12-30T07:29:13.683853Z","iopub.status.idle":"2021-12-30T07:29:13.691997Z","shell.execute_reply.started":"2021-12-30T07:29:13.683683Z","shell.execute_reply":"2021-12-30T07:29:13.691151Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.eval() # eval : 평가하는 과정에서는 모든 노드를 사용하겠다는 의미(dropout 없음)\ncpu_device = torch.device(\"cpu\") # 한장이라서??\n\noutputs = model(images)\noutputs = [{k: v.to(cpu_device) for k, v in t.items()} for t in outputs]","metadata":{"execution":{"iopub.status.busy":"2021-12-30T07:29:14.332985Z","iopub.execute_input":"2021-12-30T07:29:14.333326Z","iopub.status.idle":"2021-12-30T07:29:14.723487Z","shell.execute_reply.started":"2021-12-30T07:29:14.333271Z","shell.execute_reply":"2021-12-30T07:29:14.722739Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(outputs[1]['boxes'].int())","metadata":{"execution":{"iopub.status.busy":"2021-12-30T07:29:14.886385Z","iopub.execute_input":"2021-12-30T07:29:14.886753Z","iopub.status.idle":"2021-12-30T07:29:14.895986Z","shell.execute_reply.started":"2021-12-30T07:29:14.886697Z","shell.execute_reply":"2021-12-30T07:29:14.89503Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 그냥 사진을 다시 보여줌..?\nfig, ax = plt.subplots(1, 1, figsize=(16, 8))\n\nfor box in boxes:\n    cv2.rectangle(sample,\n                  (box[0], box[1]),\n                  (box[2], box[3]),\n                  (220, 0, 0), 3)\n    \nax.set_axis_off()\nax.imshow(sample)","metadata":{"execution":{"iopub.status.busy":"2021-12-30T07:29:17.34982Z","iopub.execute_input":"2021-12-30T07:29:17.350199Z","iopub.status.idle":"2021-12-30T07:29:17.682232Z","shell.execute_reply.started":"2021-12-30T07:29:17.350142Z","shell.execute_reply":"2021-12-30T07:29:17.681445Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 모델을 이용해 예측한 바운딩 박스 (따로 추가)\nsample = images[1].permute(1,2,0).cpu().numpy()\nfig, ax = plt.subplots(1, 1, figsize=(16, 8))\n\nfor box in outputs[1]['boxes'].int():\n    cv2.rectangle(sample,\n                  (box[0], box[1]),\n                  (box[2], box[3]),\n                  (220, 0, 0), 3)\n    \nax.set_axis_off()\nax.imshow(sample)","metadata":{"execution":{"iopub.status.busy":"2021-12-30T07:29:19.506538Z","iopub.execute_input":"2021-12-30T07:29:19.506894Z","iopub.status.idle":"2021-12-30T07:29:19.833982Z","shell.execute_reply.started":"2021-12-30T07:29:19.50684Z","shell.execute_reply":"2021-12-30T07:29:19.83289Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"모델을 범용적(cpu, gpu 상관없이)으로 저장\n\n[모델을 저장하고 불러오기](https://tutorials.pytorch.kr/recipes/recipes/save_load_across_devices.html)","metadata":{}},{"cell_type":"code","source":"torch.save(model.state_dict(), 'fasterrcnn_resnet50_fpn.pth')","metadata":{"execution":{"iopub.status.busy":"2021-12-30T07:21:35.777831Z","iopub.execute_input":"2021-12-30T07:21:35.778205Z","iopub.status.idle":"2021-12-30T07:21:35.991814Z","shell.execute_reply.started":"2021-12-30T07:21:35.778152Z","shell.execute_reply":"2021-12-30T07:21:35.990983Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"[pytorch에서 가장 간단한 방법으로 객체 감지를 수행하는 방법](https://ichi.pro/ko/faster-rcnneulo-pytorcheseo-gajang-swiun-gaegche-gamji-232142356479573)\n\n- 현 코드에는 유효성 검사 기능이 없음\n- 가지고있는 라벨이 한 개\n- 바운딩 박스용 코드","metadata":{}},{"cell_type":"code","source":"boxes = targets[6]['boxes'].cpu().numpy().astype(np.int32)\nsample = images[6].permute(1,2,0).cpu().numpy()\n\nfig, ax = plt.subplots(1, 1, figsize=(16, 8))\n\nfor box in boxes:\n    cv2.rectangle(sample,\n                  (box[0], box[1]),\n                  (box[2], box[3]),\n                  (220, 0, 0), 3)\n    \nax.set_axis_off()\nax.imshow(sample)","metadata":{"execution":{"iopub.status.busy":"2021-12-30T07:50:28.804911Z","iopub.execute_input":"2021-12-30T07:50:28.805379Z","iopub.status.idle":"2021-12-30T07:50:29.112684Z","shell.execute_reply.started":"2021-12-30T07:50:28.805304Z","shell.execute_reply":"2021-12-30T07:50:29.111685Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"samples = [image.permute(1,2,0).cpu().numpy() for image in images]\nfig, axs = plt.subplots(4, 2, figsize=(15, 35))\nfor i in range(len(outputs)):\n    for box in outputs[i]['boxes'].int():\n        cv2.rectangle(samples[i],\n                        (box[0], box[1]),\n                        (box[2], box[3]),\n                        (220, 0, 0), 3)\n    col_num = i // 4\n    row_num = i % 4\n    axs[row_num, col_num].set_axis_off()\n    axs[row_num, col_num].imshow(samples[i])\n    axs[row_num, col_num].set_title(f'{i} : ID[{image_ids[i]}]')","metadata":{"execution":{"iopub.status.busy":"2021-12-30T08:28:29.332898Z","iopub.execute_input":"2021-12-30T08:28:29.333248Z","iopub.status.idle":"2021-12-30T08:28:31.231908Z","shell.execute_reply.started":"2021-12-30T08:28:29.333196Z","shell.execute_reply":"2021-12-30T08:28:31.227604Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"a = range(8)\nb = range(8)\n\nfor i in range(len(list(a)+list(b))):\n    row = i % 8\n    col = i // 8\n    \n    if col:\n        print(row, col, 'b', a[row])\n    else:\n        print(row, col, 'a', b[row])\n    \nprint(list(a)+list(b))","metadata":{"execution":{"iopub.status.busy":"2021-12-30T08:43:55.313197Z","iopub.execute_input":"2021-12-30T08:43:55.313572Z","iopub.status.idle":"2021-12-30T08:43:55.327252Z","shell.execute_reply.started":"2021-12-30T08:43:55.31351Z","shell.execute_reply":"2021-12-30T08:43:55.326533Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}