본문 바로가기

mingsDB

MACs & FLOPs 측정하기

728x90

딥러닝 모델의 경량화나 속도에 대한 언급을 할때 FLOPs와 MACs에 대한 값을 지표로 많이 사용합니다.
그렇다면 우선 FLOPs 란 무엇일까요?

 

  • FLOPs란 FLoating point OPerations를 의미하며, 사칙연산을 포함한 다양한 연산을 각각 하나의 연산으로 계산합니다.

그럼 MACs 는 무엇일까요?

  • MACs는 Multiply–ACcumulates를 의미하며, 곱셈과 덧셈을 결합한 연산을 하나로 계산합니다.
  • 딥러닝의 연산은 가중치에 바이어스를 더한  WX+b 와 같은 연산을 많이 사용하기에 
    FLOPs ≒ 2 X MACs라 볼 수 있습니다.

그렇다면 실제로  FLOPs ≒ 2 X MACs 이 성립할지 궁금했습니다. 

 

그래서 우선  MACs를 계산하는 Library를 찾던 중 thop library를 찾게되었습니다.

테스트를 위해 resnet18을 사용했으며 결과는 

 

MACs: 27336291840.0

 

가 나왔습니다. 

 

FLOPs를 계산하는 Library는 calflops를 사용했습니다. 

해당 Library는 FLOPs와 MACs를 모두 얻을 수 있었기에 위의 테스트와 같이 resnet18에 적용한 결과

 

FLOPs:54.5188 GFLOPS 
MACs:27.2155 GMACs

 

와 같이 나왔습니다.

 

MACs와 FLOPs가 거의 비슷하기에  FLOPs ≒ 2 X MACs가 성립한다는 것을 확인할 수 있었습니다!!

 

주의할 부분은 FLOPS와 FLOPs가 다르다는 것입니다.

 

FLOPS는 초당 FLOPs를 처리하는 양을 나타냅니다 (flops/sec).
따라서 두 단어가 다르다는 것을 기억하면 좋을 것 같습니다!!!

 

사용한 코드는 아래와 같습니다

  • resnet18
# 테스트를 위한 모델 사용 
import torch
import torch.nn as nn
import torch.nn.functional as F

class ResidualBlock(nn.Module):
    def __init__(self, inchannel, outchannel, stride=1):
        super(ResidualBlock, self).__init__()
        self.left = nn.Sequential(
            nn.Conv2d(inchannel, outchannel, kernel_size=3, stride=stride, padding=1, bias=False),
            nn.BatchNorm2d(outchannel),
            nn.ReLU(inplace=True),
            nn.Conv2d(outchannel, outchannel, kernel_size=3, stride=1, padding=1, bias=False),
            nn.BatchNorm2d(outchannel)
        )
        self.shortcut = nn.Sequential()
        if stride != 1 or inchannel != outchannel:
            self.shortcut = nn.Sequential(
                nn.Conv2d(inchannel, outchannel, kernel_size=1, stride=stride, bias=False),
                nn.BatchNorm2d(outchannel)
            )
            
    def forward(self, x):
        out = self.left(x)
        out = out + self.shortcut(x)
        out = F.relu(out)
        
        return out

class ResNet(nn.Module):
    def __init__(self, ResidualBlock, num_classes=10):
        super(ResNet, self).__init__()
        self.inchannel = 64
        self.conv1 = nn.Sequential(
            nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False),
            nn.BatchNorm2d(64),
            nn.ReLU()
        )
        self.layer1 = self.make_layer(ResidualBlock, 64, 2, stride=1)
        self.layer2 = self.make_layer(ResidualBlock, 128, 2, stride=2)
        self.layer3 = self.make_layer(ResidualBlock, 256, 2, stride=2)        
        self.layer4 = self.make_layer(ResidualBlock, 512, 2, stride=2)     
        self.avgpool = nn.AdaptiveAvgPool2d((1, 1))   
        self.fc = nn.Linear(512, num_classes)
        
    def make_layer(self, block, channels, num_blocks, stride):
        strides = [stride] + [1] * (num_blocks - 1)
        layers = []
        for stride in strides:
            layers.append(block(self.inchannel, channels, stride))
            self.inchannel = channels
        return nn.Sequential(*layers)
    
    def forward(self, x):
        out = self.conv1(x)
        out = self.layer1(out)
        out = self.layer2(out)
        out = self.layer3(out)
        out = self.layer4(out)
        out = self.avgpool(out)
        out = out.view(out.size(0), -1)
        out = self.fc(out)
        return out

 

  • MACs 계산(thop 사용)
from thop import profile

model = ResNet(ResidualBlock)
input = torch.randn(1, 3, 224, 224)
macs, params = profile(model, inputs=(input, ))

print(f"MACs: {macs}")
print(f"Params: {params}")

 

  • FLOPs & MACs 계산(calflops 사용)
from calflops import calculate_flops

model = ResNet(ResidualBlock)
input_shape = (1, 3, 224, 224)

flops, macs, params = calculate_flops(model=model, 
                                      input_shape=input_shape,
                                      output_as_string=True,
                                      output_precision=4)
print("ResNet FLOPs:%s   MACs:%s   Params:%s \n" %(flops, macs, params))

 

코드는 제 깃허브에서도 확인하실 수 있습니다!!

'mingsDB' 카테고리의 다른 글

vs code 효과음 끄기  (0) 2024.08.28
Unity WebSocket 통신  (0) 2024.08.14
Jetson nano 포트포워딩  (1) 2024.07.13
Denoising-AutoEncoder 결과에 대한 고찰(Model Collapse)  (1) 2024.06.30
labelme2yolo에 label_list 지정하는 법  (1) 2024.06.24