|
|
자율주행 인공지능 모델 개발 가이드라인
데이터셋
작년 대회에서 사용한 동적객체 검출 데이터셋이랑 같은 걸로 수집한 것을 확인
https://epretx.etri.re.kr/dataDetail?lang=ko&id=411
레이블 포맷은 x y z dx dy dz heading_angle category_name
라이다 기반 3D객체 검출
Waymo 3D detection 지표 (mAP/L2) 사용
: 가장 어려운 레벨에서 mAP 를 점수로 활용한다는 뜻
Waymo 3D Detection 지표 (mAP/L2) 상세 설명
mAP (mean Average Precision) 기본 개념
mAP는 탐지된 바운딩 박스가 실제 정답 박스와 얼마나 정확하게 겹치는지를
IoU(Intersection over Union)를 기준으로 평가하는, 객체 탐지의 정확도 지표
Waymo의 LEVEL_1 / LEVEL_2 난이도 구분
Waymo는 모든 객체를 동일하게 평가하지 않고, 탐지 난이도에 따라 LEVEL_1과 LEVEL_2로 나누어 채점함
LEVEL_1 (L1): 탐지하기 쉬운 객체. 객체를 구성하는 LiDAR 포인트가 5개 이상인 경우. 비교적 가깝고 명확하게 보이는 객체들이 여기에 속함.
LEVEL_2 (L2): 탐지하기 어려운 객체. 객체를 구성하는 LiDAR 포인트가 1개에서 4개 사이인 경우. 멀리 있거나,
다른 물체에 많이 가려지거나, 매우 작은 객체들이 여기에 해당함.
mAP/L2는 이 LEVEL_2 난이도에 해당하는 객체들만을 대상으로 계산한 mAP 점수를 의미함.
작년 대회에서 학습을 돌릴 시 검증 결과가 이런 식으로 출력이 됨
각 로그 설명
로그의 각 라인은 [객체 타입]_[난이도]/[평가 지표] 형식으로 구성되어 있음
OBJECT_TYPE_...: 평가 대상이 되는 객체의 클래스를 의미
VEHICLE: 차량
PEDESTRIAN: 보행자
SIGN: 표지판
CYCLIST: 자전거 탑승자
LEVEL_1 / LEVEL_2: 탐지 난이도
LEVEL_1: 탐지하기 쉬운 객체 (객체에 LiDAR 포인트가 5개 이상).
LEVEL_2: 탐지하기 어려운 객체 (객체에 LiDAR 포인트가 1~4개). 멀리 있거나 가려진 객체
/AP (Average Precision): 위치 정확도
예측된 3D 박스가 실제 정답 박스와 얼마나 정확하게 겹치는지를 나타내는 지표. (IoU 기반)
/APH (Average Precision weighted by Heading): 위치와 방향 정확도를 함께 고려한 지표
박스 위치가 정확해도 차량의 앞뒤 방향(heading)이 틀리면 감점을 주는 방식.
/APL (Average Precision weighted by Longitudinal error): 위치와 길이방향 오차를 함께 고려한 지표
차량의 길이 방향(앞뒤)으로 오차가 클수록 감점을 주는 방식
FLOPs?
: Floating Point Operations, 모델이 한 번의 예측을 수행하는 데 필요한 총 계산량을 의미함
소수점 연산의 횟수를 나타내며 값이 클수록 복잡하고 무거운 모델이라는 뜻
FLOPs 확인 코드 작성, pytorch에 라이브러리가 있는데 OpenPCDet 파이썬 버전과 호환이 안 되어서 작성함.
---------------------------------------------------------------------------------------------------------------------------------------
# tools/demo.py의 DemoDataset 클래스를 그대로 가져옴.
class DemoDataset(DatasetTemplate):
def __init__(self, dataset_cfg, class_names, training=True, root_path=None, logger=None, ext='.bin'):
super().__init__(
dataset_cfg=dataset_cfg, class_names=class_names, training=training, root_path=root_path, logger=logger
)
self.root_path = root_path
self.ext = ext
data_file_list = glob.glob(str(root_path / f'*{self.ext}')) if self.root_path.is_dir() else [self.root_path]
self.sample_file_list = data_file_list
def __len__(self):
return len(self.sample_file_list)
def __getitem__(self, index):
points = np.fromfile(self.sample_file_list[index], dtype=np.float32).reshape(-1, 4)
input_dict = {'points': points, 'frame_id': index}
data_dict = self.prepare_data(data_dict=input_dict)
return data_dict
# 설정
config_path = './cfgs/kitti_models/PartA2.yaml'
checkpoint_path = './PartA2_7940.pth'
# 설정 파일 로드
cfg_from_yaml_file(config_path, cfg)
logger = common_utils.create_logger()
# 모델 생성 (demo.py 방식과 동일)
temp_file_path = Path('./temp_dummy_data.bin')
demo_dataset = DemoDataset(
dataset_cfg=cfg.DATA_CONFIG, class_names=cfg.CLASS_NAMES, training=False,
root_path=temp_file_path, ext='.bin', logger=logger
)
model = build_network(model_cfg=cfg.MODEL, num_class=len(cfg.CLASS_NAMES), dataset=demo_dataset)
model.load_params_from_file(filename=checkpoint_path, logger=logger, to_cpu=False)
model.cuda()
model.eval()
#더미 데이터 생성 및 임시 파일로 저장
num_point_features = 4 # .bin 파일은 보통 x,y,z,intensity (4)
num_points = 120000
point_cloud_range = np.array(cfg.DATA_CONFIG.POINT_CLOUD_RANGE, dtype=np.float32)
pc_range_min = point_cloud_range[0:3]
pc_range_max = point_cloud_range[3:6]
dummy_points_xyz = np.random.uniform(pc_range_min, pc_range_max, size=(num_points, 3))
dummy_points_intensity = np.random.uniform(0, 1, size=(num_points, 1))
dummy_points = np.hstack((dummy_points_xyz, dummy_points_intensity)).astype(np.float32)
dummy_points.tofile(temp_file_path)
# DemoDataset을 통해 batch_dict 생성
with torch.no_grad():
data_dict = demo_dataset[0]
batch_dict = demo_dataset.collate_batch([data_dict])
load_data_to_gpu(batch_dict)
# 임시 파일 삭제
os.remove(temp_file_path)
total_flops = 0
def flops_hook(module, input, output):
global total_flops
if isinstance(module, (nn.Conv2d, nn.ConvTranspose2d, nn.Conv1d)):
output_shape = output.shape
macs = output_shape[1] * np.prod(output_shape[2:]) * \
module.in_channels * np.prod(module.kernel_size)
flops = 2 * macs
total_flops += flops
elif isinstance(module, nn.Linear):
macs = module.out_features * module.in_features
flops = 2 * macs
total_flops += flops
def register_hooks(module):
if isinstance(module, (nn.Conv2d, nn.ConvTranspose2d, nn.Conv1d, nn.Linear)):
module.register_forward_hook(flops_hook)
model.apply(register_hooks)
# 모델을 한번 실행시켜 모든 훅이 작동하도록 함
with torch.no_grad():
model(batch_dict)
total_gflops = total_flops / 1e9
total_params = sum(p.numel() for p in model.parameters()) / 1e6
print(f"\nTotal GFLOPs (Hook-based): {total_gflops:.4f} G")
print(f"Total Parameters: {total_params:.2f} M")
---------------------------------------------------------------------------------------------------------------------------------------
flops_hook(module, input, output) 함수:
모델이 forward를 실행할 때, 데이터가 특정 레이어(Conv, Linear 등)를 통과하는 순간 이 함수가 자동으로 호출
isinstance(...)로 레이어의 종류를 확인하고,
해당 레이어의 입력/출력 채널 수, 커널 크기, 그리고 실제 출력 데이터의 크기(output.shape)를 이용해 FLOPs를 계산
계산된 FLOPs를 전역 변수인 total_flops에 계속해서 더함.
register_hooks(module) 함수:
model.apply()가 전달해주는 각 레이어(module)를 받아서, 계산하고자 하는 타입(Conv, Linear)인 경우에만
flops_hook하는 역할
model.apply(register_hooks):
모델의 모든 하위 레이어를 순회하며 register_hooks 함수를 실행
pv-rcnn
작년 대회에서 제공하는 베이스라인 모델(CenterPoint-Pillars)의 FLOPs 확인

