Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create format.yml #1

Merged
merged 4 commits into from
May 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions .github/workflows/format.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Ultralytics πŸš€ - AGPL-3.0 license
# Ultralytics Actions https://github.com/ultralytics/actions
# This workflow automatically formats code and documentation in PRs to official Ultralytics standards

name: Ultralytics Actions

on:
push:
branches: [main]
pull_request_target:
branches: [main]
types: [opened, closed, synchronize]

jobs:
format:
runs-on: ubuntu-latest
steps:
- name: Run Ultralytics Formatting
uses: ultralytics/actions@main
with:
token: ${{ secrets.GITHUB_TOKEN }} # automatically generated, do not modify
python: true # format Python code and docstrings
markdown: true # format Markdown
prettier: true # format YAML
spelling: true # check spelling
links: false # check broken links
summary: true # print PR summary with GPT4 (requires 'openai_api_key' or 'openai_azure_api_key' and 'openai_azure_endpoint')
openai_azure_api_key: ${{ secrets.OPENAI_AZURE_API_KEY }}
openai_azure_endpoint: ${{ secrets.OPENAI_AZURE_ENDPOINT }}
108 changes: 56 additions & 52 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,43 +1,47 @@
# THOP: PyTorch-OpCounter

## How to install
`pip install thop` (now continously intergrated on [Github actions](https://github.com/features/actions))
## How to install

`pip install thop` (now continuously integrated on [Github actions](https://github.com/features/actions))

OR

`pip install --upgrade git+https://github.com/Lyken17/pytorch-OpCounter.git`

## How to use
* Basic usage

## How to use

- Basic usage

```python
from torchvision.models import resnet50
from thop import profile
model = resnet50()
input = torch.randn(1, 3, 224, 224)
macs, params = profile(model, inputs=(input, ))
```
```

- Define the rule for 3rd party module.

* Define the rule for 3rd party module.
```python
class YourModule(nn.Module):
# your definition
def count_your_model(model, x, y):
# your rule here

input = torch.randn(1, 3, 224, 224)
macs, params = profile(model, inputs=(input, ),
macs, params = profile(model, inputs=(input, ),
custom_ops={YourModule: count_your_model})
```
* Improve the output readability

- Improve the output readability

Call `thop.clever_format` to give a better format of the output.

```python
from thop import clever_format
macs, params = clever_format([macs, params], "%.3f")
```
```

## Results of Recent Models

The implementation are adapted from `torchvision`. Following results can be obtained using [benchmark/evaluate_famous_models.py](benchmark/evaluate_famous_models.py).
Expand All @@ -47,48 +51,48 @@ The implementation are adapted from `torchvision`. Following results can be obta
<tr>
<td>

Model | Params(M) | MACs(G)
---|---|---
alexnet | 61.10 | 0.77
vgg11 | 132.86 | 7.74
vgg11_bn | 132.87 | 7.77
vgg13 | 133.05 | 11.44
vgg13_bn | 133.05 | 11.49
vgg16 | 138.36 | 15.61
vgg16_bn | 138.37 | 15.66
vgg19 | 143.67 | 19.77
vgg19_bn | 143.68 | 19.83
resnet18 | 11.69 | 1.82
resnet34 | 21.80 | 3.68
resnet50 | 25.56 | 4.14
resnet101 | 44.55 | 7.87
resnet152 | 60.19 | 11.61
wide_resnet101_2 | 126.89 | 22.84
wide_resnet50_2 | 68.88 | 11.46
| Model | Params(M) | MACs(G) |
| ---------------- | --------- | ------- |
| alexnet | 61.10 | 0.77 |
| vgg11 | 132.86 | 7.74 |
| vgg11_bn | 132.87 | 7.77 |
| vgg13 | 133.05 | 11.44 |
| vgg13_bn | 133.05 | 11.49 |
| vgg16 | 138.36 | 15.61 |
| vgg16_bn | 138.37 | 15.66 |
| vgg19 | 143.67 | 19.77 |
| vgg19_bn | 143.68 | 19.83 |
| resnet18 | 11.69 | 1.82 |
| resnet34 | 21.80 | 3.68 |
| resnet50 | 25.56 | 4.14 |
| resnet101 | 44.55 | 7.87 |
| resnet152 | 60.19 | 11.61 |
| wide_resnet101_2 | 126.89 | 22.84 |
| wide_resnet50_2 | 68.88 | 11.46 |

</td>
<td>

Model | Params(M) | MACs(G)
---|---|---
resnext50_32x4d | 25.03 | 4.29
resnext101_32x8d | 88.79 | 16.54
densenet121 | 7.98 | 2.90
densenet161 | 28.68 | 7.85
densenet169 | 14.15 | 3.44
densenet201 | 20.01 | 4.39
squeezenet1_0 | 1.25 | 0.82
squeezenet1_1 | 1.24 | 0.35
mnasnet0_5 | 2.22 | 0.14
mnasnet0_75 | 3.17 | 0.24
mnasnet1_0 | 4.38 | 0.34
mnasnet1_3 | 6.28 | 0.53
mobilenet_v2 | 3.50 | 0.33
shufflenet_v2_x0_5 | 1.37 | 0.05
shufflenet_v2_x1_0 | 2.28 | 0.15
shufflenet_v2_x1_5 | 3.50 | 0.31
shufflenet_v2_x2_0 | 7.39 | 0.60
inception_v3 | 27.16 | 5.75
| Model | Params(M) | MACs(G) |
| ------------------ | --------- | ------- |
| resnext50_32x4d | 25.03 | 4.29 |
| resnext101_32x8d | 88.79 | 16.54 |
| densenet121 | 7.98 | 2.90 |
| densenet161 | 28.68 | 7.85 |
| densenet169 | 14.15 | 3.44 |
| densenet201 | 20.01 | 4.39 |
| squeezenet1_0 | 1.25 | 0.82 |
| squeezenet1_1 | 1.24 | 0.35 |
| mnasnet0_5 | 2.22 | 0.14 |
| mnasnet0_75 | 3.17 | 0.24 |
| mnasnet1_0 | 4.38 | 0.34 |
| mnasnet1_3 | 6.28 | 0.53 |
| mobilenet_v2 | 3.50 | 0.33 |
| shufflenet_v2_x0_5 | 1.37 | 0.05 |
| shufflenet_v2_x1_0 | 2.28 | 0.15 |
| shufflenet_v2_x1_5 | 3.50 | 0.31 |
| shufflenet_v2_x2_0 | 7.39 | 0.60 |
| inception_v3 | 27.16 | 5.75 |

</td>
</tr>
Expand Down
4 changes: 2 additions & 2 deletions TODO.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
TODOs.

1. A more user-friendly warning for un-defined modules. [Done]
1. A more user-friendly warning for un-defined modules. \[Done\]
2. Supports for models in torchvision (e.g., residual add).
3. Layer wise printing

Integration with torchprofile?
Integration with torchprofile?
25 changes: 11 additions & 14 deletions benchmark/README.md
Original file line number Diff line number Diff line change
@@ -1,33 +1,30 @@
# MACs, FLOPs, what is the difference?

`FLOPs` is abbreviation of **floating operations** which includes mul / add / div ... etc.
`FLOPs` is abbreviation of **floating operations** which includes mul / add / div ... etc.

`MACs` stands for **multiply–accumulate operation** that performs `a <- a + (b x c)`.
`MACs` stands for **multiply–accumulate operation** that performs `a <- a + (b x c)`.

As shown in the text, one `MACs` has one `mul` and one `add`. That is why in many places `FLOPs` is nearly two times as `MACs`.

However, the application in real world is far more complex. Let's consider a matrix multiplication example.
`A` is an matrix of dimension `mxn` and `B` is an vector of `nx1`.
However, the application in real world is far more complex. Let's consider a matrix multiplication example. `A` is an matrix of dimension `mxn` and `B` is an vector of `nx1`.

```python
for i in range(m):
for j in range(n):
C[i][j] += A[i][j] * B[j] # one mul-add
```
```

It would be `mn` `MACs` and `2mn` `FLOPs`. But such implementation is slow and parallelization is necessary to run faster


```python
```python
for i in range(m):
parallelfor j in range(n):
d[j] = A[i][j] * B[j] # one mul
C[i][j] = sum(d) # n adds
parallelfor j in range(n):
d[j] = A[i][j] * B[j] # one mul
C[i][j] = sum(d) # n adds
```

Then the number of `MACs` is no longer `mn` .

Then the number of `MACs` is no longer `mn` .

When comparing MACs /FLOPs, we want the number to be implementation-agnostic and as general as possible. Therefore in THOP, **we only consider the number of multiplications** and ignore all other operations.
When comparing MACs /FLOPs, we want the number to be implementation-agnostic and as general as possible. Therefore in THOP, **we only consider the number of multiplications** and ignore all other operations.

PS: The FLOPs is approximated by multiplying two.
PS: The FLOPs is approximated by multiplying two.
5 changes: 2 additions & 3 deletions benchmark/evaluate_famous_models.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import torch
from torchvision import models

from thop.profile import profile

model_names = sorted(
Expand All @@ -24,6 +25,4 @@
dsize = (1, 3, 299, 299)
inputs = torch.randn(dsize).to(device)
total_ops, total_params = profile(model, (inputs,), verbose=False)
print(
"%s | %.2f | %.2f" % (name, total_params / (1000 ** 2), total_ops / (1000 ** 3))
)
print("%s | %.2f | %.2f" % (name, total_params / (1000**2), total_ops / (1000**3)))
17 changes: 5 additions & 12 deletions benchmark/evaluate_rnn_models.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import torch
import torch.nn as nn

from thop.profile import profile

input_size = 160
Expand All @@ -18,15 +19,9 @@
"BiRNN": nn.Sequential(nn.RNN(input_size, hidden_size, bidirectional=True)),
"BiGRU": nn.Sequential(nn.GRU(input_size, hidden_size, bidirectional=True)),
"BiLSTM": nn.Sequential(nn.LSTM(input_size, hidden_size, bidirectional=True)),
"stacked-BiRNN": nn.Sequential(
nn.RNN(input_size, hidden_size, bidirectional=True, num_layers=4)
),
"stacked-BiGRU": nn.Sequential(
nn.GRU(input_size, hidden_size, bidirectional=True, num_layers=4)
),
"stacked-BiLSTM": nn.Sequential(
nn.LSTM(input_size, hidden_size, bidirectional=True, num_layers=4)
),
"stacked-BiRNN": nn.Sequential(nn.RNN(input_size, hidden_size, bidirectional=True, num_layers=4)),
"stacked-BiGRU": nn.Sequential(nn.GRU(input_size, hidden_size, bidirectional=True, num_layers=4)),
"stacked-BiLSTM": nn.Sequential(nn.LSTM(input_size, hidden_size, bidirectional=True, num_layers=4)),
}

print("{} | {} | {}".format("Model", "Params(M)", "FLOPs(G)"))
Expand All @@ -49,9 +44,7 @@

# validate batch_first support
inputs = torch.randn(100, 32, input_size)
ops_time_first = profile(
nn.Sequential(nn.LSTM(input_size, hidden_size)), (inputs,), verbose=False
)[0]
ops_time_first = profile(nn.Sequential(nn.LSTM(input_size, hidden_size)), (inputs,), verbose=False)[0]
ops_batch_first = profile(
nn.Sequential(nn.LSTM(input_size, hidden_size, batch_first=True)),
(inputs.transpose(0, 1),),
Expand Down
7 changes: 4 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
#!/usr/bin/env python
import os, sys
import shutil
import datetime
import os
import shutil
import sys

from setuptools import setup, find_packages
from setuptools import find_packages, setup
from setuptools.command.install import install

readme = open("README.md").read()
Expand Down
25 changes: 14 additions & 11 deletions tests/test_conv2d.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
from jinja2 import StrictUndefined
import pytest
import torch
import torch.nn as nn
from jinja2 import StrictUndefined

from thop import profile


class TestUtils:
def test_conv2d_no_bias(self):
n, in_c, ih, iw = 1, 3, 32, 32 # torch.randint(1, 10, (4,)).tolist()
n, in_c, ih, iw = 1, 3, 32, 32 # torch.randint(1, 10, (4,)).tolist()
out_c, kh, kw = 12, 5, 5
s, p, d, g = 1, 1, 1, 1

Expand All @@ -17,11 +18,11 @@ def test_conv2d_no_bias(self):

_, _, oh, ow = out.shape

flops, params = profile(net, inputs=(data, ))
flops, params = profile(net, inputs=(data,))
assert flops == 810000, f"{flops} v.s. {810000}"

def test_conv2d(self):
n, in_c, ih, iw = 1, 3, 32, 32 # torch.randint(1, 10, (4,)).tolist()
n, in_c, ih, iw = 1, 3, 32, 32 # torch.randint(1, 10, (4,)).tolist()
out_c, kh, kw = 12, 5, 5
s, p, d, g = 1, 1, 1, 1

Expand All @@ -31,14 +32,14 @@ def test_conv2d(self):

_, _, oh, ow = out.shape

flops, params = profile(net, inputs=(data, ))
flops, params = profile(net, inputs=(data,))
assert flops == 810000, f"{flops} v.s. {810000}"

def test_conv2d_random(self):
for i in range(10):
out_c, kh, kw = torch.randint(1, 20, (3,)).tolist()
n, in_c, ih, iw = torch.randint(1, 20, (4,)).tolist() # torch.randint(1, 10, (4,)).tolist()
ih += kh
out_c, kh, kw = torch.randint(1, 20, (3,)).tolist()
n, in_c, ih, iw = torch.randint(1, 20, (4,)).tolist() # torch.randint(1, 10, (4,)).tolist()
ih += kh
iw += kw
s, p, d, g = 1, 1, 1, 1

Expand All @@ -48,6 +49,8 @@ def test_conv2d_random(self):

_, _, oh, ow = out.shape

flops, params = profile(net, inputs=(data, ))
flops, params = profile(net, inputs=(data,))
print(flops, params)
assert flops == n * out_c * oh * ow // g * in_c * kh * kw , f"{flops} v.s. {n * out_c * oh * ow // g * in_c * kh * kw}"
assert (
flops == n * out_c * oh * ow // g * in_c * kh * kw
), f"{flops} v.s. {n * out_c * oh * ow // g * in_c * kh * kw}"
10 changes: 5 additions & 5 deletions tests/test_matmul.py
Original file line number Diff line number Diff line change
@@ -1,29 +1,29 @@
import pytest
import torch
import torch.nn as nn

from thop import profile


class TestUtils:
def test_matmul_case2(self):
n, in_c, out_c = 1, 100, 200
net = nn.Linear(in_c, out_c)
flops, params = profile(net, inputs=(torch.randn(n, in_c), ))
flops, params = profile(net, inputs=(torch.randn(n, in_c),))
print(flops, params)
assert flops == n * in_c * out_c

def test_matmul_case2(self):
for i in range(10):
n, in_c, out_c = torch.randint(1, 500, (3,)).tolist()
net = nn.Linear(in_c, out_c)
flops, params = profile(net, inputs=(torch.randn(n, in_c), ))
flops, params = profile(net, inputs=(torch.randn(n, in_c),))
print(flops, params)
assert flops == n * in_c * out_c

def test_conv2d(self):
n, in_c, out_c = torch.randint(1, 500, (3,)).tolist()
net = nn.Linear(in_c, out_c)
flops, params = profile(net, inputs=(torch.randn(n, in_c), ))
flops, params = profile(net, inputs=(torch.randn(n, in_c),))
print(flops, params)
assert flops == n * in_c * out_c

Loading