Skip to content

Commit

Permalink
Create format.yml (#1)
Browse files Browse the repository at this point in the history
Co-authored-by: UltralyticsAssistant <[email protected]>
  • Loading branch information
glenn-jocher and UltralyticsAssistant authored May 31, 2024
1 parent 43c064a commit 4052703
Show file tree
Hide file tree
Showing 21 changed files with 193 additions and 193 deletions.
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

0 comments on commit 4052703

Please sign in to comment.