서론

저번에 말했던 것처럼 Transpose를 조금 손보고 시작하자.

Transpose를 오버라이드 하는 법

Transpose (.T)는 아무래도 @property인 것 같다.

그래서 이런 식으로 오버라이드 하는 것 같다.

@property
def T(self)
    # blah blah
    return self.transpose()

이걸 바탕으로, 계산 그래프에다가 끼워 넣는 방법을 잘 생각해서 만들자. Broadcast보다는 쉬울꺼다.

만들었는데 아마도 잘 돌아가는 것 같다. 아마도…

몫의 미분법 테스트

인터넷에서 ‘몫의 미분법’을 검색한 후, 나오는 아무 공식이나로 한번 테스트해보자.

quotrule

여기서 긁어온 이미지다.

x가 1일 때 y의 x에 대한 미분 값은 13/25가 나와야 한다.

그런데 결과는 0.28이 나온다.

아무래도 나누기를 잘못 생각한게 아닐까 싶다.

하나 빼먹은게 있다. a/b = z에서 z를 b로 편미분하면 -(a/b^2)이 나와야 하는데 -를 적어두질 않았다.

Negative 함수 구현도 포함해서 뚝딱뚝딱 해주자.

이번엔 0.52가 나온다.

0.52가 13/25인걸 생각해보면 잘 나온다.

x값을 3으로 바꿔보자. 13/121가 나와야 하고, 대략 0.107이다.

잘 나온다!

몫의 미분법대로 잘 나오는 모습이다.

CalcGraph 조금 최적화

CalcGraph의 코드를 다시 보다 보니까 약간 거슬리는 부분이 눈에 보인다.

무엇이 거슬리냐 하지 지금 코드가 말도 안되게 비효율적이다. (Gradient를 계산할 때마다 이전 계산 그래프 전체를 다시 계산함)

지금 CalcGraph는 다음과 같은 구조이다,

paramCalcGraph의 리스트고, funcFunc 타입, 그리고 tensorTensor이다.

여기에 새로운 변수 value를 추가하여, 처음 그래프가 만들어질 때 한 번 계산하고 이후에는 재사용하게 하면 될 것 같다.

그래프는 한번 생성된 다음에는 정적으로 유지된다고 생각하자.

CalcGraph.__str__

조금 __str__을 더 예쁘게 보여줄 수 있을까?

이것 저것 건드려봤고, __str__의 구현이라기에는 믿을 수 없을 정도로 길게 (대충 30줄 정도는 썼다.) 무언가를 적은 결과 나름 보기 좋은 것을 얻었다.

TrueDivide (3,)----------------------------------------------------------------------------------------------------------------|
Substract (3,)-------------------------------------------------|Add (3,)-------------------------------------------------------|
Multiply (3,)-----------------------|Broadcast(() -> (3,)) (3,)|Multiply (3,)-----------------------|Broadcast(() -> (3,)) (3,)|
Broadcast(() -> (3,)) (3,)|Leaf (3,)|Leaf ()-------------------|Broadcast(() -> (3,)) (3,)|Leaf (3,)|Leaf ()-------------------|
Leaf ()-------------------|         |                          |Leaf ()-------------------|         |                          |

꽤 근사하다.

이름 붙은 텐서

텐서에 이름을 붙여주는 것도 좋지 않을까?

이름은 전역 변수를 사용해서 서로 다르게 붙여주자.

중간 텐서의 이름까지 출력해주도록 바꿨다. 덕분에 __str__의 길이는 더 길어졌다.

아무튼 그 결과는 이렇다.

y (3,)                                                                                               │
TrueDivide────────────────────────────────────────┬──────────────────────────────────────────────────┤
tensor92 (3,)                                     │tensor102 (3,)                                    │
Substract───────────────────┬─────────────────────┤Add─────────────────────────┬─────────────────────┤
tensor87 (3,)               │tensor94 (3,)        │tensor97 (3,)               │tensor104 (3,)       │
Multiply─────────────┬──────┤Broadcast(() -> (3,))┤Multiply─────────────┬──────┤Broadcast(() -> (3,))┤
tensor89 (3,)        │x (3,)│tensor93 ()          │tensor99 (3,)        │x (3,)│tensor103 ()         │
Broadcast(() -> (3,))┤      │                     │Broadcast(() -> (3,))┤      │                     │
tensor88 ()          │      │                     │tensor98 ()          │      │                     │

박스 문자까지 써서 만들었다. 근사하다.

다음 시간

매번 하는 소리지만 나머지 함수들을 구현하자.

이번에는 그래프 출력에 이런 저런 공을 많이 들이기는 했는데… 솔직히 그럴만한 가치가 있다고 생각한다.

멋있잖아.