기본개념: 코루틴, 메인루틴, 서브루틴

코루틴을 이해하기위해서는 메인루틴과 서브루틴을 이해하고 있으면, 더 쉽게 이해가 됩니다[이전포스팅]. 이 3가지 루틴을 정리하면 아래와 같습니다.

  • 메인루틴(Main routine): 메인루틴은 보통 프로그램의 시작점이며, 프로그램의 주 흐름을 담당합니다. 메인루틴은 일련의 작업을 수행하고 다른 서브루틴이나 코루틴을 호출할 수 있습니다. 프로그램이 시작되는 메인코드라고 생각하면 됩니다.
  • 서브루틴(subroutine): 메인루틴에서 호출되는 함수, 또는 서브루틴에서 호출되는 함수들을 의미합니다. 즉, 다른 루틴에서 호출되는 경우를 의미합니다.
  • 코루틴(Coroutine): 메인루틴에서 호출되지만, 코루틴은 실행되는 도중에, 일시중단되어 다시 메인루틴으로 전환되었다가 다시 코루틴으러 전환될 수 있는 "제어흐름"이 가능한 루틴을 의미합니다.

 

코루틴과 제너레이터

코루틴과 제너레이터 중, 코루틴이 더 일반적인 개념이며 코루틴 중에 반복가능한 데이터를생성하는 한 종류가 제너레이터라고 할 수 있습니다. 이 제너레이터와 코루틴을 굳이 비교하자면 아래와 같이 비교해볼 수 있습니다.

  코루틴 제너레이터
공통점 1. 함수 형태로 작성
2. yield 키워드로 생성하거나 반환
3. 상태유지: 이전 상태를 유지하며, 중단시점부터 재개가 가능
1. 함수 형태로 작성
2. yield 키워드로 생성하거나 반환
3. 상태유지: 이전 상태를 유지하며, 중단시점부터 재개가 가능
  종료 yield 완료시: StopIteration예외 yield 완료시: StopIteration예외
 차이점    
   목적 주로 비통기 작버을 처리하기 위해 사용 반복 가능한 객체를 사용
예) yield 1; yield 2..
   작성방법 yield 외에 await을 이용해서 중간에 값을 보내거 받을 수 있음  
   호출방법 send()메서드로 값을 주고 받음.  next()함수로 값을 하나씩받음
   종료 StopIteration 예외 StopIteration 예외

 

코루틴의 간단한 예시입니다.

def simple_coroutine():
    print("Coroutine started")
    x = yield  # 처음 호출될 때까지 대기
    print(f"Received: {x}")
    y = yield x * 2  # yield 우측에 있는 값은 반환하는 값입니다.
    print(f"Received: {y}")

# 코루틴 생성
coro = simple_coroutine()

# 코루틴 시작
print(next(coro))  # Coroutine started, 첫 번째 yield까지 실행

# 데이터 전송
print(coro.send(10))  # Received: 10

# 데이터 전송
coro.send(20)  # Received: 20

 

위의 예시처럼 코루틴을 시작하려면 반드시 "next()"을 호출하여 실행시켜야 합니다. 그렇지 않으면 아래와 같이 에러가 발생합니다. 즉, coroutine 시작지점까지는 함수가 실행되어 대기중이어야합니다.

Cell In[24], line 1
----> 1 coro.send(20)

TypeError: can't send non-None value to a just-started generator

 

 

코루틴과 마찬가지로, generator도 yield의 반환이 없으면 StopIteration 예외가 발생합니다.

In [1]: def simple_generator():
   ...:     yield 1
   ...:     yield 2
   ...:     yield 3
   ...: 

In [2]: gen = simple_generator()

In [4]: next(gen)
Out[4]: 1

In [5]: next(gen)
Out[5]: 2

In [6]: next(gen)
Out[6]: 3

In [7]: next(gen)
StopIteration                             Traceback (most recent call last)
Cell In[7], line 1
----> 1 next(gen)

StopIteration:

 

 

코루틴의 4가지 상태: GEN_CREATE, GEN_RUNNING, GEN_SUSPENDED, GEN_CLOSE

  1. GEN_CREATED (생성 상태): 코루틴이 생성되었지만 아직 시작되지 않은 상태입니다.
  • 특징: __next__() 또는 send(None)이 호출되기 전의 상태입니다.
def coroutine_example():
    yield

coro = coroutine_example()
print(coro)  # 코루틴 객체가 생성된 상태, 아직 실행되지 않음

