본문 바로가기
Artificial Intelligence/60. Python

[PYTHON] 대규모 텐서 객체에서 copy.deepcopy 성능 저하를 해결하는 7가지 방법

by Papa Martino V 2026. 4. 22.
728x90

copy.deepcopy
copy.deepcopy

 

 

파이썬(Python) 기반의 데이터 과학 및 딥러닝 프로젝트를 진행하다 보면, 복잡한 신경망 모델이나 대규모 텐서(Tensor) 객체를 복사해야 하는 상황을 자주 마주하게 됩니다. 이때 가장 먼저 떠오르는 도구는 표준 라이브러리의 copy.deepcopy()입니다. 하지만 수 GB 단위의 텐서 데이터에서 이 함수를 호출하는 순간, 프로그램은 응답을 멈추고 메모리 점유율은 수직 상승하게 됩니다.

본 포스팅에서는 왜 copy.deepcopy()가 대규모 텐서에서 유독 느린지 그 내부 메커니즘을 분석하고, 실무 개발 현장에서 즉시 적용 가능한 7가지 고성능 최적화 해결 방법을 심도 있게 다룹니다.


1. 왜 copy.deepcopy는 대규모 텐서에서 느린가?

copy.deepcopy()는 파이썬의 모든 객체를 재귀적으로 탐색하며 복사합니다. 이 과정에서 객체 메모(Memoization)라는 메커니즘을 사용하는데, 이미 복사된 객체를 추적하여 순환 참조를 방지합니다. 하지만 수백만 개의 요소를 가진 텐서 객체에서는 이 재귀적 탐색과 메모이제이션 과정이 엄청난 오버헤드를 발생시킵니다. 특히 PyTorch나 TensorFlow와 같은 라이브러리의 텐서는 단순한 파이썬 객체가 아니라 C++ 수준에서 관리되는 메모리 뷰(View)를 가지고 있습니다. deepcopy는 이러한 저수준 최적화를 무시하고 파이썬 인터프리터 수준에서 복사를 시도하기 때문에 성능 저하가 필연적입니다.


2. 전략별 성능 비교 요약

다음은 대규모 텐서 복사 시 사용할 수 있는 주요 전략들을 비교한 표입니다.

방법론 주요 메커니즘 성능(속도) 메모리 효율 권장 상황
Standard deepcopy 재귀적 전체 객체 복사 매우 느림 매우 낮음 소규모 일반 객체
Framework Clone C++ 수준 메모리 복사 매우 빠름 높음 단일 텐서 복사
In-place Sharing 메모리 주소 공유 (View) 즉시 완료 최상 읽기 전용 작업
Serialization 바이트 스트림 변환 후 복원 보통 보통 프로세스 간 전송
State Dict Copy 파라미터 가중치만 복사 빠름 매우 높음 모델 가중치 백업

3. 실무 적용 가능한 고성능 Example 7가지

개발자가 자신의 환경에 맞춰 즉시 복사하여 사용할 수 있는 실무 코드를 소개합니다.

Example 1: PyTorch 전용 clone() 및 detach() 조합

PyTorch 사용자라면 deepcopy 대신 엔진 내부에서 최적화된 clone()을 사용해야 합니다.

import torch

def fast_tensor_copy(tensor):
    # clone()은 메모리를 새로 할당하고 내용을 복사하며, 
    # detach()는 계산 그래프에서 분리하여 메모리 누수를 방지합니다.
    return tensor.clone().detach()

# 사용 예시
large_tensor = torch.randn(10000, 10000)
copied_tensor = fast_tensor_copy(large_tensor)

Example 2: NumPy View를 활용한 제로 카피(Zero-copy)

데이터를 수정하지 않고 구조만 변경하거나 읽기만 한다면 메모리를 복사할 필요가 없습니다.

import numpy as np

def get_readonly_view(array):
    # 새로운 객체를 생성하지만 원본 버퍼를 공유합니다.
    view = array.view()
    view.flags.writeable = False
    return view

