DonHurry

step38. ν˜•μƒ λ³€ν™˜ ν•¨μˆ˜ λ³Έλ¬Έ

DeZero/πŸ—»μ œ4κ³ μ§€

step38. ν˜•μƒ λ³€ν™˜ ν•¨μˆ˜

_도녁 2023. 2. 13. 01:45

πŸ“’ λ³Έ ν¬μŠ€νŒ…μ€ λ°‘λ°”λ‹₯λΆ€ν„° μ‹œμž‘ν•˜λŠ” λ”₯λŸ¬λ‹3을 기반으둜 μž‘μ„±ν•˜μ˜€μŠ΅λ‹ˆλ‹€. 배운 λ‚΄μš©μ„ κΈ°λ‘ν•˜κ³ , 개인적인 곡뢀λ₯Ό μœ„ν•΄ μž‘μ„±ν•˜λŠ” ν¬μŠ€νŒ…μž…λ‹ˆλ‹€. μžμ„Έν•œ λ‚΄μš©μ€ ꡐ재 ꡬ맀λ₯Ό κ°•λ ₯ μΆ”μ²œλ“œλ¦½λ‹ˆλ‹€.

 

 

이번 λ‹¨κ³„μ—μ„œλŠ” ν…μ„œμ˜ ν˜•μƒμ„ λ³€ν™˜ν•˜λŠ” reshape ν•¨μˆ˜μ™€ 행렬을 μ „μΉ˜ν•˜λŠ” transpose ν•¨μˆ˜λ₯Ό μ‚΄νŽ΄λ³΄κ² μŠ΅λ‹ˆλ‹€. λ„˜νŒŒμ΄ λΌμ΄λΈŒλŸ¬λ¦¬μ—λŠ” 이미 reshape ν•¨μˆ˜κ°€ μ‘΄μž¬ν•©λ‹ˆλ‹€. ν•˜μ§€λ§Œ DeZero λ²„μ „μ—μ„œ reshape ν•¨μˆ˜λŠ” μ—­μ „νŒŒλ₯Ό κ³ λ €ν•΄μ•Όν•©λ‹ˆλ‹€. μ΄λ•Œ κ°€μž₯ μ€‘μš”ν•œ 것은 λ³€μˆ˜μ˜ 데이터와 기울기의 ν˜•μƒμ΄ μΌμΉ˜ν•΄μ•Όν•œλ‹€λŠ” κ²ƒμž…λ‹ˆλ‹€. x.data.shape와 x.grad.shapeκ°€ κ°™μ•„μ•Ό ν•œλ‹€λŠ” 것이죠.

 

κ΅¬ν˜„ν•  λ•Œ μ£Όμ˜ν•΄μ•Όν•  점은 μ—­μ „νŒŒ μ‹œμ—λŠ” 직접 κ΅¬ν˜„ν•œ ν•¨μˆ˜λ₯Ό ν™œμš©ν•΄μ•Ό ν•œλ‹€λŠ” κ²ƒμž…λ‹ˆλ‹€. backward(gy)μ—μ„œ 인수 gyκ°€ Variable μΈμŠ€ν„΄μŠ€μ΄κΈ° λ•Œλ¬Έμž…λ‹ˆλ‹€. λ”°λΌμ„œ Variable μΈμŠ€ν„΄μŠ€λ₯Ό λ‹€λ£° 수 μžˆλŠ” DeZero의 ν•¨μˆ˜λ‘œ 계산해야 ν•©λ‹ˆλ‹€.

class Reshape(Function):
    def __init__(self, shape):
        self.shape = shape

    def forward(self, x):
        self.x_shape = x.shape
        y = x.reshape(self.shape)
        return y
    
    def backward(self, gy):
        return reshape(gy, self.x_shape)


def reshape(x, shape):
    if x.shape == shape:
        return as_variable(x)
    return Reshape(shape)(x)

 