첫댓글 flops 계산을 어떻게 하는지 설명추가할것
작년 테스트 코드 실행결과에서 모든 항목을 설명할것
Waymo 3D detection 지표 (mAP/L2) 사용
: 가장 어려운 레벨에서 mAP 를 점수로 활용한다는 뜻 -> 구체적을 설명할것
수정했습니다
flops 계산은 정확하지 않아서 추후에 다시 확인하고 보고서 작성하도록 하겠습니다
Flops ㄱㅖ산에서 G가 두번나오는게 맞는지
Pvrcnn 이 파라미터는 많은데 flops는 작은게 맞는지
G는 잘못붙였습니닷.. FLOPs: xx.xx G 가 맞습니다
연산 방식에서 PV-RCNN은 3D Sparse Convolution을 사용하고 CenterPoint-Pillars는 2D Convolution을 사용하기 때문에 모델 자체의 크기가 PV-RCNN이 더 크더라도 연산 처리 방식에 따라 FLOPs가 더 작게 나올 수 있습니다
@신민서 신경망이 웨이트(파라미터)*입력 이고 flops는 실수곱셈의 갯수인데 그러면 flops는 파라미터갯수에 비례함 모델이 크더라도 연산이 적게 나온다는게 말이 돼냐?
저 데이터의 근거자료를 제시할것
@Sungryul Lee Sparse Convolution이 weigth matrix에서 0인 항목은 연산을 생략하는 구조이기 때문에 Dense Convolution보다 FLOPs이 작게 나올 수 있습니다
https://moon-walker.medium.com/deep-learning-%ED%95%99%EC%8A%B5-%EC%8B%9C-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EC%A0%88%EA%B0%90-%EB%B0%A9%EB%B2%95-153343cd125d
@신민서 그럼 파라미터도 줄어들잖아 파라미터는 많은데 연산을 안한다는 얘기내 쓰지도 않을 파라미터는 왜 있는건대
@Sungryul Lee Sparse Convolution에서 연산 생략을 해서 FLOPs가 줄어들긴 하지만 weight값은 0이어도 여전히 메모리에 저장해야 하므로 parameters 개수는 줄지 않습니다
위에서 출력한 parameters가 모델의 구조적으로 계산할 수 있는 weight + bias의 개수입니다. 모델의 크기를 뜻하기 때문에 모델의 sparse convolution 같은 연산 생략을 하면 FLOPs는 줄어들 수 있고 parameters는 변하지 않습니다.