DataLoader 이해 - Boosting-Crowd-Counting... 을 기반으로
GitHub - LoraLinH/Boosting-Crowd-Counting-via-Multifaceted-Attention: Official Implement of CVPR 2022 paper 'Boosting Crowd Coun
Official Implement of CVPR 2022 paper 'Boosting Crowd Counting via Multifaceted Attention' - GitHub - LoraLinH/Boosting-Crowd-Counting-via-Multifaceted-Attention: Official Implement of CVPR...
github.com
해당 test.py를 진행했는데, 결과파일이 나오지 않아서 어떤 식으로 함수가 진행되는지 작성하려 함.
datasets = Crowd(os.path.join(args.data_dir, 'test'), 512, 8, is_gray=False, method='val')
dataloader = torch.utils.data.DataLoader(datasets, 1, shuffle=False,
num_workers=8, pin_memory=False)
...
for inputs, count, name in dataloader:
...
with torch.set_grad_enabled(False):
outputs = model(inputs)[0]
res = count[0].item() - torch.sum(outputs).item()
epoch_minus.append(res)
다음과 같은 부분이 있기에, 사람 수를 세는 프로그램인 만큼, 아마
count나 output에 연관되어 있는 정보가 담겨있음을 추측 가능.
set_grad_enabled()는 아래에서 참조 가능.
set_grad_enabled — PyTorch 1.13 documentation
set_grad_enabled — PyTorch 1.13 documentation
Shortcuts
pytorch.org
gradient 계산을 켜거나 끌 수 있도록 설정하는 텍스트 관리자.
set_grad_enabled는 인수 모드에 따라 그라데이션을 활성화하거나 비활성화한다고 한다. 즉, 위에선 grad 계산을 off시켰다는 것. 아마도 Train이 아닌 Test모드다 보니까 그렇게 한 것 같다.
일단 실험 결과, count는 ground_truth를 출력하는 것 같다.
그런데 어째서인지 img_0001과 0002, 0003에 자체 사진을 넣은 결과, count가 각각 15, 0, 283이 출력되었다.
기존의 이미지에서는 975, 923, 350이 출력되었음을 보면 의미심장.
이를 이해하기 위해, DataLoader을 살펴본다.
Dataset과 DataLoader — 파이토치 한국어 튜토리얼 (PyTorch tutorials in Korean)ㅇ
Dataset과 DataLoader
파이토치(PyTorch) 기본 익히기|| 빠른 시작|| 텐서(Tensor)|| Dataset과 DataLoader|| 변형(Transform)|| 신경망 모델 구성하기|| Autograd|| 최적화(Optimization)|| 모델 저장하고 불러오기 데이터 샘플을 처리하는 코
tutorials.pytorch.kr
"""
iter(호출가능한객체, 반복을끝낼값)
"""
>>> import random
>>> it = iter(lambda : random.randint(0, 5), 2)
>>> next(it)
0
>>> next(it)
3
>>> next(it)
1
>>> next(it)
Traceback (most recent call last):
File "<pyshell#37>", line 1, in <module>
next(it)
StopIteration
다음은 random.randint(0, 5)와 같이 0부터 5까지 무작위로 숫자를 생성할 때 2가 나오면 반복을 끝내는 함수라 한다.
iter는 반복 가능한 객체에서 이터레이터를 반환하고, next는 이터레이터에서 값을 차례대로 꺼낸다.
이를 바탕으로 아래를 보면
from torch.utils.data import DataLoader
"""
Dataset 함수
"""
training_data = datasets.FashionMNIST(
root="data", # 데이터 저장 경로
train=True,
download=True, # root에 없는 경우, 인터넷에서 다운로드
transform=ToTensor() # 특징(feature)와 정답(label) 변형(transform)을 지정.
)
test_data = datasets.FashionMNIST(
root="data",
train=False,
download=True,
transform=ToTensor() # 특징(feature)와 정답(label) 변형(transform)을 지정.
)
# ----------------------------------------------#
# DataLoader
#-----------------------------------------------#
train_dataloader = DataLoader(training_data, batch_size=64, shuffle=True)
test_dataloader = DataLoader(test_data, batch_size=64, shuffle=True)
# 이미지와 정답(label)을 표시합니다.
train_features, train_labels = next(iter(train_dataloader))
print(f"Feature batch shape: {train_features.size()}")
print(f"Labels batch shape: {train_labels.size()}")
img = train_features[0].squeeze()
label = train_labels[0]
plt.imshow(img, cmap="gray")
plt.show()
print(f"Label: {label}")
# -------------output------------------- #
Feature batch shape: torch.Size([64, 1, 28, 28])
Labels batch shape: torch.Size([64])
Label: 1
Dataset 은 root에 존재하는 데이터셋의 특징(feature)을 가져오고 하나의 샘플에 정답(label)을 지정하는 일을 한 번에 한다. 모델을 학습할 때, 일반적으로 샘플들을 “미니배치(minibatch)”로 전달하고, 매 에폭(epoch)마다 데이터를 다시 섞어서 과적합(overfit)을 막고, Python의 multiprocessing 을 사용하여 데이터 검색 속도를 높이려고 한다.
DataLoader 는 간단한 API로 이러한 복잡한 과정들을 추상화한 순회 가능한 객체(iterable)이다.
DataLoader 에 데이터셋을 불러온 뒤에는 필요에 따라 데이터셋을 순회(iterate)할 수 있다. 위의 각 순회(iteration)는 (각각 batch_size=64 의 특징(feature)과 정답(label)을 포함하는) train_features 와 train_labels 의 묶음(batch)을 반환한다. shuffle=True 로 지정했으므로, 모든 배치를 순회한 뒤 데이터가 섞인다. (데이터 불러오기 순서를 보다 세밀하게(finer-grained) 제어하려면 Samplers 를 살펴보면 된다고 한다.)
즉, 위의 inputs, count, name은 dataLoader을 부르면 반환하는 features와 labels, 그리고 그 이름인 것.
실제로 이 features(=실례의 inputs)는 [1, 3, height, width] 형태로 나타나며, features[0].sqeeze()를 실행하면 그 이미지 자체가 나타나는 것을 확인할 수 있다.
아무튼 DataLoader는 특정 데이터셋의 정보를 담고 있다는 것으로 알 수 있다. 이름부터 Loader이기도 하고..
그렇다면 ann쪽을 살펴봐야 할 것 같기도 하다.
결과적으로 330.06(원본), 295.65(업스케일링)가 뜨며, 이는
torch.sum(outputs).item()
을 통해 나타난다. 이 때, item()은 텐서값을 num 형태로 가져오는 거라 함.
여기에서 torch.sum...이 나오는 주요부분이 바로 마지막 즈음의
with torch.set_grad_enabled(False):
outputs = model(inputs)[0]
res = count[0].item() - torch.sum(outputs).item()
epoch_minus.append(res)
부분인데, model(inputs)[0]이 무엇인가?
일단 그냥 outputs.shape는 비율이 마치 축소되듯이 나왔는데,
[1, 3, 512, 910] -> [1, 1, 32, 56]
[1, 3, 2048, 3092] -> [1, 1, 128, 193]
[1, 3, 528, 800] -> [1, 1, 33, 50] 처럼, 마치 그냥 이미지를 어느 비율로 축소한 듯이 나왔다.
그렇다면 model(inputs)[0]은 말 그대로 [#, 축소된 이미지 shape] 와 같은 것이라는 건데...
당연히 output은 그 inputs을 shape에 나온 결과일 것이다. 그렇다면 model(=vgg19_trans)를 한 번 봐보자.
def vgg19_trans():
"""VGG 19-layer model (configuration "E")
model pre-trained on ImageNet
"""
model = VGG_Trans(make_layers(cfg['E']))
model.load_state_dict(model_zoo.load_url(model_urls['vgg19']), strict=False)
return model
우선 모델 자체는 test.py의 37번째 줄인
model = vgg19_trans()
model.to(device)
model.eval()
model.load_state_dict(torch.load(args.save_dir, device))
에서 정의된다. 이 때 class의 __init__이 실행되고
05. 클래스로 파이토치 모델 구현하기 - PyTorch로 시작하는 딥 러닝 입문 (wikidocs.net)
05. 클래스로 파이토치 모델 구현하기
파이토치의 대부분의 구현체들은 대부분 모델을 생성할 때 클래스(Class)를 사용하고 있습니다. 앞서 배운 선형 회귀를 클래스로 구현해보겠습니다. 앞서 구현한 코드와 다른 점은 …
wikidocs.net
을 보면,
forward() 함수는 model 객체를 데이터와 함께 호출하면 자동으로 실행이됩니다. 예를 들어 model이란 이름의 객체를 생성 후, model(입력 데이터)와 같은 형식으로 객체를 호출하면 자동으로 forward 연산이 수행됩니다.
고 나와있다. 즉, model(inputs)과 같이 실행하면 자동으로 forward가 연산된다는 것을 알 수 있다.(실제로 실험 결과 그러함) 따라서 forward를 살펴보면 됨.
def forward(self, x):
b, c, h, w = x.shape
rh = int(h) // 16
rw = int(w) // 16
x = self.features(x) # vgg network
bs, c, h, w = x.shape
x = x.flatten(2).permute(2, 0, 1)
x, features = self.encoder(x, (h,w)) # transformer
x = x.permute(1, 2, 0).view(bs, c, h, w)
#
x = F.upsample_bilinear(x, size=(rh, rw))
x = self.reg_layer_0(x) # regression head
return torch.relu(x), features
이 논문은 까다로운 군중 계수 작업에 초점을 맞춘다. 군중 이미지 내에 대규모 변형이 존재하는 경우가 많기 때문에 CNN의 고정 크기 컨볼루션 커널이나 최근 비전 변압기의 고정 크기 주의는 이러한 종류의 변형을 잘 처리할 수 없다. 이 문제를 해결하기 위해, 우리는 로컬 공간 관계 인코딩에서 변압기 모델을 개선하기 위한 다면적 주의 네트워크(MAN)를 제안한다. MAN은 바닐라 트랜스포머의 글로벌 어텐션, 학습 가능한 로컬 어텐션 및 인스턴스 어텐션을 카운팅 모델에 통합한다. 첫째, 각 기능 위치에 대한 배타적 주의를 동적으로 할당하기 위해 로컬 학습 가능 영역 주의(LRA)가 제안된다. 둘째로, 우리는 다양한 특징 위치에 대한 주의 간의 편차를 최소화하여 LRA의 훈련을 감독하기 위해 로컬 주의 정규화를 설계한다. 마지막으로, 우리는 훈련 중에 가장 중요한 인스턴스에 동적으로 초점을 맞추기 위한 인스턴스 주의 메커니즘을 제공한다. ShanghaiTech, UCF-QNRF, JHU++ 및 NWPU와 같은 네 가지 까다로운 크라우드 카운팅 데이터 세트에 대한 광범위한 실험을 통해 제안된 방법을 검증했다.
네트워크 구조: 우리는 ImageNet에서 사전 훈련된 CNN 백본 네트워크로 VGG-19를 채택한다. 우리는 변압기 인코더의 구조에 대해 [36]을 참조하고 제안된 LRA로 주의 모듈을 대체한다. 구체적으로, 다음과 같다.
LRA는 공간 인식이며, 위치 인코딩 없이 기능 맵이 인코더에 직접 공급된다. 우리의 회귀 디코더는 활성화 ReLU 기능이 있는 업샘플링 레이어와 3개의 컨볼루션 레이어로 구성된다. 처음 두 계층의 커널 크기는 3 x 3이고 마지막 계층의 커널 크기는 1 x 1입니다.
교육 세부 정보: 우리는 먼저 각 훈련 이미지에 대해 무작위 스케일링과 수평 플립을 채택한다. 그런 다음 512 x 512 크기의 이미지 패치를 임의로 자릅니다. 상하이 테크 A의 일부 이미지는 더 작은 해상도를 포함하기 때문에 이 데이터 세트의 크롭 크기는 256 x 256으로 변경된다. 우리는 또한 모든 데이터 세트에서 각 이미지의 짧은 쪽을 2048픽셀 내로 제한한다. 우리는 매개 변수를 최적화하기 위해 학습률 105의 Adam 알고리즘[12]을 사용한다. 우리는 인코더 레이어 T의 수를 4로 설정하고 손실 균형 매개 변수 A를 100으로 설정한다.
그림 1 : Multifaceted Attention Network의 프레임워크입니다. 군중 이미지는 먼저 CNN에 입력된다. 그런 다음 플랫 출력 피쳐 맵 학습 가능 영역 주의와 함께 변압기 인코더로 전송됩니다. 마지막으로, 회귀 디코더는 밀도 맵을 예측한다. 로컬 주의 정규화 및 인스턴스 주의 손실(라일락 상자)은 훈련 과정 중에 최적화된다.
3.5 . Local Attention Regularizatin
우리는 인간의 시각 시스템이 보통 유사한 실제 크기를 가진 물체에 유사한 주의를 기울인다는 인간 행동 연구의 최근 발견에서 영감을 얻는다[5]. 이러한 현상을 모방하기 위해, 우리는 지역 학습 가능 지역 주의 모듈의 훈련을 감독하기 위한 지역 주의 정규화 모듈을 설계한다. 목표는 지역 주의 분포의 균형을 맞추고 지역에 할당된 주의 사이의 편차를 처벌하는 것이다. 보다 구체적으로, 예측된 학습 가능한 영역 맵 [1]와 피처 맵[2]가 주어지면, 우리는 주의 가중 특징을 계산하는데, 이는 첫 번째와 두 번째 모드의 eRi[6]와 함께 F의 두 번째와 세 번째 모드의 이중 텐서 수축으로 공식화될 수 있다.
Boosting Crowd Counting via Multifaceted Attention 이해
서론 :
군중 계수는 혼잡 추정, 비디오 감시 및 군중 관리에서 필수적인 역할을 한다. 특히 코로나바이러스병(코로나19) 발생 이후 실시간 군중 감지 및 집계가 더욱 주목받고 있다.
최근 몇 년 동안 일반적인 계산 방법은 컨볼루션 신경망(CNN)을 백본 및 회귀 밀도 맵으로 활용하여 총 군중 수를 예측한다. 그러나 카메라의 넓은 시야각과 2D 투시 투영으로 인해 군중 이미지에 대규모 변형이 존재하는 경우가 많다. 고정 크기 컨볼루션 커널이 있는 기존 CNN은 이러한 변형을 처리하기 어렵고 카운팅 성능이 심각하게 제한된다. 이 문제를 완화하기 위해 다중 스케일 블롭[48], 피라미드 네트워크[22] 및 다중 열 네트워크와 같은 다중 스케일 메커니즘이 설계된다. 이러한 방법은 직관적인 국소 구조 유도 편향을 도입하여 각 필드가 물체의 크기에 적응해야 함을 제안한다[43].
최근 글로벌 자기주의 메커니즘을 채택한 트랜스포머 모델의 꽃은 다양한 자연어 처리 작업의 성능을 크게 향상시켰다. 그럼에도 불구하고, ViT[10]가 패치 분할을 로컬 구조 유도 편향으로 도입해야만 트랜스포머 모델이 비전 작업에서 CNN 모델과 경쟁하고 심지어 능가할 수 있다. 비전 변압기의 개발은 글로벌 자기 주의 메커니즘과 국소 귀납적 편향 모두 비전 작업에 중요하다는 것을 시사한다.
변압기 기반 군중 계수에 대한 연구는 예비 단계[19, 49]에 불과하며 혼잡한 장면에서 변압기 모델에 국소 귀납적 편향을 도입하는 데 큰 어려움을 겪고 있다. 이러한 모델은 일반적으로 고정 크기 주의를 ViT로 사용하는데, 이는 [10]에서 지적한 대로 2D 로컬 구조를 인코딩하는 데 제한적이며 군중 이미지의 대규모 변형을 처리하기에는 분명히 부적절하다. 이 문제를 해결하기 위해 본 논문에서는 다음의 세 가지 관점에서 군중 계수를 위한 비전 변환기의 구조와 훈련 체계를 모두 개선한다.
첫째, 로컬 영역 인코딩의 이러한 한계에 대응하여 로컬 컨텍스트를 강조하기 위해 학습 가능한 영역 주의(LRA)를 제안한다. 고정 패치 분할 체계를 채택하는 이전의 비전 변압기와 달리, LRA는 각 기능 위치에 대해 어느 지역에 주의를 기울여야 하는지 유연하게 결정할 수 있다. 결과적으로, 지역 주의 모듈은 규모 변화에 대해 가장 관련성이 높은 지역 정보를 추출하는 효율적인 방법을 제공한다. 더욱이, 그것은 로컬 공간 관계를 인코딩하는 데 비효율적인 것으로 입증된 ViT의 위치 임베딩 모듈에 대한 의존성에서 더 멀어진다[10].
둘째, 우리는 LRA 모듈의 훈련을 정규화하기 위한 효율적인 LAR(Local Attention Regularization) 방법을 제안한다. 사람들이 2D 이미지의 크기에 관계없이 종종 유사한 실제 크기를 가진 물체에 유사한 주의 자원을 할당한다는 인간 행동[5]의 최근 발견에서 영감을 받아, 우리는 각 특징 위치에 할당된 주의를 유사하게 해야 한다. 이러한 이해를 바탕으로, 우리는 그들 사이의 편차를 처벌함으로써 지역 주의의 분포를 최적화하도록 LAR을 설계한다.
그림 1. 다면적 주의 네트워크의 프레임워크입니다. 군중 이미지는 먼저 CNN에 입력된다. 그런 다음 플랫 출력 피쳐 맵이 학습 가능 영역 주의와 함께 변압기 인코더로 전송됩니다. 마지막으로, 회귀 디코더는 밀도 맵을 예측한다. 로컬 주의 정규화 및 인스턴스 주의 손실(라일락 상자)은 훈련 과정 중에 최적화된다.
LAR은 균형 있고 효율적인 주의 할당을 위해 군중 영역에서 시각적 주의 범위를 작게 강제하며, 그 반대의 경우도 마찬가지이다.
마지막으로, 우리는 이미지의 인스턴스(즉, 포인트 주석) 수준에 주의 메커니즘을 적용하고 인스턴스 주의 모듈을 제안하려고 시도한다. 대중적인 군중 벤치마크에서 제공되는 포인트 주석은 예비적이고 전체 인간 머리의 매우 작은 부분만 차지할 수 있기 때문에 주석 오류가 발생할 수밖에 없다. 이 문제를 완화하기 위해, 우리는 인스턴스 주의를 사용하여 훈련 중에 가장 중요한 인스턴스에 동적으로 초점을 맞춘다.
요약하면, 우리는 군중 이미지의 대규모 변화를 해결하기 위해 다면적 주의 네트워크(MAN)라고 불리는 다면적 주의를 가진 계수 모델을 제안한다. 기여 내용은 다음과 같이 더 요약됩니다.
• 우리는 각 기능 위치 전용 주의 영역을 동적으로 할당하기 위해 로컬 학습 가능 영역 주의를 제안한다.
• 우리는 LRA의 훈련을 감독하기 위해 지역 주의 정규화 방법을 설계한다.
• 우리는 훈련 중에 가장 중요한 인스턴스를 동적으로 선택하는 효과적인 인스턴스 주의 메커니즘을 소개한다.
• ShanghaiTech, UCF-QNRF, JHU++ 및 NWPU를 포함한 인기 있는 데이터 세트에 대한 광범위한 실험을 수행하고 제안된 방법이 성능을 계산하는 데 있어 확고한 진전을 이룬다는 것을 보여준다.