This commit is contained in:
610
docs/version2.x/ppocr/model_compress/knowledge_distillation.en.md
Executable file
610
docs/version2.x/ppocr/model_compress/knowledge_distillation.en.md
Executable file
@@ -0,0 +1,610 @@
|
||||
---
|
||||
comments: true
|
||||
---
|
||||
|
||||
# Knowledge Distillation
|
||||
|
||||
## 1. Introduction
|
||||
|
||||
### 1.1 Introduction to Knowledge Distillation
|
||||
|
||||
In recent years, deep neural networks have been proved to be an extremely effective method for solving problems in the fields of computer vision and natural language processing.
|
||||
By constructing a suitable neural network and training it, the performance metrics of the final network model will basically exceed the traditional algorithm.
|
||||
When the amount of data is large enough, increasing the amount of parameters by constructing a reasonable network model can significantly improve the performance of the model,
|
||||
but this brings about the problem of a sharp increase in the complexity of the model. Large models are more expensive to use in actual scenarios.
|
||||
Deep neural networks generally have more parameter redundancy. At present, there are several main methods to compress the model and reduce the amount of its parameters.
|
||||
Such as pruning, quantification, knowledge distillation, etc., where knowledge distillation refers to the use of teacher models to guide student models to learn specific tasks,
|
||||
to ensure that the small model obtains a relatively large performance improvement under the condition of unchanged parameters.
|
||||
In addition, in the knowledge distillation task, a mutual learning model training method was also derived.
|
||||
The paper [Deep Mutual Learning](https://arxiv.org/abs/1706.00384) pointed out that using two identical models to supervise each other during the training process can achieve better results than a single model training.
|
||||
|
||||
### 1.2 Introduction to PaddleOCR Knowledge Distillation
|
||||
|
||||
Whether it is a large model distilling a small model, or a small model learning from each other and updating parameters,
|
||||
they are essentially the output between different models or mutual supervision between feature maps.
|
||||
The only difference is (1) whether the model requires fixed parameters. (2) Whether the model needs to be loaded with a pre-trained model.
|
||||
For the case where a large model distills a small model, the large model generally needs to load the pre-trained model and fix the parameters.
|
||||
For the situation where small models distill each other, the small models generally do not load the pre-trained model, and the parameters are also in a learnable state.
|
||||
|
||||
In the task of knowledge distillation, it is not only the distillation between two models, but also the situation where multiple models learn from each other.
|
||||
Therefore, in the knowledge distillation code framework, it is also necessary to support this type of distillation method.
|
||||
|
||||
The algorithm of knowledge distillation is integrated in PaddleOCR. Specifically, it has the following main features:
|
||||
|
||||
- It supports mutual learning of any network, and does not require the sub-network structure to be completely consistent or to have a pre-trained model. At the same time, there is no limit to the number of sub-networks, just add it in the configuration file.
|
||||
- Support arbitrarily configuring the loss function through the configuration file, not only can use a certain loss, but also a combination of multiple losses.
|
||||
- Support all model-related environments such as knowledge distillation training, prediction, evaluation, and export, which is convenient for use and deployment.
|
||||
|
||||
Through knowledge distillation, in the common Chinese and English text recognition task, without adding any time-consuming prediction,
|
||||
the accuracy of the model can be improved by more than 3%. Combining the learning rate adjustment strategy and the model structure fine-tuning strategy,
|
||||
the final improvement is more than 5%.
|
||||
|
||||
## 2. Configuration File Analysis
|
||||
|
||||
In the process of knowledge distillation training, there is no change in data preprocessing, optimizer, learning rate, and some global attributes.
|
||||
The configuration files of the model structure, loss function, post-processing, metric calculation and other modules need to be fine-tuned.
|
||||
|
||||
The following takes the knowledge distillation configuration file for recognition and detection as an example to analyze the training and configuration of knowledge distillation.
|
||||
|
||||
### 2.1 Recognition Model Configuration File Analysis
|
||||
|
||||
The configuration file is in [ch_PP-OCRv2_rec_distillation.yml](https://github.com/PaddlePaddle/PaddleOCR/tree/main/configs/rec/ch_PP-OCRv2/ch_PP-OCRv2_rec_distillation.yml).
|
||||
|
||||
#### 2.1.1 Model Structure
|
||||
|
||||
In the knowledge distillation task, the model structure configuration is as follows.
|
||||
|
||||
```yaml linenums="1"
|
||||
Architecture:
|
||||
model_type: &model_type "rec" # Model category, recognition, detection, etc.
|
||||
name: DistillationModel # Structure name, in the distillation task, it is DistillationModel
|
||||
algorithm: Distillation # Algorithm name
|
||||
Models: # Model, including the configuration information of the subnet
|
||||
Teacher: # The name of the subnet, it must include at least the `pretrained` and `freeze_params` parameters, and the other parameters are the construction parameters of the subnet
|
||||
pretrained: # Does this sub-network need to load pre-training weights
|
||||
freeze_params: false # Do you need fixed parameters
|
||||
return_all_feats: true # Do you need to return all features, if it is False, only the final output is returned
|
||||
model_type: *model_type # Model category
|
||||
algorithm: SVTR # The algorithm name of the sub-network. The remaining parameters of the sub-network are consistent with the general model training configuration
|
||||
Transform:
|
||||
Backbone:
|
||||
name: MobileNetV1Enhance
|
||||
scale: 0.5
|
||||
last_conv_stride: [1, 2]
|
||||
last_pool_type: avg
|
||||
Head:
|
||||
name: MultiHead
|
||||
head_list:
|
||||
- CTCHead:
|
||||
Neck:
|
||||
name: svtr
|
||||
dims: 64
|
||||
depth: 2
|
||||
hidden_dims: 120
|
||||
use_guide: True
|
||||
Head:
|
||||
fc_decay: 0.00001
|
||||
- SARHead:
|
||||
enc_dim: 512
|
||||
max_text_length: *max_text_length
|
||||
Student: # Another sub-network, here is a distillation example of DML, the two sub-networks have the same structure, and both need to learn parameters
|
||||
pretrained: # The following parameters are the same as above
|
||||
freeze_params: false
|
||||
return_all_feats: true
|
||||
model_type: *model_type
|
||||
algorithm: SVTR
|
||||
Transform:
|
||||
Backbone:
|
||||
name: MobileNetV1Enhance
|
||||
scale: 0.5
|
||||
last_conv_stride: [1, 2]
|
||||
last_pool_type: avg
|
||||
Head:
|
||||
name: MultiHead
|
||||
head_list:
|
||||
- CTCHead:
|
||||
Neck:
|
||||
name: svtr
|
||||
dims: 64
|
||||
depth: 2
|
||||
hidden_dims: 120
|
||||
use_guide: True
|
||||
Head:
|
||||
fc_decay: 0.00001
|
||||
- SARHead:
|
||||
enc_dim: 512
|
||||
max_text_length: *max_text_length
|
||||
```
|
||||
|
||||
If you want to add more sub-networks for training, you can also add the corresponding fields in the configuration file according to the way of adding `Student` and `Teacher`.
|
||||
For example, if you want 3 models to supervise each other and train together, then `Architecture` can be written in the following format.
|
||||
|
||||
```yaml linenums="1"
|
||||
Architecture:
|
||||
model_type: &model_type "rec"
|
||||
name: DistillationModel
|
||||
algorithm: Distillation
|
||||
Models:
|
||||
Teacher:
|
||||
pretrained:
|
||||
freeze_params: false
|
||||
return_all_feats: true
|
||||
model_type: *model_type
|
||||
algorithm: SVTR
|
||||
Transform:
|
||||
Backbone:
|
||||
name: MobileNetV1Enhance
|
||||
scale: 0.5
|
||||
last_conv_stride: [1, 2]
|
||||
last_pool_type: avg
|
||||
Head:
|
||||
name: MultiHead
|
||||
head_list:
|
||||
- CTCHead:
|
||||
Neck:
|
||||
name: svtr
|
||||
dims: 64
|
||||
depth: 2
|
||||
hidden_dims: 120
|
||||
use_guide: True
|
||||
Head:
|
||||
fc_decay: 0.00001
|
||||
- SARHead:
|
||||
enc_dim: 512
|
||||
max_text_length: *max_text_length
|
||||
Student:
|
||||
pretrained:
|
||||
freeze_params: false
|
||||
return_all_feats: true
|
||||
model_type: *model_type
|
||||
algorithm: SVTR
|
||||
Transform:
|
||||
Backbone:
|
||||
name: MobileNetV1Enhance
|
||||
scale: 0.5
|
||||
last_conv_stride: [1, 2]
|
||||
last_pool_type: avg
|
||||
Head:
|
||||
name: MultiHead
|
||||
head_list:
|
||||
- CTCHead:
|
||||
Neck:
|
||||
name: svtr
|
||||
dims: 64
|
||||
depth: 2
|
||||
hidden_dims: 120
|
||||
use_guide: True
|
||||
Head:
|
||||
fc_decay: 0.00001
|
||||
- SARHead:
|
||||
enc_dim: 512
|
||||
max_text_length: *max_text_length
|
||||
Student2:
|
||||
pretrained:
|
||||
freeze_params: false
|
||||
return_all_feats: true
|
||||
model_type: *model_type
|
||||
algorithm: SVTR
|
||||
Transform:
|
||||
Backbone:
|
||||
name: MobileNetV1Enhance
|
||||
scale: 0.5
|
||||
last_conv_stride: [1, 2]
|
||||
last_pool_type: avg
|
||||
Head:
|
||||
name: MultiHead
|
||||
head_list:
|
||||
- CTCHead:
|
||||
Neck:
|
||||
name: svtr
|
||||
dims: 64
|
||||
depth: 2
|
||||
hidden_dims: 120
|
||||
use_guide: True
|
||||
Head:
|
||||
fc_decay: 0.00001
|
||||
- SARHead:
|
||||
enc_dim: 512
|
||||
max_text_length: *max_text_length
|
||||
```
|
||||
|
||||
When the model is finally trained, it contains 3 sub-networks: `Teacher`, `Student`, `Student2`.
|
||||
|
||||
The specific implementation code of the `DistillationModel` class can refer to [distillation_model.py](../../ppocr/modeling/architectures/distillation_model.py).
|
||||
The final model output is a dictionary, the key is the name of all the sub-networks, for example, here are `Student` and `Teacher`, and the value is the output of the corresponding sub-network,
|
||||
which can be `Tensor` (only the last layer of the network is returned) and `dict` (also returns the characteristic information in the middle).
|
||||
In the recognition task, in order to add more loss functions and ensure the scalability of the distillation method, the output of each sub-network is saved as a `dict`, which contains the sub-module output.
|
||||
Take the recognition model as an example. The output result of each sub-network is `dict`, the key contains `backbone_out`, `neck_out`, `head_out`, and `value` is the tensor of the corresponding module. Finally, for the above configuration file, `DistillationModel` The output format is as follows.
|
||||
|
||||
```json
|
||||
{
|
||||
"Teacher": {
|
||||
"backbone_out": tensor,
|
||||
"neck_out": tensor,
|
||||
"head_out": tensor,
|
||||
},
|
||||
"Student": {
|
||||
"backbone_out": tensor,
|
||||
"neck_out": tensor,
|
||||
"head_out": tensor,
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.1.2 Loss Function
|
||||
|
||||
In the knowledge distillation task, the loss function configuration is as follows.
|
||||
|
||||
```yaml linenums="1"
|
||||
Loss:
|
||||
name: CombinedLoss # Loss function name
|
||||
loss_config_list: # List of loss function configuration files, mandatory functions for CombinedLoss
|
||||
- DistillationCTCLoss: # CTC loss function based on distillation, inherited from standard CTC loss
|
||||
weight: 1.0 # The weight of the loss function. In loss_config_list, each loss function must include this field
|
||||
model_name_list: ["Student", "Teacher"] # For the prediction results of the distillation model, extract the output of these two sub-networks and calculate the CTC loss with gt
|
||||
key: head_out # In the sub-network output dict, take the corresponding tensor
|
||||
- DistillationDMLLoss: # DML loss function, inherited from the standard DMLLoss
|
||||
weight: 1.0
|
||||
act: "softmax" # Activation function, use it to process the input, can be softmax, sigmoid or None, the default is None
|
||||
model_name_pairs: # The subnet name pair used to calculate DML loss. If you want to calculate the DML loss of other subnets, you can continue to add it below the list
|
||||
- ["Student", "Teacher"]
|
||||
key: head_out
|
||||
multi_head: True # whether to use mult_head
|
||||
dis_head: ctc # assign the head name to calculate loss
|
||||
name: dml_ctc # prefix name of the loss
|
||||
- DistillationDMLLoss: # DML loss function, inherited from the standard DMLLoss
|
||||
weight: 0.5
|
||||
act: "softmax" # Activation function, use it to process the input, can be softmax, sigmoid or None, the default is None
|
||||
model_name_pairs: # The subnet name pair used to calculate DML loss. If you want to calculate the DML loss of other subnets, you can continue to add it below the list
|
||||
- ["Student", "Teacher"]
|
||||
key: head_out
|
||||
multi_head: True # whether to use mult_head
|
||||
dis_head: sar # assign the head name to calculate loss
|
||||
name: dml_sar # prefix name of the loss
|
||||
- DistillationDistanceLoss: # Distilled distance loss function
|
||||
weight: 1.0
|
||||
mode: "l2" # Support l1, l2 or smooth_l1
|
||||
model_name_pairs: # Calculate the distance loss of the subnet name pair
|
||||
- ["Student", "Teacher"]
|
||||
key: backbone_out
|
||||
- DistillationSARLoss: # SAR loss function based on distillation, inherited from standard SAR loss
|
||||
weight: 1.0 # The weight of the loss function. In loss_config_list, each loss function must include this field
|
||||
model_name_list: ["Student", "Teacher"] # For the prediction results of the distillation model, extract the output of these two sub-networks and calculate the SAR loss with gt
|
||||
key: head_out # In the sub-network output dict, take the corresponding tensor
|
||||
multi_head: True # whether it is multi-head or not, if true, SAR branch is used to calculate the loss
|
||||
```
|
||||
|
||||
Among the above loss functions, all distillation loss functions are inherited from the standard loss function class.
|
||||
The main functions are: Analyze the output of the distillation model, find the intermediate node (tensor) used to calculate the loss,
|
||||
and then use the standard loss function class to calculate.
|
||||
|
||||
Taking the above configuration as an example, the final distillation training loss function contains the following five parts.
|
||||
|
||||
- CTC branch of the final output `head_out` for `Student` and `Teacher` calculates the CTC loss with gt (loss weight equals 1.0). Here, because both sub-networks need to update the parameters, both of them need to calculate the loss with gt.
|
||||
- SAR branch of the final output `head_out` for `Student` and `Teacher` calculates the SAR loss with gt (loss weight equals 1.0). Here, because both sub-networks need to update the parameters, both of them need to calculate the loss with gt.
|
||||
- DML loss between CTC branch of `Student` and `Teacher`'s final output `head_out` (loss weight equals 1.0).
|
||||
- DML loss between SAR branch of `Student` and `Teacher`'s final output `head_out` (loss weight equals 0.5).
|
||||
- L2 loss between `Student` and `Teacher`'s backbone network output `backbone_out` (loss weight equals 1.0).
|
||||
|
||||
For more specific implementation of `CombinedLoss`, please refer to: [combined_loss.py](../../ppocr/losses/combined_loss.py#L23).
|
||||
For more specific implementations of distillation loss functions such as `DistillationCTCLoss`, please refer to [distillation_loss.py](../../ppocr/losses/distillation_loss.py)
|
||||
|
||||
#### 2.1.3 Post-processing
|
||||
|
||||
In the knowledge distillation task, the post-processing configuration is as follows.
|
||||
|
||||
```yaml linenums="1"
|
||||
PostProcess:
|
||||
name: DistillationCTCLabelDecode # CTC decoding post-processing of distillation tasks, inherited from the standard CTCLabelDecode class
|
||||
model_name: ["Student", "Teacher"] # For the prediction results of the distillation model, extract the outputs of these two sub-networks and decode them
|
||||
key: head_out # Take the corresponding tensor in the subnet output dict
|
||||
multi_head: True # whether it is multi-head or not, if true, CTC branch is used to calculate the loss
|
||||
```
|
||||
|
||||
Taking the above configuration as an example, the CTC decoding output of the two sub-networks `Student` and `Teacher` will be calculated at the same time.
|
||||
Among them, `key` is the name of the subnet, and `value` is the list of subnets.
|
||||
|
||||
For more specific implementation of `DistillationCTCLabelDecode`, please refer to: [rec_postprocess.py](../../ppocr/postprocess/rec_postprocess.py#L128)
|
||||
|
||||
#### 2.1.4 Metric Calculation
|
||||
|
||||
In the knowledge distillation task, the metric calculation configuration is as follows.
|
||||
|
||||
```yaml linenums="1"
|
||||
Metric:
|
||||
name: DistillationMetric # CTC decoding post-processing of distillation tasks, inherited from the standard CTCLabelDecode class
|
||||
base_metric_name: RecMetric # The base class of indicator calculation. For the output of the model, the indicator will be calculated based on this class
|
||||
main_indicator: acc # The name of the indicator
|
||||
key: "Student" # Select the main_indicator of this subnet as the criterion for saving the best model
|
||||
ignore_space: False # whether to ignore space during evaluation
|
||||
```
|
||||
|
||||
Taking the above configuration as an example, the accuracy metric of the `Student` subnet will be used as the judgment metric for saving the best model.
|
||||
At the same time, the accuracy metric of all subnets will be printed out in the log.
|
||||
|
||||
For more specific implementation of `DistillationMetric`, please refer to: [distillation_metric.py](../../ppocr/metrics/distillation_metric.py#L24).
|
||||
|
||||
#### 2.1.5 Fine-tuning Distillation Model
|
||||
|
||||
There are two ways to fine-tune the recognition distillation task.
|
||||
|
||||
1. Fine-tuning based on knowledge distillation: this situation is relatively simple, download the pre-trained model. Then configure the pre-training model path and your own data path in [PP-OCRv3_mobile_rec_distillation.yml](https://github.com/PaddlePaddle/PaddleOCR/tree/main/configs/rec/PP-OCRv3/PP-OCRv3_mobile_rec_distillation.yml) to perform fine-tuning training of the model.
|
||||
2. Do not use knowledge distillation in fine-tuning: In this case, you need to first extract the student model parameters from the pre-training model. The specific steps are as follows.
|
||||
|
||||
- First download the pre-trained model and unzip it.
|
||||
|
||||
```bash linenums="1"
|
||||
wget https://paddleocr.bj.bcebos.com/PP-OCRv3/chinese/ch_PP-OCRv3_rec_train.tar
|
||||
tar -xf ch_PP-OCRv3_rec_train.tar
|
||||
```
|
||||
|
||||
- Then use python to extract the student model parameters
|
||||
|
||||
```python linenums="1"
|
||||
import paddle
|
||||
# Load the pre-trained model
|
||||
all_params = paddle.load("ch_PP-OCRv3_rec_train/best_accuracy.pdparams")
|
||||
# View the keys of the weight parameter
|
||||
print(all_params.keys())
|
||||
# Weight extraction of student model
|
||||
s_params = {key[len("Student."):]: all_params[key] for key in all_params if "Student." in key}
|
||||
# View the keys of the weight parameters of the student model
|
||||
print(s_params.keys())
|
||||
# Save weight parameters
|
||||
paddle.save(s_params, "ch_PP-OCRv3_rec_train/student.pdparams")
|
||||
```
|
||||
|
||||
After the extraction is complete, use [PP-OCRv3_mobile_rec.yml](https://github.com/PaddlePaddle/PaddleOCR/tree/main/configs/rec/PP-OCRv3/PP-OCRv3_mobile_rec.yml) to modify the path of the pre-trained model (the path of the exported `student.pdparams` model) and your own data path to fine-tune the model.
|
||||
|
||||
### 2.2 Detection Model Configuration File Analysis
|
||||
|
||||
The configuration file of the detection model distillation is in the ```PaddleOCR/configs/det/ch_PP-OCRv3/``` directory, which contains three distillation configuration files:
|
||||
|
||||
- ```PP-OCRv3_det_cml.yml```, Use one large model to distill two small models, and the two small models learn from each other
|
||||
- ```PP-OCRv3_det_dml.yml```, Method of mutual distillation of two student models
|
||||
|
||||
#### 2.2.1 Model Structure
|
||||
|
||||
In the knowledge distillation task, the model structure configuration is as follows:
|
||||
|
||||
```yaml linenums="1"
|
||||
Architecture:
|
||||
name: DistillationModel # Structure name, in the distillation task, it is DistillationModel
|
||||
algorithm: Distillation # Algorithm name
|
||||
Models: # Model, including the configuration information of the subnet
|
||||
Student: # The name of the subnet, it must include at least the `pretrained` and `freeze_params` parameters, and the other parameters are the construction parameters of the subnet
|
||||
pretrained: ./pretrain_models/MobileNetV3_large_x0_5_pretrained # Does this sub-network need to load pre-training weights
|
||||
freeze_params: false # Do you need fixed parameters
|
||||
return_all_feats: false # Do you need to return all features, if it is False, only the final output is returned
|
||||
model_type: det
|
||||
algorithm: DB
|
||||
Backbone:
|
||||
name: ResNet
|
||||
in_channels: 3
|
||||
layers: 50
|
||||
Neck:
|
||||
name: LKPAN
|
||||
out_channels: 256
|
||||
Head:
|
||||
name: DBHead
|
||||
kernel_list: [7,2,2]
|
||||
k: 50
|
||||
Teacher: # Another sub-network, here is a distillation example of a large model distill a small model
|
||||
pretrained: ./pretrain_models/ch_ppocr_server_v2.0_det_train/best_accuracy
|
||||
return_all_feats: false
|
||||
model_type: det
|
||||
algorithm: DB
|
||||
Transform:
|
||||
Backbone:
|
||||
name: ResNet
|
||||
in_channels: 3
|
||||
layers: 50
|
||||
Neck:
|
||||
name: LKPAN
|
||||
out_channels: 256
|
||||
Head:
|
||||
name: DBHead
|
||||
kernel_list: [7,2,2]
|
||||
k: 50
|
||||
|
||||
```
|
||||
|
||||
If DML is used, that is, the method of two small models learning from each other, the Teacher network structure in the above configuration file needs to be set to the same configuration as the Student model.
|
||||
Refer to the configuration file for details. [PP-OCRv3_det_dml.yml](https://github.com/PaddlePaddle/PaddleOCR/tree/main/configs/det/PP-OCRv3/PP-OCRv3_det_dml.yml)
|
||||
|
||||
The following describes the configuration file parameters [PP-OCRv3_det_cml.yml](https://github.com/PaddlePaddle/PaddleOCR/tree/main/configs/det/PP-OCRv3/PP-OCRv3_mobile_det.yml):
|
||||
|
||||
```yaml linenums="1"
|
||||
Architecture:
|
||||
name: DistillationModel
|
||||
algorithm: Distillation
|
||||
model_type: det
|
||||
Models:
|
||||
Teacher: # Teacher model configuration of CML distillation
|
||||
pretrained: ./pretrain_models/ch_ppocr_server_v2.0_det_train/best_accuracy
|
||||
freeze_params: true # Teacher does not train
|
||||
return_all_feats: false
|
||||
model_type: det
|
||||
algorithm: DB
|
||||
Transform:
|
||||
Backbone:
|
||||
name: ResNet
|
||||
in_channels: 3
|
||||
layers: 50
|
||||
Neck:
|
||||
name: LKPAN
|
||||
out_channels: 256
|
||||
Head:
|
||||
name: DBHead
|
||||
kernel_list: [7,2,2]
|
||||
k: 50
|
||||
Student: # Student model configuration for CML distillation
|
||||
pretrained: ./pretrain_models/MobileNetV3_large_x0_5_pretrained
|
||||
freeze_params: false
|
||||
return_all_feats: false
|
||||
model_type: det
|
||||
algorithm: DB
|
||||
Backbone:
|
||||
name: MobileNetV3
|
||||
scale: 0.5
|
||||
model_name: large
|
||||
disable_se: true
|
||||
Neck:
|
||||
name: RSEFPN
|
||||
out_channels: 96
|
||||
shortcut: True
|
||||
Head:
|
||||
name: DBHead
|
||||
k: 50
|
||||
Student2: # Student2 model configuration for CML distillation
|
||||
pretrained: ./pretrain_models/MobileNetV3_large_x0_5_pretrained
|
||||
freeze_params: false
|
||||
return_all_feats: false
|
||||
model_type: det
|
||||
algorithm: DB
|
||||
Transform:
|
||||
Backbone:
|
||||
name: MobileNetV3
|
||||
scale: 0.5
|
||||
model_name: large
|
||||
disable_se: true
|
||||
Neck:
|
||||
name: RSEFPN
|
||||
out_channels: 96
|
||||
shortcut: True
|
||||
Head:
|
||||
name: DBHead
|
||||
k: 50
|
||||
|
||||
```
|
||||
|
||||
The specific implementation code of the distillation model `DistillationModel` class can refer to [distillation_model.py](../../ppocr/modeling/architectures/distillation_model.py).
|
||||
|
||||
The final model output is a dictionary, the key is the name of all the sub-networks, for example, here are `Student` and `Teacher`, and the value is the output of the corresponding sub-network,
|
||||
which can be `Tensor` (only the last layer of the network is returned) and `dict` (also returns the characteristic information in the middle).
|
||||
|
||||
In the distillation task, in order to facilitate the addition of the distillation loss function, the output of each network is saved as a `dict`, which contains the sub-module output.
|
||||
The key contains `backbone_out`, `neck_out`, `head_out`, and `value` is the tensor of the corresponding module. Finally, for the above configuration file, the output format of `DistillationModel` is as follows.
|
||||
|
||||
```json
|
||||
{
|
||||
"Teacher": {
|
||||
"backbone_out": tensor,
|
||||
"neck_out": tensor,
|
||||
"head_out": tensor,
|
||||
},
|
||||
"Student": {
|
||||
"backbone_out": tensor,
|
||||
"neck_out": tensor,
|
||||
"head_out": tensor,
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.2.2 Loss Function
|
||||
|
||||
The distillation loss function configuration(`PP-OCRv3_det_cml.yml`) is shown below.
|
||||
|
||||
```yaml linenums="1"
|
||||
Loss:
|
||||
name: CombinedLoss
|
||||
loss_config_list:
|
||||
- DistillationDilaDBLoss:
|
||||
weight: 1.0
|
||||
model_name_pairs:
|
||||
- ["Student", "Teacher"]
|
||||
- ["Student2", "Teacher"] # 1. Calculate the loss of two Student and Teacher
|
||||
key: maps
|
||||
balance_loss: true
|
||||
main_loss_type: DiceLoss
|
||||
alpha: 5
|
||||
beta: 10
|
||||
ohem_ratio: 3
|
||||
- DistillationDMLLoss: # 2. Add to calculate the loss between two students
|
||||
model_name_pairs:
|
||||
- ["Student", "Student2"]
|
||||
maps_name: "thrink_maps"
|
||||
weight: 1.0
|
||||
# act: None
|
||||
key: maps
|
||||
- DistillationDBLoss:
|
||||
weight: 1.0
|
||||
model_name_list: ["Student", "Student2"] # 3. Calculate the loss between two students and GT
|
||||
balance_loss: true
|
||||
main_loss_type: DiceLoss
|
||||
alpha: 5
|
||||
beta: 10
|
||||
ohem_ratio: 3
|
||||
```
|
||||
|
||||
For more specific implementation of `DistillationDilaDBLoss`, please refer to: [distillation_loss.py](https://github.com/PaddlePaddle/PaddleOCR/blob/release%2F2.4/ppocr/losses/distillation_loss.py#L185).
|
||||
For more specific implementations of distillation loss functions such as `DistillationDBLoss`, please refer to: [distillation_loss.py](https://github.com/PaddlePaddle/PaddleOCR/blob/04c44974b13163450dfb6bd2c327863f8a194b3c/ppocr/losses/distillation_loss.py?_pjax=%23js-repo-pjax-container%2C%20div%5Bitemtype%3D%22http%3A%2F%2Fschema.org%2FSoftwareSourceCode%22%5D%20main%2C%20%5Bdata-pjax-container%5D#L148)
|
||||
|
||||
#### 2.2.3 Post-processing
|
||||
|
||||
In the task of detecting knowledge distillation, the post-processing configuration of detecting distillation is as follows.
|
||||
|
||||
```yaml linenums="1"
|
||||
PostProcess:
|
||||
name: DistillationDBPostProcess # The post-processing of the DB detection distillation task, inherited from the standard DBPostProcess class
|
||||
model_name: ["Student", "Student2", "Teacher"] # Extract the output of multiple sub-networks and decode them. The network that does not require post-processing is not set in model_name
|
||||
thresh: 0.3
|
||||
box_thresh: 0.6
|
||||
max_candidates: 1000
|
||||
unclip_ratio: 1.5
|
||||
```
|
||||
|
||||
Taking the above configuration as an example, the output of the three subnets `Student`, `Student2` and `Teacher` will be calculated at the same time for post-processing calculations.
|
||||
Since there are multiple inputs, there are also multiple outputs returned by post-processing.
|
||||
For a more specific implementation of `DistillationDBPostProcess`, please refer to: [db_postprocess.py](../../ppocr/postprocess/db_postprocess.py#L195)
|
||||
|
||||
#### 2.2.4 Metric Calculation
|
||||
|
||||
In the knowledge distillation task, the metric calculation configuration is as follows.
|
||||
|
||||
```yaml linenums="1"
|
||||
Metric:
|
||||
name: DistillationMetric
|
||||
base_metric_name: DetMetric
|
||||
main_indicator: hmean
|
||||
key: "Student"
|
||||
```
|
||||
|
||||
Since distillation needs to include multiple networks, only one network metrics needs to be calculated when calculating the metrics.
|
||||
The `key` field is set to `Student`, it means that only the metrics of the `Student` network is calculated.
|
||||
Model Structure
|
||||
|
||||
#### 2.2.5 Fine-tuning Distillation Model
|
||||
|
||||
There are three ways to fine-tune the detection distillation task:
|
||||
|
||||
- `ch_PP-OCRv3_det_distill.yml`, The teacher model is set to the model provided by PaddleOCR or the large model you have trained.
|
||||
- `PP-OCRv3_det_cml.yml`, Use cml distillation. Similarly, the Teacher model is set to the model provided by PaddleOCR or the large model you have trained.
|
||||
- `PP-OCRv3_det_dml.yml`, Distillation using DML. The method of mutual distillation of the two Student models has an accuracy improvement of about 1.7% on the data set used by PaddleOCR.
|
||||
|
||||
In fine-tune, you need to set the pre-trained model to be loaded in the `pretrained` parameter of the network structure.
|
||||
|
||||
In terms of accuracy improvement, `cml` > `dml` > `distill`. When the amount of data is insufficient or the accuracy of the teacher model is similar to that of the student, this conclusion may change.
|
||||
|
||||
In addition, since the distillation pre-training model provided by PaddleOCR contains multiple model parameters, if you want to extract the parameters of the student model, you can refer to the following code:
|
||||
|
||||
```sh
|
||||
# Download the parameters of the distillation training model
|
||||
wget https://paddle-model-ecology.bj.bcebos.com/paddlex/official_pretrained_model/PP-OCRv3_mobile_det_pretrained.pdparams
|
||||
```
|
||||
|
||||
```python linenums="1"
|
||||
import paddle
|
||||
# Load the pre-trained model
|
||||
all_params = paddle.load("ch_PP-OCRv3_det_distill_train/best_accuracy.pdparams")
|
||||
# View the keys of the weight parameter
|
||||
print(all_params.keys())
|
||||
# Extract the weights of the student model
|
||||
s_params = {key[len("Student."):]: all_params[key] for key in all_params if "Student." in key}
|
||||
# View the keys of the weight parameters of the student model
|
||||
print(s_params.keys())
|
||||
# Save
|
||||
paddle.save(s_params, "ch_PP-OCRv3_det_distill_train/student.pdparams")
|
||||
```
|
||||
|
||||
Finally, the parameters of the student model will be saved in `ch_PP-OCRv3_det_distill_train/student.pdparams` for the fine-tune of the model.
|
||||
593
docs/version2.x/ppocr/model_compress/knowledge_distillation.md
Normal file
593
docs/version2.x/ppocr/model_compress/knowledge_distillation.md
Normal file
@@ -0,0 +1,593 @@
|
||||
---
|
||||
comments: true
|
||||
---
|
||||
|
||||
# 知识蒸馏
|
||||
|
||||
## 1. 简介
|
||||
|
||||
### 1.1 知识蒸馏介绍
|
||||
|
||||
近年来,深度神经网络在计算机视觉、自然语言处理等领域被验证是一种极其有效的解决问题的方法。通过构建合适的神经网络,加以训练,最终网络模型的性能指标基本上都会超过传统算法。
|
||||
|
||||
在数据量足够大的情况下,通过合理构建网络模型的方式增加其参数量,可以显著改善模型性能,但是这又带来了模型复杂度急剧提升的问题。大模型在实际场景中使用的成本较高。
|
||||
|
||||
深度神经网络一般有较多的参数冗余,目前有几种主要的方法对模型进行压缩,减小其参数量。如裁剪、量化、知识蒸馏等,其中知识蒸馏是指使用教师模型(teacher model)去指导学生模型(student model)学习特定任务,保证小模型在参数量不变的情况下,得到比较大的性能提升。
|
||||
|
||||
此外,在知识蒸馏任务中,也衍生出了互学习的模型训练方法,论文[Deep Mutual Learning](https://arxiv.org/abs/1706.00384)中指出,使用两个完全相同的模型在训练的过程中互相监督,可以达到比单个模型训练更好的效果。
|
||||
|
||||
### 1.2 PaddleOCR知识蒸馏简介
|
||||
|
||||
无论是大模型蒸馏小模型,还是小模型之间互相学习,更新参数,他们本质上是都是不同模型之间输出或者特征图(feature map)之间的相互监督,区别仅在于 (1) 模型是否需要固定参数。(2) 模型是否需要加载预训练模型。
|
||||
|
||||
对于大模型蒸馏小模型的情况,大模型一般需要加载预训练模型并固定参数;对于小模型之间互相蒸馏的情况,小模型一般都不加载预训练模型,参数也都是可学习的状态。
|
||||
|
||||
在知识蒸馏任务中,不只有2个模型之间进行蒸馏的情况,多个模型之间互相学习的情况也非常普遍。因此在知识蒸馏代码框架中,也有必要支持该种类别的蒸馏方法。
|
||||
|
||||
PaddleOCR中集成了知识蒸馏的算法,具体地,有以下几个主要的特点:
|
||||
|
||||
- 支持任意网络的互相学习,不要求子网络结构完全一致或者具有预训练模型;同时子网络数量也没有任何限制,只需要在配置文件中添加即可。
|
||||
- 支持loss函数通过配置文件任意配置,不仅可以使用某种loss,也可以使用多种loss的组合
|
||||
- 支持知识蒸馏训练、预测、评估与导出等所有模型相关的环境,方便使用与部署。
|
||||
|
||||
通过知识蒸馏,在中英文通用文字识别任务中,不增加任何预测耗时的情况下,可以给模型带来3%以上的精度提升,结合学习率调整策略以及模型结构微调策略,最终提升提升超过5%。
|
||||
|
||||
## 2. 配置文件解析
|
||||
|
||||
在知识蒸馏训练的过程中,数据预处理、优化器、学习率、全局的一些属性没有任何变化。模型结构、损失函数、后处理、指标计算等模块的配置文件需要进行微调。
|
||||
|
||||
下面以识别与检测的知识蒸馏配置文件为例,对知识蒸馏的训练与配置进行解析。
|
||||
|
||||
### 2.1 识别配置文件解析
|
||||
|
||||
配置文件在[PP-OCRv3_mobile_rec_distillation.yml](https://github.com/PaddlePaddle/PaddleOCR/tree/main/configs/rec/PP-OCRv3/PP-OCRv3_mobile_rec_distillation.yml)。
|
||||
|
||||
#### 2.1.1 模型结构
|
||||
|
||||
知识蒸馏任务中,模型结构配置如下所示。
|
||||
|
||||
```yaml linenums="1"
|
||||
Architecture:
|
||||
model_type: &model_type "rec" # 模型类别,rec、det等,每个子网络的模型类别
|
||||
name: DistillationModel # 结构名称,蒸馏任务中,为DistillationModel,用于构建对应的结构
|
||||
algorithm: Distillation # 算法名称
|
||||
Models: # 模型,包含子网络的配置信息
|
||||
Teacher: # 子网络名称,至少需要包含`pretrained`与`freeze_params`信息,其他的参数为子网络的构造参数
|
||||
pretrained: # 该子网络是否需要加载预训练模型
|
||||
freeze_params: false # 是否需要固定参数
|
||||
return_all_feats: true # 子网络的参数,表示是否需要返回所有的features,如果为False,则只返回最后的输出
|
||||
model_type: *model_type # 模型类别
|
||||
algorithm: SVTR # 子网络的算法名称,该子网络其余参数均为构造参数,与普通的模型训练配置一致
|
||||
Transform:
|
||||
Backbone:
|
||||
name: MobileNetV1Enhance
|
||||
scale: 0.5
|
||||
last_conv_stride: [1, 2]
|
||||
last_pool_type: avg
|
||||
Head:
|
||||
name: MultiHead
|
||||
head_list:
|
||||
- CTCHead:
|
||||
Neck:
|
||||
name: svtr
|
||||
dims: 64
|
||||
depth: 2
|
||||
hidden_dims: 120
|
||||
use_guide: True
|
||||
Head:
|
||||
fc_decay: 0.00001
|
||||
- SARHead:
|
||||
enc_dim: 512
|
||||
max_text_length: *max_text_length
|
||||
Student:
|
||||
pretrained:
|
||||
freeze_params: false
|
||||
return_all_feats: true
|
||||
model_type: *model_type
|
||||
algorithm: SVTR
|
||||
Transform:
|
||||
Backbone:
|
||||
name: MobileNetV1Enhance
|
||||
scale: 0.5
|
||||
last_conv_stride: [1, 2]
|
||||
last_pool_type: avg
|
||||
Head:
|
||||
name: MultiHead
|
||||
head_list:
|
||||
- CTCHead:
|
||||
Neck:
|
||||
name: svtr
|
||||
dims: 64
|
||||
depth: 2
|
||||
hidden_dims: 120
|
||||
use_guide: True
|
||||
Head:
|
||||
fc_decay: 0.00001
|
||||
- SARHead:
|
||||
enc_dim: 512
|
||||
max_text_length: *max_text_length
|
||||
```
|
||||
|
||||
当然,这里如果希望添加更多的子网络进行训练,也可以按照`Student`与`Teacher`的添加方式,在配置文件中添加相应的字段。比如说如果希望有3个模型互相监督,共同训练,那么`Architecture`可以写为如下格式。
|
||||
|
||||
```yaml linenums="1"
|
||||
Architecture:
|
||||
model_type: &model_type "rec"
|
||||
name: DistillationModel
|
||||
algorithm: Distillation
|
||||
Models:
|
||||
Teacher:
|
||||
pretrained:
|
||||
freeze_params: false
|
||||
return_all_feats: true
|
||||
model_type: *model_type
|
||||
algorithm: SVTR
|
||||
Transform:
|
||||
Backbone:
|
||||
name: MobileNetV1Enhance
|
||||
scale: 0.5
|
||||
last_conv_stride: [1, 2]
|
||||
last_pool_type: avg
|
||||
Head:
|
||||
name: MultiHead
|
||||
head_list:
|
||||
- CTCHead:
|
||||
Neck:
|
||||
name: svtr
|
||||
dims: 64
|
||||
depth: 2
|
||||
hidden_dims: 120
|
||||
use_guide: True
|
||||
Head:
|
||||
fc_decay: 0.00001
|
||||
- SARHead:
|
||||
enc_dim: 512
|
||||
max_text_length: *max_text_length
|
||||
Student:
|
||||
pretrained:
|
||||
freeze_params: false
|
||||
return_all_feats: true
|
||||
model_type: *model_type
|
||||
algorithm: SVTR
|
||||
Transform:
|
||||
Backbone:
|
||||
name: MobileNetV1Enhance
|
||||
scale: 0.5
|
||||
last_conv_stride: [1, 2]
|
||||
last_pool_type: avg
|
||||
Head:
|
||||
name: MultiHead
|
||||
head_list:
|
||||
- CTCHead:
|
||||
Neck:
|
||||
name: svtr
|
||||
dims: 64
|
||||
depth: 2
|
||||
hidden_dims: 120
|
||||
use_guide: True
|
||||
Head:
|
||||
fc_decay: 0.00001
|
||||
- SARHead:
|
||||
enc_dim: 512
|
||||
max_text_length: *max_text_length
|
||||
Student2:
|
||||
pretrained:
|
||||
freeze_params: false
|
||||
return_all_feats: true
|
||||
model_type: *model_type
|
||||
algorithm: SVTR
|
||||
Transform:
|
||||
Backbone:
|
||||
name: MobileNetV1Enhance
|
||||
scale: 0.5
|
||||
last_conv_stride: [1, 2]
|
||||
last_pool_type: avg
|
||||
Head:
|
||||
name: MultiHead
|
||||
head_list:
|
||||
- CTCHead:
|
||||
Neck:
|
||||
name: svtr
|
||||
dims: 64
|
||||
depth: 2
|
||||
hidden_dims: 120
|
||||
use_guide: True
|
||||
Head:
|
||||
fc_decay: 0.00001
|
||||
- SARHead:
|
||||
enc_dim: 512
|
||||
max_text_length: *max_text_length
|
||||
```
|
||||
|
||||
最终该模型训练时,包含3个子网络:`Teacher`, `Student`, `Student2`。
|
||||
|
||||
蒸馏模型`DistillationModel`类的具体实现代码可以参考[distillation_model.py](../../ppocr/modeling/architectures/distillation_model.py)。
|
||||
|
||||
最终模型`forward`输出为一个字典,key为所有的子网络名称,例如这里为`Student`与`Teacher`,value为对应子网络的输出,可以为`Tensor`(只返回该网络的最后一层)和`dict`(也返回了中间的特征信息)。
|
||||
|
||||
在识别任务中,为了添加更多损失函数,保证蒸馏方法的可扩展性,将每个子网络的输出保存为`dict`,其中包含子模块输出。以该识别模型为例,每个子网络的输出结果均为`dict`,key包含`backbone_out`,`neck_out`, `head_out`,`value`为对应模块的tensor,最终对于上述配置文件,`DistillationModel`的输出格式如下:
|
||||
|
||||
```json
|
||||
{
|
||||
"Teacher": {
|
||||
"backbone_out": tensor,
|
||||
"neck_out": tensor,
|
||||
"head_out": tensor,
|
||||
},
|
||||
"Student": {
|
||||
"backbone_out": tensor,
|
||||
"neck_out": tensor,
|
||||
"head_out": tensor,
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.1.2 损失函数
|
||||
|
||||
知识蒸馏任务中,损失函数配置如下所示。
|
||||
|
||||
```yaml linenums="1"
|
||||
Loss:
|
||||
name: CombinedLoss
|
||||
loss_config_list:
|
||||
- DistillationDMLLoss: # 蒸馏的DML损失函数,继承自标准的DMLLoss
|
||||
weight: 1.0 # 权重
|
||||
act: "softmax" # 激活函数,对输入使用激活函数处理,可以为softmax, sigmoid或者为None,默认为None
|
||||
use_log: true # 对输入计算log,如果函数已经
|
||||
model_name_pairs: # 用于计算DML loss的子网络名称对,如果希望计算其他子网络的DML loss,可以在列表下面继续填充
|
||||
- ["Student", "Teacher"]
|
||||
key: head_out # 取子网络输出dict中,该key对应的tensor
|
||||
multi_head: True # 是否为多头结构
|
||||
dis_head: ctc # 指定用于计算损失函数的head
|
||||
name: dml_ctc # 蒸馏loss的前缀名称,避免不同loss之间的命名冲突
|
||||
- DistillationDMLLoss: # 蒸馏的DML损失函数,继承自标准的DMLLoss
|
||||
weight: 0.5 # 权重
|
||||
act: "softmax" # 激活函数,对输入使用激活函数处理,可以为softmax, sigmoid或者为None,默认为None
|
||||
use_log: true # 对输入计算log,如果函数已经
|
||||
model_name_pairs: # 用于计算DML loss的子网络名称对,如果希望计算其他子网络的DML loss,可以在列表下面继续填充
|
||||
- ["Student", "Teacher"]
|
||||
key: head_out # 取子网络输出dict中,该key对应的tensor
|
||||
multi_head: True # 是否为多头结构
|
||||
dis_head: sar # 指定用于计算损失函数的head
|
||||
name: dml_sar # 蒸馏loss的前缀名称,避免不同loss之间的命名冲突
|
||||
- DistillationDistanceLoss: # 蒸馏的距离损失函数
|
||||
weight: 1.0 # 权重
|
||||
mode: "l2" # 距离计算方法,目前支持l1, l2, smooth_l1
|
||||
model_name_pairs: # 用于计算distance loss的子网络名称对
|
||||
- ["Student", "Teacher"]
|
||||
key: backbone_out # 取子网络输出dict中,该key对应的tensor
|
||||
- DistillationCTCLoss: # 基于蒸馏的CTC损失函数,继承自标准的CTC loss
|
||||
weight: 1.0 # 损失函数的权重,loss_config_list中,每个损失函数的配置都必须包含该字段
|
||||
model_name_list: ["Student", "Teacher"] # 对于蒸馏模型的预测结果,提取这两个子网络的输出,与gt计算CTC loss
|
||||
key: head_out # 取子网络输出dict中,该key对应的tensor
|
||||
- DistillationSARLoss: # 基于蒸馏的SAR损失函数,继承自标准的SARLoss
|
||||
weight: 1.0 # 损失函数的权重,loss_config_list中,每个损失函数的配置都必须包含该字段
|
||||
model_name_list: ["Student", "Teacher"] # 对于蒸馏模型的预测结果,提取这两个子网络的输出,与gt计算CTC loss
|
||||
key: head_out # 取子网络输出dict中,该key对应的tensor
|
||||
multi_head: True # 是否为多头结构,为true时,取出其中的SAR分支计算损失函数
|
||||
```
|
||||
|
||||
上述损失函数中,所有的蒸馏损失函数均继承自标准的损失函数类,主要功能为: 对蒸馏模型的输出进行解析,找到用于计算损失的中间节点(tensor),再使用标准的损失函数类去计算。
|
||||
|
||||
以上述配置为例,最终蒸馏训练的损失函数包含下面5个部分。
|
||||
|
||||
- `Student`和`Teacher`最终输出(`head_out`)的CTC分支与gt的CTC loss,权重为1。在这里因为2个子网络都需要更新参数,因此2者都需要计算与g的loss。
|
||||
- `Student`和`Teacher`最终输出(`head_out`)的SAR分支与gt的SAR loss,权重为1.0。在这里因为2个子网络都需要更新参数,因此2者都需要计算与g的loss。
|
||||
- `Student`和`Teacher`最终输出(`head_out`)的CTC分支之间的DML loss,权重为1。
|
||||
- `Student`和`Teacher`最终输出(`head_out`)的SAR分支之间的DML loss,权重为0.5。
|
||||
- `Student`和`Teacher`的骨干网络输出(`backbone_out`)之间的l2 loss,权重为1。
|
||||
|
||||
关于`CombinedLoss`更加具体的实现可以参考: [combined_loss.py](../../ppocr/losses/combined_loss.py#L23)。关于`DistillationCTCLoss`等蒸馏损失函数更加具体的实现可以参考[distillation_loss.py](../../ppocr/losses/distillation_loss.py)。
|
||||
|
||||
#### 2.1.3 后处理
|
||||
|
||||
知识蒸馏任务中,后处理配置如下所示。
|
||||
|
||||
```yaml linenums="1"
|
||||
PostProcess:
|
||||
name: DistillationCTCLabelDecode # 蒸馏任务的CTC解码后处理,继承自标准的CTCLabelDecode类
|
||||
model_name: ["Student", "Teacher"] # 对于蒸馏模型的预测结果,提取这两个子网络的输出,进行解码
|
||||
key: head_out # 取子网络输出dict中,该key对应的tensor
|
||||
multi_head: True # 多头结构时,会取出其中的CTC分支进行计算
|
||||
```
|
||||
|
||||
以上述配置为例,最终会同时计算`Student`和`Teahcer` 2个子网络的CTC解码输出,返回一个`dict`,`key`为用于处理的子网络名称,`value`为用于处理的子网络列表。
|
||||
|
||||
关于`DistillationCTCLabelDecode`更加具体的实现可以参考: [rec_postprocess.py](../../ppocr/postprocess/rec_postprocess.py#L128)
|
||||
|
||||
#### 2.1.4 指标计算
|
||||
|
||||
知识蒸馏任务中,指标计算配置如下所示。
|
||||
|
||||
```yaml linenums="1"
|
||||
Metric:
|
||||
name: DistillationMetric # 蒸馏任务的CTC解码后处理,继承自标准的CTCLabelDecode类
|
||||
base_metric_name: RecMetric # 指标计算的基类,对于模型的输出,会基于该类,计算指标
|
||||
main_indicator: acc # 指标的名称
|
||||
key: "Student" # 选取该子网络的 main_indicator 作为作为保存保存best model的判断标准
|
||||
ignore_space: False # 评估时是否忽略空格的影响
|
||||
```
|
||||
|
||||
以上述配置为例,最终会使用`Student`子网络的acc指标作为保存best model的判断指标,同时,日志中也会打印出所有子网络的acc指标。
|
||||
|
||||
关于`DistillationMetric`更加具体的实现可以参考: [distillation_metric.py](../../ppocr/metrics/distillation_metric.py#L24)。
|
||||
|
||||
#### 2.1.5 蒸馏模型微调
|
||||
|
||||
对蒸馏得到的识别蒸馏进行微调有2种方式。
|
||||
|
||||
(1)基于知识蒸馏的微调:这种情况比较简单,下载预训练模型,在[PP-OCRv3_mobile_rec_distillation.yml](https://github.com/PaddlePaddle/PaddleOCR/tree/main/configs/rec/PP-OCRv3/PP-OCRv3_mobile_rec_distillation.yml)中配置好预训练模型路径以及自己的数据路径,即可进行模型微调训练。
|
||||
|
||||
(2)微调时不使用知识蒸馏:这种情况,需要首先将预训练模型中的学生模型参数提取出来,具体步骤如下:
|
||||
|
||||
- 首先下载预训练模型并解压。
|
||||
|
||||
```bash linenums="1"
|
||||
# 下面预训练模型并解压
|
||||
wget https://paddleocr.bj.bcebos.com/PP-OCRv3/chinese/ch_PP-OCRv3_rec_train.tar
|
||||
tar -xf ch_PP-OCRv3_rec_train.tar
|
||||
```
|
||||
|
||||
- 然后使用python,对其中的学生模型参数进行提取
|
||||
|
||||
```python linenums="1"
|
||||
import paddle
|
||||
# 加载预训练模型
|
||||
all_params = paddle.load("ch_PP-OCRv3_rec_train/best_accuracy.pdparams")
|
||||
# 查看权重参数的keys
|
||||
print(all_params.keys())
|
||||
# 学生模型的权重提取
|
||||
s_params = {key[len("Student."):]: all_params[key] for key in all_params if "Student." in key}
|
||||
# 查看学生模型权重参数的keys
|
||||
print(s_params.keys())
|
||||
# 保存
|
||||
paddle.save(s_params, "ch_PP-OCRv3_rec_train/student.pdparams")
|
||||
```
|
||||
|
||||
转化完成之后,使用[PP-OCRv3_mobile_rec.yml](https://github.com/PaddlePaddle/PaddleOCR/tree/main/configs/rec/PP-OCRv3/PP-OCRv3_mobile_rec.yml),修改预训练模型的路径(为导出的`student.pdparams`模型路径)以及自己的数据路径,即可进行模型微调。
|
||||
|
||||
### 2.2 检测配置文件解析
|
||||
|
||||
检测模型蒸馏的配置文件在PaddleOCR/configs/det/ch_PP-OCRv3/目录下,包含两个个蒸馏配置文件:
|
||||
|
||||
- PP-OCRv3_det_cml.yml,采用cml蒸馏,采用一个大模型蒸馏两个小模型,且两个小模型互相学习的方法
|
||||
- PP-OCRv3_det_dml.yml,采用DML的蒸馏,两个Student模型互蒸馏的方法
|
||||
|
||||
#### 2.2.1 模型结构
|
||||
|
||||
知识蒸馏任务中,模型结构配置如下所示:
|
||||
|
||||
```yaml linenums="1"
|
||||
Architecture:
|
||||
name: DistillationModel # 结构名称,蒸馏任务中,为DistillationModel,用于构建对应的结构
|
||||
algorithm: Distillation # 算法名称
|
||||
Models: # 模型,包含子网络的配置信息
|
||||
Student: # 子网络名称,至少需要包含`pretrained`与`freeze_params`信息,其他的参数为子网络的构造参数
|
||||
freeze_params: false # 是否需要固定参数
|
||||
return_all_feats: false # 子网络的参数,表示是否需要返回所有的features,如果为False,则只返回最后的输出
|
||||
model_type: det
|
||||
algorithm: DB
|
||||
Backbone:
|
||||
name: ResNet
|
||||
in_channels: 3
|
||||
layers: 50
|
||||
Neck:
|
||||
name: LKPAN
|
||||
out_channels: 256
|
||||
Head:
|
||||
name: DBHead
|
||||
kernel_list: [7,2,2]
|
||||
k: 50
|
||||
Teacher: # 另外一个子网络,这里给的是DML蒸馏示例,
|
||||
freeze_params: true
|
||||
return_all_feats: false
|
||||
model_type: det
|
||||
algorithm: DB
|
||||
Transform:
|
||||
Backbone:
|
||||
name: ResNet
|
||||
in_channels: 3
|
||||
layers: 50
|
||||
Neck:
|
||||
name: LKPAN
|
||||
out_channels: 256
|
||||
Head:
|
||||
name: DBHead
|
||||
kernel_list: [7,2,2]
|
||||
k: 50
|
||||
|
||||
```
|
||||
|
||||
如果是采用DML,即两个小模型互相学习的方法,上述配置文件里的Teacher网络结构需要设置为Student模型一样的配置,具体参考配置文件[PP-OCRv3_det_dml.yml](https://github.com/PaddlePaddle/PaddleOCR/tree/main/configs/det/PP-OCRv3/PP-OCRv3_det_dml.yml)。
|
||||
|
||||
下面介绍[PP-OCRv3_det_cml.yml](https://github.com/PaddlePaddle/PaddleOCR/tree/main/configs/det/PP-OCRv3/PP-OCRv3_mobile_det.yml)的配置文件参数:
|
||||
|
||||
```yaml linenums="1"
|
||||
Architecture:
|
||||
name: DistillationModel
|
||||
algorithm: Distillation
|
||||
model_type: det
|
||||
Models:
|
||||
Teacher: # CML蒸馏的Teacher模型配置
|
||||
pretrained: ./pretrain_models/ch_ppocr_server_v2.0_det_train/best_accuracy
|
||||
freeze_params: true # Teacher 不训练
|
||||
return_all_feats: false
|
||||
model_type: det
|
||||
algorithm: DB
|
||||
Transform:
|
||||
Backbone:
|
||||
name: ResNet
|
||||
in_channels: 3
|
||||
layers: 50
|
||||
Neck:
|
||||
name: LKPAN
|
||||
out_channels: 256
|
||||
Head:
|
||||
name: DBHead
|
||||
kernel_list: [7,2,2]
|
||||
k: 50
|
||||
Student: # CML蒸馏的Student模型配置
|
||||
pretrained: ./pretrain_models/MobileNetV3_large_x0_5_pretrained
|
||||
freeze_params: false
|
||||
return_all_feats: false
|
||||
model_type: det
|
||||
algorithm: DB
|
||||
Backbone:
|
||||
name: MobileNetV3
|
||||
scale: 0.5
|
||||
model_name: large
|
||||
disable_se: true
|
||||
Neck:
|
||||
name: RSEFPN
|
||||
out_channels: 96
|
||||
shortcut: True
|
||||
Head:
|
||||
name: DBHead
|
||||
k: 50
|
||||
Student2: # CML蒸馏的Student2模型配置
|
||||
pretrained: ./pretrain_models/MobileNetV3_large_x0_5_pretrained
|
||||
freeze_params: false
|
||||
return_all_feats: false
|
||||
model_type: det
|
||||
algorithm: DB
|
||||
Transform:
|
||||
Backbone:
|
||||
name: MobileNetV3
|
||||
scale: 0.5
|
||||
model_name: large
|
||||
disable_se: true
|
||||
Neck:
|
||||
name: RSEFPN
|
||||
out_channels: 96
|
||||
shortcut: True
|
||||
Head:
|
||||
name: DBHead
|
||||
k: 50
|
||||
|
||||
```
|
||||
|
||||
蒸馏模型`DistillationModel`类的具体实现代码可以参考[distillation_model.py](../../ppocr/modeling/architectures/distillation_model.py)。
|
||||
|
||||
最终模型`forward`输出为一个字典,key为所有的子网络名称,例如这里为`Student`与`Teacher`,value为对应子网络的输出,可以为`Tensor`(只返回该网络的最后一层)和`dict`(也返回了中间的特征信息)。
|
||||
|
||||
在蒸馏任务中,为了方便添加蒸馏损失函数,每个网络的输出保存为`dict`,其中包含子模块输出。每个子网络的输出结果均为`dict`,key包含`backbone_out`,`neck_out`, `head_out`,`value`为对应模块的tensor,最终对于上述配置文件,`DistillationModel`的输出格式如下:
|
||||
|
||||
```json
|
||||
{
|
||||
"Teacher": {
|
||||
"backbone_out": tensor,
|
||||
"neck_out": tensor,
|
||||
"head_out": tensor,
|
||||
},
|
||||
"Student": {
|
||||
"backbone_out": tensor,
|
||||
"neck_out": tensor,
|
||||
"head_out": tensor,
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.2.2 损失函数
|
||||
|
||||
检测PP-OCRv3_det_cml.yml蒸馏损失函数配置如下所示。
|
||||
|
||||
```yaml linenums="1"
|
||||
Loss:
|
||||
name: CombinedLoss
|
||||
loss_config_list:
|
||||
- DistillationDilaDBLoss:
|
||||
weight: 1.0
|
||||
model_name_pairs:
|
||||
- ["Student", "Teacher"]
|
||||
- ["Student2", "Teacher"] # 改动1,计算两个Student和Teacher的损失
|
||||
key: maps
|
||||
balance_loss: true
|
||||
main_loss_type: DiceLoss
|
||||
alpha: 5
|
||||
beta: 10
|
||||
ohem_ratio: 3
|
||||
- DistillationDMLLoss: # 改动2,增加计算两个Student之间的损失
|
||||
model_name_pairs:
|
||||
- ["Student", "Student2"]
|
||||
maps_name: "thrink_maps"
|
||||
weight: 1.0
|
||||
# act: None
|
||||
key: maps
|
||||
- DistillationDBLoss:
|
||||
weight: 1.0
|
||||
model_name_list: ["Student", "Student2"] # 改动3,计算两个Student和GT之间的损失
|
||||
balance_loss: true
|
||||
main_loss_type: DiceLoss
|
||||
alpha: 5
|
||||
beta: 10
|
||||
ohem_ratio: 3
|
||||
|
||||
```
|
||||
|
||||
关于`DistillationDilaDBLoss`更加具体的实现可以参考: [distillation_loss.py](https://github.com/PaddlePaddle/PaddleOCR/blob/release%2F2.4/ppocr/losses/distillation_loss.py#L185)。关于`DistillationDBLoss`等蒸馏损失函数更加具体的实现可以参考[distillation_loss.py](https://github.com/PaddlePaddle/PaddleOCR/blob/04c44974b13163450dfb6bd2c327863f8a194b3c/ppocr/losses/distillation_loss.py?_pjax=%23js-repo-pjax-container%2C%20div%5Bitemtype%3D%22http%3A%2F%2Fschema.org%2FSoftwareSourceCode%22%5D%20main%2C%20%5Bdata-pjax-container%5D#L148)。
|
||||
|
||||
#### 2.2.3 后处理
|
||||
|
||||
知识蒸馏任务中,检测蒸馏后处理配置如下所示。
|
||||
|
||||
```yaml linenums="1"
|
||||
PostProcess:
|
||||
name: DistillationDBPostProcess # DB检测蒸馏任务的CTC解码后处理,继承自标准的DBPostProcess类
|
||||
model_name: ["Student", "Student2", "Teacher"] # 对于蒸馏模型的预测结果,提取多个子网络的输出,进行解码,不需要后处理的网络可以不在model_name中设置
|
||||
thresh: 0.3
|
||||
box_thresh: 0.6
|
||||
max_candidates: 1000
|
||||
unclip_ratio: 1.5
|
||||
```
|
||||
|
||||
以上述配置为例,最终会同时计算`Student`,`Student2`和`Teacher` 3个子网络的输出做后处理计算。同时,由于有多个输入,后处理返回的输出也有多个,
|
||||
|
||||
关于`DistillationDBPostProcess`更加具体的实现可以参考: [db_postprocess.py](../../ppocr/postprocess/db_postprocess.py#L195)
|
||||
|
||||
#### 2.2.4 蒸馏指标计算
|
||||
|
||||
知识蒸馏任务中,检测蒸馏指标计算配置如下所示。
|
||||
|
||||
```yaml linenums="1"
|
||||
Metric:
|
||||
name: DistillationMetric
|
||||
base_metric_name: DetMetric
|
||||
main_indicator: hmean
|
||||
key: "Student"
|
||||
```
|
||||
|
||||
由于蒸馏需要包含多个网络,甚至多个Student网络,在计算指标的时候只需要计算一个Student网络的指标即可,`key`字段设置为`Student`则表示只计算`Student`网络的精度。
|
||||
|
||||
#### 2.2.5 检测蒸馏模型finetune
|
||||
|
||||
PP-OCRv3检测蒸馏有两种方式:
|
||||
|
||||
- 采用PP-OCRv3_det_cml.yml,采用cml蒸馏,同样Teacher模型设置为PaddleOCR提供的模型或者您训练好的大模型
|
||||
- 采用PP-OCRv3_det_dml.yml,采用DML的蒸馏,两个Student模型互蒸馏的方法,在PaddleOCR采用的数据集上相比单独训练Student模型有1%-2%的提升。
|
||||
|
||||
在具体fine-tune时,需要在网络结构的`pretrained`参数中设置要加载的预训练模型。
|
||||
|
||||
在精度提升方面,cml的精度>dml的精度蒸馏方法的精度。当数据量不足或者Teacher模型精度与Student精度相差不大的时候,这个结论或许会改变。
|
||||
|
||||
另外,由于PaddleOCR提供的蒸馏预训练模型包含了多个模型的参数,如果您希望提取Student模型的参数,可以参考如下代码:
|
||||
|
||||
```bash linenums="1"
|
||||
# 下载蒸馏训练模型的参数
|
||||
wget https://paddleocr.bj.bcebos.com/PP-OCRv2/chinese/ch_PP-OCRv3_det_distill_train.tar
|
||||
```
|
||||
|
||||
```python linenums="1"
|
||||
import paddle
|
||||
# 加载预训练模型
|
||||
all_params = paddle.load("ch_PP-OCRv3_det_distill_train/best_accuracy.pdparams")
|
||||
# 查看权重参数的keys
|
||||
print(all_params.keys())
|
||||
# 学生模型的权重提取
|
||||
s_params = {key[len("Student."):]: all_params[key] for key in all_params if "Student." in key}
|
||||
# 查看学生模型权重参数的keys
|
||||
print(s_params.keys())
|
||||
# 保存
|
||||
paddle.save(s_params, "ch_PP-OCRv3_det_distill_train/student.pdparams")
|
||||
```
|
||||
|
||||
最终`Student`模型的参数将会保存在`ch_PP-OCRv3_det_distill_train/student.pdparams`中,用于模型的fine-tune。
|
||||
75
docs/version2.x/ppocr/model_compress/prune.en.md
Normal file
75
docs/version2.x/ppocr/model_compress/prune.en.md
Normal file
@@ -0,0 +1,75 @@
|
||||
---
|
||||
comments: true
|
||||
---
|
||||
|
||||
# PP-OCR Models Pruning
|
||||
|
||||
Generally, a more complex model would achieve better performance in the task, but it also leads to some redundancy in the model. Model Pruning is a technique that reduces this redundancy by removing the sub-models in the neural network model, so as to reduce model calculation complexity and improve model inference performance.
|
||||
|
||||
This example uses PaddleSlim provided [APIs of Pruning](https://github.com/PaddlePaddle/PaddleSlim/tree/develop/docs/zh_cn/api_cn/dygraph/pruners) to compress the OCR model.
|
||||
[PaddleSlim](https://github.com/PaddlePaddle/PaddleSlim), an open source library which integrates model pruning, quantization (including quantization training and offline quantization), distillation, neural network architecture search, and many other commonly used and leading model compression technique in the industry.
|
||||
|
||||
It is recommended that you could understand following pages before reading this example:
|
||||
|
||||
1. [PaddleOCR training methods](../model_train/training.en.md)
|
||||
2. [The demo of prune](https://github.com/PaddlePaddle/PaddleSlim/blob/release%2F2.0.0/docs/zh_cn/tutorials/pruning/dygraph/filter_pruning.md)
|
||||
|
||||
## Quick start
|
||||
|
||||
### 1. Install PaddleSlim
|
||||
|
||||
```bash linenums="1"
|
||||
git clone https://github.com/PaddlePaddle/PaddleSlim.git
|
||||
cd PaddleSlim
|
||||
git checkout develop
|
||||
python3 setup.py install
|
||||
```
|
||||
|
||||
### 2. Download Pre-trained Model
|
||||
|
||||
Model prune needs to load pre-trained models.
|
||||
PaddleOCR also provides a series of [models](../model_list.en.md). Developers can choose their own models or use their own models according to their needs.
|
||||
|
||||
### 3. Pruning sensitivity analysis
|
||||
|
||||
After the pre-trained model is loaded, sensitivity analysis is performed on each network layer of the model to understand the redundancy of each network layer, and save a sensitivity file which named: sen.pickle. After that, user could load the sensitivity file via the [methods provided by PaddleSlim](https://github.com/PaddlePaddle/PaddleSlim/blob/develop/paddleslim/prune/sensitive.py#L221) and determining the pruning ratio of each network layer automatically. For specific details of sensitivity analysis, see:[Sensitivity analysis](https://github.com/PaddlePaddle/PaddleSlim/blob/develop/docs/en/tutorials/image_classification_sensitivity_analysis_tutorial_en.md)
|
||||
The data format of sensitivity file:
|
||||
|
||||
```python linenums="1"
|
||||
sen.pickle(Dict){
|
||||
'layer_weight_name_0': sens_of_each_ratio(Dict){'pruning_ratio_0': acc_loss, 'pruning_ratio_1': acc_loss}
|
||||
'layer_weight_name_1': sens_of_each_ratio(Dict){'pruning_ratio_0': acc_loss, 'pruning_ratio_1': acc_loss}
|
||||
}
|
||||
```
|
||||
|
||||
example:
|
||||
|
||||
```python linenums="1"
|
||||
{
|
||||
'conv10_expand_weights': {0.1: 0.006509952684312718, 0.2: 0.01827734339798862, 0.3: 0.014528405644659832, 0.6: 0.06536008804270439, 0.8: 0.11798612250664964, 0.7: 0.12391408417493704, 0.4: 0.030615754498018757, 0.5: 0.047105205602406594}
|
||||
'conv10_linear_weights': {0.1: 0.05113190831455035, 0.2: 0.07705573833558801, 0.3: 0.12096721757739311, 0.6: 0.5135061352930738, 0.8: 0.7908166677143281, 0.7: 0.7272187676899062, 0.4: 0.1819252083008504, 0.5: 0.3728054727792405}
|
||||
}
|
||||
```
|
||||
|
||||
The function would return a dict after loading the sensitivity file. The keys of the dict are name of parameters in each layer. And the value of key is the information about pruning sensitivity of corresponding layer. In example, pruning 10% filter of the layer corresponding to conv10_expand_weights would lead to 0.65% degradation of model performance. The details could be seen at: [Sensitivity analysis](https://github.com/PaddlePaddle/PaddleSlim/blob/release/2.0-alpha/docs/zh_cn/algo/algo.md)
|
||||
|
||||
The function would return a dict after loading the sensitivity file. The keys of the dict are name of parameters in each layer. And the value of key is the information about pruning sensitivity of corresponding layer. In example, pruning 10% filter of the layer corresponding to conv10_expand_weights would lead to 0.65% degradation of model performance. The details could be seen at: [Sensitivity analysis](https://github.com/PaddlePaddle/PaddleSlim/blob/develop/docs/zh_cn/algo/algo.md#2-%E5%8D%B7%E7%A7%AF%E6%A0%B8%E5%89%AA%E8%A3%81%E5%8E%9F%E7%90%86)
|
||||
|
||||
Enter the PaddleOCR root directory,perform sensitivity analysis on the model with the following command:
|
||||
|
||||
```bash linenums="1"
|
||||
python3 deploy/slim/prune/sensitivity_anal.py -c configs/det/ch_ppocr_v2.0/ch_det_mv3_db_v2.0.yml -o Global.pretrained_model="your trained model" Global.save_model_dir=./output/prune_model/
|
||||
```
|
||||
|
||||
### 5. Export inference model and deploy it
|
||||
|
||||
We can export the pruned model as inference_model for deployment:
|
||||
|
||||
```bash linenums="1"
|
||||
python deploy/slim/prune/export_prune_model.py -c configs/det/ch_ppocr_v2.0/ch_det_mv3_db_v2.0.yml -o Global.pretrained_model=./output/det_db/best_accuracy Global.save_inference_dir=./prune/prune_inference_model
|
||||
```
|
||||
|
||||
Reference for prediction and deployment of inference model:
|
||||
|
||||
1. [inference model python prediction](../infer_deploy/python_infer.en.md)
|
||||
2. [inference model C++ prediction](../infer_deploy/cpp_infer.en.md)
|
||||
71
docs/version2.x/ppocr/model_compress/prune.md
Normal file
71
docs/version2.x/ppocr/model_compress/prune.md
Normal file
@@ -0,0 +1,71 @@
|
||||
---
|
||||
comments: true
|
||||
---
|
||||
|
||||
# PP-OCR模型裁剪
|
||||
|
||||
复杂的模型有利于提高模型的性能,但也导致模型中存在一定冗余,模型裁剪通过移出网络模型中的子模型来减少这种冗余,达到减少模型计算复杂度,提高模型推理性能的目的。
|
||||
本教程将介绍如何使用飞桨模型压缩库PaddleSlim做PaddleOCR模型的压缩。
|
||||
[PaddleSlim](https://github.com/PaddlePaddle/PaddleSlim)集成了模型剪枝、量化(包括量化训练和离线量化)、蒸馏和神经网络搜索等多种业界常用且领先的模型压缩功能,如果您感兴趣,可以关注并了解。
|
||||
|
||||
在开始本教程之前,建议先了解:
|
||||
|
||||
1. [PaddleOCR模型的训练方法](../model_train/training.md)
|
||||
2. [模型裁剪教程](https://github.com/PaddlePaddle/PaddleSlim/blob/release%2F2.0.0/docs/zh_cn/tutorials/pruning/dygraph/filter_pruning.md)
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 1.安装PaddleSlim
|
||||
|
||||
```bash linenums="1"
|
||||
git clone https://github.com/PaddlePaddle/PaddleSlim.git
|
||||
cd PaddleSlim
|
||||
git checkout develop
|
||||
python3 setup.py install
|
||||
```
|
||||
|
||||
### 2.获取预训练模型
|
||||
|
||||
模型裁剪需要加载事先训练好的模型,PaddleOCR也提供了一系列[模型](../model_list.md),开发者可根据需要自行选择模型或使用自己的模型。
|
||||
|
||||
### 3.敏感度分析训练
|
||||
|
||||
加载预训练模型后,通过对现有模型的每个网络层进行敏感度分析,得到敏感度文件:sen.pickle,可以通过PaddleSlim提供的[接口](https://github.com/PaddlePaddle/PaddleSlim/blob/9b01b195f0c4bc34a1ab434751cb260e13d64d9e/paddleslim/dygraph/prune/filter_pruner.py#L75)加载文件,获得各网络层在不同裁剪比例下的精度损失。从而了解各网络层冗余度,决定每个网络层的裁剪比例。
|
||||
敏感度文件内容格式:
|
||||
|
||||
```python linenums="1"
|
||||
sen.pickle(Dict){
|
||||
'layer_weight_name_0': sens_of_each_ratio(Dict){'pruning_ratio_0': acc_loss, 'pruning_ratio_1': acc_loss}
|
||||
'layer_weight_name_1': sens_of_each_ratio(Dict){'pruning_ratio_0': acc_loss, 'pruning_ratio_1': acc_loss}
|
||||
}
|
||||
```
|
||||
|
||||
例子:
|
||||
|
||||
```python linenums="1"
|
||||
{
|
||||
'conv10_expand_weights': {0.1: 0.006509952684312718, 0.2: 0.01827734339798862, 0.3: 0.014528405644659832, 0.6: 0.06536008804270439, 0.8: 0.11798612250664964, 0.7: 0.12391408417493704, 0.4: 0.030615754498018757, 0.5: 0.047105205602406594}
|
||||
'conv10_linear_weights': {0.1: 0.05113190831455035, 0.2: 0.07705573833558801, 0.3: 0.12096721757739311, 0.6: 0.5135061352930738, 0.8: 0.7908166677143281, 0.7: 0.7272187676899062, 0.4: 0.1819252083008504, 0.5: 0.3728054727792405}
|
||||
}
|
||||
```
|
||||
|
||||
加载敏感度文件后会返回一个字典,字典中的keys为网络模型参数模型的名字,values为一个字典,里面保存了相应网络层的裁剪敏感度信息。例如在例子中,conv10_expand_weights所对应的网络层在裁掉10%的卷积核后模型性能相较原模型会下降0.65%,详细信息可见[PaddleSlim](https://github.com/PaddlePaddle/PaddleSlim/blob/develop/docs/zh_cn/algo/algo.md#2-%E5%8D%B7%E7%A7%AF%E6%A0%B8%E5%89%AA%E8%A3%81%E5%8E%9F%E7%90%86)
|
||||
|
||||
进入PaddleOCR根目录,通过以下命令对模型进行敏感度分析训练:
|
||||
|
||||
```bash linenums="1"
|
||||
python3 deploy/slim/prune/sensitivity_anal.py -c configs/det/ch_ppocr_v2.0/ch_det_mv3_db_v2.0.yml -o Global.pretrained_model="your trained model" Global.save_model_dir=./output/prune_model/
|
||||
```
|
||||
|
||||
### 4.导出模型、预测部署
|
||||
|
||||
在得到裁剪训练保存的模型后,我们可以将其导出为inference_model:
|
||||
|
||||
```bash linenums="1"
|
||||
python3.7 deploy/slim/prune/export_prune_model.py -c configs/det/ch_ppocr_v2.0/ch_det_mv3_db_v2.0.yml -o Global.pretrained_model=./output/det_db/best_accuracy Global.save_inference_dir=./prune/prune_inference_model
|
||||
```
|
||||
|
||||
inference model的预测和部署参考:
|
||||
|
||||
1. [inference model python端预测](../infer_deploy/python_infer.md)
|
||||
2. [inference model C++预测](../infer_deploy/cpp_infer.md)
|
||||
71
docs/version2.x/ppocr/model_compress/quantization.en.md
Normal file
71
docs/version2.x/ppocr/model_compress/quantization.en.md
Normal file
@@ -0,0 +1,71 @@
|
||||
---
|
||||
comments: true
|
||||
---
|
||||
|
||||
# PP-OCR Models Quantization
|
||||
|
||||
Generally, a more complex model would achieve better performance in the task, but it also leads to some redundancy in the model.
|
||||
Quantization is a technique that reduces this redundancy by reducing the full precision data to a fixed number,
|
||||
so as to reduce model calculation complexity and improve model inference performance.
|
||||
|
||||
This example uses PaddleSlim provided [APIs of Quantization](https://github.com/PaddlePaddle/PaddleSlim/blob/develop/docs/zh_cn/api_cn/dygraph/quanter/qat.rst) to compress the OCR model.
|
||||
|
||||
It is recommended that you could understand following pages before reading this example:
|
||||
|
||||
- [The training strategy of OCR model](../model_train/training.en.md)
|
||||
- [PaddleSlim Document](https://github.com/PaddlePaddle/PaddleSlim/blob/develop/docs/zh_cn/api_cn/dygraph/quanter/qat.rst)
|
||||
|
||||
## Quick Start
|
||||
|
||||
Quantization is mostly suitable for the deployment of lightweight models on mobile terminals.
|
||||
After training, if you want to further compress the model size and accelerate the prediction, you can use quantization methods to compress the model according to the following steps.
|
||||
|
||||
1. Install PaddleSlim
|
||||
2. Prepare trained model
|
||||
3. Quantization-Aware Training
|
||||
4. Export inference model
|
||||
5. Deploy quantization inference model
|
||||
|
||||
### 1. Install PaddleSlim
|
||||
|
||||
```bash linenums="1"
|
||||
pip3 install paddleslim==2.3.2
|
||||
```
|
||||
|
||||
### 2. Download Pre-trained Model
|
||||
|
||||
PaddleOCR provides a series of pre-trained [models](../model_list.en.md).
|
||||
If the model to be quantified is not in the list, you need to follow the [Regular Training](../quick_start.en.md) method to get the trained model.
|
||||
|
||||
### 3. Quant-Aware Training
|
||||
|
||||
Quantization training includes offline quantization training and online quantization training.
|
||||
Online quantization training is more effective. It is necessary to load the pre-trained model.
|
||||
After the quantization strategy is defined, the model can be quantified.
|
||||
|
||||
The code for quantization training is located in `slim/quantization/quant.py`. For example, the training instructions of slim PPOCRv3 detection model are as follows:
|
||||
|
||||
```bash linenums="1"
|
||||
# download provided model
|
||||
wget https://paddleocr.bj.bcebos.com/PP-OCRv3/chinese/ch_PP-OCRv3_det_distill_train.tar
|
||||
tar xf ch_PP-OCRv3_det_distill_train.tar
|
||||
|
||||
python deploy/slim/quantization/quant.py -c configs/det/ch_PP-OCRv3/ch_PP-OCRv3_det_cml.yml -o Global.pretrained_model='./ch_PP-OCRv3_det_distill_train/best_accuracy' Global.save_model_dir=./output/quant_model_distill/
|
||||
```
|
||||
|
||||
If you want to quantify the text recognition model, you can modify the configuration file and loaded model parameters.
|
||||
|
||||
### 4. Export inference model
|
||||
|
||||
Once we got the model after pruning and fine-tuning, we can export it as an inference model for the deployment of predictive tasks:
|
||||
|
||||
```bash linenums="1"
|
||||
python deploy/slim/quantization/export_model.py -c configs/det/ch_PP-OCRv3/ch_PP-OCRv3_det_cml.yml -o Global.checkpoints=output/quant_model/best_accuracy Global.save_inference_dir=./output/quant_inference_model
|
||||
```
|
||||
|
||||
### 5. Deploy
|
||||
|
||||
The numerical range of the quantized model parameters derived from the above steps is still FP32, but the numerical range of the parameters is int8.
|
||||
The derived model can be converted through the `opt tool` of PaddleLite.
|
||||
|
||||
For quantitative model deployment, please refer to [Mobile terminal model deployment](../infer_deploy/lite.en.md)
|
||||
67
docs/version2.x/ppocr/model_compress/quantization.md
Normal file
67
docs/version2.x/ppocr/model_compress/quantization.md
Normal file
@@ -0,0 +1,67 @@
|
||||
---
|
||||
comments: true
|
||||
---
|
||||
|
||||
# PP-OCR模型量化
|
||||
|
||||
复杂的模型有利于提高模型的性能,但也导致模型中存在一定冗余,模型量化将全精度缩减到定点数减少这种冗余,达到减少模型计算复杂度,提高模型推理性能的目的。
|
||||
模型量化可以在基本不损失模型的精度的情况下,将FP32精度的模型参数转换为Int8精度,减小模型参数大小并加速计算,使用量化后的模型在移动端等部署时更具备速度优势。
|
||||
|
||||
本教程将介绍如何使用飞桨模型压缩库PaddleSlim做PaddleOCR模型的压缩。
|
||||
[PaddleSlim](https://github.com/PaddlePaddle/PaddleSlim) 集成了模型剪枝、量化(包括量化训练和离线量化)、蒸馏和神经网络搜索等多种业界常用且领先的模型压缩功能,如果您感兴趣,可以关注并了解。
|
||||
|
||||
在开始本教程之前,建议先了解[PaddleOCR模型的训练方法](../model_train/training.md)以及[PaddleSlim](https://paddleslim.readthedocs.io/zh_CN/latest/index.html)
|
||||
|
||||
## 快速开始
|
||||
|
||||
量化多适用于轻量模型在移动端的部署,当训练出一个模型后,如果希望进一步的压缩模型大小并加速预测,可使用量化的方法压缩模型。
|
||||
|
||||
模型量化主要包括五个步骤:
|
||||
|
||||
1. 安装 PaddleSlim
|
||||
2. 准备训练好的模型
|
||||
3. 量化训练
|
||||
4. 导出量化推理模型
|
||||
5. 量化模型预测部署
|
||||
|
||||
### 1. 安装PaddleSlim
|
||||
|
||||
```bash linenums="1"
|
||||
pip3 install paddleslim==2.3.2
|
||||
```
|
||||
|
||||
### 2. 准备训练好的模型
|
||||
|
||||
PaddleOCR提供了一系列训练好的[模型](../model_list.md),如果待量化的模型不在列表中,需要按照[常规训练](../quick_start.md)方法得到训练好的模型。
|
||||
|
||||
### 3. 量化训练
|
||||
|
||||
量化训练包括离线量化训练和在线量化训练,在线量化训练效果更好,需加载预训练模型,在定义好量化策略后即可对模型进行量化。
|
||||
|
||||
量化训练的代码位于slim/quantization/quant.py 中,比如训练检测模型,以PPOCRv3检测模型为例,训练指令如下:
|
||||
|
||||
```bash linenums="1"
|
||||
# 下载检测预训练模型:
|
||||
wget https://paddleocr.bj.bcebos.com/PP-OCRv3/chinese/ch_PP-OCRv3_det_distill_train.tar
|
||||
tar xf ch_PP-OCRv3_det_distill_train.tar
|
||||
|
||||
python deploy/slim/quantization/quant.py -c configs/det/ch_PP-OCRv3/ch_PP-OCRv3_det_cml.yml -o Global.pretrained_model='./ch_PP-OCRv3_det_distill_train/best_accuracy' Global.save_model_dir=./output/quant_model_distill/
|
||||
```
|
||||
|
||||
如果要训练识别模型的量化,修改配置文件和加载的模型参数即可。
|
||||
|
||||
### 4. 导出模型
|
||||
|
||||
在得到量化训练保存的模型后,我们可以将其导出为inference_model,用于预测部署:
|
||||
|
||||
```bash linenums="1"
|
||||
python deploy/slim/quantization/export_model.py -c configs/det/PP-OCRv3/PP-OCRv3_det_cml.yml -o Global.checkpoints=output/quant_model/best_accuracy Global.save_inference_dir=./output/quant_inference_model
|
||||
```
|
||||
|
||||
### 5. 量化模型部署
|
||||
|
||||
上述步骤导出的量化模型,参数精度仍然是FP32,但是参数的数值范围是int8,导出的模型可以通过PaddleLite的opt模型转换工具完成模型转换。
|
||||
|
||||
量化模型移动端部署的可参考 [移动端模型部署](../infer_deploy/lite.md)
|
||||
|
||||
备注:量化训练后的模型参数是float32类型,转inference model预测时相对不量化无加速效果,原因是量化后模型结构之间存在量化和反量化算子,如果要使用量化模型部署,建议使用TensorRT并设置precision为INT8加速量化模型的预测时间。
|
||||
Reference in New Issue
Block a user