large_data = np.zeros((5000, 5000))
safe_view = get_readonly_view(large_data)

Example 3: State Dictionary를 이용한 모델 가중치 고속 복사

전체 모델 객체를 deepcopy하는 대신, 학습에 필요한 파라미터(Weight)만 추출하여 복사하는 방법입니다.

import torch.nn as nn
import io

def shadow_copy_model(model):
    # 가중치 딕셔너리만 CPU 메모리에서 고속으로 복사합니다.
    buffer = io.BytesIO()
    torch.save(model.state_dict(), buffer)
    buffer.seek(0)
    
    new_model = type(model)() # 동일 클래스의 새 인스턴스 생성
    new_model.load_state_dict(torch.load(buffer))
    return new_model

Example 4: 다차원 배열의 슬라이싱 복사 최적화

텐서의 특정 부분만 복사할 때 copy() 메서드를 명시적으로 호출하여 메모리 연속성을 보장합니다.

def copy_sub_tensor(tensor, start_idx, end_idx):
    # 슬라이싱 후 copy()를 호출하면 해당 부분만 새로운 메모리 블록에 할당됩니다.
    return tensor[start_idx:end_idx].clone()

Example 5: 공유 메모리(Shared Memory)를 이용한 프로세스 간 복사

멀티프로세싱 환경에서 대규모 텐서를 복사할 때 발생하는 직렬화 오버헤드를 피하는 방법입니다.

import torch.multiprocessing as mp

def move_to_shared_memory(tensor):
    # 텐서를 공유 메모리로 이동시켜 프로세스 간 복사 없이 접근 가능하게 합니다.
    return tensor.share_memory_()

Example 6: pickling 최적화 (Pickle Protocol 5)

객체를 직렬화하여 복사할 때 최신 파이썬 프로토콜을 사용하여 대용량 데이터를 처리합니다.

import pickle

def fast_pickle_copy(obj):
    # Protocol 5는 out-of-band 데이터를 지원하여 대규모 수치 데이터에 최적화되어 있습니다.
    return pickle.loads(pickle.dumps(obj, protocol=5))

Example 7: 커스텀 __deepcopy__ 메서드 구현을 통한 선택적 복사

클래스 내부에 __deepcopy__를 직접 정의하여, 무거운 텐서 데이터는 clone()으로 처리하고 나머지는 일반 복사를 수행하게 제어합니다.

class NeuralNetworkNode:
    def __init__(self, weights):
        self.weights = weights
        self.metadata = {"version": 1.0}

    def __deepcopy__(self, memo):
        # 텐서는 최적화된 방식으로, 일반 속성은 표준 방식으로 복사
        new_weights = self.weights.clone()
        new_obj = self.__class__(new_weights)
        memo[id(self)] = new_obj
        return new_obj

4. 결론 및 성능 최적화 제언

대규모 텐서 객체를 다룰 때 copy.deepcopy()를 무분별하게 사용하는 것은 소프트웨어의 성능을 갉아먹는 주요 원인이 됩니다. 핵심은 "파이썬의 일반 객체 계층""저수준 라이브러리(C++/CUDA)의 데이터 계층"을 분리해서 생각하는 것입니다.

가장 권장되는 해결 방법은 프레임워크가 제공하는 전용 메서드(.clone(), .copy())를 사용하는 것이며, 모델 복제 시에는 state_dict를 활용한 가중치 전송 방식을 채택하는 것입니다. 이러한 접근 만으로도 복사 속도를 최소 10배에서 최대 100배 이상 개선할 수 있습니다.


5. 참고 문헌 및 출처

  • Python Software Foundation. "copy — Shallow and deep copy operations." docs.python.org.
  • PyTorch Documentation. "Tensor.clone() vs Tensor.detach()." pytorch.org/docs.
  • NumPy Manual. "Copies and Views." numpy.org/doc.
  • Effective Python by Brett Slatkin, Item 53: Use copy.deepcopy sparingly for large data.
728x90