From 2cb280147afe74f28ed0bbe4904bd4473e2e93dd Mon Sep 17 00:00:00 2001 From: JYChen Date: Wed, 17 May 2023 14:52:35 +0800 Subject: [PATCH] remove fluid memory_usage_calc&model_stat&op_frequence (#53838) --- python/paddle/fluid/contrib/__init__.py | 8 - .../paddle/fluid/contrib/memory_usage_calc.py | 119 ---------- python/paddle/fluid/contrib/model_stat.py | 211 ------------------ python/paddle/fluid/contrib/op_frequence.py | 109 --------- .../tests/unittests/test_memory_usage.py | 74 ------ 5 files changed, 521 deletions(-) delete mode 100644 python/paddle/fluid/contrib/memory_usage_calc.py delete mode 100644 python/paddle/fluid/contrib/model_stat.py delete mode 100644 python/paddle/fluid/contrib/op_frequence.py delete mode 100644 python/paddle/fluid/tests/unittests/test_memory_usage.py diff --git a/python/paddle/fluid/contrib/__init__.py b/python/paddle/fluid/contrib/__init__.py index deeb9b2f15b..7f8edf0c8cb 100644 --- a/python/paddle/fluid/contrib/__init__.py +++ b/python/paddle/fluid/contrib/__init__.py @@ -14,21 +14,13 @@ # limitations under the License. -from . import memory_usage_calc -from .memory_usage_calc import * -from . import op_frequence -from .op_frequence import * from . import extend_optimizer from .extend_optimizer import * -from . import model_stat -from .model_stat import * from . import optimizer from .optimizer import * __all__ = [] -__all__ += memory_usage_calc.__all__ -__all__ += op_frequence.__all__ __all__ += extend_optimizer.__all__ __all__ += optimizer.__all__ diff --git a/python/paddle/fluid/contrib/memory_usage_calc.py b/python/paddle/fluid/contrib/memory_usage_calc.py deleted file mode 100644 index 8a8dcb55a00..00000000000 --- a/python/paddle/fluid/contrib/memory_usage_calc.py +++ /dev/null @@ -1,119 +0,0 @@ -# Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserve. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -""" -This module provides a memory usage calculate function for user. -The purpose of this API is to allow users to estimate memory usage of -a program under a special batch size, then user can set appropriate -batch size to fully utilize a GPU. - -This API is still under active development and may change drastically. -""" - -from .. import core -from ..framework import Program, Variable - -__all__ = ['memory_usage'] - -dtype_to_size = { - core.VarDesc.VarType.FP16: 2, - core.VarDesc.VarType.FP32: 4, - core.VarDesc.VarType.FP64: 8, - core.VarDesc.VarType.INT16: 2, - core.VarDesc.VarType.INT32: 4, - core.VarDesc.VarType.INT64: 8, - core.VarDesc.VarType.BOOL: 1, - core.VarDesc.VarType.UINT8: 1, -} - -DEBUG = False - - -def memory_usage(program, batch_size): - r""" - Get the estimate memory usage of program with input batch size. - - Args: - program(Program): The current Program. - batch_size(int): The current input data batch_size. - - Returns: - min_total_memory(float): the estimate memory usage lower bound. - max_total_memory(float): the estimate memory usage upper bound. - unit_str(string): the unit of estimate usage result. - - Examples: - - >>> import paddle.fluid as fluid - >>> lower_usage, upper_usage, unit = fluid.contrib.memory_usage( - fluid.default_main_program(), batch_size=10) - >>> print "memory usage is about %.3f - %.3f %s" % \ - (lower_usage, upper_usage, unit) - - """ - - # Parameters check - if not isinstance(program, Program): - raise TypeError( - "Calculating Memory Usage requires Program as its Parameter." - "But you passed in %s" % (type(program)) - ) - if batch_size <= 0: - raise ValueError("The batch size need to be positive.") - - # Get the var_name list of first block and calculate - total_memory = 0.0 - processed_var_names = set(["@EMPTY@"]) - for op in program.global_block().ops: - for var_name in op.output_arg_names: - if var_name in processed_var_names: - continue - processed_var_names.add(var_name) - var = program.global_block().vars[var_name] - if var.desc.type() != core.VarDesc.VarType.LOD_TENSOR: - continue - - data_count = 1 - neg_dim_count = 0 - for x in var.shape: - if x < 0: - if neg_dim_count >= 1: - raise ValueError( - "Var %s has more than one negative dim." - % (var_name) - ) - neg_dim_count += 1 - data_count *= batch_size * (-x) - else: - data_count *= x - var_memory = data_count * dtype_to_size[var.dtype] - if DEBUG: - print("%s memory usage: %d" % (var.name, var_memory)) - total_memory += var_memory - if DEBUG: - print("total memory usage: %.2f" % (total_memory)) - - # Convert appropriate unit - unit_str = "B" - if total_memory > 1024: - total_memory /= 1024 - unit_str = "KB" - if total_memory > 1024: - total_memory /= 1024 - unit_str = "MB" - - # Append extra memory consumption (5% - 10%) - min_total_memory = total_memory * 1.05 - max_total_memory = total_memory * 1.1 - - return min_total_memory, max_total_memory, unit_str diff --git a/python/paddle/fluid/contrib/model_stat.py b/python/paddle/fluid/contrib/model_stat.py deleted file mode 100644 index 0c18deec5da..00000000000 --- a/python/paddle/fluid/contrib/model_stat.py +++ /dev/null @@ -1,211 +0,0 @@ -# Copyright (c) 2019 PaddlePaddle Authors. All Rights Reserved -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -''' -Example: - >>from paddle.fluid.contrib.model_stat import summary - >>main_program = ... - >>summary(main_program) - +-----+------------+----------------+----------------+---------+------------+ - | No. | TYPE | INPUT | OUTPUT | PARAMs | FLOPs | - +-----+------------+----------------+----------------+---------+------------+ - | 0 | conv2d | (3, 200, 200) | (64, 100, 100) | 9408 | 188160000 | - | 1 | batch_norm | (64, 100, 100) | (64, 100, 100) | 256 | 640000 | - | 2 | relu | (64, 100, 100) | (64, 100, 100) | 0 | 640000 | - | 3 | pool2d | (64, 100, 100) | (64, 50, 50) | 0 | 1440000 | - ... - | 176 | conv2d | (512, 7, 7) | (512, 7, 7) | 2359296 | 231211008 | - | 177 | relu | (512, 7, 7) | (512, 7, 7) | 0 | 25088 | - | 178 | conv2d | (512, 7, 7) | (2048, 7, 7) | 1048576 | 102760448 | - | 179 | relu | (2048, 7, 7) | (2048, 7, 7) | 0 | 100352 | - | 180 | pool2d | (2048, 7, 7) | (2048, 1, 1) | 0 | 100352 | - +-----+------------+----------------+----------------+---------+------------+ - Total PARAMs: 48017344(0.0480G) - Total FLOPs: 11692747751(11.69G) -''' -from collections import OrderedDict - - -def summary(main_prog): - ''' - It can summary model's PARAMS, FLOPs until now. - It support common operator like conv, fc, pool, relu, sigmoid, bn etc. - Args: - main_prog: main program - Returns: - print summary on terminal - ''' - collected_ops_list = [] - for one_b in main_prog.blocks: - block_vars = one_b.vars - for one_op in one_b.ops: - op_info = OrderedDict() - spf_res = _summary_model(block_vars, one_op) - if spf_res is None: - continue - # TODO: get the operator name - op_info['type'] = one_op.type - op_info['input_shape'] = spf_res[0][1:] - op_info['out_shape'] = spf_res[1][1:] - op_info['PARAMs'] = spf_res[2] - op_info['FLOPs'] = spf_res[3] - collected_ops_list.append(op_info) - - summary_table, total = _format_summary(collected_ops_list) - _print_summary(summary_table, total) - - -def _summary_model(block_vars, one_op): - ''' - Compute operator's params and flops. - Args: - block_vars: all vars of one block - one_op: one operator to count - Returns: - in_data_shape: one operator's input data shape - out_data_shape: one operator's output data shape - params: one operator's PARAMs - flops: : one operator's FLOPs - ''' - if one_op.type in ['conv2d', 'depthwise_conv2d']: - k_arg_shape = block_vars[one_op.input("Filter")[0]].shape - in_data_shape = block_vars[one_op.input("Input")[0]].shape - out_data_shape = block_vars[one_op.output("Output")[0]].shape - c_out, c_in, k_h, k_w = k_arg_shape - _, c_out_, h_out, w_out = out_data_shape - assert c_out == c_out_, 'shape error!' - k_groups = one_op.attr("groups") - kernel_ops = k_h * k_w * (c_in / k_groups) - bias_ops = 0 if one_op.input("Bias") == [] else 1 - params = c_out * (kernel_ops + bias_ops) - flops = h_out * w_out * c_out * (kernel_ops + bias_ops) - # base nvidia paper, include mul and add - flops = 2 * flops - - elif one_op.type == 'pool2d': - in_data_shape = block_vars[one_op.input("X")[0]].shape - out_data_shape = block_vars[one_op.output("Out")[0]].shape - _, c_out, h_out, w_out = out_data_shape - k_size = one_op.attr("ksize") - params = 0 - flops = h_out * w_out * c_out * (k_size[0] * k_size[1]) - - elif one_op.type == 'mul': - k_arg_shape = block_vars[one_op.input("Y")[0]].shape - in_data_shape = block_vars[one_op.input("X")[0]].shape - out_data_shape = block_vars[one_op.output("Out")[0]].shape - # TODO: fc has mul ops - # add attr to mul op, tell us whether it belongs to 'fc' - # this's not the best way - if 'fc' not in one_op.output("Out")[0]: - return None - k_in, k_out = k_arg_shape - # bias in sum op - params = k_in * k_out + 1 - flops = k_in * k_out - - elif one_op.type in ['sigmoid', 'tanh', 'relu', 'leaky_relu', 'prelu']: - in_data_shape = block_vars[one_op.input("X")[0]].shape - out_data_shape = block_vars[one_op.output("Out")[0]].shape - params = 0 - if one_op.type == 'prelu': - params = 1 - flops = 1 - for one_dim in in_data_shape: - flops *= one_dim - - elif one_op.type == 'batch_norm': - in_data_shape = block_vars[one_op.input("X")[0]].shape - out_data_shape = block_vars[one_op.output("Y")[0]].shape - _, c_in, h_out, w_out = in_data_shape - # gamma, beta - params = c_in * 2 - # compute mean and std - flops = h_out * w_out * c_in * 2 - - else: - return None - - return in_data_shape, out_data_shape, params, flops - - -def _format_summary(collected_ops_list): - ''' - Format summary report. - Args: - collected_ops_list: the collected operator with summary - Returns: - summary_table: summary report format - total: sum param and flops - ''' - _verify_dependent_package() - - from prettytable import PrettyTable - - summary_table = PrettyTable( - ["No.", "TYPE", "INPUT", "OUTPUT", "PARAMs", "FLOPs"] - ) - summary_table.align = 'r' - - total = {} - total_params = [] - total_flops = [] - for i, one_op in enumerate(collected_ops_list): - # notice the order - table_row = [ - i, - one_op['type'], - one_op['input_shape'], - one_op['out_shape'], - int(one_op['PARAMs']), - int(one_op['FLOPs']), - ] - summary_table.add_row(table_row) - total_params.append(int(one_op['PARAMs'])) - total_flops.append(int(one_op['FLOPs'])) - - total['params'] = total_params - total['flops'] = total_flops - - return summary_table, total - - -def _verify_dependent_package(): - """ - Verify whether `prettytable` is installed. - """ - try: - from prettytable import PrettyTable - except ImportError: - raise ImportError( - "paddle.summary() requires package `prettytable`, place install it firstly using `pip install prettytable`. " - ) - - -def _print_summary(summary_table, total): - ''' - Print all the summary on terminal. - Args: - summary_table: summary report format - total: sum param and flops - ''' - parmas = total['params'] - flops = total['flops'] - print(summary_table) - print( - 'Total PARAMs: {}({:.4f}M)'.format(sum(parmas), sum(parmas) / (10**6)) - ) - print('Total FLOPs: {}({:.2f}G)'.format(sum(flops), sum(flops) / 10**9)) - print( - "Notice: \n now supported ops include [Conv, DepthwiseConv, FC(mul), BatchNorm, Pool, Activation(sigmoid, tanh, relu, leaky_relu, prelu)]" - ) diff --git a/python/paddle/fluid/contrib/op_frequence.py b/python/paddle/fluid/contrib/op_frequence.py deleted file mode 100644 index ee435ac657a..00000000000 --- a/python/paddle/fluid/contrib/op_frequence.py +++ /dev/null @@ -1,109 +0,0 @@ -# Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserve. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from collections import OrderedDict - -from ..framework import Program - -__all__ = ['op_freq_statistic'] - - -def op_freq_statistic(program): - """ - Statistics of Op frequency. - - Args: - program(Program): The current Program. - - Returns: - uni_op_freq(dict): the single op frequency. - adj_2_op_freq(dict): the two adjacent ops frequency. - - Examples: - - >>> import paddle.fluid as fluid - >>> uni_op_freq, adj_2_op_freq = fluid.contrib.op_freq_statistic( - >>> fluid.default_main_program()) - >>> for op_type, op_num in uni_op_freq: - >>> print("%s \t %d" % (op_type, op_num)) - >>> for op_type, op_num in adj_2_op_freq: - >>> print("%s \t %d" % (op_type, op_num)) - - """ - - if not isinstance(program, Program): - raise TypeError( - "The input type should be Porgram." - "But you passed in %s" % (type(program)) - ) - - uni_op_freq = OrderedDict() - adj_2_op_freq = OrderedDict() - op_in_ops = OrderedDict() - - parameters = [p.name for p in program.blocks[0].all_parameters()] - - # get uni_op_freq - for op in program.global_block().ops: - had_recorded = False - for var_name in op.output_arg_names: - if var_name in parameters: - continue - if not had_recorded and uni_op_freq.has_key(op.type): - uni_op_freq[op.type] += 1 - had_recorded = True - elif not had_recorded: - uni_op_freq[op.type] = 1 - had_recorded = True - - # get adj_2_op_freq - var_gen_op = {} - for op in program.global_block().ops: - for var_name in op.input_arg_names: - if var_name in parameters: - continue - if var_gen_op.has_key(var_name): - assert len(var_gen_op[var_name]) > 0 - if op_in_ops.has_key(op.type): - op_in_ops[op.type].append(var_gen_op[var_name][-1]) - else: - op_in_ops[op.type] = [var_gen_op[var_name][-1]] - else: - print( - "Var's generate op is not found,%s, %s" - % (var_name, op.type) - ) - - for var_name in op.output_arg_names: - if var_gen_op.has_key(var_name): - var_gen_op[var_name].append(op.type) - else: - var_gen_op[var_name] = [op.type] - - for op, in_ops in op_in_ops.iteritems(): - for in_op in in_ops: - op_op = in_op + "->" + op - if adj_2_op_freq.has_key(op_op): - adj_2_op_freq[op_op] += 1 - else: - adj_2_op_freq[op_op] = 1 - - uni_op_freq = sorted( - uni_op_freq.items(), key=lambda item: item[1], reverse=True - ) - adj_2_op_freq = sorted( - adj_2_op_freq.items(), key=lambda item: item[1], reverse=True - ) - - return uni_op_freq, adj_2_op_freq diff --git a/python/paddle/fluid/tests/unittests/test_memory_usage.py b/python/paddle/fluid/tests/unittests/test_memory_usage.py deleted file mode 100644 index 55b3eaa9989..00000000000 --- a/python/paddle/fluid/tests/unittests/test_memory_usage.py +++ /dev/null @@ -1,74 +0,0 @@ -# Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import contextlib -import unittest - -import paddle -from paddle import fluid - - -def train_simulator(test_batch_size=10): - if test_batch_size <= 0: - raise ValueError( - "batch_size should be a positive integeral value, " - "but got batch_size={}".format(test_batch_size) - ) - - x = paddle.static.data(name='x', shape=[-1, 13], dtype='float32') - y_predict = paddle.static.nn.fc(x, size=1, activation=None) - y = paddle.static.data(name='y', shape=[-1, 1], dtype='float32') - - cost = paddle.nn.functional.square_error_cost(input=y_predict, label=y) - avg_cost = paddle.mean(cost) - - sgd_optimizer = fluid.optimizer.SGD(learning_rate=0.001) - sgd_optimizer.minimize(avg_cost) - - # Calculate memory usage in current network config - lower_usage, upper_usage, unit = fluid.contrib.memory_usage( - fluid.default_main_program(), batch_size=test_batch_size - ) - - print( - "memory usage is about %.3f - %.3f %s" - % (lower_usage, upper_usage, unit) - ) - - -class TestMemoryUsage(unittest.TestCase): - def test_with_unit_B(self): - with self.program_scope_guard(): - train_simulator() - - def test_with_unit_KB(self): - with self.program_scope_guard(): - train_simulator(test_batch_size=1000) - - def test_with_unit_MB(self): - with self.program_scope_guard(): - train_simulator(test_batch_size=100000) - - @contextlib.contextmanager - def program_scope_guard(self): - prog = fluid.Program() - startup_prog = fluid.Program() - scope = fluid.core.Scope() - with fluid.scope_guard(scope): - with fluid.program_guard(prog, startup_prog): - yield - - -if __name__ == '__main__': - unittest.main() -- GitLab