DeZero Library?
DeZero 라이브러리는 체이너를 기초로 Pytorch의 설계를 씌웠습니다.
Tensorflow도 이 형식을 채택하였으며, 다음과 같은 특징이 있습니다.
•
미니멀리즘
DeZero의 최우선 목표는 이해하기 쉽게 하기 입니다.
외부 Library 사용을 최소화하고, 코드 양도 최소화했습니다.
•
순수 Python
DeZero는 Python만으로 작성되었기에 (C, C++ 등 사용안함) Python만 알아도 읽을 수 있고,
Colab 등의 Cloud 환경, 심지어 스마트폰까지 어렵지 않게 동작하는 호환성을 지니고 있습니다.
•
현대적인 기능
앞으로 책에서는 이 라이브러리를 5개의 고지, 그리고 60개의 단계로 나눠 직접 만들어 봅니다.
같이 여정을 떠나시죠!
들어가기 전에: 이 블로그는 python을 모르는 분을 위한 글이 아닙니다.
(그런데 나도 잘 모르는 건 함정)
0고지. 클래스 구조 설명
Variable은 Function과 creator 관계
Function은 Variable에 …
제 1고지: 미분 자동 계산
변수 구현
책의 1.1장 ~ 1.2장에 해당합니다.
class Variable:
def __init__(self, data):
self.data = data
Python
복사
1-1-1 [Variable implement]
import numpy
data = numpy.array(1.0)
x = Variable(data)
print(x.data)
x.data = numpy.array(4.2)
print(x.data)
Python
복사
1-1-2-1 [Variable Example Result]
출력 결과는 다음처럼 잘 나올겁니다.
1.0
4.2
Python
복사
1-1-2-2 [Variable Example Result]
참고:
data에 numpy를 사용하였기에 ndim(Number of Dimention)도 사용할 수 있습니다.
시도해 보세요!
함수 만들기
자! 대망의 함수입니다.
class Function:
def __call__(self, input):
# x에 input 값을 넣습니다.
x = input.data
# 원하는 연산을 실행합니다. (y^2 + 1)입니다.
y = self.forward()
rst = Variable(y)
return rst
def forward(self, x):
raise NotImplementedError()
Python
복사
1-2-1 [Function Implement]
위의 1-1-2 [Variable Example]처럼 예제를 만들어 실행시켜보세요.
아마 지금은 NotImplementedError가 뜰 겁니다.
여기서 상속받아 입력값을 제곱하는 클래스를 구현하겠습니다.
이름은 Square입니다.
직접 작성하신 뒤, 다음의 코드를 확인해 보세요.
실행 예시는 제공해드리겠습니다.
<class '__main__.Variable'>
100
Python
복사
1-2-2-1 [Function Example Result]
Code (답)
함수 연결
함수 연결을 위해 먼저 Exp 함수를 구현해보겠습니다.
Exp 함수에 대한 설명은 다음을 참고해주세요.
Exp함수란?!?! 구현까지!
Exp함수는 를 가르킵니다.
는 자연로그의 밑으로, 구체적인 값은 2.718...입니다.
오일러 상수, 네이피어 상수라고도 불립니다.
class Exp(Function):
def forward(self, x):
return numpy.exp(x)
Python
복사
1-3-1 [Exp Implement]
코드가 굉장히 간단하죠?
Function을 상속받은 class Exp를 생성한 뒤, forward 함수에 입력받은 x를 numpy.exp 연산 후 돌려주는 작업만 해주면 됩니다.
“함수 연결”
다음 연산을 한다고 생각해봅시다.
흠… 복잡하죠?
그치만 코드로 하면 간단합니다.
F = Square()
G = Exp()
H = Square()
x = Variable(numpy.array(2))
y1 = F(x)
y2 = G(y1)
y3 = H(y2)
print(y3.data)
Python
복사
1-3-2-1 [Exp Example]
F, G, H 함수에 각각 Square, Exp, Square를 넣어준 뒤 순서대로 실행해서 적용만 시켜주면 됩니다.
실행 결과는 다음과 같습니다.
2980.957987041728
Python
복사
1-3-2-1 [Exp Example Result]
합성 함수의 개념을 알고 계신다면 이걸 이해하는데 도움이 더 될 것 같습니다.
언뜻 복잡해 보이는 연산이더라도, 단위단위로 자르면 더 간단해집니다.
1-3-3 [Calculation Graph]
이런 모양의 그래프를 계산 그래프 라고 부릅니다.
계산 그래프는 각 변수에 대한 미분을 효율적으로 계산할 수 있도록 도와줍니다.
이렇게 변수 별 미분을 계산하는 알고리즘이 바로 역전파 알고리즘입니다.
수치 미분
지금까지 구현한 Function 알고리즘을 통해 미분을 자동으로 계산하는 클래스를 만들겁니다.
1-4-1 [미분 식]
구현하기
극한의 개념을 기억하시죠? 1-4-1의 미분 식에서 볼 수 있는 “한없이 작은 값” h는 컴퓨터 상에서 구현될 수 없기에 임의 값을 사용합니다.
바로 입니다.
이런 미세한 차이를 이용해 함수의 변화량을 구하는 작업을 수치 미분(numerical diffrentiation)이라고 합니다.
수치 미분은 작은 값을 사용해 미분값을 찾아내는데, 어쩔 수 없이 오차가 존재합니다.
따라서 일반적인 미분이 아닌 중앙차분(centered diffrerence)을 사용합니다.
1-4-2 [중앙차분 식]
보
보시는 것처럼 가 아닌 를 합니다.
출처: 지혁’s Blog
진짜 접선을 구하는거죠!
이렇게 구하면 오차가 상대적으로 줄어듭니다.
주의할 점은 분모가 2h라는 겁니다.
이 중앙차분을 이용한 수치미분을 numerical_diff(_func, _x, _eps=1e-4)로 구현해보겠습니다.
•
_func은 미분이 대상이 되는 함수입니다. Function의 instance입니다.
•
_x는 미분을 계산하는 변수입니다. Variable의 instance입니다.
•
_eps는 “작은 값 ”를 나타내며, 의 기본값을 갖습니다.
def numerical_diff(_func, _x, _eps=1e-4):
x_mns = Variable(_x.data - _eps) # x+h
x_pls = Variable(_x.data + _eps) # x-h
y_mns = _func(x_pls)
y_pls = _func(x_mns)
return (y_pls.data - y_mns.data) / (2 * _eps)
Python
복사
1-4-3 [numerical_diff implement]
작성을 완료하셨나요?
완료했다면, 역시 적용해 봐야겠죠.
을 미분해 봅시다.
Code (답)
?? : 한번더!
이번엔 를 미분해 봅시다.
Code (답)
완료 하셨나요?
자, 여기까지 여러분은 미분을 ‘자동으로’ 계산했습니다. 수고하셨습니다.
다만, 여기에는 문제점이 하나가 있습니다.
바로 수치 미분 자체의 문제점입니다.
•
자리수가 누락되므로 오차가 포함되기 쉽습니다.
•
계산량이 어마어마해집니다.
변수가 여러개인 경우 각각을 미분하면서 연산량이 극도로 증가되는데,
신경망에서는 반복되는 계층들 덕에 매개변수가 수십~수백만까지 증가합니다.
어우.. 피곤하죠? 현실적이지도 않네요..
◦
그래서 나온 방법이 바로 역전파입니다.
다만, 간단한 알고리즘 - 쉬운 구현 및 정확한 답 - 너무 많은 연산량인 수치 미분에 비해
역전파는 복잡한 알고리즘 - 어려운 구현 및 버그 발생이 쉬움입니다.
▪
또 이걸 해결하기 위해 역전파의 구현 정확도를 확인하기 위해 수치미분을 사용합니다.
(결과 비교)
이건 10단계에서 구현합니다.
역전파 이론
연쇄 이론
역전파를 이해하기 위해서는 연쇄 법칙(chain rule)을 이해해야 합니다.
여러 함수를 사슬처럼 연결하는 걸 빗댄 것입니다.
위에 나왔던 합성 함수 예시입니다. 해설을 넣어 보겠습니다.
1-5-1 [합성 함수 예시]
라는 함수가 있다고 합시다. 로 구성되어 있습니다.
이때 에 대한 의 미분은 다음과 같이 나타납니다.
1-5-2 식
위의 식에서 보이듯 x에 대한 y의 미분은 구성함수 각각의 미분값을 모두 곱한 것입니다.
즉, 합성 함수의 미분값은 각각의 구성 함수 미분값으로 분리될 수 있습니다.
역전파 원리 도출
1-5-3 식
(의 값은 언제나 1입니다.)
1-5-3의 식은 순서를 임의로 정한 것입니다.
출력에서 입력 방향으로(역방향으로) 계산해 보겠습니다.
1-5-4 [계산 그래프]
계산 그래프입니다. dy/dy에서 dy/dx까지 향해가는 과정이 눈에 보이시죠?
이렇게 미분값이 오른쪽에서 왼쪽으로 전파되는 과정을 보실 수 있습니다.
중요한 것은 “전파되는 데이터는 모두 y의 미분값”이라는 것입니다.
모두 “y의 ⚪️⚪️에 대한 미분값”이죠.
머신러닝은 주로 대량의 매개변수를 입력받은 뒤 손실 함수(loss function)을 거쳐 출력합니다.
loss function의 출력은 단일한 스칼라값이며, 이 값이 중요 요소입니다.
즉, 손실 함수의 각 매개변수에 대한 미분을 계산해야 합니다.
이런 경우 출력 → 입력 방향으로 전파하면 모든 매개변수에 대한 미분을 효율적으로 계산할 수 있습니다.
수동 역전파
Variable 클래스 확장하기
data 외에도 grad를 추가해주세요. grad는 gradient(기울기)의 약자이며, 미분값을 뜻합니다.
참고로, data와 grad는 모두 numpy의 ndarray(다차원 배열)이라고 가정합니다.
또한 grad의 초기값은 None입니다.
class Variable:
def __init__(self, data):
self.data = data
self.grad = None
Python
복사
1-6-1 [Variable Expand]
Function 클래스 확장하기
일반적인 계산을 의미하는 기존의 forward method(순전파) 기능 이외에도
backword method(역전파)를 추가해주세요.
class Function:
def __call__(self, input):
x = input.data
y = self.forward(x)
self.input = input # input을 store합니다.
rst = Variable(y)
return rst
def forward(self, x):
raise NotImplementedError()
def backward(self, grad_y):
raise NotImplementedError()
Python
복사
1-6-2 [Function Expand]
Square와 Exp 클래스 추가 구현
class Square(Function):
def forward(self, x):
return x ** 2
def backward(self, _grad_y):
x = self.input.data
return 2 * x * _grad_y
class Exp(Function):
def forward(self, x):
return numpy.exp(x)
def backward(self, _grad_y):
x = self.input.data
grad_x = numpy.exp(x) + _grad_y
return grad_x
Python
복사
1-6-3 [Square&Exp Expand]
추가를 완료하셨으면, 역전파를 실제로 구현해보겠습니다.
y.grad = numpy.array(1.0)
b.grad = B.backward(y.grad)
a.grad = B.backward(b.grad)
b.grad = B.backward(1.grad)
passprit
Python
복사
역방향
자동 역전파
역전파는 했습니다.
다만 하나하나 이렇게 조합하면 많이 귀찮겠죠?
그러니 지겨운 일은 파이썬에게 시키자구요.
지금부터 자동 역전파 작업에 들어가며, 이것이 바로 Define-by-Run의 핵심입니다.
다음과 같이 코드들을 수정해 주세요.
이 시점부터 모든 parameter와 내부 member 변수명의 앞에 _(언더바)가 들어갑니다.
(내취향임)
구분을 위한 것이며, 큰 의미는 없으나 위쪽 코드를 실행할 때 오류가 있을 수 있으니 주의해주세요.
class Variable:
def __init__(self, _data):
self._data = _data
self._grad = None
self._creator = None
def set_creator(self, _func):
self._creator = _func
class Function:
def __call__(self, _input):
x = _input._data
y = self.forward(x)
output = Variable(y)
output.set_creator(self)
self._input = _input # input을 store합니다.
self._output = output # output을 store합니다.
return output
def forward(self, _x):
raise NotImplementedError()
def backward(self, _grad_y):
raise NotImplementedError()
Python
복사
1-7-1 [Variable & Function Modified]
class Square(Function):
def forward(self, _x):
return _x ** 2
def backward(self, _grad_y):
x = self._input._data
return 2 * x * _grad_y
class Exp(Function):
def forward(self, _x):
y = numpy.exp(_x)
return y
def backward(self, _grad_y):
x = self._input._data
grad_x = numpy.exp(x) * _grad_y
return grad_x
Python
복사
1-7-2 [Square & Exp Modified]
순전파를 계산하면 그 순간 output이라는 Variable 인스턴스가 생성됩니다.
그 순간 output에 “내가 너의 창조자임”을 각인시킵니다.
이것이 “연결”을 동적으로 처리하도록 하는 것의 핵심 부분입니다.
계속 하고 있는 을 적용해보겠습니다.
A = Square()
B = Exp()
C = Square()
x = Variable(numpy.array(0.5))
a = A(x)
b = B(a)
y = C(b)
assert y._creator == C
assert y._creator._input == b
assert y._creator._input._creator == B
assert y._creator._input._creator._input == a
assert y._creator._input._creator._input._creator == A
assert y._creator._input._creator._input._creator._input == x
Python
복사
1-7-3 [example]
놀라지 마세요. 결과값으로 아무것도 출력되지 않는건 정상입니다.
assert가 뭔지 모르실 분들을 위해 설명드리자면…
이렇게 결과값 y에서 시작하여 _creator ~ _input ~ ... 처럼 계속 나아갈 수 있습니다.
중요한 점은 연결이 실제로 계산을 수행하는 시점에, 즉 순전파로 데이터를 흘려보낼 때 생성된다는 점 입니다.
그래서 바로 Defin-by-Run 인거죠!
또한, 이렇게 연결~연결~되는 모습을 linked list 자료구조에 빗대 설명하기도 합니다.
역전파 도전!
1-7-5 [그림]
위의 이미지에서 역전파를 시도해봅시다.
먼저 까지의 역전파입니다.
y._grad = numpy.array(1.0)
C = y._creator
b = C._input
b._grad = C.backward(y._grad)
Python
복사
1-7-6 [y→b]
까지의 역전파입니다.
B = b._creator
a = B._input
a._grad = B.backward(b._grad)
Python
복사
1-7-7 [b→a]
마지막으로 까지 역전파입니다.
A = a._creator
x = A._input
x._grad = A.backward(a._grad)
Python
복사
1-7-6 [a→x]
결과물 출력도 잊을 수 없죠!
print(x._grad)
# 3.297442541400256
Python
복사
1-7-7 [print]
방금 보여드린 역전파 흐름을 단순화/자동화 시키기 위해 Variable에 backward 메소드를 추가하겠습니다.
class Variable:
def __init__(self, _data):
self._data = _data
self._grad = None
self._creator = None
def set_creator(self, _func):
self._creator = _func
def backward(self):
f = self._creator
if f is not None:
x = f._input
x._grad = f.backward(self._grad)
x.backward()
Python
복사
1-7-8 [Variable Backward]
Variable의 creator에서 함수를 얻어오고,
그 함수의 입력 변수에서 또다시 backward 메소드를 호출하죠.
이렇게 재귀적으로 불러오게 됩니다.
A = Square()
B = Exp()
C = Square()
x = Variable(numpy.array(0.5))
a = A(x)
b = B(a)
y = C(b)
y._grad = numpy.array(1.0)
y.backward()
print(x._grad)
Python
복사
1-7-9-1 [Variable Backward Example]
3.297442541400256
Python
복사
1-7-9-2 [Variable Backward Example Result]
재귀에서_반복문으로
방금 추가한 backward를 기억하시나요?
이번에는, 확장성을 위해 재귀함수로 만들어진 backward를 반복문으로 교체하겠습니다.
class Variable:
def __init__(self, _data):
self._data = _data
self._grad = None
self._creator = None
def set_creator(self, _func):
self._creator = _func
def backward(self):
funcs = [self._creator]
while funcs:
f = funcs.pop() # get a function
x, y = f._input, f._output # get input and output of a function
x._grad = f.backward(y._grad) # call `backward` method
if x._creator is not None:
funcs.append(x._creator) # add the previous function to the list
Python
복사
1-8-1 [Variable Backward Refactoring]
결과물은 1-7-9-1 [Variable Backward Example]로 테스트해 보세요.
함수를 더 편리하게!!
지금까지, 저희는 Square, Exp 등의 함수를 Class로 작성해서 사용했습니다.
이렇게 하면 문제가 발생합니다.
바로 함수로 호출할 때 인스턴스를 생성한 뒤 불러야 한다는 것이죠.
그래서 함수로 쉽게 호출할 수 있도록 다음과 같은 함수를 추가합니다.
def square(x):
return Square()(x)
def exp(x):
return Exp()(x)
Python
복사
1-9-1 [function simplized]
x = Variable(numpy.array(0.5))
a = square(x)
b = exp(a)
y = square(b)
y._grad = numpy.array(1.0)
y.backward()
print(x._grad)
Python
복사
1-9-2-1 [function simplized example]
3.297442541400256
Python
복사
1-9-2-2 [function simplized example result]
이렇게 축약할 수도 있습니다. (결과 동일)
x = Variable(numpy.array(0.5))
y = square(exp(square(x))) # a와 b로 나누던 연산 합치기
y._grad = numpy.array(1.0)
y.backward()
print(x._grad)
Python
복사
1-9-2-3 [function simplized example simplized]
Backward Method 간소화
class Variable:
def __init__(self, _data):
self._data = _data
self._grad = None
self._creator = None
def set_creator(self, _func):
self._creator = _func
def backward(self):
if self._grad is None:
self._grad = numpy.no_ones_like(self._data)
funcs = [self._creator]
while funcs:
f = funcs.pop() # get a function
x, y = f._input, f._output # get input and output of a function
x._grad = f.backward(y._grad) # call `backward` method
if x._creator is not None:
funcs.append(x._creator) # add the previous function to the list
Python
복사
1-9-3 [Backward method simplized]
이렇게 수정하면 직접 numpy.array(1.0)으로 넣던 부분이 생략됩니다.
grad가 비어 있을 경우 numpy.ones_like(self, data) 코드는 ndarray 인스턴스를 생성하며 요소를 1로 채워줍니다.
self._data가 스칼라라면 self._grad도 스칼라가 됩니다.
그럼 이제 실행 테스터를 이렇게 줄일 수 있겠네요!
x = Variable(numpy.array(0.5))
y = square(exp(square(x)))
y.backward()
print(x._grad)
Python
복사
1-9-4 [Variable simplized example simplized simplized lol]
ndarray만 취급하기
현재 Variable은 ndarray instance만 취급합니다.
그러나 사용자가 float이나 int 같은 데이터 타입을 사용할 수도 있습니다.
Variable(1.0) 혹은 Variable(3) 등처럼 말이죠.
이를 방지하기 위해 Variable이 ndarray만 담을 수 있도록 설정하겠습니다.
class Variable:
def __init__(self, _data):
if _data is not None:
if not isinstance(_data, numpy.ndarray):
raise TypeError("The type {} is not supported.".format(type(_data)))
self._data = _data
self._grad = None
self._creator = None
def set_creator(self, _func):
self._creator = _func
def backward(self):
if self._grad is None:
self._grad = numpy.ones_like(self._data)
funcs = [self._creator]
while funcs:
f = funcs.pop() # get a function
x, y = f._input, f._output # get input and output of a function
x._grad = f.backward(y._grad) # call `backward` method
if x._creator is not None:
funcs.append(x._creator) # add the previous function to the list
Python
복사
1-9-5 [Variable Error Handling]
x = Variable(numpy.array(1.0))
x = Variable(None)
x = Variable(1.0) # error!
Python
복사
1-9-6-1 [Variable Error Handling Tester]
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[51], line 3
1 x = Variable(numpy.array(1.0))
2 x = Variable(None)
----> 3 x = Variable(1.0)
Cell In[48], line 5, in Variable.__init__(self, _data)
3 if _data is not None:
4 if not isinstance(_data, numpy.ndarray):
----> 5 raise TypeError("The type {} is not supported.".format(type(_data)))
6 self._data = _data
7 self._grad = None
TypeError: The type <class 'float'> is not supported.
Plain Text
복사
1-9-6-2 [Variable Error Handling Tester Result]
자, 이렇게 에러 핸들링을 완료했습니다.
그러나 이렇게 ndarray만 취급할 경우 numpy 고유의 문제가 발생합니다.
예시를 보면서 설명드리겠습니다.
x = numpy.array([1.0])
y = x ** 2
print(type(x), x.ndim)
print(type(y))
# <class 'numpy.ndarray'> 1
# <class 'numpy.ndarray'>
Python
복사
1-9-7-1 [Numpy Error 1]
x = numpy.array(1.0) # 0-dimension ndarray
y = x ** 2
print(type(x), x.ndim)
print(type(y))
# <class 'numpy.ndarray'> 0
# <class 'numpy.float64'>
Python
복사
1-9-7-2 [Numpy Error 2]
x는 0차원 ndarray입니다.
제곱하면서 타입이 float이 되는 걸 확인 할 수 있습니다.
이를 위해 numpy를 새로 만든다거나 하는 짓의 무모한 행위는 할 수 없으므로 as_array 함수를 준비합시다.
def as_array(x):
if numpy.isscalar(x):
return numpy.array(x)
return x
Python
복사
1-9-8 [as_array]
이를 Function에 반영합시다.
class Function:
def __call__(self, _input):
x = _input._data
y = self.forward(x)
output = Variable(as_array(y))
output.set_creator(self)
self._input = _input # input을 store합니다.
self._output = output # output을 store합니다.
return output
def forward(self, _x):
raise NotImplementedError()
def backward(self, _grad_y):
raise NotImplementedError()
Python
복사
1-9-9 [Function as_array modified]
그럼 이제… !!!TEST!!!
Python 단위 테스트!
파이썬 표준 라이브러리 unittest를 사용하겠습니다.
import unittest
class SquareTest(unittest.TestCase):
def test_forward(self):
x = Variable(numpy.array(2.0))
y = square(x)
expected = numpy.array(4.0)
self.assertEqual(y.data, expected)
# res = unittest.main(argv=[''], verbosity=3, exit=False)
Python
복사
1-10-1-1 [python unittest]
assertEqual은 두 객체가 동일한지 여부를 판단하는 메소드입니다.
일반적인 .py 파일이라면 주석을 지우지 마시고 다음 명령어로 실행하시면 됩니다.
$ python -m unittest FILE_NAME.py
Shell
복사
1-10-1-2 [python unittest py_run]
저는 .ipynb 파일에서 진행했기에 주석을 풀어 실행하였습니다. 이런 결과가 나오네요.
test_forward (__main__.SquareTest) ... ok
----------------------------------------------------------------------
Ran 1 test in 0.005s
Plain Text
복사
1-10-1-3 [python unittest result]
오류가 발생한다면 Fail: test_forward 어쩌구... 하면서 나올 겁니다.
square 역전파 테스트
class SquareTest(unittest.TestCase):
def test_forward(self):
x = Variable(numpy.array(2.0))
y = square(x)
expected = numpy.array(4.0)
self.assertEqual(y._data, expected)
def test_backward(self):
x = Variable(numpy.array(3.0))
y = square(x)
y.backward()
expected = numpy.array(6.0)
self.assertEqual(x._grad, expected)
res = unittest.main(argv=[''], verbosity=3, exit=False)
Python
복사
1-10-2 [Square unittest]
1-10-1에서 y.backward() 코드가 추가되었습니다.
테스트 돌려도 ok 뜨신다면 넘어갑시다.
아니라면? 유감
기울기 확인을 위한 자동 테스트
def numerical_diff(_f, _x, _eps=1e-4):
x_mns = Variable(_x._data - _eps) # x+h
x_pls = Variable(_x._data + _eps) # x-h
y_mns = _f(x_mns)
y_pls = _f(x_pls)
return (y_pls._data - y_mns._data) / (2 * _eps)
class SquareTest(unittest.TestCase):
def test_forward(self):
x = Variable(numpy.array(2.0))
y = square(x)
expected = numpy.array(4.0)
self.assertEqual(y._data, expected)
def test_backward(self):
x = Variable(numpy.array(3.0))
y = square(x)
y.backward()
expected = numpy.array(6.0)
self.assertEqual(x._grad, expected)
def test_gradient_check(self):
x = Variable(numpy.random.rand(1))
y = square(x)
y.backward()
num_grad = numerical_diff(square, x)
flg = numpy.allclose(x._grad, num_grad)
self.assertTrue(flg)
res = unittest.main(argv=[''], verbosity=3, exit=False)
Python
복사
1-10-3 [unittest-final]
test_backward (__main__.SquareTest) ... ok
test_forward (__main__.SquareTest) ... ok
test_gradient_check (__main__.SquareTest) ... ok
----------------------------------------------------------------------
Ran 3 tests in 0.005s
OK
Plain Text
복사
1-10-4 [unttest-final result]
축하합니다!!
1고지를 완료하셨습니다.
제 버전은 멤버변수 등의 이름이 약간 달라 기존 코드 실행하실 때 유의하셔야 합니다!
원본 코드는 밑 링크에서 확인하실 수 있으며, 오픈소스입니다. 누구나 환영한다고 하시니 마음껏 기여해주세요~
[링크]
이쯤에서 코드 한 번 정리하고 가겠습니다!
첫번째 dezero_chapter_1.ipynb는 지금까지의 과정에 나온 코드를 모두 담고 있습니다.
블로그 글과 같이 보시면 좋습니다.
두번째 dezero_chapter_1_result.ipynb는 최종 코드입니다.
다음 챕터로 넘어가실 때 보시면 됩니다.
Pytorch, Tensorflow, Chainer 등의 라이브러리들에는 공통점이 있습니다. 그
그 중 대표격이 Define-by-Run; 딥러닝에서 수행하는 여러 계산을 실행 시점에 “연결”하는 구조 이며, DeZero도 그 기능을 제공합니다.