Repository: PaddlePaddle/PaddleNLP

Issue:
[Question]: paddle.jit.save将动态图模型转化为静态图模型的一些疑问
### 请提出你的问题

paddle和paddlenlp选择默认的，如下图
<img width="185" alt="1677913368116" src="https://user-images.githubusercontent.com/41726317/222881246-ecb1cbfd-3607-45bc-8728-4086a80ffda9.png">

参考https://github.com/PaddlePaddle/PaddleNLP/tree/develop/applications/neural_search/ranking/ernie_matching训练一个排序模型。
训练阶段是一个pairwise对，所以预测或者部署阶段使用函数predict来推理。paddle.jit.save默认转化模型的forward为静态图。
**现在问题是我搞不明白在模型的predict函数中定义了paddle.jit.to_static，那直接使用paddle.jit.save时保存的是predict这一块还是forward**，如下图。看官方给的例子和文档使用说明好像是会对加了to_static的函数进行转化。
<img width="384" alt="1677911890173" src="https://user-images.githubusercontent.com/41726317/222880341-c5437587-5f1c-4110-aede-bcc70760c904.png">

但实际操作过程不是这样。因为我图中稍微改了一下forward层的输入参数格式，让它与predict要求输入数量不一致（官方代码forward和predict都是要求至少两个输入），如下图。
<img width="456" alt="1677912445432" src="https://user-images.githubusercontent.com/41726317/222880659-184a9110-60b7-44cc-b8e6-861996868749.png">
当我按照官方代码方式进行保存时，如下图，却提示我输入参数量不一致。按照报错推理，应该还是按照forward分支去转化。
<img width="296" alt="1677912515625" src="https://user-images.githubusercontent.com/41726317/222880714-9aa28003-9fde-4235-b4b1-cc5392fa1bab.png">
<img width="865" alt="1677912549536" src="https://user-images.githubusercontent.com/41726317/222880758-6ce7068b-a280-47e9-9f6e-4a8eb960e64e.png">

那我尝试使用model.predict去转化的时候，模型能转化成静态图，如下图。
<img width="290" alt="1677912874861" src="https://user-images.githubusercontent.com/41726317/222880933-21ddaac0-2d54-4c68-9fde-b0e1c788b89d.png">
但动态图预测结果与静态图预测结果不一致，如下面两张图。虽然排序顺序没有变。使用paddle.load直接加载*.pdiparams。发现权重矩阵只保存了embedding的数量，40000个数组。
<img width="291" alt="1677913049645" src="https://user-images.githubusercontent.com/41726317/222881036-6921a0c2-f2c1-4fd2-a5ec-c812ac34eb27.png">
<img width="369" alt="1677913120407" src="https://user-images.githubusercontent.com/41726317/222881070-0f6bf48d-cdcc-4f14-aa85-e0bf8591194d.png">

**还有另外两个个问题想请教。
1.无论是我在训练阶段使用paddle.jit.save保存的静态图模型，还是训练完后保存静态图模型，都无法使用paddle.jit.load直接加载。会报无forward keyerror的问题。**
<img width="719" alt="1677913569340" src="https://user-images.githubusercontent.com/41726317/222881383-765ec725-98c5-4e8e-ade6-59205ae26b79.png">

此外在训练阶段保存静态图会出现内存无法释放的问题，然后导致内存溢出，kernel崩溃。类似[issue]#3235(https://github.com/PaddlePaddle/PaddleOCR/issues/3235#issue-934585945)。但是我是用的比较新的paddle版本。不知道为什么还是这样情况。要加入什么代码来自动释放内存吗？代码如下图
<img width="509" alt="1677914068792" src="https://user-images.githubusercontent.com/41726317/222881700-b29054f2-5afc-47d8-a2c2-1b50e4be7d8d.png">

**2、如何像动态图一样，比较方便查看静态图保存的权重和网络结构。尝试使用paddle.inference.create_predictor去查看。想使用register_output_hook去输出中间结果，却提示无这个函数。**
<img width="418" alt="b7718672505a81bbca2b04618d9a8d5" src="https://user-images.githubusercontent.com/41726317/222882221-ba218820-60be-431d-87b8-428b521caf09.png">

