pytorch模型压缩方法总结

6、训练模型BiLSTM&HMM

一个是在channel粒度上做剪枝,另一个是在神经元Unit维度上做剪枝

torch 增加维度_torch扩展维度torch 增加维度_torch扩展维度


torch 增加维度_torch扩展维度


torch 增加维度_torch扩展维度


1.torch.quantize_per_tensor()函数的scale和zero_point需要自己设定。

所谓动态是指这个函数torch.quantization.quantize_dynamic能自动选择最合适的scale和zero_point。

QuantStub使用的是HistogramObserver,根据输入从[-3,3]的分布,HistogramObserver计算得到min_val、max_val分别是-3、2.9971,而qmin和qmax又分别是0、127,其schema为per_tensor_affine,因此套用上面的per_tensor_affine逻辑可得:

Post Training Dynamic Quantization,简称为Dynamic Quantization,也就是动态量化,或者叫作Weight-only的量化,是提前把模型中某些op的参数量化为INT8,然后在运行的时候动态的把输入量化为INT8,然后在当前op输出的时候再把结果requantization回到float32类型。动态量化默认只适用于Linear以及RNN的变种。

当对整个模型进行转换时,默认只对以下的op进outp.write(sentence.strip() + '行转换:

Linear

LSTM

LSTMCell

RNNCell

GRUCell

为啥呢?因为dynamic quantization只是把权重参数进行量化,而这些layer一般参数数量很大,在整个模型中参数量占比极高,因此边际效益高。对其它layer进行dynamic quantization几乎没有实际的意义。

与其介绍t training static quantization是什么,我们不如先来说明下它和dynamic quantization的相同点和区别是什么。相同点就是,都是把网络的权重参数转从float32转换为int8;不同点是,需要把训练集或者和训练集分布类似的数据喂给模型(注意没有反向传播),然后通过每个op输入的分布特点来计算activation的量化参数(scale和zp)——称之为Calibrate(定标)。是的,静态量化包含有activation了,也就是t process,也就是op forward之后的后处理。为什么静态量化需要activation呢?因为静态量化的前向推理过程自(始+1)至(终-1)都是INT计算,activation需要确保一个op的输入符合下一个op的输入。

PyTorch会使用五部曲来完成模型的静态量化:

这一步不是训练。是为了获取数据的分布特点,来更好的计算activation的scale和zp。至少要喂上几百个迭代的数据,

per tensor 和 per channel。Per tensor 是说一个tensor里的所有value按照同一种方式去scale和offset; per channel是对于tensor的某一个维度(通常是channel的维度)上的值按照一种方式去scale和offset,也就是一个tensor里有多种不同的scale和offset的方式(组成一个vector),如此以来,在量化的时候相比per tensor的方式会引入更少的错误。PyTorch目前支持conv2d()、conv3d()、linear()的per channel量化。

NLP命名体识别bilstm+crf

outp.write(line[i].split('/')[0][1:])

"""

i += 1

NLP命名体识别bilstm+crf

1、准备数据:origin_handle_entities()

读取源数据文件,把人名,地名,机构名合并起来

2、读取处理后的数据:origin_handle_mark()

把预处理后的的文本标注成BMO的格式,

3、句子切分:sentence_split()

按照指定的格式,比如标点等内容对数据完成切分

4、保存数据

a.将标注的句子拆分自成列表和对应的标注序列

b.创建词汇表和标签

c.文本的向量化表示

d.划分训练集和测试集

e.保存成二进制pkl文件

5、加载数据

7、保存训练后的模型用于预测

8、预测

"""

import codecs

import re

import collections

import pickle

import TorchCRF as CRF

import numpy as np

from tensorflow.keras.preprocessing.sequence import pad_sequences #使用tensorflow的pad_sequences进行数据对齐 tensorflow2.3.1

from sklearn.model_selection import train_test_split

def origin_handle_entities():

open('middle/renmin2.txt','w',encoding='utf-8')

as outp:

#读取源文件中的数据

for line in inp.readlines():

#按照空格切分

line = line.split(' ')

i = 1

while i < len(line) - 1:

while i < len(line) - 1 and line[i].find(']') == -1:

if line[i] !='':

#print(line[i].split('/')[0])

outp.write(line[i].split('/')[0])

outp.write(line[i].split('/')[0].strip()+'/'+line[i])

elif line[i].split('/')[1] == 'nr':

word = line[i].split('/')[0]

if i < len(line) - 1 and line[i].split('/')[1] == 'nr':

outp.write(word + line[i].split('/')[0] + 'nr')

else:

outp.write(word + '/nr ')

continue

else:

outp.write(line[i] + '/no ')

outp.write('

')

import codecs

def origin_handle_mark():

"""

1、读取数据预处理后的renmin2.txt

2、将标注好的数据写入renmin3.txt

a.打开输入和输出文件

b.遍历输入文件renmin2.txt

:return:

"""

codecs.open('middle/renmin3.txt','w',encoding='utf-8') as outp:

#########句子切分###################################

import re

def sentence_split():

with codecs.open('middel/renmin3.txt','r',encoding='utf-8') as inp,

codecs.open('middle/renmin4.txt','w',encoding='utf-8') as outp:

#文本文件的内容设置为对应的utf-8编码,python3:先encode,再decode

texts = inp.read().encode('utf-8').decode('utf-8')

#切分句子

sentences =

re.split('[,。!?、''"":]/[0]'.encode('utf-8').decode('utf-8'),

texts)

for sentence in sentences:

if sentence != ' ':

')

"""

将文本数据保存成二进制pkl文件

:return:

"""

def main():

# 数据清洗

origin_handle_entities()

#数据标注(字)

origin_handle_mark()

# 句子切分

# 数据转换

data_to_pkl()

if name == ' main ':

main()

##################################################################################################

def load_data():

pickle_path = '../data_target_pkl/renmindata.pkl'

with open(pickle_path,'rb') as inp:

word2id,id2word,tag2id,id2tag,x_train,y_train,x_test,y_test,x_valid,y_valid =pickle.load(inp)

def main():

word2id = load_data()

print(len(word2id))

if name == ' main ':

main()

import torch

import torch.nn as nn

from torch.utils.data import Dataset # 批量读取数据

class NERDataSet(Dataset):

"""

X:表示样本,Y:表示标签

"""

def init (self,X,Y, args, kwargs):

"""

class Config():

embedding_dim = 100 #词向量的维度

config = Config()

class NERLSTM_CRF(nn.Module):

"""

1、输入层

2、词映射(Embedding(vocab_size,embedding_dim))

3、LSTM

4、全连接层

"""

def init (self):

super(NERLSTM_CRF,self). init ()

self.embeding_dim = config.embeding_dim

self.hidden_dim = config.hidden_dim

self.vocab_size = config.vocab_size

self.num_tags = config.num_tags

##################################################

from torch.utils.data import DataLoader #批量加载数据

import torch

import torch.optim as op

def utils_to_train():

dev = torch.dev('cpu')

max_epoch = 1

batch_size = 32

num_workers =4 #开启几个线程取执行程序

def parse_tags(text,path):

id2tag = load_data()

tags = [id2tag[idx] for idx in path]

##################################################

from import classification_report,precision_score,recall_score,f1_score

word2id = load_data()[0]

max_epoch,dev,train_data_loader,valid_data_loader,test_data_loader,model = utils_to_train()

class ChineseNER(object):

def train(self):

for epoch in range(max_epoch):

torch.cat()使用方法

hidden_B(begin)、M(middle)、E(end)、O(other)dim = 200

torch.cat() 可以对tensor进行上下或左右拼接,其传入的参数为:

dim 控制拼接的维度, dim=0 为上下拼接, dim=1 为左右拼接 [1] 。

下面是实例详解:

NLP命名体识别bilstm+crf

sentence_split()

"""

NLP命名体识别bilstm+crf

1、准备数据:origin_handle_entities()

读取源数据文件,把人名,地名,机构名合并起来

2、读取处理后的数据:origin_handle_mark()

把预处理后的的文本标注成BMO的格式,

3、句子切分:sentence_split()

按照指定的格式,比如标点等内容对数据完成切分

4、保存数据

a.将标注的句子拆分自成列表和对应的标注序列

b.创建词汇表和标签

c.文本的向量化表示

d.划分训练集和测试集

e.保存成二进制pkl文件

5、加载数据

7、保存训练后的模型用于预测

8、预测

"""

import codecs

import re

import collections

import pickle

import TorchCRF as CRF

im#######################################################################################port numpy as np

from tensorflow.keras.preprocessing.sequence import pad_sequences #使用tensorflow的pad_sequences进行数据对齐 tensorflow2.3.1

from sklearn.model_selection import train_test_split

def origin_handle_entities():

open('middle/renmin2.txt','w',encoding='utf-8')

as outp:

#读取源文件中的数据

for line in inp.readlines():

#按照空格切分

line = line.split(' ')

i = 1

while i < len(line) - 1:

while i < len(line) - 1 and line[i].find(']') == -1:

if line[i] !='':

#print(line[i].split('/')[0])

outp.write(line[i].split('/')[0])

outp.write(line[i].split('/')[0].strip()+'/'+line[i])

elif line[i].split('/')[1] == 'nr':

word = line[i].split('/')[0]

if i < len(line) - 1 and line[i].split('/')[1] == 'nr':

outp.write(word + line[i].split('/')[0] + 'nr')

else:

outp.write(word + '/nr ')

continue

else:

outp.write(line[i] + '/no ')

outp.write('

')

import codecs

def origin_handle_mark():

"""

1、读取数据预处理后的renmin2.txt

2、将标注好的数据写入renmin3.txt

a.打开输入和输出文件

b.遍历输入文件renmin2.txt

:return:

"""

codecs.open('middle/renmin3.txt','w',encoding='utf-8') as outp:

#########句子切分###################################

import re

def sentence_split():

with codecs.open('middel/renmin3.txt','r',encoding='utf-8') as inp,

codecs.open('middle/renmin4.txt','w',encoding='utf-8') as outp:

#文本文件的内容设置为对应的utf-8编码,python3:先encode,再decode

texts = inp.read().encode('utf-8').decode('utf-8')

#切分句子

sentences =

re.split('[,。!?、''"":]/[0]'.encode('utf-8').decode('utf-8'),

texts)

for sentence in sentences:

if sentence != ' ':

')

"""

将文本数据保存成二进制pkl文件

:return:

"""

def main():

# 数据清洗

origin_handle_entities()

#数据标注(字)

origin_handle_mark()

# 句子切分

# 数据转换

data_to_pkl()

if name == ' main ':

main()

##################################################################################################

def load_data():

pickle_path = '../data_target_pkl/renmindata.pkl'

with open(pickle_path,'rb') as inp:

word2id,id2word,tag2id,id2tag,x_train,y_train,x_test,y_test,x_valid,y_valid =pickle.load(inp)

def main():

word2id = load_data()

print(len(word2id))

if name == ' main ':

main()

import torch

import torch.nn as nn

from torch.utils.data import Dataset # 批量读取数据

class NERDataSet(Dataset):

"""

X:表示样本,Y:表示标签

"""

def init (self,X,Y, args, kwargs):

"""

class Config():

embedding_dim = 100 #词向量的维度

config = Config()

class NERLSTM_CRF(nn.Module):

"""

1、输入层

2、词映射(Embedding(vocab_size,embedding_dim))

3、LSTM

4、全连接层

"""

def init (self):

super(NERLSTM_CRF,self). init ()

self.embeding_dim = config.embeding_dim

self.hidden_dim = config.hidden_dim

self.vocab_size = config.vocab_size

self.num_tags = config.num_tags

##################################################

from torch.utils.data import DataLoader #批量加载数据

import torch

import torch.optim as op

def utils_to_train():

dev = torch.dev('cpu')

max_epoch = 1

batch_size = 32

num_workers =4 #开启几个线程取执行程序

def parse_tags(text,path):

id2tag = load_data()

tags = [id2tag[idx] for idx in path]

##################################################

from import classification_report,precision_score,recall_score,f1_score

word2id = load_data()[0]

max_epoch,dev,train_data_loader,valid_data_loader,test_data_loader,model = utils_to_train()

class ChineseNER(object):

def train(self):

for epoch in range(max_epoch):

pytorch模型压缩方法总结

with open('renmin.txt','r',encoding='utf-8') as inp,

一个是在channel粒度上做剪枝,另一个是在神经元Unit维度上做剪枝

1.torch.quantize_per_tensor()函数的scale和zero_point需要自己设定。

所谓动态是指这个函数torch.quantization.quantize_dynamic能自动选择最合适的scale和zero_point。

QuantStub使用的是HistogramObserver,根据输入从[-3,3]的分布,HistogramObserver计算得到min_val、max_val分别是-3、2.9971,而qmin和qmax又分别是0、127,其schema为per_tensor_affine,因此套用上面的per_tensor_affine逻辑可得:

Post Training Dynamic Quantization,简称为Dynamic Quantization,也就是动态量化,或者叫作Weight-only的量化,是提前把模型中某些op的参数量化为INT8,然后在运行的时候动态的把输入量化为INT8,然后在当前op输出的时候再把结果requantization回到float32类型。动态量化默认只适用于Linear以及RNN的变种。

当对整个模型进行转换时,默认只对以下的op进行转换:

Linear

LSTM

LSTMCell

RNNCell

GRUCell

为啥呢?因为dynamic quantization只是把权重参数进行量化,而这些layer一般参数数量很大,在整个模型中参数量占比极高,因此边际效益高。对其它layer进行dynamic quantization几乎没有实际的意义。

与其介绍t training static quantization是什么,我们不如先来说明if line[i][0] == '[':下它和dynamic quantization的相同点和区别是什么。相同点就是,都是把网络的权重参数转从float32转换为int8;不同点是,需要把训练集或者和训练集分布类似的数据喂给模型(注意没有反向传播),然后通过每个op输入的分布特点来计算activation的量化参数(scale和zp)——称之为Calibrate(定标)。是的,静态量化包含有activation了,也就是t process,也就是op forward之后的后处理。为什么静态量化需要activation呢?因为静态量化的前向推理过程自(始+1)至(终-1)都是INT计算,activation需要确保一个op的输入符合下一个op的输入。

PyTorch会使用五部曲来完成模型的静态量化:

这一步不是训练。是为了获取数据的分布特点,来更好的计算activation的scale和zp。至少要喂上几百个迭代的数据,

per tensor 和 per channel。Per tensor 是说一个tensor里的所有value按照同一种方式去scale和offset; per channel是对于tensor的某一个维度(通常是channel的维度)上的值按照一种方式去scale和offset,也就是一个tensor里有多种不同的scale和offset的方式(组成一个vector),如此以来,在量化的时候相比per tensor的方式会引入更少的错误。PyTorch目前支持conv2d()、conv3d()、linear()的per channel量化。

torch.cat()使用方法

def data_to_pkl():

torch.cat() 可以对tensor进行上下或左右拼接,其传入的参数为:

dim 控制拼接的维度, dim=0 with codecs.open('middle/renmin2.txt','r',encoding='utf-8') as inp,为上下拼接, dim=1 为左右拼接 [1] 。

下面是实例详解: