【Pytorch】 DETR code teardown reports / 핵심 배운점 2개

  • DETR github : https://github.com/facebookresearch/detr
  • Remarks
    1. Dockerfile 제공 (사용하지 말기)
    2. Demo code 제공
  • 한글 주석 포함 github 링크
  • 의문 정리 (검색하기)
    • demo에서 0.1을 왜 곱해주지??

    • coco_evaluator 를 어떻게 사용하는건지 패스했다. 나중에 공부해보자.

    • multihead attention에서 width height가 계속 다르게 들어가는데, W(linear)를 어떻게 학습시키지? linear도 input, output dimension을 고정시켜줘야 할 텐데…

      • 굳이 이해하려 하지말고, torch.nn.MULTIHEADATTENTION 그대로 사용하자.

      • vector의 갯수는 상관없다. 그냥 key, value 적당한 차원으로 넣어주면 된다.

      • 예를 들어서 아래와 같은 코드가 있다. 아래에 주석 참조!

        class TransformerEncoderLayer(nn.Module):
            def __init__(self, d_model=512, nhead=8, dim_feedforward=2048, dropout=0.1,
                         activation="relu", normalize_before=False):
                super().__init__()
                self.self_attn = nn.MultiheadAttention(d_model, nhead, dropout=dropout)
                self.linear1 = nn.Linear(d_model, dim_feedforward) 
                # (512 -> 2048) x (feature_map width x height) 이 모든 것에 같은 linear 연산이 이뤄진다.
                # self.linear1의 weight.shape = 512x2048 
                      
            def forward_post(self,
                q = k = self.with_pos_embed(src, pos)
                src2, score = self.self_attn(q, k, value=src, attn_mask=src_mask,
                                      key_padding_mask=src_key_padding_mask)
                src = src + self.dropout1(src2)
                src = self.norm1(src)
                # 2. Feed Forward
                src2 = self.linear2(self.dropout(self.activation(self.linear1(src))))
        
  • 의문 해결

    • detr.py에 num_classes = 91 if args.dataset_file != 'coco' else 20num_classes = 20 if args.dataset_file != 'coco' else 91 로 바꾸면, 왜 main.py 에서 디버깅 실행하면 from models import build_model 에서 에러가 나는 거지? 에러내용은 아래 사진 (해결 - 반성하자)
  • 추신

    • 아래의 목차 순서 잘 분리해놓았으니, 무시하지 말고 꼭 신경쓰기

0. 핵심 배운점

0.1 디버깅 배운점 (1)

  • 나의 현재 문제점
    1. 코드(main.py)를 처음부터 똑바로 안봤다. torch.utils.data.dataset이 아니라, build_dataset이었는데.. 아무 생각 없이 패스했다.
    2. dataloader의 파라미터 중에서 collate_fu이 정말 중요했는데, 이것도 무시했다.
    3. 이건* 나중에 보자!라는 마음으로 패스하고, 나중에 그걸* 안봐서 너무 힘들었다.
    4. 내가 지금 뭐하지는 모르고 계속 했던거 또하고 했던거 또했다.
  • 해결책
    1. 정말 하나하나! 꼼꼼히! 순서대로! 부셔야 한다.
    2. 그냥 아무 생각없이 디버깅 하기 전에 아래의 방법** 중 지금의 에러를 해결하기 위해 사용해야하는 방법이 무엇인지 진지하게 생각하고! 들어가자. 손부터 움직이지 말고 머리를 쓰자.
    3. 좌절하지 말자. 포기하지 말자. 할 수 있다. 아자아자
  • 최적의 디버깅 방법**이 무엇인가?
    • 코드 직접 수정하기
    • pdb 이용하기 / pdb의 interact 이용하기
    • python debuger 이용하기 / Watch, Debug console이용하기
    • 코드 전체에서 (특정 클래스, 함수) 검색해보기 / VScode의 define(F12)과 reference(shift+F12) 잘 이용하기
    • (위의 방법 섞기)
    • 코드를 직접 수정하기 + pdb이용하기
    • 코드를 직접 수정하기 + Python debuger를 이용하기
  • 신경망에 있어서 디버깅 방법
    • __init__ 과 forward가 실행되는 시간 차는 매우 다르다. 따라서 분리해서 생각하도록 하자.
    • forward는 for x,y in data_loader: 이후에 실행이 된다. 그 이전에 model을 build하는 과정에서는 모두 __init__만 실행된다.
  • 추가 꿀팁
    1. 뭔가 안된다면, worker = 1 로 해놓고 디버깅 할 것.
    2. 왜 안되는지 앞으로 따라가 보고, 앞으로 따라가도 모르겠으면
    3. 뒤로 가야한다. 뒤로가서 무엇을 하고 나서 이상이 생긴건지.

0.2 개발자로써 배운점 (2)

  • 4일 동안 DETR 코드를 하나하나 씹어먹으며 공부하다가, 결국 나는 아래와 같은 큰~~!! 깨달음을 얻었다.
  • 코딩 공부는 고등학교 시험공부, 대학교 시험공부 처럼 하는게 아니다.
  • Just Do It. 뭐든 만들어 보고, 뭐든 시도해봐야한다. (by nomadcoders 니꼬쌤 . 나의 동기, 선배님!)
  • 따라서! 아래와 같은 생각은 틀렸다. 그냥 100프로 틀렸다.
    • 모든 것 하나하나 다 부셔버리고, 다 알고 넘어가야 한다.
    • 기초부터 차근차근 모두 다 알아야 한다.
    • 나중에 내가 스스로 만들 수 있게 충분히 이해해야 한다.
    • 언젠간 내가 처음부터 끝까지 만들 수 있어야 한다.
  • 이게 아니고! 아래와 같이 생각하는게 정답이다. 이게 무조건 맞다. 100프로 이다.
    • 그냥 사용할 수 있으면 장땡이다. 대충 그런것 같은데… 라고 input 넣어서 원하는 output 얻었으면 끝! 더 이상 볼 필요도 없다.
    • 왜냐면 어차피 그 함수, 프레임워크 미친듯이 공부하고 완벽히 이해했다고 해도, 곧! 언젠가! 그 함수 프레임워크 보다 좋은게 나온다.
    • 그럼 내가 기초부터 쌓았다고 좋아했던 모든 시간들이 쓰레기가 된다.
    • 개발자는 기초 따위는 중요하지 않다. 파이썬 쓰면서 C언어 안 보잖아. numpy쓰면서 그 안에 어떻게 돌아가는지 몰라도 되잖아. 기초가 중요하다는 소리는 이제 나에게 필요없는 소리다.
    • 빨리 무언가 만들어보고 실험해보는 자세가 앞으로 개발자로써 내가 가져야 하는 진짜 자세이다.
    • 패키지는 내가 만드는게 아니다. 내가 해야할 것은 남이 만든 패키지를 이리저리 섞는 것이다. 남이 만든 패키지도 결국 누군가가 만들어 놓은 것을 융합해놓은 것일 뿐이다.
    • ‘이러한 기능을 하는 함수/클래스가 필요한데..’ 라는 생각이 들면, 패키지를 처음부터 끝까지 공부하면서 그 함수/클래스를 찾아야 하는게 아니라, 많은 패키지에서 그 함수와 클래스를 (랜덤적으로 뒤져보면서) 결국 찾아내서 사용하기만 하면 끝이다.
    • 정신 차려라 개발자가 기초를 생각하기엔 쇠퇴 및 발전 속도는 미치도록 빠르다.

1. detr_demo.py. Inference 흐름 따라가기

  • Github/facebookresearch/detr Code link

  • Error 해결

    $ pip install torch==1.5.0+cu101 torchvision==0.6.0+cu101 -f https://download.pytorch.org/whl/torch_stable.html 
    # docker Image 그대로 사용했어야 했다. requirements.txt가 개세끼다
    $ conda install -c conda-forge ipywidgets
    $ pip install pdbpp
    
  • 주요 코드 설명

    1. h = self.transformer(pos + 0.1 * h.flatten(2).permute(2, 0, 1), self.query_pos.unsqueeze(1)).transpose(0, 1)
      • 위의 transformer 함수 내부 : ((625, 1, 256) + 0.1 * (625(갯수), 1, 256(백터) , (100, 1 ,256)) : 0.1을 왜 곱해주지??
      • transformer ouput : (100, 1 ,256)
      • h.shape : (by transpose) : (1, 100, 256)
  • 이 코드는 nn.transformer를 그대로 사용하기 때문에.. 여기서 그만 공부..

SmartSelect_20210418-161421_Samsung Notes.jpg


2. Evaluation. Inference 흐름 따라가기

  • main.py는 train.py 코드도 되고, test.py 코드도 된다. --eval 옵션만 넣고 빼주면 된다.
[Terminal]
$ python main.py \
		--batch_size 1\
        --no_aux_loss\
        --eval\
        --resume https://dl.fbaipublicfiles.com/detr/detr-r50-e632da11.pth
        --coco_path /workspace/coco # /path/to/coco

$ python main.py \
       	--batch_size 2\
        --no_aux_loss\
        --eval\
        --resume checkpoints/detr-r50-e632da11.pth\
        --num_workers 4\
        --world_size 2\
        --coco_path /dataset/coco\
        --output_dir result

[Vscode Debugging] 
# ./vscode/launch.json
"args" : ["--batch_size", "2", 
        "--no_aux_loss", 
        "--eval", 
        "--resume", "checkpoints/detr-r50-e632da11.pth", 
        "--num_workers", "4",
        "--world_size", "2",
        "--coco_path", "/dataset/coco",
        "--output_dir", "result"]

2.0 main.py 분석해보기

  • print(args)

    - Namespace(aux_loss=False, backbone='resnet50', batch_size=1, bbox_loss_coef=5, clip_max_norm=0.1, coco_panoptic_path=None, coco_path='/workspace/coco', dataset_file='coco', dec_layers=6, device='cuda', dice_loss_coef=1, dilation=False, dim_feedforward=2048, dist_url='env://', distributed=False, dropout=0.1, enc_layers=6, eos_coef=0.1, epochs=300, eval=True, frozen_weights=None, giou_loss_coef=2, hidden_dim=256, lr=0.0001, lr_backbone=1e-05, lr_drop=200, mask_loss_coef=1, masks=False, nheads=8, num_queries=100, num_workers=2, output_dir='', position_embedding='sine', pre_norm=False, remove_difficult=False, resume='https://dl.fbaipublicfiles.com/detr/detr-r50-e632da11.pth', seed=42, set_cost_bbox=5, set_cost_class=1, set_cost_giou=2, start_epoch=0, weight_decay=0.0001, world_size=1)
    
  • 코드 순서 요약하기

    1. args 설정 및 seed 설정
    2. model, criterion, postprocessors = build_model(args)
    3. 총 파라메터 갯수 계산 하기
    4. backbone / Transformer-encoder, decoder / detector head 각각의 learning rate를 다르게 주기
    5. optimizer와 lr_scheduler 설정
    6. data_loader 만들어 주기 - 1. dataset 정의 , 2. batchSampler 정의
    7. coco_api 를 사용한 dataset validation = evaluate AP 계산하는 방법
    8. Model Parameters load 하기(1) - frozen_weights 경로가 있을 경우 (= panoptic segmentaion 모듈만 학습시키고 싶은 경우)
    9. Model Parameters load 하기(2.1) - Evaluate 하기 위한 파라메터
    10. Model Parameters load 하기(2.2) - Train 하기 위한 파라메터
    11. Evaluation만 하고 코드 종료(return) (1) model infernece하기 (2) coco api로 AP 구하기
    12. If args.eval=False 이라면, 바로 위 코드 안하고, Traiining 시작하기

2.1 datasets/coco.py /build_dataset()

  • torchvision.datasets.CocoDetection 를 상속한다. (링크) 여기서! target_transform 가 의미하는 것은, (Image, label) 쌍에서 image augmentation만해주는게 아니라, label에 대한 변형(agumentation)까지도 해주는 것을 의미한다.

  • dataset/coco.py 안의 make_coco_transforms함수에서 Transforms(agumentation)을 정의한다. 이때 dataset/transforms.py 에 정한 Transformer만을 사용한다. 여기서 Transforms(agumentation)을 정의하는 것을 보면, 다 공통적으로 아래와 같은 구조이다. 따라서 내가 구현하고 싶은 Agumentation이 존재한다면 참고해서 만들도록 하자.

    class New_Transformer_Name(object):
        def __init__(self, p=0.5):
            # just 맴버 변수 정의
    	def __call__(self, img, target=None):
            return img, target
    
  • Backbone에 이미지가 들어가기 전에, DataLoader에서 나오는 변수의 타입이 type(Image, label) = (torch.tensor, dict) 이었다가 (NestedTensor, dict) 으로 바뀐다. 그 이유는 torch.utils.dataloader의 파라메터인 collate_fn=utils.collate_fn 덕분이다.

  • dataset_val에는 build_dataset()으로 부터 받은 torch.utils.dataset클래스이다. 따라서 transforms가 적용된 후! collate_fu이 적용되는 것이다.

    ## main.py 아래의 collate_fn=utils.collate_fn !! 덕분이다.
    data_loader_val = DataLoader(dataset_val, args.batch_size, sampler=sampler_val,
                                     drop_last=False, collate_fn=utils.collate_fn, num_workers=args.num_workers)
    ## util/misc.py
    def collate_fn(batch):
        # batch[0] : len이 batch_size인 tuple. Image 정보 들어가 있다. batch[0][0]에는 torch tensor가 들어가 있다.
        # batch[1] : len이 batch_size인 tuple. label 정보 들어가 있다. batch[1][0]에는 dict()가 들어가 있다. dict_keys(['boxes', 'labels', 'image_id', 'area', 'iscrowd', 'orig_size', 'size'])
        batch = list(zip(*batch))
        batch[0] = nested_tensor_from_tensor_list(batch[0])
        return tuple(batch)
      
    def nested_tensor_from_tensor_list(tensor_list: List[Tensor]):
        return NestedTensor(tensor, mask)
      
    ## datasets/transforms.py
    def resize(image, target, size, max_size=None):
        """
        이미지에서 (w,h 중) 작은 쪽을 size(val일때 800) 크기로 변환해준다. 
        작은 쪽을 800으로 변한해서 큰쪽이 max_size보다 커치면, 큰쪽이 max_size가 되도록 이미지를 변환한다.
        """
    
  • collate_fn 함수는 misc.py의 Nested_tensor_from_tensor_list() 함수에 의해서 정의 되어있다.
    SmartSelect_20210418-161447_Samsung Notes.jpg

2.2 models/detr.py

  • 아래로 내려가면서, 함수가 호출된다. build에서 핵심적인 내용반 뽑았다.
# main.py
from models import build_model
model, criterion, postprocessors = build_model(args)

# models/detr.py
def build(args):
    backbone = build_backbone(args)
    transformer = build_transformer(args)
    model = DETR(backbone, transformer, num_classes=num_classes, num_queries=args.num_queries, aux_loss=args.aux_loss)
    matcher = build_matcher(args)
    criterion = SetCriterion(num_classes, matcher=matcher, weight_dict=weight_dict, eos_coef=args.eos_coef, losses=losses)
    postprocessors = {'bbox': PostProcess()}
    return model, criterion, postprocessors

따라서 아래의 과정을 따라서 차근차근 공부해나갈 예정이다.

  1. build_dataset()
  2. build_backbone()
  3. build_transformer()
  4. model = DETR()
  5. build_matcher()
  6. SetCriterion()
  7. PostProcess()

2.2.1 models/position_encoding.py /build_position_encoding()

  • 2가지 방법 embeding 방법이 존재한다.]
  1. Leaned - Positional Embeding
    • nn.Embedding, nn.init.uniform_ 를 사용해서 row_embed, col_embed 변수 정의하기
    • pos = torch.cat([x_emb.unsqueeze(0).repeat(h, 1, 1),y_emb.unsqueeze(1).repeat(1, w, 1)], dim=-1).permute(2, 0, 1).unsqueeze(0).repeat(x.shape[0], 1, 1, 1)
    • (demo) 최종 pos의 shape : (N장, 256, 25, 25) 여기서 25는 feature map의 width, hight
  2. sinusoidal - Positional Embeding
    • 어려울 것 없이, 아래의 4. Additions. Positional Embeding Code 와 똑같은 코드이다. 이 코드에 의해서도 shape( #Vector, Vector_dim )이 만들어진다. 아래에서 최종적으로 만들어진 pos_x , pos_y 또한 똑같다.
    • pos_x : shape[2, 28, 38, 128] -> 여기서 28개 모두 같은 값이고, 결국 만들어진 것은 38*128이다. (아래의 4. Additions 참조)
    • pos_y : shape[2, 28, 38, 128] -> 여기서 38개 모두 같은 값이고, 결국 만들어진 것은 28*128이다. (아래의 4. Additions 참조)
    • (main.py debug) 최종 pos의 shape : (N장, 256, 28, 38) 여기서 25는 feature map의 width, hight
      SmartSelect_20210418-161517_Samsung Notes.jpg

2.2.2 models/backbone.py /build_backbone()

def build_backbone(args):
    # 핵심 module 정의 1. position_embedding
    position_embedding = build_position_encoding(args)
    
    # 핵심 module 정의 2. backbone
    train_backbone = args.lr_backbone > 0
    return_interm_layers = args.masks
    backbone = Backbone(args.backbone, train_backbone, return_interm_layers, args.dilation) # torchvision.models

    # nn.Sequential 로 2개의 모듈 묶어주기
    model = Joiner(backbone, position_embedding)

    # model의 type은 nn.Sequential 이기 때문에, 아무런 맴버변수가 없다. 아래에 의해서 클래서 맴버변수 하나 만들어 놓음
    model.num_channels = backbone.num_channels
    return model


class Joiner(nn.Sequential):
    def __init__(self, backbone, position_embedding):
        super().__init__(backbone, position_embedding)

    def forward(self, tensor_list: NestedTensor):
        xs = self[0](tensor_list) # self.backbone(tensor_list)
        # xs['0'].tensors.shape = torch.Size([2, 2048, 28, 38])
        # 만약에 resnet 중간에 feature map을 뽑아 왔다면, xs['1'], xs['2'], xs['3'] 순차적으로 저장된다. 
        out: List[NestedTensor] = []
        pos = []
        for name, x in xs.items():
            out.append(x)
            # position encoding
            pos.append(self[1](x).to(x.tensors.dtype)) # self.position_embedding(x)

        # 여기서 0은 backbone에서 가장 마지막 C4 layer에서 뽑은 결과
        # out[0].tensors.shape = torch.Size([2, 2048, 28, 38]). out[0].mask 있음
        # pos[0].shape = torch.Size([2, 256, 28, 38])
        return out, pos

2.2.3 models/transformer.py /build_transformer()

def build_transformer(args):
    return Transformer()

class Transformer(nn.Module):
	def __init__(self, d_model=512, nhead=8, num_encoder_layers=6,
                 num_decoder_layers=6, dim_feedforward=2048, dropout=0.1,
                 activation="relu", normalize_before=False,
                 return_intermediate_dec=False):

        encoder_layer = TransformerEncoderLayer(d_model, nhead, dim_feedforward,
                                                dropout, activation, normalize_before)
        encoder_norm = nn.LayerNorm(d_model) if normalize_before else None
        self.encoder = TransformerEncoder(encoder_layer, num_encoder_layers, encoder_norm)

        decoder_layer = TransformerDecoderLayer(d_model, nhead, dim_feedforward,
                                                dropout, activation, normalize_before)
        decoder_norm = nn.LayerNorm(d_model)
        self.decoder = TransformerDecoder(decoder_layer, num_decoder_layers, decoder_norm,
                                          return_intermediate=return_intermediate_dec)
        
        # 모델의 전체 파라미터 초기화를 아래와 같이 한다. 잘 알아두기.
        self._reset_parameters()
	def _reset_parameters(self):
        for p in self.parameters():
            if p.dim() > 1:
                nn.init.xavier_uniform_(p)

image-20210418173318543

  1. 모델 전체 파라미터 초기화 nn.init.xavier_uniform_(p)
  2. 위의 코드처럼, models/transformer.py에 정의된 아래의 함수들을 순차적으로 사용한다. 차근차근 알아가보자.
    1. TransformerEncoderLayer
    2. TransformerEncoder
    3. TransformerDecoderLayer
    4. TransformerDecoder
  3. 코드 전체에서 attn_mask tgt_mask 변수는 사용되지 않는다.(=None 이다) 이 Mask 기법은 All you need attention 논문에서, decoder의 sequencial한 input과 output을 구현해 학습시키기 위해서 사용되는 변수이다. 자세한 내용은 아래 4. Attention 부분의 내용을 참조할 것.
  4. 대신 key_padding_mask 변수 은 사용한다. 배치에 들어간 모든 이미지를 한꺼번에 처리하기 위한 Transformer를 구현하기 위해, 배치 속에서 상대적으로 작은 이미지는 pading된다. 이 pading된 값에 대해서는 Attention을 구하면 안되므로, Mask처리를 해준다. Value도 0이다. 위의 Nested_tensor_from_tensor_list 내용에 있는 손 그림 참조.

image-20210418173519152

  1. MultiheadAttention

    • torch.nn.module.MultiheadAttention
    • 사용 예시 self.self_attn = nn.MultiheadAttention(d_model=512, nhead=8, dropout=dropout)
      image-20210418193545367
  2. TransformerEncoderLayer

    • MHA 이나 Feed Forward하기 전에 Normalization 하기 = forward_pre로 구현
    • MHA 이나 Feed Forward한 후에 Normalization 하기 = forward_post로 구현
      image-20210418200621077
    • dropout은 임의로 노드를 잠궈버리는 것. 즉 Zero로 만들어 버리는 것이다. 따라서 dropout의 forward를 위한 파라미터는 노드를 넣어줘야한다. (코드 예시. src = src + self.dropout1(src2))
  3. TransformerEncoder

    • 같은 TransformerEncoderLayer를 서로 다른 layer로 구성하기 위해서 아래와 같은 코드기법을 사용했다.

      def _get_clones(module, N):
          return nn.ModuleList([copy.deepcopy(module) for i in range(N)])
           
      class TransformerEncoder(nn.Module):
          def __init__(self, encoder_layer, num_layers, norm=None):
              super().__init__()
              self.layers = _get_clones(encoder_layer, num_layers)
                   
          def forward(self, src,
                      mask: Optional[Tensor] = None,
                      src_key_padding_mask: Optional[Tensor] = None,
                      pos: Optional[Tensor] = None):
              output = src
              for layer in self.layers:
                  output = layer(output, src_mask=mask, src_key_padding_mask=src_key_padding_mask, pos=pos)
      
  4. TransformerDecoderLayer

    • MHA 이나 Feed Forward하기 전에 Normalization 하기 = forward_pre로 구현
    • MHA 이나 Feed Forward한 후에 Normalization 하기 = forward_post로 구현
    • 그림은 나중에 추가할 예정(코드 미리 쪼개고 분석해놨으므로 금방한다.)
  5. TransformerDecoder

    • 위의 TransformerEncoder 코드와 같이 _get_clones 함수를 이용한다.
    • 나머지는 별거 없다.
    • 최종 Output= [100, 2, 256] * 6개 (decoder layer에서 나온 결과 모두) = torch.Size([6, 100, 2, 256])

2.2.4 models/detr.py /DETR()

self.class_embed = nn.Linear(hidden_dim, num_classes + 1) # 91 + 1 -> 92

self.bbox_embed = MLP(hidden_dim, hidden_dim, output_dim=4, num_layers=3)

# Backbone을 통과하고 나오는 결과의 Channel은 1024인데, Channel Reduction을 해준다. (to 256)
self.input_proj = nn.Conv2d(backbone.num_channels, hidden_dim, kernel_size=1)

2.2.5 models/matcher.py /build_matcher()

return HungarianMatcher(cost_class=args.set_cost_class, cost_bbox=args.set_cost_bbox, cost_giou=args.set_cost_giou)

class HungarianMatcher(nn.Module):
    def __init__(self, cost_class: float = 1, cost_bbox: float = 1, cost_giou: float = 1):
        super().__init__()
        self.cost_class = cost_class # 1
        self.cost_bbox = cost_bbox # 5
        self.cost_giou = cost_giou # 2
   @torch.no_grad()
   def forward(self, outputs, targets):
		C = self.cost_bbox * cost_bbox + self.cost_class * cost_class + self.cost_giou * cost_giou
        C = C.view(bs, num_queries, -1).cpu() # torch.Size([2 batch, 100 예측 object, 21 GT object])
        
        sizes = [len(v["boxes"]) for v in targets] #  [img1 num_box, img2 num_box]
        indices = [linear_sum_assignment(c[i]) for i, c in enumerate(C.split(sizes, -1))]
  • forward 앞에 @torch.no_grad() 가 정의되어 있다. 이런 식으로 어떤 특정 layer, module에만 @torch.no_grad()처리를 해줄 수 있다.
  • 아래의 그림에서 보라색 별이 indices 의 결과로 나온 값이다.
  • indices는 (batch, all_predict_obect, all_GT_obect) 으로 구성되어 있다. all_GT_obect 각각이 all_predict_obect 중 어디에 매칭되어야 하는지에 대한 정보가 들어가 있다.
  • linear_sum_assignment가 the Hungarian algorithm 을 사용해서, 최적의 매칭을 찾아준다. Hungarian algorithm을 사용하지 않고 Naive한 방법을 사용한다면, O(n!) (100P#GTobjec0=1.043196014E+41)s의 매칭을 고려하여 최적의 매칭을 찾아야 하지만, 헝가리안 알고리즘을 사용해서 O(n^3 = 10^e6) 의 시간복잡도 안에 최적의 매칭을 찾을 수 있다.
  • 아래의 그림에서 batch_Image 1에는 GT object가 20개가 있다. 100개의 예측 중, 20개는 object중 80개는 non-object로 분류된다.

image-20210419111125329

2.2.6 models/detr.py /class SetCriterion(nn.Module)

class SetCriterion(nn.Module):
    def __init__(self, num_classes, matcher, weight_dict, eos_coef, losses):
    def loss_labels(self, outputs, targets, indices, num_boxes, log=True):
        # 'loss_ce': Classification loss Using F.cross_entropy
        # 'class_error': Score만을 봤을 때, 정확한 예측을 한 예측의 겟수 비율을 점수로 계산 수 100점을 빼주어 error계산한다. 
    def loss_cardinality(self, outputs, targets, indices, num_boxes):
        # 100개의 예측 증 object라고 판단한 예측의 갯수가 target과 같은지 l1_loss를 계산한다
    def loss_boxes(self, outputs, targets, indices, num_boxes):
        # 'loss_bbox': l1_loss
        # 'loss_giou': using loss_giou
    def get_loss(self, loss, outputs, targets, indices, num_boxes, **kwargs):
        # 위의 3개의 loss 중에서 선택된 하나의 loss를 계산하여, dict에 값을 넣어주는 형태로, loss 값 return 해준다.
    def forward(self, outputs, targets):
        losses = {}
        for loss in self.losses: # type(loss) = (str)
            losses.update(self.get_loss(loss, outputs, targets, indices, num_boxes))
        return losses
    	'''
    	return 되는 예시.
    	losses :
    	{'cardinality_error': tensor(3.5000, devic...='cuda:0'), 
    	'class_error': tensor(23.8095, devi...='cuda:0'), 
    	'loss_bbox': tensor(0.0446, devic...='cuda:0'), 
    	'loss_ce': tensor(0.5508, devic...='cuda:0'), 
    	'loss_giou': tensor(0.4350, devic...='cuda:0')}
    	'''

2.2.7 models/detr.py /class PostProcess(nn.Module):

  • the model’s output format을 coco api에서 필요한 format으로 바꾸는 클래스이다.
class PostProcess(nn.Module):
    @torch.no_grad()
    def forward(self, outputs, target_sizes):
        out_logits, out_bbox = outputs['pred_logits'], outputs['pred_boxes']
        ## 중간 계산 절차를 거친다.
        results = [{'scores': s, 'labels': l, 'boxes': b} for s, l, b in zip(scores, labels, boxes)] 
        return results        
  • batch 2일 때, results의 결과 예시
    image-20210419152739090

2.3 engine.py /def evaluate()

# main.py
model, criterion, postprocessors = build_model(args)
test_stats, coco_evaluator = evaluate(model, criterion, postprocessors, data_loader_val, base_ds, device, args.output_dir)

# engine.py /def evaluate()
def evaluate(model, criterion, postprocessors, data_loader, base_ds, device, output_dir):
    for samples, targets in metric_logger.log_every(data_loader, 10, header):
        outputs = model(samples) # ['pred_logits'] ([2, 100, 92]),['pred_boxes'] ([2, 100, 4])
        metric_logger.update(loss=sum(loss_dict_reduced_scaled.values()),
                             **loss_dict_reduced_scaled,
                             **loss_dict_reduced_unscaled)
        metric_logger.update(class_error=loss_dict_reduced['class_error'])
    # 2500개의 validataion 이미지가 모든 계산된 이후에 아래의 작업이 수행된다.
    stats = {k: meter.global_avg for k, meter in metric_logger.meters.items()}
    return stats, coco_evaluator
    # 계산된 loss들이 stats에 들어가 반횐되고,
    # coco_evaluator는 나중에 필요하면 공부하자

3. Train 흐름 따라가기

똑같이 main.py 함수를 사용한다. 그리고 위에서 사용한 함수와 클래스들을 그대로 사용한다.

차이점은, Evaluation에서 사용하지 않던 값들은 여기 Train에서는 사용한다.

# main.py
for epoch in range(args.start_epoch, args.epochs):
    train_stats = train_one_epoch(model, criterion, data_loader_train, optimizer, device, epoch, args.clip_max_norm)
    lr_scheduler.step()
    # 이후에 checkpoint_paths에 .pth 파일 저장
    
# engine.py /train_one_epoch
def train_one_epoch(..)
	for samples, targets in metric_logger.log_every(data_loader, print_freq, header):
        outputs = model(samples)
        loss_dict = criterion(outputs, targets)
        losses = sum(loss_dict[k] * weight_dict[k] for k in loss_dict.keys() if k in weight_dict)
        optimizer.zero_grad()
        losses.backward()
        optimizer.step()
        # metric_logger 에 return 해주고 싶은 값들을 넣어준다.  
        metric_logger.update(loss=loss_value, **loss_dict_reduced_scaled, **loss_dict_reduced_unscaled)
        metric_logger.update(class_error=loss_dict_reduced['class_error'])
        metric_logger.update(lr=optimizer.param_groups[0]["lr"])
    # 1 epoch 동안 계산된 모든 것, return
	return {k: meter.global_avg for k, meter in metric_logger.meters.items()} 

4. detr_hands_on.ipynb 파일 분석하기

  • 아래 New modules에 있는 함수 중, register_forward_hook 사용해서 score 값을 뽑아 낸다.

  • 그리고 아름답게 함수를 구현해서 아래와 같은 plot 혹은 program을 만든다. 2번째 그림의 program은 신기하고 재미있으니 시간나면 한번 꼭 공부해보자. 코드는 맨 아래에 추가했다.

    1. 아래 이미지에서 좌표는, 실제 이미지 상의 좌표를 의미한다.
      image-20210419202039373

    2. 꼭 어떻게 만드는지 배워보자. (코랩 코드)

      image-20210419202103996


5. New modules

  1. torch.repeat(sizes), torch.expand

    • sizes (torch.Size or int…) – 각 차원에 대한 반복 수 (The number of times to repeat this tensor along each dimension)
    >>> x = torch.tensor([1, 2, 3])
    >>> x.repeat(4, 2)
    tensor([[ 1,  2,  3,  1,  2,  3],
            [ 1,  2,  3,  1,  2,  3],
            [ 1,  2,  3,  1,  2,  3],
            [ 1,  2,  3,  1,  2,  3]])
    >>> x.repeat(4, 2, 1).size()
    torch.Size([4, 2, 3])
       
    self.col_embed[:W].unsqueeze(0) >> torch.Size([1, 25, 128])
    self.col_embed[:W].unsqueeze(0).repeat(H, 1, 1) >> torch.Size[25,25,125] 
    
  2. torch.flatten(input, start_dim=0 : int, end_dim=-1 : int) → Tensor

    • h : (1, 256,25,25)
    • h.flatten(2) = h.flatten(start_dim = 2) : (1, 256, 625)
  3. torch.permute(2,0,1)

    • 차원 치환/교환

    • (1, 256, 625) -> (625, 1, 256)

  4. torch.unsqueeze(d)

    • d: unsqueeze하고 싶은 차원
    • d =1 -> (625, 256) -> (625, 1,256)
  5. torch.transpose(input, dim0, dim1)

    • 딱 2개의 차원을 교환한다
  6. torch.nn.Linear(in_features_int, out_features_int)

    • forward에 들어갈 수 있는 shape는, 무조건 in_feature_int 차원의 1차원 백터가 아니다!! 아래의 차원이 될 수 있다.
    • Input : (N,*,H_in), 이렇게만 forward로 들어가면 된다. Output: (N, *, H_out)
    • 여기서 H_in = in_features :int, H_out = out_features :int 이다.
  7. argparse

    • config 파일을 사용해서 환경변수를 저장하기도 하지만, 여기서는 간단하게 argparse만으로 환경변수를 정의했다.
    • main.py의 argparse 기법을 사용하면, args.junha = 1 만 코드에 추가해줘도 자동으로 새로운 key, valuse가 생성된다.
  8. torch.tensor.numel()

    • tensor 안에 들어 있는 파라메터 갯수 자연수로 반환
  9. nn.Module.named_parameters(), nn.Module.parameters()

    • iteration 이다.
    • [p.shape for p in model.parameters()], [p for p in model.parameters()] 이런식으로 출력해서 보기
    • [n for n, p in model_without_ddp.named_parameters() if "backbone" in n and p.requires_grad]
    • [(n,p) for n, p in model.named_parameters()]
      image-20210408133142137
  10. nn.Embedding

  11. nn.init.uniform_

    • torch.nn.init 여기에 모델 weight를 init하는 방법이 다 있다. 사용은 아래와 같이 한다.
    • nn.init.uniform_(self.row_embed.weight)
  12. torch.tensor.cumsum(input, dim)

    • dim 차원으로 바라봤을 때, 나오는 1차원 백터들에 대해서 누적된 합을 계산한 텐서 반환.
    • [1, 2, 3] -> [1, 3, 6]
  13. nn.Dropout(p)

    • p = 노드를 zero로 만들어 버릴 가능성
    • dropout은 임의로 노드를 잠궈버리는 것. 즉 Zero로 만들어 버리는 것이다. 따라서 dropout의 forward를 위한 파라미터는 노드를 넣어줘야한다. (코드 예시. src = src + self.dropout1(src2))
  14. nn.diag(x)

    • x가 2D이면, 대각행렬만 뽑아서 1D를 return해준다.
    • x가 1D이면, 1D를 대각항으로 가지는 2D를 return해준다.
  15. nn.topk(x,k)

    • top k개
    • tensor x중에서 가장 큰 수 k개를 뽑아낸다.
  16. torch.nn.Module.register_forward_hook(hook_function)

    • (1) torch document, (2) 한글 설명 tutorial

    • Network의 특정 module에서의 input, ouput을 확인하고 싶거나, 바꾸고 싶을 때 사용한다.

    • 해당 nn.moulde의 forward가 실행된 직후에 설정해 놓은 함수*가 실행된다. 어떻게든 register_forward_hook를 정의해 놓는 순간부터, 해당 코드에서 Network 전체 forward가 돌아가면 무조건 그 함수*가 실행된다.

    • 아래와 같이 global을 사용하지 않더라고 전역변수처럼 변수를 모듈 내부에서 사용할 수 있다.

      # use lists to store the outputs via up-values
      conv_features, enc_attn_weights, dec_attn_weights = [], [], []
            
      hooks = [
          model.backbone[-2].register_forward_hook(
              lambda self, input, output: conv_features.append(output)
          ),
          model.transformer.encoder.layers[-1].self_attn.register_forward_hook(
              lambda self, input, output: enc_attn_weights.append(output[1])
          ),
          model.transformer.decoder.layers[-1].multihead_attn.register_forward_hook(
              lambda self, input, output: dec_attn_weights.append(output[1])
          ),
      ]
            
      # propagate through the model
      outputs = model(img)
            
      for hook in hooks:
          hook.remove()
          # forward 이후에 실행해달라고 만들어 놓은 함수가 hook이다. 
          # 이 hook을 제거한다. (network를 원상복구한다.)
            
      # don't need the list anymore
      conv_features = conv_features[0] # 최종 feature map의 width, hight를 파악하기 위해서. 
      enc_attn_weights = enc_attn_weights[0] # 마지막 encoder layer의 attention score를 파악하기 위해서.
      dec_attn_weights = dec_attn_weights[0] # 마지막 decoder layer의 attention score를 파악하기 위해서.
      
  17. torchvision dataset 함수 수정해서 path 뽑아내기

    • 아래와 같이 dataset함수를 수정하니까 dataloader에서 나오는 값이 그대로 바뀌었다.
    • 즉 dataset class의 return 값만 변경해줌으로써 dataloader에서 나오는 값의 형식이 다르게 만들수 있다.
    1. torchvision.datasets.CocoDetection 여기서 path 변수 사용하는  파악
    2. detr/datatset/coco.py class CocoDetection
       - class CocoDetection(torchvision.datasets.CocoDetection):
       - 	path = self.coco.loadImgs(self.ids[idx])\[0\][\'file_name\']
       - 	return img, target, path
       -	# 위와 같이 path 내용 추가!
    3. for samples, targets, paths in metric_logger.log_every(data_loader, 10, header):
       # paths 추가! 
    

6. Additions

4.1 논문 외 보충 내용

  1. Attention is All you need의 논문 내용 정리! 같은 색 매칭해서 보기! - 그리기 코드는 맨 아래에 참조
    image-20210416222918201

    • Sinusoidal - Positional Embedding Code

      import numpy as np
      d_vector = 256
      num_vector = 625
      PEs = np.empty((num_vector,d_vector))
           
      period = 1000
      for i in range(num_vector):
          if i%2 == 0:
              w = 1/ period**(2*i/d_vector) # 상수. for문에 의해서 num_vector개 만들어짐
              pos = np.arange(256)
              PEs[i] = np.sin(pos*w)
          if i%2 != 0:    
              w = 1/ period**(2*i/d_vector)
              pos = np.arange(256)
              PEs[i] = np.cos(pos*w)
           
      %matplotlib inline
      import matplotlib.pyplot as plt
      from matplotlib.pyplot import figure
           
      figure(figsize=(25, 23), dpi=80, facecolor='black')
      imgplot = plt.imshow(PEs)
      plt.colorbar()
      
  2. Multi head self attention에서 Mask 개념, Masked Self-attention

    • Reference
      1. Transformer를 정말 완벽하게 표현설명한 외국 블로그글
      2. Transformer 코드 잘 만들어 놓은 한국 블로그글
      3. Transformer Architecture를 도식그림으로 잘 그려놓은 한국 블로그글
      4. Teacher forcing을 잘 설명해 놓은 한국 블로그글
    • NLP에서 Mask는 Decoder에서 사용되어야 하는 Layer이다. Decoder에서 3번쨰 단어(fine)를 예측할 때, Decoder의 (Emcoder 결과 말고) Input(I, am)으로 2개의 단어가 들어간다. 학습할 때 우리는 Input(I, am, find)를 모두 가지고 있으므로, find은 가린체로 decoder의 Input으로 넣어줘야한다. 그게 Mask가 하는 역할이다.
    • Mask가 처리되어야 하는 부분은 다른 곳이 아니라 저 부분만 이다. 그래서 Masked 개념은 Decoder에서만 사용된다. image-20210417165538067
    • Mask를 이용한 연산 처리 방법
      image-20210417170332292

4.2 추가 추신

  1. COCO dataset 다운로드 하기

    $ apt-get install wget
    $ wget https://gist.githubusercontent.com/mkocabas/a6177fc00315403d31572e17700d7fd9/raw/a6ad5e9d7567187b65f222115dffcb4b8667e047/coco.sh
    $ sh coco.sh
    
  2. dockerfile

    • 그대로 사용했다가, torchvision 버전 엉망됐다. requirements.txt에서 torch, torchvision, sumitit 삭제하고 설치하자.
    • $ pip install torch==1.5.0+cu101 torchvision==0.6.0+cu101 -f https://download.pytorch.org/whl/torch_stable.html
    • docker-hub의 -runtime , -devel 태크 분석하기. 지금 내가 쓰고 있는게 pytorch/pytorch:1.5-cuda10.1-cudnn7-runtime이다. 아래의 단서로 runtime은 그냥 가볍게 만든 우분투, devel은 최대한 다 넣어놓은 우분투 라고 예측할 수 있다.
      1. 지금 runtime image에 wget도 설치가 안되어 있다.
      2. docker-hub를 보면 runtime은 3.3G 정도, devel은 5.3G 정도이다.
  3. vscode에서 #%%를 사용하면서 pdb이용하기
    image-20210406212137524

    • $ pip install pdbpp
  4. vscode python debugging debug args setting 설정

    • ,"args": ["--batch_size", "1", "--no_aux_loss", "--eval", "--resume", "https://dl.fbaipublicfiles.com/detr/detr-r50-e632da11.pth", "--coco_path", "/workspace/coco"]

    • 위의 내용을, /pythonPackage/.vscode/launch.json의 config 파일에 넣어두기

      {
           "version": "0.2.0",
           "configurations": [
               {
                   "name": "Python: Current File",
                   "type": "python",
                   "request": "launch",
                   "program": "${file}",
                   "console": "integratedTerminal",
                   "debugOptions" : ["DebugStdLib"],
                   "justMyCode": false,
                   "args" : ["--batch_size", "1", "--no_aux_loss", "--eval", "--resume", "https://dl.fbaipublicfiles.com/detr/detr-r50-e632da11.pth", "--coco_path", "/workspace/coco"]
                 }
           ]
       }
      
  5. Pytorch 분산학습

    • rank, world size 을 detr에서 설정해줘야 Multi-GPU사용이 가능한데, 이게 뭔지모르니까 막무가네로 확경변수 설정 못하겠다.
    • 필요하면 다음의 Tuturial을 공부하자. Tuto1 Tuto2
  6. 추가 저장

    # debug에 사용
    from via import via; via(samples.tensors[0].cpu(), out='real_img' , color_img= True)
       
    i == self.num_layers - 1
       
    _ ,num_v ,_ = score.shape
    from via import via; via(score.reshape(num_v ,34,25)[28::40].cpu(), out='encoder_attention')
    
  7. 신경망 파라미터 변경하기
    image-20210423102540533

  8. 신경망 파라미터! 도대체 너는 뭐냐!!

    nn.Module의 __init__ 내부에 self.variable과 같이 맴버변수로 저장된 것들을, 모델 호출에 사용할 수 있다.

    image-20210423104253416

  9. Netron 프로그램 사용방법 및 파라미터 검색 방법
    image-20210423104219302

  10. 신경망 파라미터 정보 읽기 - torch.nn.Module.load_state_dict 동작원리 파악하기
    image-20210423105658212

【Transformer】Pyramid Vision Transformer



Pyramid Vision Transformer

1. Conclusion, Abstract

  • Pure Transformer backbone으로써 사용할 수 있는 PVT 를 제안했다. 특히나 이 backbone을 사용하면 dense prediction task(CNN의 Pyramid구조 그대로 output을 만들어 낼 수 있다.)
  • 새롭게 개발한 아래의 두 모듈을 사용했다. 두 모듈을 사용해서, 다음 2가지 장점을 얻을 수 있었다. (1) Pyramid 구조 생성함으로써 초반의 high resolution output 획득 가능 (2) computation/memory resources의 효율적으로 사용 가능
    1. a progressive shrinking pyramid
    2. spatial-reduction attention layer
  • PVT를 비교할 때, ResNet18,50,108 모델과 유사항 파라미터수를 가지는 모델을 만들고 그것과 성능비교를 해보았다.
  • CNN에는 SE [16], SK [24], dilated convolution [57], NAS [48], Res2Net [12], EfficientNet [48], and ResNeSt [60] 와 같은 많은 발전 모델들이 존재한다. 하지만 Transformer는 여전히 연구 초기 단계이므로 연구 개발의 많은 potential이 존재한다.
  • PS. 전체적으로 봐서, Deformable DETR과 목적이 같은 논문이다. Deformable DETR에서는 key,value를 pyramid features의 전체를 사용하는 것이 아니라, 모델이 스스로 선택한 4개*(4 level)의 key,value만을 선택해서 MHA을 수행한다. 여기서도 원래 key,value 전체를 shrink하여 갯수를 줄여서 MHA을 수행하겠다는 취지를 가지고 있다. 거기다가 Pyramid 구조를 만들었다는 것에도 큰 의의를 둘 수 있다.

2. Instruction, Relative work

  • 아래 그림이 약간 모호하니, 완벽하게 이해하려고 하지 말기

image-20210405121235389

  • 성능 비교

image-20210405121321299


3. Method

  • 아래 그림을 통해서 거의 전부 이해가 가능하다.

image-20210405122325135

image-20210405123207725

  • a progressive shrinking pyramid : 원래 ViT는 Patchsize = 1 로 하기 때문에, query의 갯수(이미지 HxW resolution)이 항상 일정하다. 하지만 PVT에서는 Patchsize는 1 이상 자연수값을 사용하기 때문에 이미지 resolution이 차츰차츰 감소한다. 따라서 Transformer만을 사용해서 Pyramid구조를 만들 수 있는 것이다.
  • 표 이미지의 청자색 필기 1~4번 필기 잘 참조하기 (핵심 및 근거 모음)
  • spatial-reduction attention layer : reduce the spatial scale(백터 갯수) of K and V 하는 것이다. 이 작업으로 largely reduces the computation/memory 가능하다.
  • Deformable DETR은 전체 HxW/P^2개의 key,value의 갯수를 특정 방식으로 몇개만 추출해서 사용했다면, 여기서는 전체 HxW/P^2개의 key,value의 갯수를 전체 HxW/R^2 개로 줄여서 사용한다.

image-20210405124016751


4. Experiments

  • Downstream Tasks
    • Classification : we append a learnable classification token (positional embeding) to the input of the last stage, and then use a fully connected layer.
    • Object Detection, Mask-RCNN : RetinaNet, Mask R-CNN
    • Semantic Segmentation : Semantic FPN (backbone의 성능을 보고 싶은 것이므로 simple한 segmentaion network)
  • Experiment Settings
    • The training image is resized to the shorter side of 800 pixels, while the longer side does not exceed 1333 pixels
    • we also randomly resize the shorter side of the input image within the range of [640, 800]
    • In the testing phase, the shorter side of the input image is fixed to 800 pixels
    • PVT+DETR : Transformer-based detection head, random flip and random scale as the data augmentation.

5. Results

  • Basic

image-20210405124523265

  • intermediate

image-20210405124408005



【docker】How to use dockerfile & docker run in detail

  • 공개된 Github 코드들 중에 Facebook, Microsoft, Google과 같은 대형 기업이 만든 패키지는 모두 Docker Installation을 제공한다. 즉 dockerfile이 제공되는데, 이것을 이용하는 방법에 대해서 간략히 공부해본다.
  • (이전 Post 링크) docker hub에서 Image를 가져올 때는 pull 명령어! 내가 Image를 배포하고 싶으면 push 명령어!
  • 미리 알아두어야할 핵심은, dockerfile로 Image를 만드는 것이다. container 만드는 것은 docker run

1. How to use dockerfile in order to make docker Image

(0) Reference

  1. https://tech.osci.kr/2020/03/23/91695884/
  2. https://javacan.tistory.com/entry/docker-start-7-create-image-using-dockerfile

(1) reference summary

  • Docker File이란 Docker Image를 만들기 위한 여러가지 명렁어의 집합이다.

  • 첫번째 reference에서는 아래의 일렬의 과정을 수행하기 위한 명령어들은 무엇이고, 이 과정이 자동으로 수행되게 만들기 위해서 dockerfile에는 어떤 내용이 들어가야하는지 설명한다.

    1. ubuntu 설치
    2. 패키지 업데이트
    3. nginx 설치
    4. 경로설정 (필요한 경우)
  • 최종적으로 dockerfile은 아래와 같이 만들어 질 수 있다.

    FROM ubuntu:14.04 
    MAINTAINER Dongbin Na "kbseo@osci.kr" 
    RUN apt-get update
    RUN apt-get install -y nginx
    WORKDIR /etc/nginx 
    CMD ["nginx", "-g", "daemon off;"]
    EXPOSE 80 
    
  • 이 내용을 한줄한줄 설명하면 다음과 같다.

    1. FROM ubuntu:14.04 -> 기반으로 할 이미지를 가져옵니다. 여기에서는 ubuntu 14.04버전의 이미지를 가져오겠습니다.
    2. MAINTAINER Dongbin Na "kbseo@osci.kr" -> 작성자의 정보를 기입해줍니다.
    3. RUN apt-get update -> RUN이라는 명령어를 통하여 쉘 스크립트를 실행하여 줍니다.
    4. RUN apt-get install -y nginx -> 도커 빌드 중에는 키보드를 입력할 수 없기에 [-y] 옵션을 넣어줍니다.
    5. WORKDIR /etc/nginx -> cd와 같다. CMD 명령어가 실행 할 경로로 먼저 이동을 해 줍니다.
    6. CMD ["nginx", "-g", "daemon off;"] -> nginx를 백그라운드로 실행합니다
    7. EXPOSE 80 -> 80번 포트를 오픈하여 웹서버에 정상적으로 접근할 수 있게 합니다.
      
    필요 내용만 정리 (명령어, 명령어 역할, 예시)
    RUN	- 직접적으로 쉘 스크립트 내에서 실행 될 명령어 앞에 적어줍니다.	RUN <command>	RUN apt-get update
    2. CMD	- 도커가 실행될 때 실행할 명령어를 정의해줍니다.	CMD ["executable", "param", "param"]	CMD ["nginx", "-g", "daemon off;"]
    3. WORKDIR	- 이후 명령어가 작업할 디렉토리로 이동합니다	WORKDIR /path	WORKDIR /etc/nginx
    4. COPY	- 파일이나 디렉토리를 이미지로 복사합니다	COPY <src> <dst>	COPY . /usr/src/app
    5. ADD	- COPY와 비슷하게 복사를 위해 사용합니다	ADD <src> <dst>	ADD . /usr/src/app
    6. EXPOSE	- 공개 하고자 하는 포트를 지정해줍니다	EXPOSE <port>	EXPOSE 80
    
  • 만든 dockerfile을 build 하기 $ docker build --force-rm --tag mynginx:0.1 .

    • docker build가 실행되는 터미널 pwd에 있는 dockerfile을 자동으로 build해준다.
    • –force-rm : 중간중간에 생성되는 임시 container를 항상 remove 한다. (--force-rm: Always remove intermediate containers)
    • –tag : 태그를 설정해줍니다. (docker-image-name : tag-name)

나의 사용 예시

  • 실제 DETR docker Image를 build하기 위해 아래의 과정을 수행했다.

    $ cd ~/git-package/
    $ git clone https://github.com/facebookresearch/detr.git
    $ cd ./detr
    $ sudo docker build ./ # 이렇게 하면 아래처럼 대참사 발생
    $ sudo docker build --force-rm --tag ImageName:tag ./  #이렇게 사용하라. 
    # 처음에 ./ 를 안해줬더니 아래 같은 에러가 떴다.
    # "docker build" requires exactly 1 argument. Usage : docker build [Options] Pash 
    
  • detr의 dockerfile을 보면 다음과 같다.

    ROM pytorch/pytorch:1.5-cuda10.1-cudnn7-runtime
    ENV DEBIAN_FRONTEND=noninteractive
    RUN apt-get update -qq && \
        apt-get install -y git vim libgtk2.0-dev && \
        rm -rf /var/cache/apk/*
    RUN pip --no-cache-dir install Cython
    COPY requirements.txt /workspace
    RUN pip --no-cache-dir install -r /workspace/requirements.txt
    
  • 생각해보니까, 내가 굳이 Physical server (내 데스크탑)에 detr package 전체를 git clone할 필요가 없었다.

  • 어차피 dockerfile에 의해서 만들어지는 이미지안에 detr package가 들어갈 거다. 그리고 그 package내부의 requirement.txt가 pip install 될 것이다.

  • –tag 옵션으로 Image 이름 꼭 설정해주자… 안그러면 아래와 같은 대참사가 발생한다.
    image

  • 나는 하나의 Image만 build하고 싶은데, 왜 많은 Image가 생성된걸까?
    image-20210402185216777

    • 우선 위의 대참사를 해결하기 위해서 –force-rm –tag 옵션을 넣어서 다시 수행했을때, 왠지는 모르겠지만 빠르게 Image가 build 되었다. 기존에 90f7 ca40 6296 4789 와 같은 Image가 존재하기 때문이다.
    • dockerfile을 build하는 과정은 다음과 같다.
      1. 맨 위에 명령어부터 차근차근 실행한다.
      2. docker-hub에서 이미지를 다운받는다.
      3. 그 이미지로 container를 생성한다.
      4. 그 container에서 우분투 명령어를 RUN한다.
      5. 그렇게 만들어진 container를 Image로 저장한다. (–force-rm옵션에 의해서 위의 임시 container를 삭제한다.)
      6. 이 과정을 반복해서 많은 Image가 생성된다.
      7. 최종적으로 만들어지는 Image는 Successfully built 7f745326ad49 에서 명시된 이미지이다.

지금까지 dockerfile을 build함으로써 docker Image는 만들었다!

이 다음부터는 $ sudo docker run 의 문제이다.

2. docker run

나의 사용 예시

  • 일단 아래처럼, ML-workspace 명령어 그대로 가져오면 안된다. 여기서 -it를 사용하지 않는 이유는 -it를 사용하지 않더라도 jupyter가 실행되며 terminal이 살아있기 때문이다.
$ sudo docker run -d \
    -p 8888:8080 \
    --name "detr" \
    --gpus all\
    -v "${PWD}/docker_ws:/workspace" \
    --shm-size 512m \
    --restart always \ # exit상태가 되면 무조건 다시 start한다.
    7f745326ad49
  • gpu사용하려면 이제 앞으로 –gpus 옵션만 넣으면 된다. 근데 이렇게 실행하면 이상하게 자동으로 exit가 되고 start를 수행하도 다시 exit가 된다. 이유 : -d 옵션을 사용하기만 하면 shell이 생성이 안되므로 자동으로 container가 죽어버린다
$ sudo docker run -d 7f74
  • 이렇게 하니가 start하면 계속 살아있네?
$ sudo docker run -it --gpus all  7f745326ad49
  • 결론 -d -it 꼭 같이 사용하자…
$ sudo docker run -d -it --gpus all  7f745326ad49
  • 다른 필요한 옵션도 추가 (이거 쓰지말고 맨 아래에 새로 만들었으니 그거 써라) 문제점 : -v에서 PWD가 들어가 있으니까, terminal PWD 생각안하고 container만들면 무조건 에러가 생기더라.
$ sudo docker run -d -it \
         --gpus all\
         --restart always\
         -p 8888:8080\	
         --name "detr" \
         -v "${PWD}/docker_ws:/workspace" \
         7f745326ad49

image

3. Error

  1. 어제까지만 잘 실행되던 container가 VScode에서 오늘 안열린다.

    • Error 내용 : /root/detr 이 존재하지 않는다.
    • 분석 : 내가 어제 git clone한 detr 폴더를 제거해버렸는데 그거 때문인가..?
    • 일단 아래 처럼 문제 해결
  2. Dockerfile 이 실행되면서 마지막에 에러가 발생하고 이미지가 안 만들어진다. (어제까지는 잘만 되더만)

    • 무식하게 분석하지 말고 에러를 일고 확실히 분석해보자.
      image-20210403180959468

    • 가장 마지막 step 이후에 만들어진 Image를 이용해서 test를 해본다. 이럴때 $ docker run --rm 옵션을 사용하는 거구나
      image-20210403181225402

    • 그렇다면 submitit package는 나중에 따로 직접 설치하다 requirement.txt에서 submitit 일단 지워 놓자.

    • 오케이 일단! sumitit 패키지가 안들어간 이미지 생성 완성
      image-20210403181805986

    • 첫번째 에러가 해결되었다!!
      image-20210403182238913

      • 근데 처음에 /root/detr이 없다고 첫번쨰 에러가 발생했는데… 새로 생긴 container에서도 detr은 존재하지 않는데…. 어떻게 된것일까 모르겠다.

      • 가장 안정된 docker run command

        • -v 옵션에서 조금이라도 문제가 있으면, 아에 -v 옵션이 적용이 안된다. 매우매우 주의할것

          sudo docker run -d -it      \
          --gpus all         \
          --restart always     \
          -p 8888:8080         \
          --name "detr"          \
          -v ~/docker/detr:/workspace   \
          detr:1
          
        • 앞으로 꼭!!! 이 과정으로 docekr 만들기

          1. $ cd ~/docker 하고 거기서 원하는 package $ git clone <packageA link>
          2. docker run의 -v옵션은 무조건 ~/docker/packageA:/workspace 으로 설정
          3. 이렇게 하면 container의 /workspace에는 자동으로 packageA도 들어가 있고 아주 개꿀이다.
          4. 참고로!! 혹시 모르니까 packageA 전체 내용은 삭제하지 말기.(첫번째 에러와 같은 문제가 다시 생길 수 있다.) 폴더를 만들고 싶다면 packageA 안에다가 폴더를 만들어서 거기서 작업하기
    • 아까 sumitit는 설치 못했으므로, 컨테이너에 직접 들어가서 패키지 설지
      image-20210403183947407

【DA】ProDA -Prototypical Pseudo Label Denoising by Microsoft

  • 논문 : Prototypical Pseudo Label Denoising and Target Structure Learning for Domain Adaptive Semantic Segmentation
  • 분류 : Domain Adaptation
  • 읽는 배경 : 선배 추천, Microsoft에서 연구된 현재까지 UDA 끝판왕
  • 느낀점 :
    • 앞으로 이렇게 알지도 못하면서 Abstract와 Conclusion 미리 정리하지 말자. Abstract와 Conclusion 제대로 이해하지도 못했는데, 일단 대충 때려 맞춰서 이해한 것을 정리한다고 시간을 쏟는거 자체가 시간 아깝다. Method 읽고 다시 처음부터 다시 Abstract와 Conclusion 읽고 정리하면 더 깔끔하고, 보기 좋고, 완벽한 정리를 할 수 있고, 시간도 절약할 수 있다.
    • 뭔지 알지도 못하면서 그냥 배경지식으로 나혼자 짜맞춰서 Abstract, Conclusion, Instruction을 정리하는 것은 무식한 것 같다.
    • 이 논문은 Few shot learning을 하던 사람이 거기서 사용하는 기법을 가져와서 DA에 잘 적용한 논문인 것 같다.
  • 읽어야 하는 논문
    • CVPR2019, FAIR, Momentum Contrast for Unsupervised Visual Representation Learning (Momentom Encoder)
    • CVPR2018, Learning to adapt structured output space for semantic segmentation
    • Arxiv, 2019, Confidence Regularized Self-Training (output-feature map regularization)
    • SimCLRv2 [11]
  • 목차
    1. 논문리뷰
    2. 논문 세미나 이후 인사이트 추가


ProDA

1. Conclusion, Abstract

  • 기존 방법들의 문제점

    1. source로 학습시킨 모델로 target image를 inference한 결과인, Pseudo labels은 너무 Noisy하고 신뢰할 수 없다.
    2. the target features(feature map이 embedinge된 공간의 모습이) are dispersed (너무 흩어져있다. 해산되어 있다.)
  • 논문 핵심 우선 정리
    1. Prototypes(centroids) 사용해서 Pseudo label을 Online으로 denoise (rectify) 하기
      • 여기서 Representative prototypes이란? The feature centroids of classes이랑 동의어이다.
      • the feature distance from centroids를 사용해서, the likelihood of pseudo labels를 계산하고 online correction(donoise)를 수행한다.
    2. target’s structure가 compact! feature space 모양이 되도록 만들었다. data augmentation 기법을 적절히 활용하였다.
    3. 위의 과정으로 +17.1%의 성능향상을 주었다. 그후에 Knowledge distillation을 적용함으로써 최종적으로 20.9% 성능을 획득했다.
  • 추가 알아야 할 것
    • Kullback–Leibler (KL) divergence : 두 확률분포의 엔트로피 차이를 계산하는 식. CrossEntropy랑 비슷한 거이다. 단순이 두 확률분포의 거리 차이랑은 개념이 조금 다르다. (기계학습 책에 잘 적혀 있었고, 공부했었으니 필요하면 참고하자.)

2. Instruction, Relative work

  • 읽어야 하는데… 선배들이 Instruction이 가장 중요하다고 했는데… Method에도 조금조금씩 분석과 Motivation에 대한 내용이 이미 나왔어서 그런지 읽기가 싫다.
  • 나중에 필요하면 읽자… ㅎㅎ
  • 이 논문의 Relative work는 따로 없고, 5.2. Comparisons with state-of-the-art methods부분에 짧게 존재한다.

3. Preliminary (Requirement)

image-20210404152232530

  • 위에 아래의 내용들을 순서대로 정리. 나중에 참고 할 것.
    1. denoting(변수정의)
    2. (un) self-supervised Domain adaptation에서 Loss함수
    3. Pseudo label 생성하는 수식 및 추가 Details

4. Method

4.1. Prototypical pseudo label denoising

  • Centroids를 사용해서 Pseudo label 보정하기 (아래 과정으로 설명 되어 있다.)
    1. formula to rectify nosiy pseudo label
    2. weight calculate
    3. Prototype(centroids) computation
    4. Pseudo label training loss
    5. Why are prototypes useful? 분석
  1. formula to rectify nosiy pseudo label

    • 문제점 : Source로 학습된 모델은, Target Image에 대한 inference결과로 Noisy labels을 생성하는데 Overfitting되었다. 그래서 Threshold를 넘는 Pseudo label을 생성하기까지 너무 오랜시간이 걸린다.

    • not good 해결책 : Pseudo label과 Network weight를 동시에 update하는 것은 그리 좋은 방법이 아니다. 학습이 불안정하게 이뤄지므로.

    • good 해결책2 : online update the pseudo labels(the pseudo labels을 그 이미지 배치 학습 그 순간순간 마다, noisy를 제거해서 다시 생성해 주는 것)

    • 해결책 2 수행 방법 : fix the soft pseudo labels & progressively weight(가중치를 주다) them by class-wise probabilities using Centroids(Prototypes) (주의!) 이때, 아래의 수식에서 P_t,o는 처음 source model에 의해서 정해진 값이고 학습과정 내내 고정되어 있다고 한다.(? 코드 확인하기)
      image-20210404154400700

  2. weight calculate

    • 아래 공식의 ω_t는 직관적으로 p_t의 비슷할테지만, 실험적으로 trust confidence(label)과 비슷한 것을 확인할 수 있다.
    • 이 weight공식은 few-shot learning에서 많이 사용되는 기술이다. few-shot learning에서는 classifying new samples을 목적으로 사용하지만 우리는 당연히 recity pseudo labels을 하기 위에서 사용한다.
      image-20210404155035886
    • Momentom Encoder가 무슨 느낌이냐면, data augmentation처럼 “모델을 힘들게 하고, 다른 결과를 생성하게 만드는 그런 혼동의 존재”의 반대이다. 비슷한 이미지가 들어오면 비슷한 결과를 추론하게 만들어 준다.
  3. Prototype(centroids) computation

    • 위의 weight공식에서 η가 각 class마다 가지고 있는 Prototype(centroids)이다. 이 것을 계산하는 공식은 아래와 같다.
    • 이 값은 on-the-fly으로 계산되고 업데이트 된다. 이 값을 계산하는 것은 computational-intensive (계산 집약된 무거운) 문제를 가질 수 있기 때문에, 아래의 수식과 같이 moving average of the cluster centroids in mini-batches을 사용해서 centroids를 업데이트 한다.
      image-20210404155616051
  4. Pseudo label training loss

    • symmetric cross-entropy (SCE) 을 사용한다. in order to further enhance the noise-tolerance to stabilize the early training phase(?)
      image-20210404155755037
  5. Why are prototypes useful? 분석

    1. 아래의 이미지에서 볼 수 있듯이, centroids는 outliers(dicision boundary)에 덜 sensitive하다. 그래서 아래 이미지의 필기 1~4 번 과정이 이뤄지면서 rectify pseudo label이 가능하다.
    2. centroids를 사용함으로써 class inbalance문제에도 덜 sensitivie하다. 만약 사람 class의 occurrence frequency(발생 빈도 = class를 가지는 이미지 수)가 매우 높다면, 비슷한 위치에 존재하는 feature이지만 다른 class인 원숭이의 학습이미지가 별로 없다면, 모델은 p(추측결과)로 사람 class를 선택할 가능성이 높다. 하지만 centroids는 그런 occurrence frequency와 관련이 없다.
    3. 실험적으로 denoise한 결과가 실제 target label에 더 가까운 값을 가지는 것을 확인했다.
    4. 따라서 centroids를 사용함으로써 gradually rectify the incorrect pseudo labels를 수행할 수 있다.

image-20210404145209925


4.2. Structure learning by enforcing consistency

  • 문제점 1
    • 위 이미지의 Figure1 (a)과 같은 도식이 나오려면 조건이, feature extractor의 최종 결과가 class마다 compact한 feature들이 나온다는 조건에서 저렇게 그려질 수 있다.
    • [42]에서 찾아진 문제점 : 만약 Figure1 (b) 처럼 각 class에 대해서 feature가 compact한 결과가 나오지 않는다면 centroids를 사용하는게 의미가 없고 차라리 성능이 더 떨어질 수도 있다. (If the darget distribution is dispersed, the prototypes fail to rectify the pseudo label)
    • 이러한 문제가 발생하는 가장 큰 이유는, 매우 적은 수의 target pseudo label들이 target domain의 모든 distribution을 커버할 수 없기 때문이다. (즉 feature embeding 공간상에서 feature vector가 너무 드문드문 존재하기 때문이다. 이러니 dispersed한 형상일 수 밖에 없다.)
  • 해결책 1
    • target domain의 underlying structure (근본적인 본질적인 구조 정보)를 사용한다! 더 compact한 feature embeding 모습을 가지기 위해서.
    • 그래서 최근 unsupervised learning에서 성공적으로 사용되고 있는, simultaneously clustering and representation learning기법을 사용한다. 그 기법은 data augmentation을 적절히 사용한다.
    • we use the prototypical assignment under weak augmentation to guide the learning for the strong augmented view
      image-20210404161819342
    • 위 필기(우상단)의 soft, hard는 label을 의미하는 것이 아니라, soft augmentation, hard augmentation을 의미한다.
    • 이 과정을 통해서 produce consistent assignments(consistent prototypical labeling for the adjacent feature points) 할 수 있게 한다. 즉 f가 좀 더 compact한 feature를 생성하도록 만드는 것이다.
  • 새로운 문제점 2
    • 위 과정의 장점이 있지만, 단점으로 degeneration issue 가 발생할 수있다. (one cluster becomes empty = P_k에서 하나만 1이 되고 나머지는 0이라면 모든 feature가 가장 compact하게 뭉치는 것이므로, 의도치 않게 f가 이런 p를 생성하는 모델이 되어진다.)
  • 2 해결책
    • use a regularization term from [76]
      image-20210404163802707
  • Total loss
    image-20210404163847806

4.3. Distillation to self-supervised model

  • 진짜 Target model을 supervised로 학습시킨 모델과 비슷한 모델이 되도록, 영혼을 다해 끌어당긴다. Knowledge distillation을 사용해서.
  • Knowledge distillation을 사용하기는 하지만, student model은 teacher와 same architecture를 가지지만 self-supervised manner(SimCLRv2 [11])로 pretrained된 모델을 사용한다.
    image-20210404165118504
  • 첫 Loss_ce값은 model의 source data에 대한 성능 저하를 막기위해 사용된다.
  • 실제 실험에서는 Knowledge distillation을 한번만 하는게 아니고 여러번 반복한다.
  • Knowledge distillation을 통해서 DA결과가 achieve even higher performance하도록 만든다.

5. Experiments

  • Training
    • DeepLabv2 [8] with ResNet-101 [25]
    • a warm-up으로 Learning to adapt structured output space 논문의 기법을 사용한다.
    • the initial learning rate as 1e-4 which is decayed by 0.9 every training epoch
    • training lasts 80 epochs
    • data augmentation : random crop, RandAugment [15] and Cutout [16]
    • SimCLRv2 model with the ResNet-101 backbone as well
    • Extra batch normalization (BN) (?)
    • distillation stage, we use hard pseudo labels with the selection threshold 0.95
    • 4 Tesla V100 GPUs
  • Dataset
    • game scenes : GTA5 [45] and SYNTHIA [46] datasets
    • real scene, the Cityscapes [14] dataset
    • The Cityscapes는 500 images for validation을 가진다. GT를 제공하지 않는 validation set이기 때문에, we conduct evaluations on its validation set.
  • Ablation Study
    image-20210404165626785
  • Result Matrix
    image-20210404165651962

세미나 이후 인사이트 추가

img img img img img img img img img img img img

【Lecture】startup company

  • 스타트업 관련 강의 정리

1. 서울로보틱스 이한빈 대표

  • B2B 같은 경우에는 절대 한국 company부터 시작하지 말아라. 외국에서 시작하라.
  • Korea Preimum은 진짜다. 다른 기업의 기술을 배껴서 싸게 많이 판다는 전략은 이제 한국에서 안 통한다. 왜냐면 중국보다 더 싸게 팔 수 없기 때문이다. 중국보다는 비싸더라도 한국 프리미엄의 신뢰성을 강조해야한다.
  • Don’t funcking waste your time. 그 좋은 머리 가지고 박사하고 논문 종이 찍어내지말고, 위험성을 감안하여 도전하고 시도해보는건 어떠냐?
  • 세계 곳곳의 지사의 장점 : 각 나라마다 장점과 특성이 있다. 현지인이기 때문에 비지니스하는데 문제가 없다.
  • 대표를 하면 인생이 갈려나가지만, 존버하면 언젠가 기회가 온다.
  • (1) Accuracy (2) Speed(Efficiency) (3) Robustness
  • 컴퓨터비전 회사는 결국 Data와 Labeling 싸움이다. Data는 회사에서 주고, Labeling은 해외회사가 일도 잘하고 싸다.
  • 현대랑 일 해봤는데, 함께 일하던 팀은 항상 1년 후에 부서 재배치 받더라. 이렇게 지긋이 못하니까 소프트웨어 회사들에 밀리는거다.
  • 박사학위가 회사 창업 성공과는 크게 관련이 없다. 하지만 고객과 회사들에게 기술력을 인정받으려면 박사학위 대표가 필요할 수도 있다.
  • 라이더 회사 아니다. 3D 컴퓨터 비전 회사다. 라이더 상용화 가능? 무조건이다. 이미 많은 차 회사들이 라이더를 이용하고 있다.
  • 진짜 필요한 능력은 (1) 알고리즘 구현 능력 - 수학적 능력 (2) 논문의 내용을 코딩으로 구현하는 능력. 그럼에도 불구하고 가장 필요한 능력은 “빨리 배우고 빨리 습득하고 능력”이다.
  • 현대랑 삼성이랑 협업 안하고도, 해외 회사들과 협업해서 살아남을 수 있다. 일본 분위기 회사가 아닌 중국 회사에 밀리지 않는 회사가 많이 나오면 좋겠다.

【DA】Domain Adaptive Semantic Segmentation Using Weak Labels

  • 논문 : Domain Adaptive Semantic Segmentation Using Weak Labels
  • 분류 : Domain Adaptation
  • 느낀점 :
  • 참고 사이트 : ECCV Presentation
  • 목차
  • 일어야할 논문들
    • Learning to adapt structured output space for semantic segmentation [49] : 이 논문에서 Sementic Segmentation을 위해서 여기서 사용하는 Architecture를 사용했다. 이 코드를 base code로 사용한 듯 하다.


DA Semantic Segmentation Using Weak Labels

이 논문의 핵심은 weak labels in a Image( 이미지 내부의 객체 유무 정보를 담은 List(1xC vector)를 이용하는것 ) 이다.

1. Conclusion, Abstract

image-20210401225204575

  • 논문의 핵심만 잘 적어 놓은 그림이다.
  • 하지만 Weak label for category-wise Alignment, Weak label classification Module은 그림으로 보고 이해하려고 하지말고, 아래 Detail과 Loss함수를 보고 이해하도록 해라.
  • 당연한 Domain Adatation의 목표 : lacking annotations in the target domain

3. DA with Weak Labels Method

3.1 Problem Definition

image-20210401230116281


3.2 Algorithm Overview

  • Model Architecture
    image-20210401230133034
  • 이 이미지에서 Domain Adaptation에서 많이 사용되는 Adversarial Discriminative Domain Adaptation이 핵심적으로 무엇인지 오른쪽 필기에 적어 놓았다. 진정한 핵심이고 많이 사용되고 있는 기술이니 알아두도록 하자.
  • Conference Presentation 자료 정리
    image-20210401235541159

3.3 Weak Labels for Category Classification

  • 이 과정의 목적은 segmentation network G can discover those categories 즉 segmentation network인 G가 domain이 변하더라고 항상 존재하는 Object/Stuff에 pay attention 하도록 만드는 것을 목표로 한다. G가 이미지 전체의 environment, atmosphere, background에 집중하지 않도록 하는데에 큰 의의가 있는 방법이다.
  • (Eq1) Global Pooling이 적용되는 방법과, (Eq2) Loss 수식에 대한 그림이다.
    image-20210401231357314
  • 이미지에 특정 class가 있는지 없는지에 대해서 집중하기(판단하기) 위해서 Global Pooling이 사용되었다.
  • 위에 (1)식에 사용되는 수식은 smooth approximation of the max function이다. k가 무한대로 크면 max pooing이 적용된 것이라고 할 수 있다. 하지만 하나의 값으로 pooling 값이 정해지는 max pooling을 사용하는 것은 Noise에 대한 위험을 안고 가는것이기 때문에, 적절하게 k=1로 사용했다고 한다.
  • Pooling에 의해서 적절한 값이 추출되게 만들기 위해서는 Loss함수가 필요한데, 그 함수를 (2)번과 같이 정의하였다. category-wise binary cross-entropy loss를 사용했다고 말할 수있다.

3.4 Weak Labels for Feature Alignment

  • image-level weak labels의 장점과 특징
    • 위의 방법을 보면 distribution alignment across the source and target domains(domain 변함에 따른 데이터 분포 변화를 고려한 재정비 기술들) 이 고려(적용)되지 않은 것을 알 수 있다.
    • 적용되지 않은 이유는, 우리가 category를 이용하기 때문이다. performing category-wise alignment를 적용하는 것에는 큰 beneficial이 있다. (3.3의 내용과 같이, class에 대한 특성은 domain이 변하더라도 일정하기 때문에)
    • 과거에 performing category-wise alignment을 수행한 논문[14]이 있기는 하다. 하지만 이 방법은 pixel-wise pseudo labels을 사용했다.(?)
    • 반면에 우리는 pixel-wise가 아니라 image-level weak labels를 사용했다. 그냥 단순하게 사용한 것이 아니라. an attention map guided by our classification module(global pooling) using weak label을 사용한 것이므로 매우 합리적이고 make sense한 방법이라고 할 수 있다.
  • Category-wise Feature Pooling
    image-20210401233013356

  • Category-wise Feature Alignment
    image-20210401233336307
    • 핵심은 Discriminator를 하나만 정의하지 않고, each category-specific discriminators independently를 사용했다는 점이다.
    • 이렇게 하면 the feature distribution for each category가 독립적으로 align되는 것이 보장될 수 있다. (맨위의 이미지를 보면 이해가 될 거다.)
    • a mixture of categories를 사용하면 the noisy distribution 문제점이 존재한다.
    • 그 이외의 내용들은 위 사진의 필기에 잘 적혀있으니 잘 참고할 것

3.5 Network Optimization

image-20210401234406864


3.6 Acquiring Weak Labels

  1. Pseudo-Weak Labels (UDA)
    • the unsupervised domain adaptation (UDA)
      image-20210401234539237
    • T는 threshold이다. 실험적으로 0.2로 세팅해서 좋은 결과를 얻었다.
    • 학습하는 동안에 the weak labels은 online 으로 생성해서 사용했다.
  2. Oracle-Weak Labels (WDA)
    • 사람의 조언(Human oracle)이 이미지 내부에 존재하는 카테고리의 리스트를 만들도록 한다.
    • weakly-supervised domain adaptation (WDA)
    • pixel-wise annotations 보다는 훨씬 쉽고 효율적이다.
    • 위의 방법 말고도 이 논문에서 Fei-Fei, L.: What’s the point: Semantic segmentation with point supervision. In: ECCV (2016) 논문에 나오는 기법을 WDA로 사용했다. (아래 Results의 성능 비교 참조)
    • 이 기법은 사람이 이미지 일정 부분만 segmentation annotation한 정보만을 이용하는 기법이다.
      image-20210401235242988

4. Results

  • 당연히 성능이 올라갔다. 자세한 내용은 논문을 참조 하거나 혹은 conference presentation 자료를 아래에서 참조하자.
  • 여기서 사용한 Weak Label은 2가지 이다. 아이러니 하게도… 이 논문에서 제안된 핵심 Weak label 기법보다 2016년에 Fei-Fei가 작성한 what’s the point 논문 기법으로 더 좋은 결과를 얻어냈다. (하지만 논문에서는 자기들 기법이 더 빠르게 anotaion할 수 있다고 한다. (?)
    image

1_Domain Adaptive Semantic Segmentation-1.png 1_Domain Adaptive Semantic Segmentation-2.png 1_Domain Adaptive Semantic Segmentation-3.png 1_Domain Adaptive Semantic Segmentation-4.png 1_Domain Adaptive Semantic Segmentation-5.png

【docker】Windows10에서 원격서버의 docker container에 접속하기

  • 최종결과 화면
    image-20210329204418671
  • 꼭 reference 사이트에 들어가서 순서대로 따라할 것.
  • 사이트 내부의 내용을 모두 정리하지 않을 계획이다.

Windows10에서 원격서버의 docker container에 접속하기

1. Reference

  1. https://www.44bits.io/ko/post/wsl2-install-and-basic-usage
  2. https://hwan-shell.tistory.com/182
  3. https://seokhyun2.tistory.com/42
  4. https://seokhyun2.tistory.com/48

2. WLS 및 docker desktop 설치

  • 참고 : https://www.44bits.io/ko/post/wsl2-install-and-basic-usage
  • WLS2와 docker desktop을 설치한다. 이 과정이 꼭 필요한 과정인지는 모르겠다. vscode에서 attach container를 하면 make sure docker deamon is running 이라는 에러가 났다. 이 문제를 해결하기 위해서 docker desktop을 설치해야하는 듯 했다.
  • windows home을 사용하기 때문에 WLS2를 설치해야만 docker desktop을 설치할 수 있었다.
  • 사이트 순서를 정리하면 다음과 같다
    1. Windows Terminal 설치하기
    2. WSL 활성화를 위해서 PowerShell에서 두개의 명령어를 복붙 처주기
    3. WSL 설치하기 = MS store에서 Ubuntu 설치하기
    4. WSL1을 2로 업데이트 시켜주기 (커널을 설치해주고 PowerShell에서 $ wsl --set-version/default 처리 해주기 )
    5. Docker Desktop 설치하기 (windows home이지만, WSL2를 설치해놨기에 docker가 잘 설치가 되었다.)
    6. Docker 세팅 바꿔서 Ubuntu Terminal in window10에서도 docker 사용할 수 있게 만들기

3. VScode에서 SSH-remote 연결하기

  • Remote - Docker Containers extension만 설치하면 안된다. 우선 SSH 연결이 필요하다

  • 따라서 아래의 사이트를 참고 해서 다음의 과정을 진행해준다.

  • 순서 정리

    1. window vscode에서 Remote Development extention 설치 (Remote 관련 extention 다 설치된다)

    2. Ubuntu Server 아래의 명령어 실행

      • $ sudo apt-get update
        $ sudo apt-get install ssh
        $ sudo apt-get install openssh-server
        $ sudo nano /etc/ssh/sshd_config # port 22 만 주석 풀어주기
        $ sudo service ssh status
        $ sudo service ssh start
        방화벽
        $ sudo ufw enable
        $ sudo ufw allow 22
        $ sudo ufw reload
        
    3. 윈도우 agent 세팅해주기

      • 관리자모드 CMD - $ sc config ssh-agent start=auto
      • $ net start ssh-agent
    4. 윈도우에서 ssh-keygen해서 ubuntu에 넣어주기 (사이트)

      • Powershell : $ ssh-keygen -t rsa -b 4096
      • Powershell : $ Get-Content .\.ssh\id_rsa.pub - 그러면 출력되는 긴~~ 결과물이 있을텐데, 그것을 복사해서 메일로든 뭐든 저장해두기
      • Ubuntu : $ code /home/junha[=userName]/.ssh/authorized_keys - Ubuntu : $ chmod 644 /home/junha/.ssh/authorized_keys : 이렇게 설정해주면 윈도우에서 ssh연결할때 우분투 비밀번호 안물어본다.
      • 여기에 그~대로 key 복붙해서 저장해두기 (아래 이미지 참조) - (에러 발생 및 문제 해결) 같은 아이피를 사용하는 우분투 케이스를 바꿔서 다시 연결하려니 안됐다. 이때 해결책 : 윈도우에서 known_hosts파일 삭제하기. $ cd C:\Users\sb020\.ssh && rm ./known_hosts
    5. 윈도우 VScode ssh config

      • VScode -> ctrl+shift+p == F1 -> Remote-SSH: Connect to Host

      • Host server1
        	HostName 143.283.153.11 # 꼭! ifconfig해서 ip확인
        

        User junha

    IdentityFile ~/.ssh/id_rsa ```

    • 위와 같이 config 파일저장해두기

    • 그리고 SSH VScode로 연결해보면 아주 잘된다.
      image-20210329211438915 ```

4. Ubuntu Docker 설치 및 Container 실행

  1. Docker 설치 : 기본 Docker 를 설치해줘야 NVIDA docker로 업그레이드 가능

  2. 우분투에 NVIDA Driver 설치

  • $ sudo ubuntu-drivers devices
    • $ sudo ubuntu-drivers autoinstall
  • $ reboot
    • 꼭 드라이버 설치하고, $ nvida-smi 하기 전에, reboot 꼭 해보기.
    • $ nvidia-smi
  1. NVIDIA-Docker 설치

    • # 정리
      1$ curl https://get.docker.com | sh \
        && sudo systemctl --now enable docker
      2$ distribution=$(. /etc/os-release;echo $ID$VERSION_ID) \
         && curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add - \
         && curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list
      3$ sudo apt-get update
      4$ sudo apt-get install -y nvidia-docker2
      5$ sudo systemctl restart docker
      6test-$ sudo docker run --rm --gpus all nvidia/cuda:11.0-base nvidia-smi
      
  2. ML workspace Docker Image 다운로드(pull) 및 container Run

    • $ sudo docker run -d \
          -p 8080:8080 \
          --name "8080ML" \
          --runtime nvidia \
          --env NVIDIA_VISIBLE_DEVICES="all" \
          -v "${PWD}/docker_ws:/workspace" \
        --env AUTHENTICATE_VIA_JUPYTER="junha" \
          --shm-size 512m \
          --restart always \
          mltooling/ml-workspace:0.12.1
      
    • ### 설명 추가
      $ sudo docker run -d \ # background 실행
          -p 8080:8080 \ # 앞 포트는 내 우분투 포트, 뒤 포트는 컨테이너 내부 우분투 포트, 실험에 의하면 host-port/container-port이며, host-port만 바꿔주고 container-port는 8080으로 고정해서 사용하자
          --name "8080ML" \ # 맘대로 해라
          --runtime nvidia \ # 이거 꼭! 
          --env NVIDIA_VISIBLE_DEVICES="all" \ # 이것도 꼭 
          -v "${PWD}/docker_ws:/workspace" \ # 터미널실행PWD=="${PWD}"/docker_ws 폴더 만들어 놓기
        --env AUTHENTICATE_VIA_JUPYTER="junha" \ # 비밀번호
          --shm-size 512m \ # 일단 해놈. 안해도 될듯 
        --restart always \ # 알지? 
          mltooling/ml-workspace:0.12.1 # docker-hub에 버전 참고
      

      ```

    ```

## 5. Docker Container 연결하기

  1. 참고

  2. VScode -> ctrl+shift+p == F1 -> Preferences: Open Settings (JSON)

  3.   {
        "docker.host": "ssh://junha@143.283.153.11"
      }
    
  4. 이렇게 수정해두기. 위에서 junha로 하는 대신 우분투에서 아래의 작업 진행

  5.   $ sudo usermod -aG docker junha
    
  6. VScode -> ctrl+shift+p == F1 -> Remote-Containers: Attach to Running Container

  7. 존버타고 있으면, 서버에 실행되고 있는 container 목록이 뜬다. 원하는거 선택하고 Open 및 설정이 완료되기까지 시간이 좀 걸린다.

  8. 그러면 최종 성공!
    image-20210329211903648

6. 완성!

  • Windows10

image-20210329213115925

  • Ubuntu

image-20210329213208677

7. VS code 환경설정

  1. 아래와 같이 Python Interpreter 설정을 해야한다.
  2. ML-workspace자체에 conda가 설치되어 있고, base env는 opt/conda/bin/python 에 존재한다. interpreter에 마우스 길게 갖다 대고 있으면 path가 나온다. 나의 window conda path와 겹칠일은 없겠지만 그래도 조심하자.
    image-20210329223237549

8. docker container에서 code 명령어 사용하기

  • reference site : The “code” command does not work when connecting to a Docker container remotely with VSCode

  • 종합적으로, 아래의 명령어를 docker container Terminal에 입력했다.

    $ ls ~/.vscode-server/bin # hash name 파악하기
    $ export PATH="$PATH:$HOME/.vscode-server/bin/<hash name>/bin/"
    (예시) $ export PATH="$PATH:$HOME/.vscode-server/bin/08a217c4d27a02a5bcde8555d7981bda5b49391b/bin/"`
      
    $ code ~/.bashrc
    (Addding in the file) export PATH="$PATH:$HOME/.vscode-server/bin/08a217c4d27a02a5bcde898555981bda5b49391b/bin/"` 
    

9. –shm-size 의 중요성

mmclassification 을 돌리면서 만난 에러가 다음과 같았다.
RuntimeError: DataLoader worker (pid 167565) is killed by signal: Bus error. It is possible that dataloader's workers are out of shared memory. Please try to raise your shared memory limit

찾아보니 원인은 다음과 같았다.

  1. 도커로 컨테이너를 생성하게 되면 호스트와 컨테이너는 공유하는 메모리 공간이 생기게 되는데 이 공간에 여유가 없어서 발생되는 에러이다.(참조사이트)

  2. container $ df -h 명령어로, shm가 얼마인지 확인할 수 있다.

  3. container run 할 때 충분한 -shm-size 를 설정해주는 방법이 답이다.

  4. ML-workspace github 참조
    image

  5. 찾아보니, 대강 이 문제가 발생한 사람들은 docker run --shm-size=2G 설정한다. 어떤 글을 보니 docker run --ipc=host 이런식으로 설정해주는 사람도 있었다. 어떤 사람은 8G로 설정하는 경우도 있었다. (문제 안생기나?)

    # 최종 실행 터미널 코드
    $ sudo docker run -d -it      \
    --gpus all         \
    --restart always     \
    -p 8000:8080         \
    --name "mmcf"          \
    --shm-size 2G      \
    -v ~/docker/mmclf/mmclassification:/workspace   \
    -v ~/hdd1T:/dataset   \
    pytorch/pytorch:1.5.1-cuda10.1-cudnn7-devel
    
  6. 또한 $ watch -d- n 1 df -h 명령어를 사용해서 현재 container가 어느정도의 –shm-size를 사용하고 있는지 알 수 있다.

  7. 참조 사이트 : pytorch-issue, share-memory-8G

10. 새로운 windows로 원격 vscode 코드 열기

  1. vscode에서 단축키 변경으로 ctrl + k + s
  2. duplicateWorkspaceInNewWindowctrl+shift+n 으로 단축키 지정해주기
  3. 참조 사이트

11. permission denied

참고 나의 포스트

  • 핵심 : $ sudo chown -R junha:junha ./detectron2/

【Transformer】Pre-Trained Image Processing Transformer



Pre-Trained Image Processing Transformer

1. Conclusion, Abstract

  • Conclusion
    • pre-trained transformer model (IPT)을 사용해서, 기본적인 이미지 프로세싱 문제(Denoising, Deraining, SRx2=super resolution 2배, SRx4)를 해결한다.
    • Class, Image Color도 다양하게 가지고 있는 종합적인 ImageNet datesets를 degraded한 이미지 데이터를 pre-trained dataset으로 사용했다. 모델이 low-level image processing을 위한 intrinsic features를 capture하는 능력을 향상시킬 수 있었다.
    • (1) supervised and self-supervised approaches (2) contrastive learning approaches 모두 융합해서 모델을 학습시킨다.
  • Abstract
    • pre-trained deep learning models을 사용해서, 원하는 Task의 모델을 만드는 것은 좋은 방법이다. 특히나 transformer module을 가지고 있는 모델은 이런 과정이 주요한 이바지를 할 것이다.
    • 그래서 우리가 image processing transformer (IPT)을 개발했다.
    • 다른 image processing task들에서도 금방 적응할 수 있도록, Contrastive learning을 수행했다!

3. Image Processing Transformer

image-20210328130543692

  • 위 이미지 그림과 필기 먼저 확실히 파악하기

3.1 IPT architecture

  • 4개의 components : (1) Head = extract features from input imaeg) (2) Encoder = (3) Decoder = 이미지에 중요한 missing 정보를 capture&recover 한다. (4) tails = Final restored images를 만들어 낸다.
  • Head
    • 각각의 Task에 대해, 3 conv layer로 이뤄진다. 이미지 x가 input으로 들어가서 f_H가 만들어진다.
      image-20210328131546974
  • Transformer encoder
    • Almost same Transformer in All you need is Attention
    • Split the given features into patches
    • Learnable position encodings -> Element-wise SUM
      image-20210328131917272
  • Transformer decoder
    • Almost same encoder Transformer : 다른 점은 a task-specific embedding (Task에 따라서 다른 emdedding 백터 사용)
    • two multi-head self-attention (MSA)
      image-20210328132514512
  • Tails
    • Head와 같이 3 conv layer로 이뤄진다.
      image-20210328132729227
    • 여기서 H’그리고 W’는 각 Task에 적절한 Size가 되면 된다. 예를 들어 Task가 SRx2 이라면 W’ = 2W, H’ = 2H가 되겠다.

3.2 Pre-training on ImageNet

  • the key factors for successfully training은 바로, the well use of large-scale datasets 이다!
  • 하지만 image processing task에 특화된 Dataset 별로 없다. 예를 들어 DIV2K (only 2000 Images). (이 Dataset은 ImageNet을 manually degrading한 것과는 다르다고 한다. 이러한 다름을 고려하여 추후에 generalization ability에 대해 분석해본다.)
  • 따라서 ImageNet을 사용해서 we generate the entire dataset for several tasks. 이것을 이용해서 Pre-training model을 만든다!
  • ImageNet에서 Label에 대한 정보는 버려버리고,, 인위적으로 여러 Task에 맞는 a variety of corrupted images를 만들었다.
    image-20210328133446178
  • 이 과정을 통해서, Model은 a large variety of image processing tasks에 대해서 the intrinsic features and transformations을 capture할 수 있는 능력이 생긴다. 그리고 추후에 Fine-tuning과정을 거치기는 해야한다. 그때는 당연히 원하는 Task에 맞는 desired task using the new provided dataset를 사용하면 된다.
  • Contrastive Learning
    • we introduce contrastive learning for learning universal features.
    • 이 과정을 통해서 the generalization ability (= adaptation, robustness of Tasks or Image domains)을 향상하는데 도움을 준다. 다시 말해, pre-trained IPT 모델이 unseen task에 빠르게 적응하고 사용되는데 도움을 받는다.
    • 한 이미지로 나오는 Feature map의 Patch들의 관계성은 매우 중요한 정보이다. NLP에서 처럼(?) 하나의 이미지에서 나오는 patch feature map은 서로 비슷한 공간에 최종적으로 embeding되어야 한다.
    • We aims to (1) minimize the distance between patched features from the same images (2) maximize the distance between patches from different images
    • 최종 수식은 아래와 같이 표현할 수 있다. 맨아래 수식이 Final 목적 함수이다
      image-20210328140204710

4. Experiments and Results

  • 각 Task에 따른, 결과 비교는 아래와 같다.

image-20210328142118123

  • Generalization Ability
    • 비록 우리가 ImageNet으로 currupted image를 만들었지만, 이 이미지와 실제 DIV2K와 같은 dataset과는 차이가 존재하고 실제 데이터셋이 더 복잡하다.
    • 데이터셋에 따라서, 모델의 성능에서도 차이가 존재할 것이기에, generalization ability를 실험해보았다. 실험은 denoised Image Task에 대해서 실험한 결과가 나와있다.
      image-20210328142558904


【Detection】Tokens-to-Token ViT



Tokens-to-Token ViT

1. Conclusion, Abstract

  • Conclusion
    • the novel tokens-to-token (T2T) 이란?? proggressively image/feature 를 tokenizing 하는 것
    • 장점(1) 이미지의 구조정보를 파악할 수 있다. (2) feature richness를 향상시킬 수 있다.
    • 특히 backbone에서는 the deep-narrow architecture = transformer layer는 많이 hidden dimention은 작게 가져가는 것이 효율적이다.
  • Abstract
    • ViT 문제점 : midsize dataset으로 학습시키면, CNN 보다 성능이 낮다.
    • 문제점 이유1 : Image patch를 그대로 tokenization해서 important local structure(edge, line, 주변 픽셀과의 관계) 등을 파악할 수 없다.
    • 문제점 이유2 : redundant attention backbone(너무 많은 Attention layer, 여기서 backbone은 Transformer encoding 앞에 있는 layer가 아니라, 그냥 Image patch의 PE이후에 Transformer encoding 전체를 의미하는 것이다.)

2. Instruction, Relative work

image-20210326211042928

  • 위 그림은 (1) ResNet (2) ViT (3) T2T-ViT 내부를 각각 들여다 본 그림이다.
  • 확실히 녹색 박스와 같이 ResNet과 T2T에서는 Desired Local Structure를 잘 파악하는 것을 알 수 있다.
  • 하지만 ViT에서는 너무 Global attention에만 집중해서 Local Structure에 대해서 잘 파악하지 못한다. 심지어 빨간 박스처럼 쓰레기 같은 결과가 나오기도 한다.
  • our contributions
    • visual transformers이 진짜 CNN을 띄어넘게 만들기 위해서, (1) T2T module (2) efficient backbone 을 만들었다.
    • a novel progressive tokenization
    • Backbone으로 Transformer encoder와 같은 구조를 차용하기도 하지만, the architecture engineering of CNNs 을 사용해서 비슷한 성능(ResNeXt)혹은 조금더 나은 성능(SENet)을 얻는다.

3. Method

  • 논문의 핵심 전체 Architecture는 아래의 이미지라고 할 수 있다.
    • 아래의 그림과 같이 T2T-ViT는 2개의 구성으로 나눌 수 있다. (1) Tokens To Token Module (2) T2T-ViT Backbone 각각의 목적과 목표는 아래 필기에 정확하게 정리해 적어놓았으니, 녹색과 빨간색 필기를 꼭 참고하기 바란다.
    • 참고로 여기서 length는 vector dimention을 의미하는게 아니라, vector의 갯수를 말한다.
      image-20210326211700095
  • T2T module(process) : 위 그림에서 T2T
    image-20210326211801773
    • Step1 : spatial 형상의 이미지처럼 토큰을 reshape한다.
    • Step2 : Soft split처리를 함으로써 이미지의 지역정보를 학습하고 토큰의 length(갯수)를 줄일 수 있다. 토큰을 overlapping을 해서 patch 형태로 split 하는 것이다. 이렇게 함으로써 주변 tokens들과의 더 강한 correlation을 파악 할 수 있다. (ViT처럼 patch로 처음에 자르고 그 patch들 (특히 주변 patch들간의 관계성에 대한 정보를 넣어주지 않으면 지역정보(edge, line)를 파악할 수 없다.)
    • 전체를 정리하면, 위 그림의 오른쪽 아래 식과 같이 나타낼 수 있다.
    • ViT에서는 Patch의 수가 16*16 즉 256개였다. 이것또한 메모리 관점으로 굉장히 많은 숫자였다. 그래서 우리의 T2T 모둘은 patch수는 어쩔 수 없고, the channel dimension을 small (32 or 64)으로 설정함으로써 메모리 효율을 높이고자 노력했다.
  • T2T-ViT Backbone
    • reduce the redundancy / improve the feature richness
    • Transformer layer를 사용하기는 할 건데, 그들의 조합을 어떤 구조로 가져갈 것인가? (자세한 구조는 Appendix를 참조)
      1. DenseNet
      2. ResNets
      3. (SE) Net
      4. ResNeXt = More split heads in multi-head attention layer
      5. GhostNe
    • 많은 실험을 통해서 the deep-narrow architecture = transformer layer는 많이 hidden dimention은 작게 가져가는 것이 효율적이라는 결론을 얻었다.
    • 여기서는 fixed length T_f가 이뤄진다. 그리고 concatenate a class token 마지막으로 Sinusoidal Position Embedding (PE)을 사용하는게 특징이다.
      image-20210326213635717
  • T2T-ViT Architecture
    • n = 2 re-structurization
    • n+1 = 3 soft spli
    • patch size P = [7, 3, 3]
    • overlapping is S = [3, 1, 1]
    • Reduces size of the input image = from 224 × 224 to 14 × 14
    • batch size 512 or 1024 with 8 NVIDIA

4. Results

  • Table1: 다양한 구조의 T2T-ViT 모델들
  • Table2,3,4 : 기존의 모델(1. ViT 2. ResNet 3. MobileNet)들과 비교 결과

image-20210326214106574

  • 어떤 구조가 가장 좋은지 비교
    image-20210326214205431

  • 좀 더 자세한 설명은 필요하면 나중에 논문 참조하기



Youtube 참고 정리

【Detection】Feature Pyramid Transformer

  • 논문 : Feature Pyramid Transformer
    논문 필기는 C:\Users\sb020\OneDrive\21.1학기\논문읽기_21.1 여기 있으니 참조
  • 분류 : Detection
  • 읽는 배경 :
  • 느낀점 :
    1. 이 논문도 약간 M2Det같다. 뭔가 오지게 많이 집어넣으면 성능향상이 당연하긴하지.. 약파는 것 같다.
    2. 비교도 무슨 Faster-RCNN, Mask-RCNN 이런거 써서 비교하는게 전부이고 약간 많이 부족하고 아쉬운 논문이다.


Feature Pyramid Transformer

image-20210325162755839

  • 이 그림이, 이 논문의 전부. FPN의 결과에 Same size + richer contects 를 가지는 feature map 만드는 것을 목표로 한다.
  • 보라색 동그라미 부분과 같이, (1) feature map 그대로 self-attention을 수행하는 Self-transformer (2) Up! 하는 Rendering Transformer (3) Down! 하는 Grounding transformer 를 제안했다. (개인적인 생각으로, 이 방법이 약간 어설프고? 약간 너무 파라메터와 레이어를 무작정 늘리는 행동? 같다.)

1. Conclusion, Abstract

  • efficient feature interaction approach
  • 3개의 Step : Encoder(Self-Transformer), Top-down(Grounding Transformer), Bottom-up(Rendering Transformer)
  • FPN(feature pyramid network)에서 나온 P2~P5에 FPT(feature pyramid transformer)를 적용해서 P2~P5는 크기는 보존되는데 좀더 Sementic한 Feature map이 되게 만든는 것을 목표로 한다.(the same size but with richer contexts) 따라서 이 모듈은 easy to plug-and-play 한 모델이다. (대신 파라메터수가 엄청 많아 진다. 결과 참조)
  • the non-local spatial interactions (2017년에 나온 논문으로 MHSA과 비슷한 구조를 가지고 있지만 좀 다르다 예를들어서 Multi head를 안쓴다던지…)는 성능향상에는 도움이 된다. 하지만 across scale 정보를 이용하지 않는다는 문제점이 있다.
  • 이 문제점을 해결하고자 interaction across both space and scales을 수행하는 Feature Pyramid Transformer (FPT) 모듈을 만들었다.

2. Instruction, Relative work

image-20210325162730412

  • 위의 그림이 개같으니 굳이 이해하지 못해도 상관하지 말기
  • Fig. 1 (d) : non-local convolution을 통해서 상호 동시 발생 패턴 (reciprocal co-occurring patterns of multiple objects)을 학습할 수 있다고 한다. 예를 들어서, 컴퓨터가 이미지에 있으면 주변에 책상이 있는게 옮바르지, 갑자기 도로가 예측되는 것을 막는다고 한다. (Self-attention 구조를 약간 멋지게 말하면 이렇게 표현할 수 있는건가? 아니면 ` non-local convolution논문에 이러한 표현을 하고 증명을 해놓은 건가? 그거까지는 모르겠지만 non-local convolution`은 Transformer 구조에 진것은 분명한 것 같다.)
  • Fig. 1 (e) : 이와 같이 cross scale interactions을 유도할 것이라고 한다.
  • Feature Pyramid Transformer (FPT) enables features to interact across space and scales. 내가 지금 부정적으로 생각해서 그렇지, 파라메터 오지게 많이 하고 깊이 오지게 많이 한다고 무조건 성능이 올라가는 것은 아니다. 그렇게 해서라도 성능이 올랐으니 일단은 긍정적으로 봐도 좋다. 하지만 FPN을 차용해서 아이디어를 짠것은 좋은데 좀더 깔끔하고 신박하고 신기하게 설계한 구조와 방법이 필요한 듯 하다.

3. Method

image-20210325162755839


3.1 Non-Local Interaction Revisited

  • typical non-local interaction 은 다음과 수식으로 이뤄진다고 할 수 있다. (하나의 level Feature map에 대해서) 하지만, 논문에서는 이 공식을 그대로 사용하지 않는다.
    image-20210325164245529
  • (사실 self-attention과 거의 같은 구조이다. 차이점에 대해서는 BottleneckTransformer를 참조하면 도움이 될 수 있다.)

3.2 Self-Transformer

  • 위의 typical non-local interaction공식에서 하나만 바꿔서, 새로운 이름을 명명했다.
  • 위에서 weight를 계산하는것이 그냥 softmax를 사용했다. 이것을 the Mixture of Softmaxes (MoS) [34] 로 바꾼다.
    image-20210325165146471
  • 위의 N에 대한 설명은 자세히 나와있지 않다. the same number of divided parts N 이라고 나와있는게 전부이다. 따라서 위에 내가 생각한게 맞는지 잘 모르겠다. [34] 논문을 참고하면 알 수도 있다.

3.3 Grounding Transformer

image-20210325165710081

  • a top-down non-local interactio을 수행하는 방법이 위와 같다.
  • 어렵게 생각할거 없고 위에 그림과 같이 q, k, v를 설정하여 self-attention을 적용한 모듈이다.
  • 예를 들어서 변수 = 변수.shape로 표현해 정리한다면, q = H * W * d, K = h * w * d 차원을 가진다고 하면, q_i = 1 * d, k_j = 1 * d 가 된다고 할 수 있다. d를 맞추는 것은 channel 크기를 맞춰주면 되는 것이기 때문에 그리 어려운 문제는 아니다.
  • Locality-constrained Grounding Transformer : 그냥 Grounding Transformer를 적용하는 방법도 있고, Locality 적용하는 방법이 지들이 제안했다고 한다. stand-alone에 있는 내용아닌가…

3.4 Rendering Transformer

  • a bottom-up fashion. self attentino을 적용한 방법이 아니다. 과정은 아래와 같다. (논문의 내용을 정리해놓은 것이고 헷갈리면 논문 다시 참조)
    image-20210325170353850

3.5 Overall Architecture

  • FPT for object detection and instance segmentation
    • BFP = FPN 지들맘대로 이름 바꿔서 사용함.
    • divided parts of N은 ST에서는 2 그리고 GT에서는 4로 설정했다.
    • FPT를 통해서 나오는 Pyramid Feature map들을 head networks에 연결되어서 예측에 사용된다.
    • head networks는 Faster R-CNN 그리고 Mask RCNN에서 사용되는 head를 사용한다.
    • (분명 retinaNet과 같은 head도 해봣을텐데, 안 넣은거 보니 성능이 그리 안 좋았나? 라는 생각이 든다.)
  • FPT for semantic segmentation.
    • dilated ResNet-101 [4]
    • Unscathed Feature Pyramid (UFP) - a pyramidal global convolutional network [29] with the internal kernel size of 1, 7, 15 and 31
    • segmentation head network, as in [14 ASPP,19]

5. Results

image-20210325171045436

image-20210325171111809

Pagination


© All rights reserved By Junha Song.