2. GEN_RUNNING (실행 중 상태): 코루틴이 현재 실행 중인 상태입니다.

  • 특징: 코루틴이 실행되고 있으며, 내부적으로 yield 문을 만날 때까지 실행됩니다. 실행 중에 다시 재개될 수 없습니다.
def coroutine_example():
    print("Running")
    yield

coro = coroutine_example()
next(coro)  # "Running" 출력, 실행 중 상태

 

3. GEN_SUSPENDED (일시 중지 상태): 코루틴이 yield 문에서 일시 중지된 상태입니다. 주의해야할 것은 RUNNING 상태는 yield을 만나기 전까지 실행되는 것인데, 여기서는 yield가 이미 실행된 상태를 의미합니다.

그리고, inpsect.getgeneratorstate 함수로 코루틴의 상태를 조회해보면 GEN_SUSPENDED을 확인할 수 있습니다.

>>> def coroutine_example():
>>>     yield "Suspended"
>>>  

>>> coro = coroutine_example()
>>> print(next(coro))

>>> import inspect
>>> inspect.getgeneratorstate(coro)
>>> 'GEN_SUSPENDED'

 

4. GEN_CLOSED(종료상태): 코루틴이 종료된 상태입니다. 종료되면 다시 시작할 수 없습니다.

  • 특징: 모든 코드가 실행되었거나 close() 메서드가 호출된 상태입니다.
def coroutine_example():
    yield "Running"
    return "Done"

coro = coroutine_example()
print(next(coro))  # "Running" 출력
try:
    next(coro)  # StopIteration 예외 발생
except StopIteration as e:
    print(e.value)  # "Done" 출력, 종료 상태

 

각 상태를 연속선상으로 확인해보면 아래처럼 확인해볼 수 있습니다.

import inspect

def coroutine_example():
    print("Coroutine started")
    x = yield "Suspended at first yield"  # GEN_SUSPENDED 상태로 진입
    print(f"Received: {x}")
    y = yield "Suspended at second yield"  # 다시 GEN_SUSPENDED 상태로 진입
    print(f"Received: {y}")
    return "Done"  # GEN_CLOSED 상태로 진입

# 코루틴 객체 생성 (GEN_CREATED 상태)
coro = coroutine_example()
print(inspect.getgeneratorstate(coro))  # GEN_CREATED

# 코루틴 시작 (GEN_RUNNING 상태)
print(next(coro))  # "Coroutine started" 출력, "Suspended at first yield" 반환
print(inspect.getgeneratorstate(coro))  # GEN_SUSPENDED

# 데이터 전송 및 재개 (GEN_RUNNING 상태로 변환 후 GEN_SUSPENDED 상태로 다시 변환)
print(coro.send(10))  # "Received: 10" 출력, "Suspended at second yield" 반환
print(inspect.getgeneratorstate(coro))  # GEN_SUSPENDED

# 데이터 전송 및 종료 (GEN_RUNNING 상태로 변환 후 GEN_CLOSED 상태로 변환)
try:
    coro.send(20)  # "Received: 20" 출력, StopIteration 예외 발생
except StopIteration as e:
    print(e.value)  # "Done" 출력
print(inspect.getgeneratorstate(coro))  # GEN_CLOSED

 

while True 구문을 이용한 코루틴

while True를 사용한 코루틴으로 지수 이동 평균 (Exponential Moving Average, EMA)을 계산하는 것들을 해볼 수 있습니다.

아래는 그 예제입니다.

def ema_coroutine(initial_ema, alpha):
    ema = initial_ema
    print(f"Starting EMA with initial value: {ema}")
    while True:
        new_value = yield ema
        ema = (alpha * new_value) + ((1 - alpha) * ema)
        print(f"Updated EMA to: {ema}")

# 코루틴 생성 및 초기화
alpha = 0.1
initial_ema = 50  # 초기 EMA 값
ema_gen = ema_coroutine(initial_ema, alpha)
current_ema = next(ema_gen)  # 코루틴 시작, 최초의 EMA 값을 받음

# 새로운 값으로 EMA 업데이트
print(ema_gen.send(55))  # 새 데이터 포인트 55를 전달하고 업데이트된 EMA 출력
print(ema_gen.send(60))  # 새 데이터 포인트 60을 전달하고 업데이트된 EMA 출력

# 코루틴 종료
ema_gen.close()

 

