Skip to content

优化LayerList类的insert函数 #71540

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 20 commits into from
Mar 19, 2025
Merged

Conversation

Qin-sx
Copy link
Contributor

@Qin-sx Qin-sx commented Mar 10, 2025

PR Category

User Experience

PR Types

Improvements

Description

优化LayerList类的insert函数
对应issue

insert函数在对index判断时没有考虑_sub_layers为空的情,即[0,0)。

assert isinstance(index, int) and -len(self._sub_layers) <= index < len(
            self._sub_layers
        ), f"index should be an integer in range [{-len(self)}, {len(self)})"

在pytorch中,并没有进行类似的判断,而是直接插入新的layer。

    def insert(self, index: int, module: Module) -> None:
        r"""Insert a given module before a given index in the list.

        Args:
            index (int): index to insert.
            module (nn.Module): module to insert
        """
        for i in range(len(self._modules), index, -1):
            self._modules[str(i)] = self._modules[str(i - 1)]
        self._modules[str(index)] = module

本次优化将insert函数的插入范围改为了左闭右闭区间,例如[0,1],[0,0]等。修改后:

  1. _sub_layers为空时,可以index=0插入新的layer。
  2. 可以在位置为len(self)处的插入新的layer。

加入了相应的测试。

Qin-sx and others added 15 commits December 5, 2024 06:36
	modified:   paddle/fluid/pybind/pybind.cc
	modified:   paddle/phi/core/memory/stats.cc
	modified:   paddle/phi/core/memory/stats.h
	modified:   python/paddle/device/cuda/__init__.py
	modified:   paddle/fluid/pybind/pybind.cc
	modified:   python/paddle/device/cuda/__init__.py
	modified:   paddle/fluid/pybind/pybind.cc
	modified:   paddle/phi/core/memory/stats.cc
	modified:   paddle/phi/core/memory/stats.h
	modified:   test/cpp/fluid/memory/stats_test.cc
	new file:   test/legacy_test/test_cuda_memory_stats.py
	new file:   test/legacy_test/test_cuda_reset_peak_memory_stats.py
	new file:   test/legacy_test/test_cuda_reset_max_memory_allocated.py
	modified:   python/paddle/device/cuda/__init__.py
	modified:   test/legacy_test/test_cuda_memory_stats.py
	modified:   test/legacy_test/test_cuda_reset_max_memory_allocated.py
	modified:   test/legacy_test/test_cuda_reset_peak_memory_stats.py
	modified:   paddle/fluid/pybind/pybind.cc
	modified:   paddle/phi/core/memory/stats.cc
	modified:   paddle/phi/core/memory/stats.h
	modified:   test/cpp/fluid/memory/stats_test.cc
	modified:   python/paddle/device/cuda/__init__.py
	modified:   test/legacy_test/test_cuda_reset_max_memory_allocated.py
	new file:   test/legacy_test/test_cuda_reset_max_memory_reserved.py
	modified:   paddle/fluid/pybind/pybind.cc
	modified:   python/paddle/device/cuda/__init__.py
	deleted:    test/legacy_test/test_cuda_memory_stats.py
	deleted:    test/legacy_test/test_cuda_reset_peak_memory_stats.py
	modified:   python/paddle/nn/layer/container.py
	modified:   test/sot/test_15_slice.py
@@ -147,5 +147,26 @@ def test_string_slice(self):
self.assert_results(string_slice, x)


class TestLayerListEmptyInsert(unittest.TestCase):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这和 SOT 有关么?为什么要加在这里?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

您好,因为我在test文件夹搜了一下,貌似只有SOT中有LayerList类的相关测试。

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

那就去 test/legacy_test 自己新增一个单测,从单测名就可以明显看出在这里加是不合适的

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

收到,已修改

@paddle-bot paddle-bot bot added the contributor External developers label Mar 10, 2025
	new file:   test/legacy_test/test_layerlist.py
	modified:   test/sot/test_15_slice.py
)
self.append(sublayer)
return

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

下面的assert可以挪到上面来,做一个整体的assert判断。另外这里能否不加额外分支,和下面代码采用相同实现?

Copy link
Contributor Author

