CUDA/MPS 환경에서 참조 기반 텐서의 안전성 이해하기

Bean·2025년 8월 12일

프로그래밍

목록 보기
23/46

1. GPU 연산 시 참조 오류가 덜 발생하는 이유

PyTorch C++ API에서 torch::from_blob()을 사용해 참조 기반 텐서를 만들면, CPU에서는 지역 변수 소멸로 인한 dangling pointer 문제가 자주 발생합니다. 하지만 CUDA나 MPS 환경에서는 비교적 안전해 보일 수 있습니다. 이유는 다음과 같습니다.

1.1 자동 데이터 복사

std::vector<float> data = {1, 2, 3, 4};
auto cpu_tensor = torch::from_blob(data.data(), {2, 2}, torch::kFloat);

// GPU/MPS로 이동 시 새로운 메모리 생성
auto cuda_tensor = cpu_tensor.to(torch::kCUDA);
auto mps_tensor  = cpu_tensor.to(torch::kMPS);

.to(device) 호출 시 원본 CPU 메모리와 독립된 GPU 메모리에 복사됩니다.

1.2 메모리 공간 분리

  • CPU 메모리와 GPU 메모리는 물리적으로 분리
  • GPU로 이동하면 원본 벡터가 소멸되어도 GPU 메모리는 영향을 받지 않음

2. 안전하지 않은 상황

GPU 복사 전 CPU 연산을 수행하면 여전히 위험합니다.

auto tensor = torch::from_blob(data.data(), {2, 2}, torch::kFloat);
auto result = tensor + 1.0; // data 유효해야 함
tensor = tensor.to(torch::kCUDA); // 그 이후에야 안전

3. 안전한 패턴

3.1 즉시 GPU로 이동

auto tensor = torch::from_blob(data.data(), {2, 2}, torch::kFloat)
                  .to(torch::kCUDA);

3.2 처음부터 GPU에서 생성

auto tensor = torch::zeros({2, 2}, torch::device(torch::kCUDA));

3.3 clone() 사용

auto safe_tensor = torch::from_blob(data.data(), {2, 2}, torch::kFloat).clone();

3.4 tensor() 생성자 사용 (가장 권장)

auto safe_tensor = torch::tensor(data); // 복사 생성

4. .to(torch::kCPU) 주의사항

  • CPU 텐서 → CPU 이동: 복사 없음 (같은 메모리 주소)
  • GPU 텐서 → CPU 이동: 복사 발생

즉, 참조 기반 CPU 텐서를 .to(torch::kCPU)로 반환해도 메모리 안전성이 보장되지 않습니다.


5. 값 복사 vs 참조 전달

  • 참조 전달: 복사 비용 없음, 하지만 원본 소멸 시 위험
  • 값 복사: 원본 소멸 위험 완화, 하지만 from_blob() 사용 시 여전히 위험
  • 참조 + clone(): 메모리 복사 시점 제어 가능, 안전성과 성능 모두 확보

6. GPU 사용 시의 추가 안전성

auto tensor = torch::from_blob(data.data(), {1, 4}, torch::kFloat)
                  .to(torch::kCUDA); // GPU 복사로 안전

7. 성능 최적화 팁

재사용 가능한 버퍼를 만들어 매번 메모리 할당을 피하면 성능과 안전성을 모두 확보할 수 있습니다.

class InferenceEngine {
    torch::Tensor buffer_;
public:
    torch::Tensor inference(const std::vector<float>& data) {
        if (buffer_.numel() != data.size())
            buffer_ = torch::zeros({1, (int)data.size()}, torch::kFloat);
        std::memcpy(buffer_.data_ptr<float>(), data.data(), data.size() * sizeof(float));
        return model.forward({buffer_}).toTensor();
    }
};

✅ 결론

  • CUDA/MPS 환경에서는 GPU 메모리 복사 덕분에 참조 오류가 덜 발생

  • 그러나 CPU에서 연산하거나 .to(torch::kCPU)를 사용할 때는 여전히 위험

  • 가장 안전한 방법:

    1. torch::tensor()로 생성
    2. .clone() 명시적 호출
    3. .to(GPU) 즉시 이동
    4. 재사용 버퍼 패턴 활용

참조 + clone()은 성능과 안전성을 동시에 확보하는 실전 추천 패턴입니다.

profile
AI developer

0개의 댓글