λ‹€μŒμœΌλ‘œ Variable ν΄λž˜μŠ€μ— μ½”λ“œλ₯Ό μΆ”κ°€ν•΄μ£Όμ–΄μ•Ό ν•©λ‹ˆλ‹€. νŠœν”Œ, 리슀트 λ“± λ‹€μ–‘ν•˜κ²Œ λ³€μˆ˜λ₯Ό λ°›κΈ° μœ„ν•¨μž…λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄ y = x.reshape(2, 3) ν˜•μ‹μ˜ κ°€λ³€ μΈμˆ˜λ„ 받을 수 있게 λ©λ‹ˆλ‹€.

class Variable:
	...
    
        def reshape(self, *shape):
                if len(shape) == 1 and isinstance(shape[0], (tuple, list)):
                    shape = shape[0]
                return dezero.functions.reshape(self, shape)

 

λ‹€μŒμœΌλ‘œ ν–‰λ ¬μ˜ μ „μΉ˜λ₯Ό μœ„ν•œ transposeμž…λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄ x의 ν˜•μƒμ΄ (2, 3)이라면 (3, 2)둜 λ³€ν™˜ν•΄μ€„ 수 μžˆμŠ΅λ‹ˆλ‹€. μ—­μ „νŒŒμ˜ 경우 μˆœμ „νŒŒμ™€ λ°˜λŒ€μ˜ λ³€ν™˜μ΄ 이루어지기 λ•Œλ¬Έμ— 좜λ ₯μ—μ„œ μ „ν•΄μ§„ 기울기λ₯Ό transpose ν•¨μˆ˜λ₯Ό ν™œμš©ν•΄ λ³€ν™˜ν•©λ‹ˆλ‹€. 본래 μ±…μ—μ„œλŠ” κ°„λ‹¨ν•˜κ²Œ 2차원 ν…μ„œμΌ λ•Œλ‘œ ν•œμ •ν•˜μ—¬ μ½”λ“œλ₯Ό κ΅¬μ„±ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€. ν•˜μ§€λ§Œ μ‹€μ œ transpose ν•¨μˆ˜λŠ” 더 λ²”μš©μ μœΌλ‘œ μ‚¬μš©λ©λ‹ˆλ‹€. [κ·Έλ¦Ό 38-4]와 같은 κΈ°λŠ₯이 λŒ€ν‘œμ μΈ μ˜ˆμž…λ‹ˆλ‹€.

 

 

μ΄λŸ¬ν•œ κΈ°λŠ₯을 ν¬ν•¨ν•œ 것이 μ•„λž˜ μ½”λ“œμž…λ‹ˆλ‹€. μˆœμ „νŒŒμ‹œμ—λŠ” λ„˜νŒŒμ΄λ₯Ό ν™œμš©ν•˜μ—¬ transposeλ₯Ό μ§„ν–‰ν•˜μ§€λ§Œ μ—­μ „νŒŒμ˜ κ²½μš°μ—λŠ” reshape와 λ§ˆμ°¬κ°€μ§€λ‘œ 직접 κ΅¬ν˜„ν•œ ν•¨μˆ˜λ₯Ό ν™œμš©ν•©λ‹ˆλ‹€.

class Transpose(Function):
    def __init__(self, axes=None):
        self.axes = axes

    def forward(self, x):
        y = x.transpose(self.axes)
        return y
    
    def backward(self, gy):
        if self.axes is None:
            return transpose(gy)
        
        axes_len = len(self.axes)
        inv_axes = tuple(np.argsort([ax % axes_len for ax in self.axes]))
        return transpose(gy, inv_axes)


def transpose(x, axes=None):
    return Transpose(axes)(x)

 

@property λ°μ½”λ ˆμ΄ν„°λŠ” y = x.transpose()λ₯Ό y = x.T와 같이 μ‚¬μš©ν•  수 μžˆλ„λ‘ ν•΄μ€λ‹ˆλ‹€.

class Variable:
	...
    
        def transpose(self, *axes):
                if len(axes) == 0:
                    axes = None
                elif len(axes) == 1:
                    if isinstance(axes[0], (tuple, list)) or axes[0] is None:
                        axes = axes[0]
                return dezero.functions.transpose(self, axes)

            @property
            def T(self):
                return dezero.functions.transpose(self)