希望有大佬可以解答，困扰一段时间了



Discussion:
1. 建议首先升级一下PaddlePaddle的版本到最新的2.4.2版本，paddle.jit.save 如果没有指定的话，走的就是forward逻辑，同时在predictor的逻辑关闭IR优化  https://github.com/PaddlePaddle/PaddleNLP/blob/f6cf94de48731dbccaab1bfe14b8af6789469c27/paddlenlp/taskflow/task.py#L217 
2. 静态图动转静的函数里面不会将hook函数动转静，这个是静态图预测的特性(图优化)，如果希望打印一些中间结果  https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/static/Print_cn.html#print

> 1. 建议首先升级一下PaddlePaddle的版本到最新的2.4.2版本，paddle.jit.save 如果没有指定的话，走的就是forward逻辑，同时在predictor的逻辑关闭IR优化  https://github.com/PaddlePaddle/PaddleNLP/blob/f6cf94de48731dbccaab1bfe14b8af6789469c27/paddlenlp/taskflow/task.py#L217
> 2. 静态图动转静的函数里面不会将hook函数动转静，这个是静态图预测的特性(图优化)，如果希望打印一些中间结果  https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/static/Print_cn.html#print

尝试升级paddle到2.4.2。并**指定模型按照函数predict的逻辑转化成动态图。然后对比动态图和静态图（这里使用paddle.inference.create_preditor导入静态图）对同一份数据的预测结果，发现仍然并不一致**。结果对比如下：

<img width="368" alt="1678018443549" src="https://user-images.githubusercontent.com/41726317/222959883-a7e3bc73-b919-4606-a99a-6b13b6253af5.png">
<img width="370" alt="1678018623843" src="https://user-images.githubusercontent.com/41726317/222959949-d36ad883-f919-4c9f-a791-9cf394f349f9.png">

**尝试使用paddle.static.load_inference_model去导入静态图进行预测**，结果发现一致。**说明paddle.jit.save保存的静态图没问题**。
<img width="371" alt="1678022406808" src="https://user-images.githubusercontent.com/41726317/222962994-8c68a203-cc55-4f3f-80ef-4c5b7f24adb3.png">

而**使用paddle.inference.create_predictor导入的静态图，则结果预测不对**。使用方式与官方说明一致。如下图：
<img width="329" alt="1678022668252" src="https://user-images.githubusercontent.com/41726317/222963180-8ea255ac-9a5a-4e96-8de0-1f5c230c2890.png">
<img width="367" alt="1678022702611" src="https://user-images.githubusercontent.com/41726317/222963198-a4291b94-2db7-44ad-b8b5-e860670d2408.png">

已确认静态图的输入embedding与动态图的输入一致。问题应该出在paddle.inference.create_preditor中的前向传播上。

这个开关是 self._config.switch_ir_optim(False) 增加？ 
> 这个开关是 self._config.switch_ir_optim(False) 增加？

本来之前的截图结果没有在predictor逻辑中加入这个开关。之后加了，但仍然是一样的结果。与动态图预测结果不一致
<img width="325" alt="1678027735211" src="https://user-images.githubusercontent.com/41726317/222967725-eb66d75b-22d6-462b-8833-b1dc4dadec97.png">

<img width="811" alt="1678027548337" src="https://user-images.githubusercontent.com/41726317/222967535-7473ccbe-3143-4f31-bb8c-8fb4e237ad5d.png">

Hi, @wenzitracyliu , 静态图的参数可以使用netron查看。https://github.com/lutzroeder/netron

Resolving patch:
diff --git a/applications/neural_search/ranking/ernie_matching/deploy/python/predict.py b/applications/neural_search/ranking/ernie_matching/deploy/python/predict.py
--- a/applications/neural_search/ranking/ernie_matching/deploy/python/predict.py
+++ b/applications/neural_search/ranking/ernie_matching/deploy/python/predict.py
@@ -16,50 +16,30 @@
 import os
 import sys
 
