deeplearning量化
deeplearning量化
量化配置
通過字典配置量化參數
TENSORRT_OP_TYPES = [
‘mul’, ‘conv2d’, ‘pool2d’, ‘depthwise_conv2d’, ‘elementwise_add’,
‘leaky_relu’
]
TRANSFORM_PASS_OP_TYPES = [‘conv2d’, ‘depthwise_conv2d’, ‘mul’]
QUANT_DEQUANT_PASS_OP_TYPES = [
“pool2d”, “elementwise_add”, “concat”, “softmax”, “argmax”, “transpose”,
“equal”, “gather”, “greater_equal”, “greater_than”, “less_equal”,
“less_than”, “mean”, “not_equal”, “reshape”, “reshape2”,
“bilinear_interp”, “nearest_interp”, “trilinear_interp”, “slice”,
“squeeze”, “elementwise_sub”, “relu”, “relu6”, “leaky_relu”, “tanh”, “swish”
]
_quant_config_default = {
# weight quantize type, default is ‘channel_wise_abs_max’
‘weight_quantize_type’: ‘channel_wise_abs_max’,
# activation quantize type, default is ‘moving_average_abs_max’
‘activation_quantize_type’: ‘moving_average_abs_max’,
# weight quantize bit num, default is 8
‘weight_bits’: 8,
# activation quantize bit num, default is 8
‘activation_bits’: 8,
# ops of name_scope in not_quant_pattern list, will not be quantized
‘not_quant_pattern’: [‘skip_quant’],
# ops of type in quantize_op_types, will be quantized
‘quantize_op_types’: [‘conv2d’, ‘depthwise_conv2d’, ‘mul’],
# data type after quantization, such as ‘uint8’, ‘int8’, etc. default is ‘int8’
‘dtype’: ‘int8’,
# window size for ‘range_abs_max’ quantization. defaulf is 10000
‘window_size’: 10000,
# The decay coefficient of moving average, default is 0.9
‘moving_rate’: 0.9,
# if True, ‘quantize_op_types’ will be TENSORRT_OP_TYPES
‘for_tensorrt’: False,
# if True, ‘quantoze_op_types’ will be TRANSFORM_PASS_OP_TYPES + QUANT_DEQUANT_PASS_OP_TYPES
‘is_full_quantize’: False
}
參數:
? weight_quantize_type(str) - 參數量化方式。可選 ‘abs_max’ , ‘channel_wise_abs_max’ , ‘range_abs_max’ , ‘moving_average_abs_max’ 。如果使用 TensorRT 加載量化后的模型來預測,使用 ‘channel_wise_abs_max’ 。 默認 ‘channel_wise_abs_max’ 。
? activation_quantize_type(str) - 激活量化方式,可選 ‘abs_max’ , ‘range_abs_max’ , ‘moving_average_abs_max’ 。如果使用 TensorRT 加載量化后的模型來預測,使用 ‘range_abs_max’, ‘moving_average_abs_max’ ,默認 ‘moving_average_abs_max’ 。
? weight_bits(int) - 參數量化bit數,默認8, 可選1-8,推薦設為8,因為量化后的數據類型是 int8 。
? activation_bits(int) - 激活量化bit數,默認8,可選1-8,推薦設為8,因為量化后的數據類型是 int8 。
? not_quant_pattern(str | list[str]) - 所有 name_scope 包含 ‘not_quant_pattern’ 字符串的 op ,都不量化, 設置方式參考 fluid.name_scope 。
? quantize_op_types(list[str]) - 需要進行量化的 op 類型,目前支持 ‘conv2d’, ‘depthwise_conv2d’, ‘mul’ 。
? dtype(int8) - 量化后的參數類型,默認 int8 , 目前僅支持 int8 。
? window_size(int) - ‘range_abs_max’ 量化方式的 window size ,默認10000。
? moving_rate(int) - ‘moving_average_abs_max’ 量化方式的衰減系數,默認 0.9。
? for_tensorrt(bool) - 量化后的模型是否使用 TensorRT 進行預測。如果是的話,量化op類型為: TENSORRT_OP_TYPES 。默認值為False.
? is_full_quantize(bool) - 是否量化所有可支持op類型。可量化op為 TRANSFORM_PASS_OP_TYPES + QUANT_DEQUANT_PASS_OP_TYPES 。 默認值為False.
quant_aware
paddleslim.quant.quant_aware(program, place, config, scope=None, for_test=False)
在 program 中加入量化和反量化op, 用于量化訓練。
參數:
? program (fluid.Program) - 傳入訓練或測試program 。
? place(fluid.CPUPlace | fluid.CUDAPlace) - 該參數表示 Executor 執行所在的設備。
? config(dict) - 量化配置表。
? scope(fluid.Scope, optional) - 傳入用于存儲 Variable 的 scope ,需要傳入 program 所使用的 scope ,一般情況下,是 fluid.global_scope() 。設置為 None 時將使用 fluid.global_scope() ,默認值為 None 。
? for_test(bool) - 如果 program 參數是一個測試 program , for_test 應設為True,否則設為False 。
返回
含有量化和反量化 operator 的 program 。
返回類型
? 當 for_test=False ,返回類型為 fluid.CompiledProgram , 注意,此返回值不能用于保存參數 。
? 當 for_test=True ,返回類型為 fluid.Program 。
注解
? 此接口會改變program 結構,并且可能增加一些persistable的變量,所以加載模型參數時注意和相應的 program 對應。
? 此接口底層經歷了 fluid.Program -> fluid.framework.IrGraph -> fluid.Program 的轉變,在 fluid.framework.IrGraph 中沒有 Parameter 的概念,Variable 只有 persistable 和not persistable的區別,所以在保存和加載參數時,使用 fluid.io.save_persistables 和 fluid.io.load_persistables 接口。
? 由于此接口會根據 program 的結構和量化配置來對program 添加op,所以 Paddle 中一些通過 fuse op 來加速訓練的策略不能使用。已知以下策略在使用量化時必須設為False : fuse_all_reduce_ops, sync_batch_norm 。
? 如果傳入的 program 中存在和任何op都沒有連接的 Variable ,則會在量化的過程中被優化掉。
convert
paddleslim.quant.convert(program, place, config, scope=None, save_int8=False)
把訓練好的量化 program ,轉換為可用于保存 inference model 的 program 。
參數:
? program (fluid.Program) - 傳入測試 program 。
? place(fluid.CPUPlace | fluid.CUDAPlace) - 該參數表示 Executor 執行所在的設備。
? config(dict) - 量化配置表。
? scope(fluid.Scope) - 傳入用于存儲 Variable 的 scope ,需要傳入 program 所使用的 scope ,一般情況下,是 fluid.global_scope() 。設置為 None 時將使用 fluid.global_scope() ,默認值為 None 。
? save_int8(bool) - 是否需要返回參數為 int8 的 program 。該功能目前只能用于確認模型大小。默認值為 False 。
返回
? program (fluid.Program) - freezed program,可用于保存inference model,參數為 float32 類型,但其數值范圍可用int8表示。
? int8_program (fluid.Program) - freezed program,可用于保存inference model,參數為 int8 類型。當 save_int8 為False 時,不返回該值。
注解
因為該接口會對 op 和 Variable 做相應的刪除和修改,所以此接口只能在訓練完成之后調用。如果想轉化訓練的中間模型,可加載相應的參數之后再使用此接口。
代碼示例
#encoding=utf8
import paddle.fluid as fluid
import paddleslim.quant as quant
train_program = fluid.Program()
with fluid.program_guard(train_program):
image = fluid.data(name=‘x’, shape=[None, 1, 28, 28])
label = fluid.data(name=‘label’, shape=[None, 1], dtype=‘int64’)
conv = fluid.layers.conv2d(image, 32, 1)
feat = fluid.layers.fc(conv, 10, act=‘softmax’)
cost = fluid.layers.cross_entropy(input=feat, label=label)
avg_cost = fluid.layers.mean(x=cost)
use_gpu = True
place = fluid.CUDAPlace(0) if use_gpu else fluid.CPUPlace()
exe = fluid.Executor(place)
exe.run(fluid.default_startup_program())
eval_program = train_program.clone(for_test=True)
#配置
config = {‘weight_quantize_type’: ‘abs_max’,
‘activation_quantize_type’: ‘moving_average_abs_max’}
build_strategy = fluid.BuildStrategy()
exec_strategy = fluid.ExecutionStrategy()
#調用api
quant_train_program = quant.quant_aware(train_program, place, config, for_test=False)
quant_eval_program = quant.quant_aware(eval_program, place, config, for_test=True)
#關閉策略
build_strategy.fuse_all_reduce_ops = False
build_strategy.sync_batch_norm = False
quant_train_program = quant_train_program.with_data_parallel(
loss_name=avg_cost.name,
build_strategy=build_strategy,
exec_strategy=exec_strategy)
inference_prog = quant.convert(quant_eval_program, place, config)
更詳細的用法參考 量化訓練demo 。
quant_post
paddleslim.quant.quant_post(executor, model_dir, quantize_model_path,sample_generator, model_filename=None, params_filename=None, batch_size=16,batch_nums=None, scope=None, algo=‘KL’, quantizable_op_type=[“conv2d”, “depthwise_conv2d”, “mul”], is_full_quantize=False, weight_bits=8, activation_bits=8, is_use_cache_file=False, cache_dir="./temp_post_training")
對保存在 ${model_dir} 下的模型進行量化,使用 sample_generator 的數據進行參數校正。
參數:
? executor (fluid.Executor) - 執行模型的executor,可以在cpu或者gpu上執行。
? model_dir(str) - 需要量化的模型所在的文件夾。
? quantize_model_path(str) - 保存量化后的模型的路徑
? sample_generator(python generator) - 讀取數據樣本,每次返回一個樣本。
? model_filename(str, optional) - 模型文件名,如果需要量化的模型的參數存在一個文件中,則需要設置 model_filename 為模型文件的名稱,否則設置為 None 即可。默認值是 None 。
? params_filename(str) - 參數文件名,如果需要量化的模型的參數存在一個文件中,則需要設置 params_filename 為參數文件的名稱,否則設置為 None 即可。默認值是 None 。
? batch_size(int) - 每個batch的圖片數量。默認值為16 。
? batch_nums(int, optional) - 迭代次數。如果設置為 None ,則會一直運行到 sample_generator 迭代結束, 否則,迭代次數為 batch_nums, 也就是說參與對 Scale 進行校正的樣本個數為 ‘batch_nums’ * ‘batch_size’ .
? scope(fluid.Scope, optional) - 用來獲取和寫入 Variable , 如果設置為 None ,則使用 fluid.global_scope() . 默認值是 None .
? algo(str) - 量化時使用的算法名稱,可為 ‘KL’ 或者 ‘direct’ 。該參數僅針對激活值的量化,因為參數值的量化使用的方式為 ‘channel_wise_abs_max’ . 當 algo 設置為 ‘direct’ 時,使用校正數據的激活值的絕對值的最大值當作 Scale 值,當設置為 ‘KL’ 時,則使用KL散度的方法來計算 Scale 值。默認值為 ‘KL’ 。
? quantizable_op_type(list[str]) - 需要量化的 op 類型列表。默認值為 [“conv2d”, “depthwise_conv2d”, “mul”] 。
? is_full_quantize(bool) - 是否量化所有可支持的op類型。如果設置為False, 則按照 ‘quantizable_op_type’ 的設置進行量化。如果設置為True, 則按照 量化配置 中 QUANT_DEQUANT_PASS_OP_TYPES + QUANT_DEQUANT_PASS_OP_TYPES 定義的op進行量化。
? weight_bits(int) - weight的量化比特位數, 默認值為8。
? activation_bits(int) - 激活值的量化比特位數, 默認值為8。
? is_use_cache_file(bool) - 是否使用硬盤對中間結果進行存儲。如果為False, 則將中間結果存儲在內存中。默認值為False。
? cache_dir(str) - 如果 ‘is_use_cache_file’ 為True, 則將中間結果存儲在此參數設置的路徑下。默認值為 ./temp_post_training 。
返回
無。
注解
? 因為該接口會收集校正數據的所有的激活值,當校正圖片比較多時,設置 ‘is_use_cache_file’ 為True, 將中間結果存儲在硬盤中。另外,‘KL’ 散度的計算比較耗時。
? 目前 Paddle-Lite 有int8 kernel來加速的op只有 [‘conv2d’, ‘depthwise_conv2d’, ‘mul’] , 其他op的int8 kernel將陸續支持。
代碼示例
警告
此示例不能直接運行,因為需要加載 ${model_dir} 下的模型,所以不能直接運行。
import paddle.fluid as fluid
import paddle.dataset.mnist as reader
from paddleslim.quant import quant_post
val_reader = reader.train()
use_gpu = True
place = fluid.CUDAPlace(0) if use_gpu else fluid.CPUPlace()
exe = fluid.Executor(place)
quant_post(
executor=exe,
model_dir=’./model_path’,
quantize_model_path=’./save_path’,
sample_generator=val_reader,
model_filename=‘model’,
params_filename=‘params’,
batch_size=16,
batch_nums=10)
quant_embedding
paddleslim.quant.quant_embedding(program, place, config, scope=None)
對 Embedding 參數進行量化。
參數:
? program(fluid.Program) - 需要量化的program
? scope(fluid.Scope, optional) - 用來獲取和寫入 Variable, 如果設置為 None,則使用 fluid.global_scope() .
? place(fluid.CPUPlace | fluid.CUDAPlace) - 運行program的設備
? config(dict) - 定義量化的配置。可以配置的參數有:
o ‘params_name’ (str, required): 需要進行量化的參數名稱,此參數必須設置。
o ‘quantize_type’ (str, optional): 量化的類型,目前支持的類型是 ‘abs_max’, 待支持的類型有 ‘log’, ‘product_quantization’ 。 默認值是 ‘abs_max’ .
o ‘quantize_bits’ (int, optional): 量化的bit數,目前支持的bit數為8。默認值是8.
o ‘dtype’ (str, optional): 量化之后的數據類型, 目前支持的是 ‘int8’. 默認值是 int8 。
o ‘threshold’ (float, optional): 量化之前將根據此閾值對需要量化的參數值進行 clip. 如果不設置,則跳過 clip 過程直接量化。
返回
量化之后的program
返回類型
fluid.Program
代碼示例
import paddle.fluid as fluid
import paddleslim.quant as quant
train_program = fluid.Program()
with fluid.program_guard(train_program):
input_word = fluid.data(name=“input_word”, shape=[None, 1], dtype=‘int64’)
input_emb = fluid.embedding(
input=input_word,
is_sparse=False,
size=[100, 128],
param_attr=fluid.ParamAttr(name=‘emb’,
initializer=fluid.initializer.Uniform(-0.005, 0.005)))
infer_program = train_program.clone(for_test=True)
use_gpu = True
place = fluid.CUDAPlace(0) if use_gpu else fluid.CPUPlace()
exe = fluid.Executor(place)
exe.run(fluid.default_startup_program())
config = {‘params_name’: ‘emb’, ‘quantize_type’: ‘abs_max’}
quant_program = quant.quant_embedding(infer_program, place, config)
總結
以上是生活随笔為你收集整理的deeplearning量化的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 卷积层通道剪裁
- 下一篇: Deeplearning知识蒸馏