-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathprofile.py
131 lines (107 loc) · 4.33 KB
/
profile.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# coding=utf-8
import sys
import time
import torch
import pandas as pd
import functools
from collections import defaultdict
from .walk import walk_modules
class Profile(object):
"""PyTorch模型的逐层分析器,可以获取模型各层初始化、执行时间和输出数据大小"""
def __init__(self, model, enabled=True, use_cuda=False, depth=-1):
"""
参数:
model:pytorch模型
enabled:是否(True/False)启用分析
use_cuda:是否(True/False)使用GPU
depth:模型层嵌套深度
"""
self._model = model
self.enabled = enabled
self.use_cuda = use_cuda
self.depth = depth
self.entered = False
self.exited = False
self.traces = ()
self.information = defaultdict(list)
# 输入层信息(默认输入数据size为3*224*224,float32)
self.information["input"].extend([0, 0, 0.15, 0.01])
def __enter__(self):
if not self.enabled:
return self
if self.entered:
raise RuntimeError("pytorchtool profiler is not reentrant")
self.entered = True
self._forwards = {} # 存储初始forwards
# 逐层初始化分析
self.traces = tuple(map(self._load_weight, walk_modules(self._model, depth=self.depth)))
# 逐层修改forwards
tuple(map(self._hook_trace, self.traces))
return self
def __exit__(self, exc_type, exc_val, exc_tb):
if not self.enabled:
return
# 逐层恢复初始forwards
tuple(map(self._remove_hook_trace, self.traces))
del self._forwards # remove unnecessary forwards
self.exited = True
def __str__(self):
return str(pd.DataFrame.from_dict(self.information, orient='index',
columns=['Parameters Loading Time(ms)', 'Model Loading Time(ms)', 'Data Size(MB)','Execute Time(ms)']))
def __call__(self, *args, **kwargs):
return self._model(*args, **kwargs)
def _load_weight(self, trace):
(name, module) = trace
start = time.time()
module.load_state_dict(torch.load("./model_weight/" +
self._model.__class__.__name__ + "/" + name + ".pth"), strict=False)
loadingTime = (time.time() - start) * 1000
self.information[name].append(loadingTime)
return trace
def _hook_trace(self, trace):
(name, module) = trace
'''
start = time.time()
m = torch.load("./model_weight/" +
self._model.__class__.__name__ + "/" + name + ".pkl")
loadingTime = (time.time() - start) * 1000
self.information[name].append(loadingTime)
'''
_forward = module.forward
self._forwards[name] = _forward
@functools.wraps(_forward)
def wrap_forward(*args, **kwargs):
print(name)
# 执行时间
if self.use_cuda:
start = torch.cuda.Event(enable_timing=True)
end = torch.cuda.Event(enable_timing=True)
start.record()
output = _forward(*args, **kwargs)
end.record()
# 等待执行完成
torch.cuda.synchronize()
exec_time = start.elapsed_time(end)
else:
start = time.time()
output = _forward(*args, **kwargs)
# 转换为ms
exec_time = (time.time() - start) * 1000
# 输出数据大小(MB)
data_size = sys.getsizeof(output.storage()) / 1024 / 1024
self.information[name].append(data_size)
self.information[name].append(exec_time)
return output
module.forward = wrap_forward
return trace
def _remove_hook_trace(self, trace):
[name, module] = trace
module.forward = self._forwards[name]
def printCsv(self, filePath='./parameters/default.csv'):
"""将模型分析结果写入csv文件
参数:
filePath:csv文件路径及文件名
"""
df = pd.DataFrame.from_dict(self.information, orient='index',
columns=['Parameters Loading Time(ms)', 'Model Loading Time(ms)', 'Data Size(MB)','Execute Time(ms)'])
df.to_csv(filePath)