-from scipy.special import softmax
-from scipy.special import expit
 import numpy as np
-import pandas as pd
-
 import paddle
 from paddle import inference
-import paddle.nn.functional as F
 
-from paddlenlp.data import Stack, Tuple, Pad
+from paddlenlp.data import Pad, Tuple
 from paddlenlp.datasets import load_dataset
+from paddlenlp.transformers import AutoTokenizer
 from paddlenlp.utils.log import logger
-from paddlenlp.transformers import AutoTokenizer, AutoModel
 
 sys.path.append(".")
 
 # yapf: disable
 parser = argparse.ArgumentParser()
-parser.add_argument("--model_dir", type=str, required=True,
-    help="The directory to static model.")
-
-parser.add_argument("--max_seq_length", default=128, type=int,
-    help="The maximum total input sequence length after tokenization. Sequences "
-    "longer than this will be truncated, sequences shorter will be padded.")
-parser.add_argument("--batch_size", default=32, type=int,
-    help="Batch size per GPU/CPU for training.")
-parser.add_argument('--device', choices=['cpu', 'gpu', 'xpu'], default="gpu",
-    help="Select which device to train model, defaults to gpu.")
-parser.add_argument("--input_file", type=str, required=True,
-    help="The test set file.")
-parser.add_argument('--use_tensorrt', default=False, type=eval, choices=[True, False],
-    help='Enable to use tensorrt to speed up.')
-parser.add_argument("--precision", default="fp32", type=str, choices=["fp32", "fp16", "int8"],
-    help='The tensorrt precision.')
-
-parser.add_argument('--cpu_threads', default=10, type=int,
-    help='Number of threads to predict when using cpu.')
-parser.add_argument('--enable_mkldnn', default=False, type=eval, choices=[True, False],
-    help='Enable to use mkldnn to speed up when using cpu.')
-
-parser.add_argument("--benchmark", type=eval, default=False,
-    help="To log some information about environment and running.")
-parser.add_argument("--save_log_path", type=str, default="./log_output/",
-    help="The file path to save log.")
+parser.add_argument("--model_dir", type=str, required=True, help="The directory to static model.")
+parser.add_argument("--max_seq_length", default=128, type=int, help="The maximum total input sequence length after tokenization. Sequences longer than this will be truncated, sequences shorter will be padded.")
+parser.add_argument("--batch_size", default=32, type=int, help="Batch size per GPU/CPU for training.")
+parser.add_argument('--device', choices=['cpu', 'gpu', 'xpu'], default="gpu", help="Select which device to train model, defaults to gpu.")
+parser.add_argument("--input_file", type=str, required=True, help="The test set file.")
+parser.add_argument('--use_tensorrt', default=False, type=eval, choices=[True, False], help='Enable to use tensorrt to speed up.')
+parser.add_argument("--precision", default="fp32", type=str, choices=["fp32", "fp16", "int8"], help='The tensorrt precision.')
+parser.add_argument('--cpu_threads', default=10, type=int, help='Number of threads to predict when using cpu.')
+parser.add_argument('--enable_mkldnn', default=False, type=eval, choices=[True, False], help='Enable to use mkldnn to speed up when using cpu.')
+parser.add_argument("--benchmark", type=eval, default=False, help="To log some information about environment and running.")
+parser.add_argument("--save_log_path", type=str, default="./log_output/", help="The file path to save log.")
 parser.add_argument('--model_name_or_path', default="ernie-3.0-medium-zh", help="The pretrained model used for training")
 args = parser.parse_args()
 # yapf: enable
@@ -202,7 +182,6 @@ def predict(self, data, tokenizer):
         sim_score = self.output_handle.copy_to_cpu()
         if args.benchmark:
             self.autolog.times.stamp()
-        sim_score = expit(sim_score)
 
         if args.benchmark:
             self.autolog.times.end(stamp=True)


Test patch: