amd
/

Image Classification
ONNX
RyzenAI
zhengrongzhang commited on
Commit
0b5f4ac
1 Parent(s): 2f5b7ff

init model

Browse files
Files changed (5) hide show
  1. EfficientNet_int.onnx +3 -0
  2. README.md +109 -0
  3. eval_onnx.py +164 -0
  4. infer_onnx.py +74 -0
  5. requirements.txt +6 -0
EfficientNet_int.onnx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:def183c935215f146c675fbf97889bfe36ff1856dfb75412a679c3f5b020cfaa
3
+ size 21760409
README.md ADDED
@@ -0,0 +1,109 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: apache-2.0
3
+ tags:
4
+ - RyzenAI
5
+ - image-classification
6
+ - onnx
7
+ datasets:
8
+ - imagenet-1k
9
+ ---
10
+
11
+ # EfficientNet
12
+
13
+ The EfficientNet model was proposed in [EfficientNet: Rethinking Model Scaling for Convolutional Neural Networks](https://arxiv.org/abs/1905.11946) by Mingxing Tan and Quoc V. Le. EfficientNets are a family of image classification models, which achieve state-of-the-art accuracy, yet being an order-of-magnitude smaller and faster than previous models. The specific version of EfficientNet here is EfficientNet-ES (EdgeTPU-Small).
14
+
15
+ We develop a modified version that could be supported by [AMD Ryzen AI](https://ryzenai.docs.amd.com/en/latest/).
16
+
17
+ ## Model description
18
+
19
+ The abstract from the paper is the following:
20
+
21
+ *Convolutional Neural Networks (ConvNets) are commonly developed at a fixed resource budget, and then scaled up for better accuracy if more resources are available. In this paper, we systematically study model scaling and identify that carefully balancing network depth, width, and resolution can lead to better performance. Based on this observation, we propose a new scaling method that uniformly scales all dimensions of depth/width/resolution using a simple yet highly effective compound coefficient. We demonstrate the effectiveness of this method on scaling up MobileNets and ResNet. To go even further, we use neural architecture search to design a new baseline network and scale it up to obtain a family of models, called EfficientNets, which achieve much better accuracy and efficiency than previous ConvNets. In particular, our EfficientNet-B7 achieves state-of-the-art 84.3% top-1 accuracy on ImageNet, while being 8.4x smaller and 6.1x faster on inference than the best existing ConvNet. Our EfficientNets also transfer well and achieve state-of-the-art accuracy on CIFAR-100 (91.7%), Flowers (98.8%), and 3 other transfer learning datasets, with an order of magnitude fewer parameters.*
22
+
23
+ The original code can be found [here](https://github.com/tensorflow/tpu/tree/master/models/official/efficientnet).
24
+
25
+ ## Intended uses & limitations
26
+
27
+ You can use the raw model for image classification. See the [model hub](https://huggingface.co/models?sort=trending&search=efficientnet) to look for fine-tuned versions on a task that interests you.
28
+
29
+ ## How to use
30
+
31
+ ### Installation
32
+
33
+ 1. Follow [Ryzen AI Installation](https://ryzenai.docs.amd.com/en/latest/inst.html) to prepare the environment for Ryzen AI.
34
+
35
+ 2. Run the following script to install pre-requisites for this model.
36
+
37
+ ```shell
38
+ pip install -r requirements.txt
39
+ ```
40
+
41
+ ### Test & Evaluation
42
+
43
+ - Inference one image (Image Classification):
44
+
45
+ ```python
46
+ import onnxruntime
47
+ import argparse
48
+ from PIL import Image
49
+ import torchvision.transforms as transforms
50
+
51
+ parser = argparse.ArgumentParser()
52
+ parser.add_argument('--onnx_path', type=str, default="EfficientNet_int.onnx", required=False)
53
+ parser.add_argument('--image_path', type=str, required=True)
54
+
55
+ args = parser.parse_args()
56
+
57
+ def read_image():
58
+ # Read a PIL image
59
+ image = Image.open(args.image_path)
60
+ normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
61
+
62
+ transform = transforms.Compose([
63
+ transforms.ToTensor(),
64
+ transforms.Resize((224, 224)),
65
+ normalize,
66
+ ])
67
+ img_tensor = transform(image).unsqueeze(0)
68
+ return img_tensor.numpy()
69
+
70
+
71
+ def main():
72
+ so = onnxruntime.SessionOptions()
73
+ ort_session = onnxruntime.InferenceSession(
74
+ args.onnx_path, so, providers=['CUDAExecutionProvider'])
75
+ ort_inputs = {
76
+ "WrapModel::input_0": read_image()
77
+ }
78
+ output = ort_session.run(None, ort_inputs)[0]
79
+ print("class id =", output[0].argmax())
80
+
81
+
82
+ if __name__ == "__main__":
83
+ main()
84
+ ```
85
+
86
+ - Evaluate ImageNet validation dataset(50,000 images), using `eval_onnx.py` .
87
+
88
+ ```shell
89
+ python eval_onnx.py --onnx_model EfficientNet_int.onnx --ipu --provider_config Path\To\vaip_config.json --data_dir /Path/To/Your/Dataset
90
+ ```
91
+
92
+ ### Performance
93
+
94
+ ​ Dataset: ImageNet validation dataset (50,000 images).
95
+
96
+ | Metric | Accuracy on IPU |
97
+ | :-----------------: | :-------------: |
98
+ | top1& top5 accuracy | 77.72% / 93.78% |
99
+
100
+ ## Citation
101
+
102
+ ```bibtex
103
+ @article{EfficientNet,
104
+ author = {Mingxing Tan and Quoc V. Le},
105
+ title = {Searching for MobileNetV3},
106
+ year = {2019},
107
+ url = {https://arxiv.org/abs/1905.11946},
108
+ }
109
+ ```
eval_onnx.py ADDED
@@ -0,0 +1,164 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python
2
+
3
+ from typing import Tuple
4
+
5
+ import argparse
6
+ import onnxruntime
7
+ import os
8
+ import sys
9
+ import time
10
+ import torch
11
+ import torchvision.datasets as datasets
12
+ import torchvision.transforms as transforms
13
+
14
+ from torch.utils.data import DataLoader
15
+ from tqdm import tqdm
16
+
17
+ parser = argparse.ArgumentParser()
18
+ parser.add_argument(
19
+ "--onnx_model", default="model.onnx", help="Input onnx model")
20
+ parser.add_argument(
21
+ "--data_dir",
22
+ default="/workspace/dataset/imagenet",
23
+ help="Directory of dataset")
24
+ parser.add_argument(
25
+ "--batch_size", default=1, type=int, help="Evaluation batch size")
26
+ parser.add_argument(
27
+ "--ipu",
28
+ action="store_true",
29
+ help="Use IPU for inference.",
30
+ )
31
+ parser.add_argument(
32
+ "--provider_config",
33
+ type=str,
34
+ default="vaip_config.json",
35
+ help="Path of the config file for seting provider_options.",
36
+ )
37
+ args = parser.parse_args()
38
+
39
+ class AverageMeter(object):
40
+ """Computes and stores the average and current value"""
41
+
42
+ def __init__(self, name, fmt=':f'):
43
+ self.name = name
44
+ self.fmt = fmt
45
+ self.reset()
46
+
47
+ def reset(self):
48
+ self.val = 0
49
+ self.avg = 0
50
+ self.sum = 0
51
+ self.count = 0
52
+
53
+ def update(self, val, n=1):
54
+ self.val = val
55
+ self.sum += val * n
56
+ self.count += n
57
+ self.avg = self.sum / self.count
58
+
59
+ def __str__(self):
60
+ fmtstr = '{name} {val' + self.fmt + '} ({avg' + self.fmt + '})'
61
+ return fmtstr.format(**self.__dict__)
62
+
63
+ def accuracy(output: torch.Tensor,
64
+ target: torch.Tensor,
65
+ topk: Tuple[int] = (1,)) -> Tuple[float]:
66
+ """Computes the accuracy over the k top predictions for the specified values of k.
67
+ Args:
68
+ output: Prediction of the model.
69
+ target: Ground truth labels.
70
+ topk: Topk accuracy to compute.
71
+
72
+ Returns:
73
+ Accuracy results according to 'topk'.
74
+ """
75
+
76
+ with torch.no_grad():
77
+ maxk = max(topk)
78
+ batch_size = target.size(0)
79
+
80
+ _, pred = output.topk(maxk, 1, True, True)
81
+ pred = pred.t()
82
+ correct = pred.eq(target.view(1, -1).expand_as(pred))
83
+
84
+ res = []
85
+ for k in topk:
86
+ correct_k = correct[:k].contiguous().view(-1).float().sum(0, keepdim=True)
87
+ res.append(correct_k.mul_(100.0 / batch_size))
88
+ return res
89
+
90
+ def prepare_data_loader(data_dir: str,
91
+ batch_size: int = 100,
92
+ workers: int = 8) -> torch.utils.data.DataLoader:
93
+ """Returns a validation data loader of ImageNet by given `data_dir`.
94
+
95
+ Args:
96
+ data_dir: Directory where images stores. There must be a subdirectory named
97
+ 'validation' that stores the validation set of ImageNet.
98
+ batch_size: Batch size of data loader.
99
+ workers: How many subprocesses to use for data loading.
100
+
101
+ Returns:
102
+ An object of torch.utils.data.DataLoader.
103
+ """
104
+
105
+ valdir = os.path.join(data_dir, 'validation')
106
+
107
+ normalize = transforms.Normalize(
108
+ mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
109
+ val_dataset = datasets.ImageFolder(
110
+ valdir,
111
+ transforms.Compose([
112
+ transforms.Resize(256),
113
+ transforms.CenterCrop(224),
114
+ transforms.ToTensor(),
115
+ normalize,
116
+ ]))
117
+
118
+ return torch.utils.data.DataLoader(
119
+ val_dataset,
120
+ batch_size=batch_size,
121
+ shuffle=False,
122
+ num_workers=workers,
123
+ pin_memory=True)
124
+
125
+ def val_imagenet():
126
+ """Validate ONNX model on ImageNet dataset."""
127
+ print(f'Current onnx model: {args.onnx_model}')
128
+
129
+ if args.ipu:
130
+ providers = ["VitisAIExecutionProvider"]
131
+ provider_options = [{"config_file": args.provider_config}]
132
+ else:
133
+ providers = ['CUDAExecutionProvider', 'CPUExecutionProvider']
134
+ provider_options = None
135
+ ort_session = onnxruntime.InferenceSession(
136
+ args.onnx_model, providers=providers, provider_options=provider_options)
137
+
138
+ val_loader = prepare_data_loader(args.data_dir, args.batch_size)
139
+
140
+ top1 = AverageMeter('Acc@1', ':6.2f')
141
+ top5 = AverageMeter('Acc@5', ':6.2f')
142
+
143
+ start_time = time.time()
144
+ val_loader = tqdm(val_loader, file=sys.stdout)
145
+ with torch.no_grad():
146
+ for batch_idx, (images, targets) in enumerate(val_loader):
147
+ inputs, targets = images.numpy(), targets
148
+ ort_inputs = {ort_session.get_inputs()[0].name: inputs}
149
+
150
+ outputs = ort_session.run(None, ort_inputs)
151
+ outputs = torch.from_numpy(outputs[0])
152
+
153
+ acc1, acc5 = accuracy(outputs, targets, topk=(1, 5))
154
+ top1.update(acc1, images.size(0))
155
+ top5.update(acc5, images.size(0))
156
+
157
+ current_time = time.time()
158
+ print('Test Top1 {:.2f}%\tTop5 {:.2f}%\tTime {:.2f}s\n'.format(
159
+ float(top1.avg), float(top5.avg), (current_time - start_time)))
160
+
161
+ return top1.avg, top5.avg
162
+
163
+ if __name__ == '__main__':
164
+ val_imagenet()
infer_onnx.py ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ # -*- coding:utf-8 -*-
3
+
4
+ # Copyright 2023 Advanced Micro Devices, Inc. on behalf of itself and its subsidiaries and affiliates.
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+
18
+ # Copyright (c) Megvii, Inc. and its affiliates.
19
+
20
+ import onnxruntime
21
+ import argparse
22
+ from PIL import Image
23
+ import torchvision.transforms as transforms
24
+
25
+ parser = argparse.ArgumentParser()
26
+ parser.add_argument('--onnx_path', type=str, default="EfficientNet_int.onnx", required=False)
27
+ parser.add_argument('--image_path', type=str, required=True)
28
+ parser.add_argument(
29
+ "--ipu",
30
+ action="store_true",
31
+ help="Use IPU for inference.",
32
+ )
33
+ parser.add_argument(
34
+ "--provider_config",
35
+ type=str,
36
+ default="vaip_config.json",
37
+ help="Path of the config file for seting provider_options.",
38
+ )
39
+
40
+ args = parser.parse_args()
41
+
42
+
43
+ def read_image():
44
+ # Read a PIL image
45
+ image = Image.open(args.image_path)
46
+ normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
47
+
48
+ transform = transforms.Compose([
49
+ transforms.ToTensor(),
50
+ transforms.Resize((224, 224)),
51
+ normalize,
52
+ ])
53
+ img_tensor = transform(image).unsqueeze(0)
54
+ return img_tensor.numpy()
55
+
56
+
57
+ def main():
58
+ if args.ipu:
59
+ providers = ["VitisAIExecutionProvider"]
60
+ provider_options = [{"config_file": args.provider_config}]
61
+ else:
62
+ providers = ['CUDAExecutionProvider', 'CPUExecutionProvider']
63
+ provider_options = None
64
+ ort_session = onnxruntime.InferenceSession(
65
+ args.onnx_path, providers=providers, provider_options=provider_options)
66
+ ort_inputs = {
67
+ ort_session.get_inputs()[0].name: read_image()
68
+ }
69
+ output = ort_session.run(None, ort_inputs)[0]
70
+ print("class id =", output[0].argmax())
71
+
72
+
73
+ if __name__ == "__main__":
74
+ main()
requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ torch==1.12.0
2
+ torchsummary==1.5.1
3
+ torchvision==0.13.0
4
+ Pillow==9.4.0
5
+ timm==0.9.8
6
+ tqdm==4.64.0