yield 에서 값을 반환하는 순서를 주의할 필요가 있습니다.

  1. send(50): 코루틴에 값을 보내면 new_value에 할당합니다. 이후 print()문까지 도달하여 출력합니다. 
  2. yield ema: 그리고나서 업데이트된 ema을 반환하여 50.5가 출력됩니다. 

 

코루틴을 초기화해주면 데코레이터: coroutine

반응형

DICE 손실 함수(Dice Loss)는  Sørensen–Dice coefficient 라고도 불리며 주로 의료 영상 분석과 같은 분야에서 세그멘테이션 문제에 많이 사용됩니다. 이 손실 함수는 이진 분류 작업에서 두 샘플 집합의 유사도를 측정하기 위해 사용되며, 특히 불균형한 데이터셋에서 좋은 성능을 보입니다.

DICE 계수는 두 샘플 집합의 유사도를 측정하는데 사용되며, 다음과 같이 정의됩니다:

  1. $|X \cap Y|$: 두 집합의 교집합의 크기입니다.
  2. |X|, |Y|: 각각 집합의 크기입니다.

 

DICE 손실함수

DICE 손실 함수는 1에서 DICE 계수를 뺀 값으로 정의됩니다. 이는 계수가 1에 가까울수록 손실이 작아지며, 예측과 실제 값 사이의 유사도가 높음을 의미합니다. 손실 함수는 다음과 같이 표현됩니다:

DICE Loss=1−DICE

이 손실 함수는 특히 클래스 간 불균형이 클 때 유용하며, 소수 클래스의 중요한 특징을 놓치지 않도록 도와줍니다.

import torch

class DiceLoss(torch.nn.Module):
    def __init__(self, smooth=1.):
        super(DiceLoss, self).__init__()
        self.smooth = smooth

    def forward(self, inputs, targets):
        inputs = torch.sigmoid(inputs)
        intersection = (inputs * targets).sum()
        dice = (2. * intersection + self.smooth) / (inputs.sum() + targets.sum() + self.smooth)
        return 1 - dice

 

DICE loss function의 미분 가능성(differentiable)

객체인식(Object detection)에서의 IoU(Intesection over Union)은 직접 미분이 안되어, 미분 가능한 형태로 변경하여 계산합니다[UnitBox]. Segmentation에서의 DICE score은 미분이 가능합니다. 특히, segementation은 픽셀단위로 계산하기 때문에 예측픽셀과 정답픽셀간의 차이를 직접 계산할 수 있습니다.

DICE loss은 아래와 같이 정의됩니다.

DICE loss = 1- DICE coefficient  (1)

여기서 TP, FP, FN을 아래와 같이 정의할 수 있습니다. 

  • $p_{i}$: predicted probability
  • $g_{i}$: label
  • TP= $\sum_{i} p_{i}g_{i} $ : 예측과 실제가 둘 다 1인 경우
  • FP= $\sum_{i} p_{i}(1-g_{i}) $: 실제가 0일 때, 예측이 1인 경우. $(1- g_{i})$로 indication을 넣음
  • FN= $\sum_{i} (1-p_{i})(g_{i})$: 실제가 1일 떄, 예측이 0인 경우의 합

 

(1)식에서 DICE coefficient만 구하면 loss은 구할 수 있습니다. 따라서, 위를 정의들을 이용하여, DICE coefficient을 다시 정의해보겠습니다.

$\text{DICE coefficient} = \frac{ 2 \sum_{i} p_{i}g_{i} }{\sum_{i} p_{i} + \sum_{i}g_{i} }$

이를 DICE coefficient식에 대입하고 p에 대해서 미분합니다.

$\frac{\partial L}{\partial p_{i}} = \frac{\partial}{\partial p_{i}} (1 - \frac{ 2 \sum_{i} p_{i}g_{i} }{\sum_{i} p_{i} + \sum_{i}g_{i} })$ (2)

$=-\frac{2g_{i} (\sum_{i} p_{i} + \sum_{i}g_{i}) - 2(\sum_{i}p_{i}g_{i})}{(\sum_{i} p_{i} + \sum_{i}g_{i})^{2}}$ (3)

(3)은 나눗셈의 미분으로 계산합니다. 분모는 분모의 제곱으로 들어가고, 분자는 분자미분*분모 + 분자*분모미분으로 계산됩니다. $\frac{f(x)}{g(x)}=\frac{f'(x)g(x) + f(x)g'(x)}{g(x)^{2}} $

 

