diff --git a/tools/count_api_without_ops.py b/tools/count_api_without_ops.py
new file mode 100644
index 0000000000000000000000000000000000000000..84dd9a6b2f63b7e5cb63c6ab4367a2591274d660
--- /dev/null
+++ b/tools/count_api_without_ops.py
@@ -0,0 +1,140 @@
+# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""
+List all operator-raleated APIs that contains append_op but not core.ops.xx.
+
+Usage:
+    python ./count_api_without_ops.py paddle
+"""
+from __future__ import print_function
+
+import importlib
+import inspect
+import collections
+import sys
+import pydoc
+import hashlib
+import six
+import functools
+
+visited_modules = set()
+
+# APIs that should not be printed into API.spec 
+omitted_list = [
+    "paddle.fluid.LoDTensor.set",  # Do not know why it should be omitted
+    "paddle.fluid.io.ComposeNotAligned",
+    "paddle.fluid.io.ComposeNotAligned.__init__",
+]
+
+api_with_ops = []
+api_without_ops = []
+
+
+def queue_dict(member, cur_name):
+    if cur_name in omitted_list:
+        return
+
+    if inspect.isclass(member):
+        pass
+    else:
+        try:
+            source = inspect.getsource(member)
+            if source.find('append_op') != -1:
+                if source.find('core.ops') != -1:
+                    api_with_ops.append(cur_name)
+                else:
+                    api_without_ops.append(cur_name)
+
+        except Exception as e:  # special for PyBind method
+            pass
+
+
+def visit_member(parent_name, member):
+    cur_name = ".".join([parent_name, member.__name__])
+    if inspect.isclass(member):
+        queue_dict(member, cur_name)
+        for name, value in inspect.getmembers(member):
+            if hasattr(value, '__name__') and (not name.startswith("_") or
+                                               name == "__init__"):
+                visit_member(cur_name, value)
+    elif inspect.ismethoddescriptor(member):
+        return
+    elif callable(member):
+        queue_dict(member, cur_name)
+    elif inspect.isgetsetdescriptor(member):
+        return
+    else:
+        raise RuntimeError("Unsupported generate signature of member, type {0}".
+                           format(str(type(member))))
+
+
+def is_primitive(instance):
+    int_types = (int, long) if six.PY2 else (int, )
+    pritimitive_types = int_types + (float, str)
+    if isinstance(instance, pritimitive_types):
+        return True
+    elif isinstance(instance, (list, tuple, set)):
+        for obj in instance:
+            if not is_primitive(obj):
+                return False
+
+        return True
+    else:
+        return False
+
+
+def visit_all_module(mod):
+    mod_name = mod.__name__
+    if mod_name != 'paddle' and not mod_name.startswith('paddle.'):
+        return
+
+    if mod_name.startswith('paddle.fluid.core'):
+        return
+
+    if mod in visited_modules:
+        return
+
+    visited_modules.add(mod)
+
+    for member_name in (
+            name
+            for name in (mod.__all__ if hasattr(mod, "__all__") else dir(mod))
+            if not name.startswith("_")):
+        instance = getattr(mod, member_name, None)
+        if instance is None:
+            continue
+
+        if is_primitive(instance):
+            continue
+
+        if not hasattr(instance, "__name__"):
+            continue
+
+        if inspect.ismodule(instance):
+            visit_all_module(instance)
+        else:
+            visit_member(mod.__name__, instance)
+
+
+modules = sys.argv[1].split(",")
+for m in modules:
+    visit_all_module(importlib.import_module(m))
+
+print('api_with_ops:', len(api_with_ops))
+print('\n'.join(api_with_ops))
+
+print('\n==============\n')
+
+print('api_without_ops:', len(api_without_ops))
+print('\n'.join(api_without_ops))