배움 기록/Deep Learning

[Segmentation, MONAI] CUDA out of memory 와의 전쟁 -2. Crop 을 통해 이미지 크기 줄이

Spezi 2023. 7. 7. 03:03
반응형

2023.07.06 - [배움 기록/Deep Learning] - [Segmentation, MONAI] CUDA out of memory 와의 전쟁 -1. Spacingd를 통한 해상도 조정

 

[Segmentation, MONAI] CUDA out of memory 와의 전쟁 -1. Spacingd를 통한 해상도 조정

요즘 segmentaion을 하는 중 가장 열받는 오류.... cuda ,,,, out of memory.... batch size 도 줄였고, 네트워크에 사용되는 patch 개수도 줄인상황.. 물론 이미지의 사이즈도! 물론 모델 자체를 바꿔볼수도 있지

jedemanfangwohnteinzauberinne.tistory.com

 

이미지의 크기를 줄임으로써 메모리 문제를 해결해 보자.

그런데 이미지를 줄인다고 하면, 내가 training에 정작 필요한 부분을 날리게 되는 수가 있다. 그래서 MONAI의 라이브러리를 이용해 crop을 좀 더 현명하게(?) 해보고자 한다.

참고로 여러 가지의 crop방법이 있으니 상황에 따라 필요한 crop방법을 사용하길 바란다.

아래에서 설명하는 방법은 내가 자주 사용하는 crop방법이라는 것.

RandCropByPosNegLabeld

이 crop 방법은 Foreground와  Background의 비율을 이용해 crop을 한다.

출처는 MONAI홈페이지 입니다.

이 경우 before이미지를 4개의 부분으로 나누어 자른 것을 볼 수 있다. 

  • spatial_size: 어떤 크기로 자를 것이냐
  • label_key: 을 label로 함으로써 label 클래스를 기준으로 크롭
  • num_classes: 몇 번 crop 할 것이냐. 즉 patch를 몇 개 만들 것이냐. 저 위의 경우 4개의 patch를 얻었기 때문에 4.

이 방법의 핵심은 pos neg ratio를 사용한다는 것인데,  Foreground와 Background의 픽셀 중 어떤 픽셀을 중심으로 랜덤 하게 크롭 할 것인지 결정하는 것이다.

예를 들어 pos/neg=1이라고 해보자. 이는 배경과 전경의 비율이 같다는 뜻이다.

[[[0, 0, 0, 0, 0],
  [0, 1, 2, 1, 0],            [[0, 1, 2],     [[2, 1, 0],
  [0, 1, 3, 0, 0],     -->     [0, 1, 3],      [3, 0, 0],
  [0, 0, 0, 0, 0],             [0, 0, 0]]      [0, 0, 0]]
  [0, 0, 0, 0, 0]]]

즉 0인 부분과 0이 아닌 부분의 개수를 같은 비율로 한다는 뜻. 위에서 보면 0이 4개 , 0 이 아닌 부분이 4개인 것을 볼 수 있다.

CenterSpatialCropd

얘는 말 그대로 중심을 기점으로 자르겠다는 것.

roi size로 어떤 크기로 자를지 정하면 중심을 기점으로 자른다. 만약에 roi size 가 input image보다 크면 crop을 하지 않는다.

 

출처는 MONAI 홈페이지 입니다.

 

RandCropByLabelClassesd


`RandCropByLabelClassesd` 변환은 클래스별로 이미지를 잘라내기 위해 사용한다. `num_classes`는 전체 클래스의 개수를 나타내며, `ratios`는 각 클래스가 잘라낸 이미지에 포함되는 비율을 나타냄. 예를 들어, `ratios`가 [1, 2, 3, 1]인 경우, 클래스 1은 잘라낸 이미지에 2배의 비율로 포함되고, 클래스 2와 3은 1배의 비율로 포함됨.

이 변환은 클래스별로 잘라낸 이미지를 사용하여 데이터를 클래스 간 밸런스를 맞출 수 있음. 예를 들어, 불균형한 클래스 분포를 가진 데이터셋에서 클래스 간 밸런스를 조정하고자 할 때! 각 클래스의 비율을 조정하여 잘라낸 이미지에 특정 클래스를 더 많이 포함시키거나 적게 포함시킬 수 있다.

cropper = RandCropByLabelClassesd(
    keys=["image", "label"],
    label_key="label",
    spatial_size=[3, 3],
    ratios=[1, 2, 3, 1],
    num_classes=4,
    num_samples=2,
)
data = {
    "image": np.array([
        [[0.0, 0.3, 0.4, 0.2, 0.0],
        [0.0, 0.1, 0.2, 0.1, 0.4],
        [0.0, 0.3, 0.5, 0.2, 0.0],
        [0.1, 0.2, 0.1, 0.1, 0.0],
        [0.0, 0.1, 0.2, 0.1, 0.0]]
    ]),
    "label": np.array([
        [[0, 0, 0, 0, 0],
        [0, 1, 2, 1, 0],
        [0, 1, 3, 0, 0],
        [0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0]]
    ]),
}
result = cropper(data)

The 2 randomly cropped samples of `label` can be:
[[0, 1, 2],     [[0, 0, 0],
 [0, 1, 3],      [1, 2, 1],
 [0, 0, 0]]      [1, 3, 0]]

 

 

더 자세한 내용은 홈페이지에 잘 설명되어있습니다.

https://docs.monai.io/en/stable/transforms.html

 

Transforms — MONAI 1.2.0 Documentation

weights – can be a list or tuple of numbers for input data with shape: [E, C, H, W[, D]]. or a Numpy ndarray or a PyTorch Tensor data. the weights will be added to input data from highest dimension, for example: 1. if the weights only has 1 dimension, it

docs.monai.io

 

 

 

 

 


배움을 기록하기 위한 공간입니다. 

수정이 필요한 내용이나 공유하고 싶은 것이 있다면 언제든 댓글로 남겨주시면 환영입니다 :D

반응형