(3)식을 보면 DICE loss은 예측값 $p_{i}$에 대해서의 미분값이며, gradient descent을 이용하여 최적화가 가능합니다. 이 식은 예측값 $p_{i}$을 얼마만큼 조정하냐에 따라 손실함수가 바뀐다는 것이냐는거고, 다시 딥러닝 parameter에 대해서 미분하는게 필요하니, 체인룰을 이용하여 ($\frac{\partial L }{\partial \theta } = \frac{\partial L }{\partial p_{i}} \frac{\partial p_{i} }{\partial \theta }$)해볼 수 있습니다.

 

 

반응형

Image to image translation은 두 이미지 사이의 연관성을 학습하는 방법입니다. 보통은 1) 두 이미지의 짝을 지은 데이터가 가 구하기 어려워서 image to image을 하기 어렵고, 2) 한 이미지를 꼭 반드시 하나의 이미지에만 짝을 지을 필요가 없어 데이터 구성이 매우 어렵습니다.

 

위의 1), 2)의 예시인데, 이렇게 이미지를 짝을 지어야하는 경우에 이 데이터를 짝짓기도 어렵고, 짝을 짓더라도 다양한 경우가 많아서 golden standard로 짝을 지었다고 보장하기 어렵습니다. 

 

방법론

DRIT++은 2개의 임베딩을 나눠 만들어내는데, 1) domain invariant content space, 2) domain-specific attribute space 을 나눠 만들어냅니다.

구성은 크게 3파트입니다.

  1. 컨텐츠 인코더(content encoder): domain invariant content space을 만들어내는 인코더가 하나 필요합니다.
  2. 속성 인코더(Attribute encoder): 속성 인코더도 하나 필요합니다. 속성 인코더가 만드는 임베딩 벡터는 컨텐트 임베딩 벡터와 공유하지 않습니다. 단, X 도메인, Y도메인에 쓰이는 인코더는 동일 합니다(shared).
  3. 제너레이터(Generator): 컨텐츠 인코더가 만든 벡터와, 속성인코더가 만든 벡터를 입력으로하여 이미지를 생성합니다.
  4. 판별부(Domain discrimator): 합성된 이미지와 진짜 이미지를 판별하는 모듈입니다.

 

테스트 타임에는 attribute vectors을 prior Gaussian distribution을 따른다고 가정하고  N(0,1)의 attribution vector을 주입합니다.

 

반응형

상피조직의 세포층에 따른 분류

  1. 단층 상피: Simple이라는 이름이 붙어짐
  2. 다층 상피: stratified라는 이름이 붙어짐.

 

상피조직의 세포 형태(높이)에 따른 분류

  1. 판상(비늘모양 판모양): squamous  (scale-, plate-like)라는 이름이 붙어짐 
  2. Cuboidal: 입방형. 가로세로가 보통 같은 모양.
  3. Columnar: 기둥형. 높은층

 

단층형 상피(Simple epithelia)

  1. Simple squamous epithelium: 단층(Simple)으로 이뤄진 낮은 크기(squamous)의 세포들로 이루어진 상피. 대부분의 신체에서 발견되고, 심장, 혈관, 림프관등에서 관찰됨. 핵은 납작하고 타원형으로 관찰됨 => 달걀처럼 행이보임. 보통 상피의 중앙에 핵이 있음.
  2. Simple cuboidal epithelium: 조직을 수직으로 자른 경우(perpendicular section)으로 주로 관찰됨. 작은 다각형형태로 보이는 경우. 보통 분비샘에서 많이보임
  3. Simple columnar epithelium: 길죽한 형태의 단층을 가진 상피. 세포의 핵이 같은 높이만크 위치하기도하지만, 바닥쯤에 있는 경우도 있음. 주로 소화기계에서 발견됨.

 

종종 외부 세포벽이 안보일수 있어서, 아래처럼만 보이는 경우가 종종 있음.

그리고, Section에 따라서 그리고 다양한 형태를 보일 수있음.

 

Ref

http://lecannabiculteur.free.fr/SITES/UNIV%20W.AUSTRALIA/mb140/CorePages/Epithelia/Epithel.htm

반응형

Human breast tissue

  • 소엽(Loublar): 여러 신체에서 볼 수 있는 구조적인 작은 단위. 보통 엽은 한자에서 "잎"을 의미하나 , 의학에서는 작은 구조적인 단위를 의미
  • Mammary duct: Terminal ductal lobular unit(TDLU)로부터 모유가 나오는데 그 모유가 나오는 관을 Mammary duct라고함.
  • Terminal Ductal Lobular Unit (TDLU): 유선(mammary duct)의 끝 부분에 위치하여 모유를 생산하는 작은 단위

 

