|
1.
현재 이전 최고점 모델의 알고리즘에
모델만 바꿔서 훈련중
resnet101 + deeplabv3plus +cityscape pretrained model pth
훈련중 31일 점심에 예측 결과 확인 예정
2.잘못된 라벨 실존확인
직접 확인 결과
대부분의 훈련이미지의 mask에 크고 작은 8번레이블 존재(하늘)
3.주요 훈련 알고리즘 분석 및 3가지 훈련데이터를 입력받는 방식 맨 아래 정리
대부분의 훈련이미지의 mask에 크고 작은 8번레이블 존재(하늘)
이미지의 하늘 부분을 배경 클래스로 변환하는 메소드
mask = cv2.imread(mask_path, cv2.IMREAD_GRAYSCALE) mask[mask == 255] = 12 # 이미지의 하늘 부분을 배경 클래스로 변환 mask[IMAGE_HEIGHT // 3 * 2:][mask[IMAGE_HEIGHT // 3 * 2:] == 8] = 12 |
=>이미지 마스크에서 아랫부분 2/3을 선택.
선택된 영역에서 클래스 레이블이 8인 픽셀을 선택.
선택된 픽셀의 클래스 레이블을 12로 변경.
3.코드 분석
훈련 검증에 적용되는 정규화 값
#Train_Source + Valid_Source 의 Mean, Std source_mean = [0.5897106 , 0.5952661 , 0.57897425] source_std = [0.16688786, 0.15721062, 0.1589595] #Train_Target 의 Mean, Std target_mean = [0.4714665 , 0.47141412, 0.49733913] target_std = [0.23908237, 0.24033973, 0.25281718] |
훈련 검증에 적용되는 기본 증식 옵션
# 공통으로 적용되는 데이터 변환을 설정합니다. self.augmentation = A.Compose([ A.ColorJitter(p=0.25), A.HorizontalFlip(p=0.5), A.RandomCrop(width=CROP_WIDTH, height=CROP_HEIGHT) ]) self.source_norm = A.Normalize(mean=source_mean, std=source_std) self.target_norm = A.Normalize(mean=target_mean, std=target_std) |
배경 이미지와 원본 이미지를 혼합하는 메소드
# 배경 이미지와 원본 이미지를 혼합하는 메소드 def mix_bg(self, source_image, source_mask, target_image): h, w, c = source_image.shape # 타원 모양의 마스크 생성 center = (IMAGE_WIDTH // 2, int(IMAGE_HEIGHT * 0.375)) # 타원 중심 좌표 (x, y) axis_length = (IMAGE_WIDTH // 2, int(IMAGE_HEIGHT * 0.64)) # 장축 반지름과 단축 반지름 mask = np.zeros((h, w, 1), dtype=np.uint8) cv2.ellipse(mask, center, axis_length, 0, 0, 360, 1, -1) # 타원 모양으로 이미지 혼합 mixed_image = source_image * mask + target_image * (1 - mask) mixed_mask = source_mask * mask[:, :, 0] + np.ones_like(source_mask) * 12 * (1 - mask[:, :, 0]) return mixed_image, mixed_mask |
타겟데이터를 mix_bg_prob확률로 이미지 혼합 작업 수행
if self.target_data is not None: # 대상 이미지 파일 경로 설정 # idx % self.len_target를 사용하여 대상 데이터에서 이미지 선택 target_img_path = self.target_data.iloc[idx % self.len_target, 1].replace('./', data_path + '/') # 대상 이미지를 읽어옵니다. target_image = cv2.imread(target_img_path) # 대상 이미지의 색상 체계를 BGR에서 RGB로 변환합니다. target_image = cv2.cvtColor(target_image, cv2.COLOR_BGR2RGB) # mix_bg_prob 확률로 이미지 혼합 작업 수행 if self.mix_bg_prob > np.random.uniform(0, 1): # 이미지 혼합을 수행할 때 distortion_image와 distortion_mask는 이미 초기화되어 있어야 합니다. distortion_image, distortion_mask = self.mix_bg(distortion_image.astype(np.uint8), distortion_mask.astype(np.uint8), target_image) |
배경 이미지 혼합 작업이 (수행 or 수행x) 이후 기본 증식과 ElasticTransform 증식이 추가로 적용되어 반환
distortion_tensor = A.Compose([self.augmentation, A.ElasticTransform(alpha=100, sigma=10, alpha_affine=25, border_mode=1, p=1), self.source_norm, ToTensorV2()])(image=distortion_image, mask=distortion_mask) |
배경과 원본 이미지를 혼합할 확률 선택 변수 mix_bg_prob = 0.25 로 설정함
입력 데이터에 마스킹 적용해 일부 영역 가리는 함수
#Mask 파라미터 masking_ratio = 0.75 mask_size = 32 |
# 입력 데이터에 마스킹을 적용하여 일부 영역을 가릴 수 있는 masking 함수 def masking(input, mask_ratio=0.5, mask_size=32): # 입력 데이터의 크기와 형태를 가져옵니다. b, c, h, w = input.shape # 입력 이미지를 분할하기 위한 패치의 수를 계산합니다. h_patch = h // mask_size w_patch = w // mask_size # 각 패치에 대한 마스크를 무작위로 생성하고, 주어진 비율(mask_ratio)에 따라 값을 설정합니다. mask = (np.random.uniform(0, 1, (h_patch, w_patch, b)) > mask_ratio).astype(np.uint8()) # 마스크 크기를 입력 이미지 크기로 다시 조정합니다. mask = cv2.resize(mask, (w, h), interpolation=cv2.INTER_NEAREST) # Numpy 배열을 PyTorch 텐서로 변환하고, 차원을 조정하여 입력 이미지와 호환되도록 합니다. mask = torch.from_numpy(mask).permute(2, 0, 1).reshape(b, 1, h, w).to(device) # 입력 이미지를 복제하고, 마스크를 곱하여 일부 영역을 가립니다. output = input.detach().clone() * mask return output |
추론시 slide window방식 사용
:전체 이미지에 대한 예측: 이미지 슬라이딩을 사용하면 모델이 전체 이미지에 대한 예측을 생성할 수 있습니다. 대규모 이미지에서 객체 또는 특징을 감지하고 분류하는 경우, 이미지 슬라이딩을 통해 모델이 전체 이미지를 처리하고 객체의 위치 및 특성을 찾을 수 있습니다.
객체의 부분 예측: 객체 또는 특정 영역의 예측을 얻을 수 있습니다. 이미지 슬라이딩을 사용하면 이미지의 작은 부분에 대한 예측을 생성할 수 있으며, 이를 통해 이미지 내에서 객체 또는 특징의 위치를 정확하게 파악할 수 있습니다.
위치 불변성 확보: 이미지 슬라이딩은 이미지 내의 객체 또는 특징의 위치에 대한 불변성을 확보합니다. 이것은 객체가 이미지 내에서 어디에 있던 간에 모델이 해당 객체를 인식하고 분류할 수 있도록 도와줍니다.
다양한 크기의 객체 처리: 이미지 슬라이딩을 사용하면 다양한 크기의 객체를 처리할 수 있습니다. 작은 객체와 큰 객체 모두를 감지하고 분류하기 위해 다양한 윈도우 크기를 사용할 수 있으며, 객체 크기에 대한 불변성을 확보할 수 있습니다.
픽셀 수준의 예측 결합: 슬라이딩된 결과를 조합하여 최종 예측을 생성할 수 있습니다. 슬라이딩된 예측을 누적하고, 슬라이딩된 횟수로 나눔으로써 전체 이미지에 대한 최종 예측을 생성할 수 있습니다.
def slide_pred(model,img,window_size=(CROP_HEIGHT,CROP_WIDTH),stride=(CROP_HEIGHT,CROP_WIDTH),softmax=False,padding=False): #추론 속도를 높이려면 입력 이미지를 나누어 Batch로 만들도록 코드를 재구성 #학습, 추론 과정 모두 Batch 단위로 입력이 들어오기 때문에 메모리 문제로 인해 Batch로 만들지 못함 #실제 적용에서는 무조건 Batch가 1이기 때문에 이미지 하나를 Batch로 만들 수 있음 b, c, h, w = img.shape if padding: # 입력 이미지 주변에 패딩을 추가합니다. padded_img = torch.zeros((b, c, h + (window_size[0] - stride[0]) * 2, w + (window_size[1] - stride[1]) * 2)).to(device) padded_img[:, :, window_size[0] - stride[0]:-(window_size[0] - stride[0]), window_size[1] - stride[1]:-(window_size[1] - stride[1])] = img output = torch.zeros((b, 14, h + (window_size[0] - stride[0]) * 2, w + (window_size[1] - stride[1]) * 2)).to(device) else: padded_img = img output = torch.zeros((b, 14, h, w)).to(device) ph, pw = padded_img.shape[2:] for i in range(0, ph - window_size[0] + 1, stride[0]): for j in range(0, pw - window_size[1] + 1, stride[1]): # 이미지를 슬라이딩하면서 작은 윈도우를 추출 input = padded_img[:, :, i:i+window_size[0], j:j+window_size[1]] if softmax: # 모델을 사용하여 입력 이미지를 추론하고 소프트맥스 적용 pred = torch.softmax(model(input)['out'], 1) else: # 모델을 사용하여 입력 이미지를 추론 pred = model(input)['out'] # 결과를 누적하여 output에 추가 output[:, :13, i:i+window_size[0], j:j+window_size[1]] += pred output[:, 13, i:i+window_size[0], j:j+window_size[1]] += 1 # 결과를 누적한 횟수로 나누어 평균을 구함 output = output[:, :13] / output[:, 13:] if padding: # 패딩을 제거하고 원래 이미지 크기로 결과를 자름 output = output[:, :, window_size[0] - stride[0]:-(window_size[0] - stride[0]), window_size[1] - stride[1]:-(window_size[1] - stride[1])] return output |
옵티마이저 설정
-AdamW(Adam with Weight Decay) 옵티마이저를 설정 ,LambdaLR 스케줄러를 설정
optimizer = torch.optim.AdamW([ {'params': model.backbone.parameters(), 'lr': 1e-4}, {'params': model.classifier.parameters(), 'lr': 1e-3}], weight_decay=0.01) save_last = True # Warmup 파라미터 warmup_epochs = 50 scheduler = torch.optim.lr_scheduler.LambdaLR(optimizer=optimizer,last_epoch=len(learning_status['lrs'])-1, lr_lambda=lambda epoch: epoch / warmup_epochs) |
손실함수 설정
-train source - crossentropy
-train target -target loss ->
LS = nn.CrossEntropyLoss() LT = target_loss(t=0.968) |
class target_loss(nn.Module): def __init__(self, t=0.968): # 클래스 초기화: 임계값 t를 설정하고 Cross Entropy Loss 함수를 초기화 super(target_loss, self).__init__() self.t = t self.celoss = nn.CrossEntropyLoss(reduction='none') def forward(self, pred, pseudo_label): b, c, h, w = pseudo_label.shape # pseudo_label에서 최대값을 찾아 신뢰도와 해당 위치(pt)를 추출 confidence, pt = torch.max(pseudo_label, dim=1) # b, h, w # 신뢰도가 t보다 큰 픽셀의 비율(qt)을 계산 qt = (torch.sum(confidence.view(b, -1) > self.t, 1) / (h * w)).view(b, 1, 1) # b, 1, 1 # 손실 계산: Cross Entropy Loss에 가중치(qt)를 곱하여 계산 loss = torch.mean(self.celoss(pred, pt) * qt) # b, h, w * b, 1, 1 -> b, h, w -> 1 # 계산된 손실 반환 return loss |
4.위의 중요 알고리즘 분석을 통해 ppt를 해석해보면,
(1).데이터 로드시
class CustomDataset(Dataset):에서
return image, mask, target_image, distortion_image, distortion_mask 를 반환함.
source image,,target_image 는 원본에 기본 증식만 추가해서 반환
#사전에 미리 Resize해둔 이미지 크기 IMAGE_WIDTH = 1024 IMAGE_HEIGHT = 512 #Crop한 이미지의 크기 CROP_WIDTH = IMAGE_WIDTH//2 CROP_HEIGHT = IMAGE_HEIGHT//2 self.augmentation = A.Compose([ A.ColorJitter(p=0.25), A.HorizontalFlip(p=0.5), A.RandomCrop(width=CROP_WIDTH, height=CROP_HEIGHT) ]) |
distortion image,mask( mix_bg_prob = 0.25 의 확률로 target 데이터의 배경과 train source image를 혼합 ) 는 위의 기본 증식+왜곡(
A.ElasticTransform(alpha=100, sigma=10, alpha_affine=25, border_mode=1, p=1),
)증식 넣어서 반환.
(2).훈련시
위의 반환된 데이터를 source image 와 .distortion 이미지는 그대로 손실 계산
-source image(Loss source)
-distortion image (Loss distortion)
-target image 는 masking_ratio = 0.75 의 확률로 이미지에 마스킹 생성한 입력을 모델에 넣은 예측과 target 이미지를 그냥 teacher 모델에 넣은 예측의 손실을 계산(Loss Target)
계획
추후 deeplabv3plus-resnet101 cityscape 사전훈련된 모델로
위와 같은 증식옵션 , 배경혼합 , 잘못된 레이블 수정 + 학습률 ,규제 + 스케줄러 외 dafomer을 사용해야하는 것 제외한 모든 것 적용해서 훈련해볼 예정
-----------------------------------------
발표자료 증식 방법 vs 이전 33점 모델 증식 방법 vs 논문 증식 방법 차이
1.발표자료 증식
self.augmentation = A.Compose([ A.ColorJitter(p=0.25), A.HorizontalFlip(p=0.5), A.RandomCrop(width=CROP_WIDTH, height=CROP_HEIGHT) A.Normalize(mean=[0.58971057, 0.59526609, 0.57897422], std=[0.16688787, 0.15721062, 0.1589595]), ]) |
-왜곡> A.ElasticTransform(alpha=100, sigma=10, alpha_affine=25, border_mode=1, p=1)
2.이전 33점 모델 증식 방법
transform = A.Compose(
[
A.RandomResizedCrop(540, 960,scale=(0.5, 1.0),ratio=(1, 1),p=0.9), # 랜덤하게 자르기
A.HorizontalFlip(p=0.5), #수평 뒤집기
A.RandomBrightness(p=0.9,limit=(-0.2, 0.0)),
A.ColorJitter(p=0.3),
A.Resize(224, 224),
A.ToGray(p=0.2),
A.Normalize(),
ToTensorV2()
]
)
-왜곡 ->fish eye
다른점 :
발표 자료에서는 RandomResizedCrop대신 RandomCrop으로 이미지의1/2을 줄임
ToGray, RandomBrightness 는 사용하지 않음.
Normalize를 정확한 값으로 설정함.
3.논문 증식 방법
밝기, 대조도, 색조, 채도 조절 랜덤 p=0.5
HorizontalFlip(p=0.5)
+fish eye 변환
|
첫댓글 발표자료의 증식을 적용하는 방법과 너희들이 사용하는 방법이 같은거냐 다른거냐?
글 마지막에 작성하였습니다!