Active Learning 연구를 예전에 했었는데 코드를 다 까먹었다.
액티브러닝만 할건 아니고 수술 영상에서 조금 특이한 연구(??)를 진행하려고 하는데, 구현할때 마음에 안들만한 구석이 있을지(?) 싶어서 기억을 더듬어 이 코드부터 다시 뜯어보려고 한다. 예전에 이걸 참고해서 짰어서.
코드 보면서 쓰는 글.
아래 코드를 보고있다.
github.com/ej0cl6/deep-active-learning
Step 1.
어떻게 동작하는지 알아야하니 우선 run.py를 보자.
일단 대략 이런식으로 동작한다.
아래 설명은 위 코드를 기반으로 하지만, 내가 연구하면서 셋팅했던 것들이 있다면 이를 반영하여 적었다.
- learning cycle 0
- pretrained model을 불러오든, 아예 처음부터 시작하든간에 아무튼 initial model이 있다. 여기서는 random_init 파라미터로 셋팅하고 학습한다.
- 나는 underfit되도록 어느정도만 학습된 모델을 pretrained model로 불러오기만 하고, 여기선 train하지 않았다.
왜냐면 다른 기법과 비교해야하는데 아직 active learning이 일어나지도 않았는데 initial 성능이 다르다면 fair comparison이 아니기 때문이다. 모델은 고정되어있는데 random initialization의 차이로 성능이 달라지니까.
- AL cycle 1
- unlabeled data pool에 있는 모든 것의 uncertainty를 측정
- top K개의 데이터를 골라 labeled data pool에 추가한다.
- learning cycle 1
- 현재의 labeled data로 모델을 학습한다.
- 이때 모델의 파라미터를 어떻게 해야하나 싶은데, 이어서 학습하면 이전에 학습한 representation이 남으니까 그냥 전부 날렸다. random init.
cycle 0에서 쓴다는 pretrained model 가져오지 않았다. 이건 AL cycle 0에 해당하는 labeled data로 만드는 representation이기 때문이다. - 방금 labeled data가 추가되었으니 학습 성능이 오를 것으로 기대한다.
- 매 learning cycle마다 AL cycle, learning cycle을 반복한다.
모델 계속 학습하고, 날리고를 반복해야하니 학습 시간이 오래 걸린다. 사이클 10번만 돌려도 일반 ResNet 학습 소요시간 * 10배의 시간이 걸린다. ImageNet 이런거 돌리기에 눈물난다. 어쩔 수 없다.
이걸 수술비디오에서 하려고 하다니 난 내 무덤을 판걸까 ㄱ-
Step 2.
음.
그러면 unlabeled data, labeled data를 어떻게 체크하고 처리하는거람. data loader는 어떻게 만들어야하지?
기억이 안나니 코드를 보러가자.
strategy.query(), strategy.train() 이런식으로 써있다.
여기서는 Strategy class를 정의하고 이 안에 모델을 학습하는 코드 및 각종 필요한 것들을 넣고,
QBC, entropy, random sampling 등의 다른 strategy들이 각각 이를 상속받도록 정의했다.
strategy.py를 보자.
역시 데이터가 달라지는건 인덱스로 저장을 하는 모양이다.
그리고 DataLoader를 새로 정의하고 _train()을 호출해 1에폭을 학습한다.
_train()은 그냥 평범한 학습 코드이니 넘어가자.
일단 데이터 구성에 대해 짧게 얘기하고 넘어간다.
CIFAR10을 예로 들어보자.
- train dataset = 4만개
- initial labeled data = 1만개
- unlabeled data pool = 4만-1만 = 3만개
- test dataset = 1만개
이렇게 되어있어서, unlabeled data에서 뽑아 labeled data에 계속 추가됨을 알아두자.
그렇다면 데이터를 이렇게 관리한다는 소리다.
- strategy class에 self.X, Y 정의. 이게 train dataset을 의미한다.
- 여기에 unlabeled data + labeled data(의 인덱스)를 보관한다.
- 그러면 AL strategy를 사용하여 unlabeled data를 뽑았으면, 그냥 idxs_lb만 수정하면 된다.
이게 idxs_train이 된다.
random_sampling.py를 보자.
위에서 언급한 self.idxs_lb중에서 값이 0인것 중 n개를 랜덤으로 추출하는 것을 볼 수 있다.
train dataset이 4만개라면, 4만개의 인덱스를 가지는 리스트를 만들어 labeled data는 1 (True), unlabeled data는 0 (False)으로 저장한다는 것을 알 수 있다.
매번 AL cycle에서 query()의 output에 해당하는 레이블을 전부 True로 바꾸는 것을 아까 메인에서 볼 수 있었다.
여기까지 봤으면 코드는 딱히 볼거 없다 이젠.
Step 3.
아직 안해봐서 모르는데 내 연구에 있어서 걱정되는 것들에 대해 적어봤다.
Q. 비디오는 대체 어떻게 처리해야하는거지?
영상 하나가 엄청 길다.
UCF, Kinetics 이런 것들은 clip 하나의 길이가 굉장히 짧기 때문에, 그냥 원래 학습하는거랑 비슷하게 하면 문제는 없어보인다. 보통 시간축에서 임의의 위치를 random crop해와서 clip length = 16 (32, 64 등) 정도로 잡아주고 불러오니까.
전체 클립이 아니라 이렇게 random crop된 클립에서만 uncertainty를 평가하고 한다고 해도 뭐 그렇게까지 큰 문제는 없을 것 같다.
그런데 수술 영상 엄청 길다... 고작 nn초, n분 이렇지 않다.
하지만 의료데이터는 annotator분들께 레이블을 요청할 때 보통 케이스 단위로 할테니까 비디오 클립 전체 단위로 중요한 것을 뽑아야한다.
그래서 MICCAI 논문을 보면 (논문의 표현을 빌리면) segment별로 active learning을 한 것도 있고, video 단위로 active learning을 한 결과를 같이 뽑아놨다.
pubmed.ncbi.nlm.nih.gov/30968355/ 이 논문이다.
미카이는 보통 코드 공개를 하지 않으니 어떻게 했는지는 모르겠는데, 아무튼 꽤 까다로운 이슈라고 볼 수 있다.
이게 public dataset이라 직접 가공하신건지 원래 그렇게 생긴 데이터셋인지는 알수 없으나, 일단 회사 동료한테 받은 것을 보면 30프레임씩 어노테이션이 되어있어서 이걸 불러와서 학습하신다.
나도 이대로 쓴다고 하면 각 30프레임마다 평가를 내리는건데, 연구결과를 뽑을때는 이렇게 segment단위로 하더라도 실제로 사용할때는 이걸 다 합치는 과정이 필요할 것 같다.
예를들면 클립별로 uncertainty값을 전부 합친 것도 같이 output으로 뽑을 수 있게. 코드가 못생겨지겠군.
일반적인 비디오 모델의 학습과정을 생각한다면 역시 이렇게 하는 게 좋겠다.
좋아. 이제 바로 내 연구에 적용하러 가야겠다.
'AIML 분야 > self supervised, Learning Theory 등' 카테고리의 다른 글
[Active Learning] A Survey of Deep Active Learning 읽기 (0) | 2021.02.23 |
---|---|
[Active Learning] 서베이 하기 (0) | 2021.02.23 |
Self-Supervised Learning 몰라서 공부하는 글 (0) | 2020.12.21 |
[20201221] active learning, self supervised learning, 비디오 연구에 대해서 생각하기 (0) | 2020.12.21 |
(작성중) Circle Loss 논문 읽는 중 (0) | 2020.12.16 |
댓글