src: https://www.google.com/imgres?q=tdlu&imgurl=https%3A%2F%2Fwww.biorxiv.org%2Fcontent%2Fbiorxiv%2Fearly%2F2023%2F03%2F12%2F2023.03.12.532249%2FF1.large.jpg&imgrefurl=https%3A%2F%2Fwww.biorxiv.org%2Fcontent%2F10.1101%2F2023.03.12.532249v1&docid=6s95-Ze3ht2DXM&tbnid=i0OrnnYq9o2heM&vet=12ahUKEwi06MSF2qCHAxUhnK8BHXeuC18QM3oECGUQAA..i&w=1280&h=619&hcb=2&ved=2ahUKEwi06MSF2qCHAxUhnK8BHXeuC18QM3oECGUQAA

 

  • Acini(Ductules, 소낭): 분비기관에서의 작은 구조적 단위. 분비세포로 이뤄져있는 구조

https://www.researchgate.net/figure/Schematic-representation-of-TDLU_fig2_30864284

 

TDLU

  • Acini (terminal ductules): 동글동글하고, 가운데 빈 공간(lumen)있는 구조물.
  • Intralobular stroma (기질): 구조물을 지지하는 역할. intra-lobular기에 lobular내부에 있어 구조를 지지하는 구조물. connective, or adiopose tissue
  • Intralobular stomra: lobular외에 있는 지지대 역할을 하는 구조물
  • Lactiferous duct(유선): mammary duct. 같은 단어.

src: https://blogs.gwu.edu/smhs-histology/mammary-gland/

 

그림으로 보면 조금 쉬움.

  • Adipose cell: 아무것도 없는 구멍같지만, 지방이 투명해서 투명한 구멍처럼보임. 지방세포
  • Blood vessel: RGB가 잘보임
  • Alveoli (Acini): 주머니모양. Acini와 같은 말 
  • Interlobular connective tissue: acini 사이사이로

src: https://www.google.com/url?sa=i&url=https%3A%2F%2Flink.springer.com%2Fchapter%2F10.1007%2F978-981-99-0035-0_3&psig=AOvVaw1UhICJE6e0Iwas33rVGmN2&ust=1720847223210000&source=images&cd=vfe&opi=89978449&ved=0CBQQjhxqFwoTCMiPhs7doIcDFQAAAAAdAAAAABAJ

 

 

Microscopic anatomy

주요 특징

  1. TDLU은 2개의 상피세포로 이뤄져있음.
    1. 내부 레이어는 luminal cell이고, 단층이거나 여러층처럼 보이는 경우가 있음. outer layer은 myoepithelial cell임. 어떤 책에서는 luminal cell들이 columnar layer을 이루고 있다고하는데, 이게 맞을 것(?) 같음. 내부 레이어의 핵은 중앙 또는 하단부에 위치해있음. 
    2. Myoepithelia cell

Reference

https://screening.iarc.fr/atlasbreastdetail.php?Index=005&e=

 

Atlas of breast cancer early detection

 

screening.iarc.fr

 

 

Atlas of breast cancer early detection

 

screening.iarc.fr

http://lecannabiculteur.free.fr/SITES/UNIV%20W.AUSTRALIA/mb140/CorePages/Epithelia/Epithel.htm

반응형

요약


  • 딥러닝에서의 stride: 컨볼루션 연산에서 커널의 이동 범위를 나타냅니다.
  • numpy 배열에서의 stride: 배열의 각 차원에서 다음 요소로 이동하기 위한 메모리 상의 바이트 수를 나타냅니다.

 

보통 딥러닝하시는 분들이면 딥러닝의 CNN layer에서 stride을 들어보셨을 텐데, numpy 에서의 stride가 어떤 개념인지 정리해보겠습니다.


numpy 배열에서의 Stride: 배열의 각 차원에서 다음 요소로 이동하기 위한 메모리 상의 바이트 수

numpy 배열에서의 stride는 메모리에서 다음 요소로 이동하기 위해 건너뛰어야 하는 바이트 수를 나타냅니다. numpy 배열은 연속된 메모리 블록을 사용하여 데이터를 저장하며, stride는 배열의 각 차원을 따라 이동할 때의 바이트 수를 지정합니다. 배열이 슬라이싱되거나 뒤집힐 때 stride가 음수가 될 수 있습니다. 이는 배열이 역순으로 참조되고 있음을 의미합니다.

예를 들어, numpy.array을 3, 3 shape의 unit8 타입의 행렬을 만들었다고 가정해보겠습니다. 여기서 [0,0]의 위치에서 그 다음인 [0, 1]을 읽으려면 uint8이기 때문에 8bit(1byte)을 이동해서 읽어야합니다. 한편, 그 다음행인 [1, 0]을 읽어야하면, 한 행이 3개의 원소를 담고 있기에, 3*8bit(3byte)을 이동해서 읽어야합니다. Axis 1이 컬럼이며, Axis 0이 행이기에, Axis[0](행)을 이동하려면 3bytes (stride=3)으로 표시되어야하며, Axis[1](열)을 이동하려면 1byte (stride=1)을 이동해야합니다.

stride: https://stackoverflow.com/questions/53097952/how-to-understand-numpy-strides-for-layman

 

아래와 같이 3, 3 정수형의 uint8을 생성해보겠습니다. 이 배열의 `.strides`속성은 축이 2개이기에, 2개의 값이 튜플로 (3, 1)로 반환됩니다. 그리고, 위에서 언급했던 것처럼 stride가 (3, 1)입니다.

>>> import numpy as np

>>> arr = np.array([
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
], dtype=np.uint8)

>>> print("배열:")
>>> print(arr)
>>> print("Stride:", arr.strides)

배열:
[[1 2 3]
 [4 5 6]
 [7 8 9]]
Stride: (3, 1)

 

Stride은 음수도 될 수 있습니다. 이 행렬을 뒤집는 경우, 다음 원소를 읽기위해서는 이전의 메모리를 참조해야합니다. 예를 들어, 행렬을 한번 뒤짚은 경우라면, `array[0]`이후에 `array[1]`을 읽으려면 +로 바이트를 이동시켜야하는게 아니라 (-)으로 바이트를 이동시켜야합니다.

>>> import numpy as np

>>> arr = np.array([1, 2, 3, 4, 5])
>>> reversed_arr = arr[::-1]

>>> print("원래 배열:", arr)
>>> print("뒤집힌 배열:", reversed_arr)
>>> print("원래 배열의 stride:", arr.strides)
>>> print("뒤집힌 배열의 stride:", reversed_arr.strides)
원래 배열: [1 2 3 4 5]
뒤집힌 배열: [5 4 3 2 1]
원래 배열의 stride: (8,)
뒤집힌 배열의 stride: (-8,)

 

딥러닝에서의 Stride: 컨볼루션 연산에서 커널의 이동 범위

딥러닝에서의 stride는 주로 컨볼루션 연산에서 사용됩니다. 컨볼루션 연산에서 stride는 커널이 입력 이미지 위를 얼마나 많이 움직이는지를 의미합니다. 예를 들어, stride가 1이면 커널이 한 픽셀씩 이동하며 연산을 수행하고, stride가 2이면 두 픽셀씩 건너뛰면서 연산을 수행합니다.

 

Filter(kernel)이 image에서 2칸씩 이동하며 연산하면 stride가 2입니다. src: https://medium.com/machine-learning-algorithms/what-is-stride-in-convolutional-neural-network-e3b4ae9baedb



연관 에러: ValueError: At least one stride in the given numpy array is negative, and tensors with negative strides are not currently supported. (You can probably work around this by making a copy of your array with array.copy().)

이미지를 전처리하는 과정에서 flip 등의 연산이 들어가게되면, 위의 예시처럼 stride가 음수가 되는 경우, 위의 에러가 발생합니다. "적어도 하나 이상의 stride가 음수가 됨을 의미합니다". 따라서 이 경우에는 flip한 array을 다시 메모리에 재할당하여(=copy)하여 처리하면 해결이됩니다.

# 변경전

transform = A.Compose(
    [
        A.RandomCrop(height=224, width=224, p=1),
        A.Resize(224, 224),
        A.HorizontalFlip(p=0.5),
        A.VerticalFlip(p=0.5),
        A.RandomRotate90(p=0.5), 
        A.Normalize(mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225)),
        ToTensorV2(),
    ]    
)


train_dataset = dataset(train_images, train_masks, transform)
train_dataset[0] # 에러 발생

# 변경

반응형

+ Recent posts