@Qin-sx Qin-sx Mar 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

收到,已修改,_get_abs_idx函数也没有考虑index=0的情况,也进行了修改。

Qin-sx added 2 commits March 12, 2025 16:31
	modified:   python/paddle/nn/layer/container.py
	modified:   test/legacy_test/test_layerlist.py
@@ -545,9 +545,11 @@ def __init__(self, sublayers: Iterable[Layer] | None = None) -> None:

def _get_abs_idx(self, idx: int) -> int:
if isinstance(idx, int):
if not (-len(self) <= idx < len(self)):
if not (len(self) == 0 and idx == 0) and not (
Copy link
Contributor

@zhwesky2010 zhwesky2010 Mar 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个是不是因为原来的阈值范围不合理,原来是:[-len, len) 前开后闭,应改成 [-len, len],对于位置为len处的插入就是在最末尾插入。你看下torch是不是这样设计的

也就是新增一个功能:在位置为len处的插入,不仅仅是针对len为0,而是一个通用功能

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pytorch

pytorch中貌似并没有考虑这个问题。
我在pytorch的insert函数中加入了打印:

    def insert(self, index: int, module: Module) -> None:
        r"""Insert a given module before a given index in the list.

        Args:
            index (int): index to insert.
            module (nn.Module): module to insert
        """
        print("inner Pytorch ModuleList insert function: ",self._modules)
        for i in range(len(self._modules), index, -1):
            self._modules[str(i)] = self._modules[str(i - 1)]
            
        self._modules[str(index)] = module

并对以下代码进行了测试:

import torch
modules = torch.nn.ModuleList()
modules.insert(2, torch.nn.Linear(20, 20))
print("outer modules:", modules)
modules.insert(3, torch.nn.Linear(30, 30))
print("outer modules:", modules)
modules.insert(0, torch.nn.Linear(10, 10))
print("outer modules:", modules)

测试代码出现了报错,应该是因为没有对输入的str(i)进行限制。

inner Pytorch ModuleList insert function:  OrderedDict()
outer modules: ModuleList(
  (0): Linear(in_features=20, out_features=20, bias=True)
)
inner Pytorch ModuleList insert function:  OrderedDict([('2', Linear(in_features=20, out_features=20, bias=True))])
outer modules: ModuleList(
  (0): Linear(in_features=20, out_features=20, bias=True)
  (1): Linear(in_features=30, out_features=30, bias=True)
)
inner Pytorch ModuleList insert function:  OrderedDict([('2', Linear(in_features=20, out_features=20, bias=True)), ('3', Linear(in_features=30, out_features=30, bias=True))])
Traceback (most recent call last):
  File "/home/qinsx/paddle_test/Modulelist/modulelist.py", line 11, in <module>
    modules.insert(0, torch.nn.Linear(10, 10))
  File "/home/qinsx/pyenv/pdbaddbmm/lib/python3.8/site-packages/torch/nn/modules/container.py", line 377, in insert
    self._modules[str(i)] = self._modules[str(i - 1)]
KeyError: '1'

paddle

在paddle中,insert函数调用了_get_abs_idx函数来获取id。

    def _get_abs_idx(self, idx: int) -> int:
        if isinstance(idx, int):
            if not (len(self) == 0 and idx == 0) and not (
                -len(self) <= idx < len(self)
            ):
                raise IndexError(
                    f'index {idx} is out of range, should be 0 for empty list or in range [{-len(self)}, {len(self)})'
                )
            if idx < 0:
                idx += len(self)
        return idx

_get_abs_idx函数也会对左闭右开进行检查。我个人认为_get_abs_idx函数应该保持左闭右开,因为如果其他函数在调用时,如果获取右区间最大值会越界。我加入的特殊情况为length为0时返回idx=0。
我认为现在可以有两种方案:

  1. 方案一:保持这种修改,即对_get_abs_idxinsert函数加入length为0的特殊情况判断。
  2. 方案二:不修改_get_abs_idx函数。在insert函数中不调用_get_abs_idx函数,而仿照_get_abs_idx函数单独进行判断。

方案二代码

        assert isinstance(index, int) and -len(self._sub_layers) <= index <= len(
            self._sub_layers
        ), f"index should be an integer in range [{-len(self)}, {len(self)}]"

        if idx < 0:
            idx += len(self)
        for i in range(len(self._sub_layers), index, -1):
            self._sub_layers[str(i)] = self._sub_layers[str(i - 1)]
        self._sub_layers[str(index)] = sublayer

Copy link
Contributor

@zhwesky2010 zhwesky2010 Mar 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Qin-sx 我可能没描述清楚,新增的功能是指:在位置为len(self)处的插入,比如长度为0的,在0位置插入,长度为1的,在1位置插入

试了下torch,这个功能是支持的。

Copy link
Contributor

@zhwesky2010 zhwesky2010 Mar 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Qin-sx 按方案二实现吧,如果_get_abs_idx不能修改为前闭后闭,那就不用调这个函数。

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

收到,已修改,并对新增的在位置为len(self)处的插入功能加入了测试。

Qin-sx added 2 commits March 17, 2025 22:27
	modified:   python/paddle/nn/layer/container.py
	modified:   test/legacy_test/test_layerlist.py
Copy link
Contributor

@zhwesky2010 zhwesky2010 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@zhwesky2010 zhwesky2010 merged commit 212d828 into PaddlePaddle:develop Mar 19, 2025
30 checks passed
YqGe585 pushed a commit to YqGe585/Paddle that referenced this pull request May 7, 2025
* added reset peak value initialization

	modified:   paddle/fluid/pybind/pybind.cc
	modified:   paddle/phi/core/memory/stats.cc
	modified:   paddle/phi/core/memory/stats.h
	modified:   python/paddle/device/cuda/__init__.py

* added comments

	modified:   paddle/fluid/pybind/pybind.cc
	modified:   python/paddle/device/cuda/__init__.py

* added cpp tests

	modified:   paddle/fluid/pybind/pybind.cc
	modified:   paddle/phi/core/memory/stats.cc
	modified:   paddle/phi/core/memory/stats.h
	modified:   test/cpp/fluid/memory/stats_test.cc

* added python tests

	new file:   test/legacy_test/test_cuda_memory_stats.py
	new file:   test/legacy_test/test_cuda_reset_peak_memory_stats.py

* added a python test for reset_max_memory_allocated

	new file:   test/legacy_test/test_cuda_reset_max_memory_allocated.py

* formatted by pre-commit

	modified:   python/paddle/device/cuda/__init__.py
	modified:   test/legacy_test/test_cuda_memory_stats.py
	modified:   test/legacy_test/test_cuda_reset_max_memory_allocated.py
	modified:   test/legacy_test/test_cuda_reset_peak_memory_stats.py

* formatted by pre-commit (clang-format)
	modified:   paddle/fluid/pybind/pybind.cc
	modified:   paddle/phi/core/memory/stats.cc
	modified:   paddle/phi/core/memory/stats.h
	modified:   test/cpp/fluid/memory/stats_test.cc

* added reset max memory reserved function

	modified:   python/paddle/device/cuda/__init__.py
	modified:   test/legacy_test/test_cuda_reset_max_memory_allocated.py
	new file:   test/legacy_test/test_cuda_reset_max_memory_reserved.py

* deleted memory stats and reset peak memory stats

	modified:   paddle/fluid/pybind/pybind.cc
	modified:   python/paddle/device/cuda/__init__.py
	deleted:    test/legacy_test/test_cuda_memory_stats.py
	deleted:    test/legacy_test/test_cuda_reset_peak_memory_stats.py

* optimized insert function in LayerList class

	modified:   python/paddle/nn/layer/container.py
	modified:   test/sot/test_15_slice.py

* removed the test file

	new file:   test/legacy_test/test_layerlist.py
	modified:   test/sot/test_15_slice.py

* optimized conditions

	modified:   python/paddle/nn/layer/container.py
	modified:   test/legacy_test/test_layerlist.py

* restored _get_abs_idx and modified insert

	modified:   python/paddle/nn/layer/container.py
	modified:   test/legacy_test/test_layerlist.py
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
contributor External developers
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants