DonHurry

step17. ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ์™€ ์ˆœํ™˜ ์ฐธ์กฐ ๋ณธ๋ฌธ

DeZero/๐Ÿ—ป์ œ2๊ณ ์ง€

step17. ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ์™€ ์ˆœํ™˜ ์ฐธ์กฐ

_๋„๋… 2023. 1. 18. 00:16

๐Ÿ“ข ๋ณธ ํฌ์ŠคํŒ…์€ ๋ฐ‘๋ฐ”๋‹ฅ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜๋Š” ๋”ฅ๋Ÿฌ๋‹3์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์ž‘์„ฑํ•˜์˜€์Šต๋‹ˆ๋‹ค. ๋ฐฐ์šด ๋‚ด์šฉ์„ ๊ธฐ๋กํ•˜๊ณ , ๊ฐœ์ธ์ ์ธ ๊ณต๋ถ€๋ฅผ ์œ„ํ•ด ์ž‘์„ฑํ•˜๋Š” ํฌ์ŠคํŒ…์ž…๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ ๊ต์žฌ ๊ตฌ๋งค๋ฅผ ๊ฐ•๋ ฅ ์ถ”์ฒœ๋“œ๋ฆฝ๋‹ˆ๋‹ค.

 

 

ํŒŒ์ด์ฌ์€ ํ•„์š” ์—†๋Š” ๊ฐ์ฒด๋ฅผ ๋ฉ”๋ชจ๋ฆฌ์—์„œ ์ž๋™์œผ๋กœ ์‚ญ์ œํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ฝ”๋“œ๋ฅผ ์ œ๋Œ€๋กœ ์ž‘์„ฑํ•˜์ง€ ์•Š์„ ์‹œ์—๋Š” ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜๋‚˜ ๋ถ€์กฑ ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํŠนํžˆ ์‹ ๊ฒฝ๋ง์€ ํฐ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค๋ฃจ๊ธฐ ๋•Œ๋ฌธ์— ์ฃผ์˜ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค. ํŒŒ์ด์ฌ(CPython)์˜ ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ๋Š” ์ฐธ์กฐ์ˆ˜๋ฅผ ์„ธ๋Š” ๋ฐฉ์‹๊ณผ ์„ธ๋Œ€๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์“ธ๋ชจ์—†๋Š” ๊ฐ์ฒด๋ฅผ ํšŒ์ˆ˜ํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ๋‚˜๋‰ฉ๋‹ˆ๋‹ค. ์ „์ž๋Š” ์ฐธ์กฐ ์นด์šดํŠธ, ํ›„์ž๋Š” GC(Garbage Collection)๋ผ๊ณ  ํ•ฉ์‹œ๋‹ค.

 

์šฐ์„  ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ ๊ธฐ๋ณธ์€ ์ฐธ์กฐ ์นด์šดํŠธ์ž…๋‹ˆ๋‹ค. ๋ชจ๋“  ๊ฐ์ฒด๋Š” ์ฐธ์กฐ ์นด์šดํŠธ๊ฐ€ 0์ธ ์ƒํƒœ๋กœ ์ƒ์„ฑ๋˜์–ด, ๋‹ค๋ฅธ ๊ฐ์ฒด๊ฐ€ ํ•ด๋‹น ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ•  ๋•Œ๋งˆ๋‹ค 1์”ฉ ์ฆ๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ๊ฐ์ฒด์— ๋Œ€ํ•œ ๋ชจ๋“  ์ฐธ์กฐ๊ฐ€ ๋Š๊ธฐ๋ฉด ์ฐธ์กฐ ์นด์šดํŠธ๊ฐ€ 0์ด ๋˜์–ด ํŒŒ์ด์ฌ ์ธํ„ฐํ”„๋ฆฌํ„ฐ๊ฐ€ ํšŒ์ˆ˜ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

 

์•„๋ž˜ ๊ทธ๋ฆผ์˜ ์™ผ์ชฝ ์ƒํƒœ์—์„œ  a = b = c = None์„ ์‹คํ–‰ํ•˜๊ฒŒ ๋˜๋ฉด ์˜ค๋ฅธ์ชฝ๊ณผ ๊ฐ™์€ ์ƒํƒœ๊ฐ€ ๋  ๊ฒ๋‹ˆ๋‹ค. ์ด๋•Œ a์˜ ์ฐธ์กฐ ์นด์šดํŠธ๋Š” 0์ด ๋˜์–ด ์ฆ‰์‹œ ์‚ญ์ œ๋˜๊ณ , ์ด์–ด์„œ b์˜ ์ฐธ์กฐ ์นด์šดํŠธ๋„ 0์ด ๋ฉ๋‹ˆ๋‹ค. c ์—ญ์‹œ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์‚ญ์ œ๋ฉ๋‹ˆ๋‹ค.

 

ํ•˜์ง€๋งŒ ์ฐธ์กฐ ์นด์šดํŠธ๋กœ ํ•ด๊ฒฐํ•  ์ˆ˜ ์—†๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ๋Š”๋ฐ, ๋ฐ”๋กœ ์ˆœํ™˜ ์ฐธ์กฐ์ž…๋‹ˆ๋‹ค. ์œ„์™€ ๊ฐ™์ด a = b = c = None์˜ ์‹คํ–‰๋งŒ์œผ๋กœ๋Š” ์ˆœํ™˜ ์ฐธ์กฐ์˜ ์นด์šดํŠธ๋ฅผ 0์œผ๋กœ ๋งŒ๋“ค ์ˆ˜ ์—†์–ด, ๋ฉ”๋ชจ๋ฆฌ์—์„œ ์‚ญ์ œ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์ƒํ™ฉ์„ ๊ณ ๋ คํ•ด GC(์„ธ๋Œ€๋ณ„ ๊ฐ€๋น„์ง€ ์ปฌ๋ ‰์…˜)๋Š” ๋ณด๋‹ค ์˜๋ฆฌํ•œ ๋ฐฉ์‹์œผ๋กœ ๋ถˆํ•„์š”ํ•œ ๊ฐ์ฒด๋ฅผ ์ฐพ์•„๋ƒ…๋‹ˆ๋‹ค. GC๋Š” ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ๋ถ€์กฑํ•ด์ง€๋Š” ์‹œ์ ์— ํŒŒ์ด์ฌ ์ธํ„ฐํ”„๋ฆฌํ„ฐ์— ์˜ํ•ด ์ž๋™ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค.

 

GC๋Š” ์ˆœํ™˜ ์ฐธ์กฐ๋ฅผ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ฒ˜๋ฆฌํ•˜์ง€๋งŒ, ๋ฉ”๋ชจ๋ฆฌ ํ•ด์ œ๋ฅผ GC์— ๋ฏธ๋ฃจ๋ฉด ํ”„๋กœ๊ทธ๋žจ ์ „์ฒด ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์ด ์ปค์ง€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ˆœํ™˜ ์ฐธ์กฐ๋Š” ์ตœ๋Œ€ํ•œ ๋งŒ๋“ค์ง€ ์•Š๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ํ˜„์žฌ์˜ DeZero์—๋Š” ์ˆœํ™˜ ์ฐธ์กฐ๊ฐ€ ์กด์žฌํ•˜๋Š”๋ฐ, ํ‘œ์ค€ ํŒŒ์ด์ฌ ๋ชจ๋“ˆ์ธ weakref๋กœ ํ•ด๊ฒฐํ•ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

 

weakref.ref ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์•ฝํ•œ ์ฐธ์กฐ๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ์•ฝํ•œ ์ฐธ์กฐ๋Š” ๋‹ค๋ฅธ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ•˜๋˜, ์ฐธ์กฐ ์นด์šดํŠธ๋Š” ์ฆ๊ฐ€์‹œํ‚ค์ง€ ์•Š์Šต๋‹ˆ๋‹ค. DeZero์—์„œ๋Š” Function์ด Variable(outputs) ์ธ์Šคํ„ด์Šค๋ฅผ ๋Œ€์ƒ์œผ๋กœ ์•ฝํ•œ ์ฐธ์กฐ๋ฅผ ํ•˜๋„๋ก ๋ณ€๊ฒฝํ•˜์—ฌ ์ˆœํ™˜ ์ฐธ์กฐ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. self.outputs๊ฐ€ ๋Œ€์ƒ์„ ์•ฝํ•œ ์ฐธ์กฐ๋กœ ๊ฐ€๋ฆฌํ‚ค๊ฒŒ ๋ณ€๊ฒฝํ•˜์˜€์Šต๋‹ˆ๋‹ค.

import weakref

class Function:
    def __call__(self, *inputs):
        xs = [x.data for x in inputs]
        ys = self.forward(*xs)
        if not isinstance(ys, tuple):
            ys = (ys, )
        outputs = [Variable(as_array(y)) for y in ys]
        
        self.generation = max([x.generation for x in inputs])
        for output in outputs:
            output.set_creator(self)
        self.inputs = inputs
        self.outputs = [weakref.ref(output) for output in outputs]
        return outputs if len(outputs) > 1 else outputs[0]

 

๋ณ€๊ฒฝ์˜ ์—ฌํŒŒ๋กœ Function ํด๋ž˜์Šค์˜ outputs๋ฅผ ์ฐธ๊ณ ํ•˜๋Š” ์ฝ”๋“œ๋„ ์ˆ˜์ •ํ•ฉ๋‹ˆ๋‹ค. output.grad๋ฅผ output().grad๋กœ ์ˆ˜์ •ํ•˜์˜€์Šต๋‹ˆ๋‹ค. ์ด์ƒ์œผ๋กœ ์ˆœํ™˜ ์ฐธ์กฐ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ–ˆ์Šต๋‹ˆ๋‹ค.

 

class Variable:
    ...
    def backward(self):
        ...
        while funcs:
            f = funcs.pop()
            gys = [output().grad for output in f.outputs]  # output์€ weakref
            ...