DonHurry

step40. λΈŒλ‘œλ“œμΊμŠ€νŠΈ ν•¨μˆ˜ λ³Έλ¬Έ

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

step40. λΈŒλ‘œλ“œμΊμŠ€νŠΈ ν•¨μˆ˜

_도녁 2023. 2. 15. 00:44

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

 

 

이전 λ‹¨κ³„μ—μ„œλŠ” DeZero만의 sum ν•¨μˆ˜λ₯Ό κ΅¬ν˜„ν–ˆμŠ΅λ‹ˆλ‹€. μ΄λ•Œ broadcast_to ν•¨μˆ˜κ°€ μ‚¬μš©λ˜μ—ˆλŠ”λ°, 이번 λ‹¨κ³„μ—μ„œ κ΅¬ν˜„ν•΄λ³΄κ² μŠ΅λ‹ˆλ‹€. μˆœμ „νŒŒμ—μ„œλŠ” μ—­μ‹œ λ„˜νŒŒμ΄μ˜ λΈŒλ‘œλ“œμΊμŠ€νŠΈλ₯Ό ν™œμš©ν•˜μ§€λ§Œ, μ—­μ „νŒŒλŠ” DeZero만의 μ½”λ“œλ₯Ό κ΅¬ν˜„ν•΄λ‚΄μ•Ό ν•©λ‹ˆλ‹€. μš°μ„  λΈŒλ‘œλ“œμΊμŠ€νŠΈ ν•¨μˆ˜μ™€ sum ν•¨μˆ˜λŠ” μƒν˜Έ 의쑴적인 κ΄€κ³„μž„μ„ μ•Œμ•„μ•Ό ν•©λ‹ˆλ‹€.

 

 

μœ„μ˜ κ·Έλ¦Όκ³Ό 같이 μ½”λ“œλ₯Ό κ΅¬ν˜„ν•˜λ©΄, broadcast_to의 μ—­μ „νŒŒμ—λŠ” sum_toκ°€ sum_to의 μ—­μ „νŒŒμ—λŠ” broadcast_toκ°€ ν™œμš©λ˜λŠ” 것을 확인할 수 μžˆμŠ΅λ‹ˆλ‹€.

class SumTo(Function):
    def __init__(self, shape):
        self.shape = shape
    
    def forward(self, x):
        self.x_shape = x.shape
        y = utils.sum_to(x, self.shape)
        return y

    def backward(self, gy):
        gx = broadcast_to(gy, self.x_shape)
        return gx


def sum_to(x, shape):
    if x.shape == shape:
        return as_variable(x)
    return SumTo(shape)(x)


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

    def forward(self, x):
        self.x_shape = x.shape
        y = np.broadcast_to(x, self.shape)
        return y
    
    def backward(self, gy):
        gx = sum_to(gy, self.x_shape)
        return gx
    

def broadcast_to(x, shape):
    if x.shape == shape:
        return as_variable(x)
    return BroadcastTo(shape)(x)

 

λ‹€μŒμœΌλ‘œ λΈŒλ‘œλ“œμΊμŠ€νŠΈ λŒ€μ‘μ΄ ν•„μš”ν•©λ‹ˆλ‹€. λ„˜νŒŒμ΄μ—μ„œλŠ” ν˜•μƒμ΄ λ‹€λ₯Έ 닀차원 λ°°μ—΄λΌλ¦¬μ˜ 연산을 κ°€λŠ₯ν•˜κ²Œ ν•©λ‹ˆλ‹€. DeZero μ—­μ‹œ λ§ˆμ°¬κ°€μ§€λ‘œ ν˜•μƒμ΄ λ‹€λ₯Ό λ•Œ, 계산 κ³Όμ •μ—μ„œ λΈŒλ‘œλ“œμΊμŠ€νŠΈ κΈ°λŠ₯을 λŒ€μ‘μ‹œν‚€λ„λ‘ ν•˜κ² μŠ΅λ‹ˆλ‹€. λ‹€μŒ μ½”λ“œλŠ” λ„˜νŒŒμ΄μ˜ λΈŒλ‘œλ“œμΊμŠ€νŠΈ κΈ°λŠ₯μž…λ‹ˆλ‹€.

x0 = np.array([1, 2, 3])
x1 = np.array([10])
y = x0 + x1
print(y)  # array([11, 12, 13])

 

핡심은 μˆœμ „νŒŒμ—μ„œ λΈŒλ‘œλ“œμΊμŠ€νŠΈκ°€ 일어났닀면, μ—­μ „νŒŒμ—μ„œ λΈŒλ‘œλ“œμΊμŠ€νŠΈμ˜ μ—­μ „νŒŒκ°€ 이루어져야 ν•œλ‹€λŠ” μ μž…λ‹ˆλ‹€. μ•žμ„œ λ³΄μ•˜λ˜ κ·Έλ¦Όκ³Ό 같이 broadcast_to ν•¨μˆ˜μ˜ μ—­μ „νŒŒλŠ” sum_to ν•¨μˆ˜μž…λ‹ˆλ‹€. λ”°λΌμ„œ DeZero의 Add 클래슀λ₯Ό λ‹€μŒκ³Ό 같이 μˆ˜μ •ν•΄μ•Ό ν•©λ‹ˆλ‹€. Mul, Sub, Div 클래슀 μ—­μ‹œ μˆ˜μ •ν•˜μ—¬μ•Ό ν•©λ‹ˆλ‹€.

class Add(Function):
    def forward(self, x0, x1):
        self.x0_shape, self.x1_shape = x0.shape, x1.shape
        y = x0 + x1
        return y
    
    def backward(self, gy):
        gx0, gx1 = gy, gy
        if self.x0_shape != self.x1_shape:  # for broadcast
            gx0 = dezero.functions.sum_to(gx0, self.x0_shape)
            gx1 = dezero.functions.sum_to(gx1, self.x1_shape)
        return gx0, gx1

 

λ§ˆμ§€λ§‰μœΌλ‘œ λ‹€μŒκ³Ό 같은 ν…ŒμŠ€νŠΈλ“€μ„ μ§„ν–‰ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

import numpy as np
from dezero import Variable

x0 = Variable(np.array([1, 2, 3]))
x1 = Variable(np.array([10]))
y = x0 + x1
print(y)  # variable([11 12 13])

y.backward()
print(x0.grad)  # variable([1 1 1])
print(x1.grad)  # variable([3])

y = x0 * x1
print(y)  # variable([10 20 30])

x0.cleargrad()
x1.cleargrad()
y.backward()
print(x0.grad)  # variable([10 10 10])
print(x1.grad)  # variable([6])

'DeZero > πŸ—»μ œ4κ³ μ§€' μΉ΄ν…Œκ³ λ¦¬μ˜ λ‹€λ₯Έ κΈ€

step42. μ„ ν˜• νšŒκ·€  (0) 2023.02.18
step41. ν–‰λ ¬μ˜ κ³±  (0) 2023.02.16
step39. 합계 ν•¨μˆ˜  (0) 2023.02.14
step38. ν˜•μƒ λ³€ν™˜ ν•¨μˆ˜  (0) 2023.02.13
step37. ν…μ„œλ₯Ό 닀루닀  (0) 2023.02.12