3939 },
4040 {
4141 "cell_type" : " code" ,
42- "execution_count" : null ,
42+ "execution_count" : 33 ,
4343 "metadata" : {},
4444 "outputs" : [],
4545 "source" : [
4646 " from __future__ import annotations\n " ,
4747 " \n " ,
4848 " import math\n " ,
4949 " from dataclasses import dataclass, field\n " ,
50- " from typing import Callable, Set \n " ,
50+ " from typing import Callable\n " ,
5151 " \n " ,
5252 " \n " ,
5353 " @dataclass\n " ,
6161 " _backward: 역전파 시 실행할 함수\n " ,
6262 " \"\"\"\n " ,
6363 " data: float\n " ,
64- " _prev: Set [Value] = field(default_factory=set, repr=False)\n " ,
64+ " _prev: set [Value] = field(default_factory=set, repr=False)\n " ,
6565 " _backward: Callable[[], None] = field(default=lambda: None, repr=False)\n " ,
6666 " grad: float = 0.0\n " ,
6767 " \n " ,
7070 " raise TypeError(\" Value.data must be a number\" )\n " ,
7171 " self.data = float(self.data)\n " ,
7272 " \n " ,
73- " def __repr__(self) -> str:\n " ,
74- " return f\" Value(data={self.data:.6f}, grad={self.grad:.6f})\" "
73+ " def __repr__(self) -> str:\n " ,
74+ " return f\" Value(data={self.data:.6f}, grad={self.grad:.6f})\"\n " ,
75+ " \n " ,
76+ " def __hash__(self) -> int:\n " ,
77+ " return id(self)\n " ,
78+ " \n " ,
79+ " def __eq__(self, other) -> bool:\n " ,
80+ " return self is other"
81+ ]
82+ },
83+ {
84+ "cell_type" : " code" ,
85+ "execution_count" : 30 ,
86+ "metadata" : {},
87+ "outputs" : [
88+ {
89+ "name" : " stdout" ,
90+ "output_type" : " stream" ,
91+ "text" : [
92+ " [1]\n " ,
93+ " [1, 2]\n " ,
94+ " [1]\n " ,
95+ " [2]\n "
96+ ]
97+ }
98+ ],
99+ "source" : [
100+ " def append_item(x, items=[]): # 가변 기본값\n " ,
101+ " items.append(x)\n " ,
102+ " return items\n " ,
103+ " \n " ,
104+ " def append_item2(x, items=None):\n " ,
105+ " if items is None:\n " ,
106+ " items = []\n " ,
107+ " items.append(x)\n " ,
108+ " return items\n " ,
109+ " \n " ,
110+ " print(append_item(1)) # [1]\n " ,
111+ " print(append_item(2)) # [1, 2] ← 이전 호출과 공유됨\n " ,
112+ " \n " ,
113+ " print(append_item2(1)) # [1]\n " ,
114+ " print(append_item2(2)) # [2]"
75115 ]
76116 },
77117 {
88128 },
89129 {
90130 "cell_type" : " code" ,
91- "execution_count" : null ,
131+ "execution_count" : 34 ,
92132 "metadata" : {},
93133 "outputs" : [],
94134 "source" : [
120160 " Value.__radd__ = lambda self, other: self.__add__(other)"
121161 ]
122162 },
163+ {
164+ "cell_type" : " code" ,
165+ "execution_count" : 36 ,
166+ "metadata" : {},
167+ "outputs" : [
168+ {
169+ "name" : " stdout" ,
170+ "output_type" : " stream" ,
171+ "text" : [
172+ " Value(data=5.0, grad=0.0)\n " ,
173+ " Value(data=5.0, grad=0.0)\n "
174+ ]
175+ }
176+ ],
177+ "source" : [
178+ " hasattr(Value, \" __add__\" ) # True가 나와야 정상\n " ,
179+ " \n " ,
180+ " a = Value(3.0)\n " ,
181+ " \n " ,
182+ " # 왼쪽이 숫자라서, int.__add__가 Value를 모르면 a.__radd__(2)가 호출됨\n " ,
183+ " c1 = 2 + a # __radd__ 경유 → __add__ 재사용\n " ,
184+ " c2 = a + 2 # __add__\n " ,
185+ " \n " ,
186+ " print(c1)\n " ,
187+ " print(c2)"
188+ ]
189+ },
123190 {
124191 "cell_type" : " markdown" ,
125192 "metadata" : {},
129196 },
130197 {
131198 "cell_type" : " code" ,
132- "execution_count" : null ,
199+ "execution_count" : 37 ,
133200 "metadata" : {},
134- "outputs" : [],
201+ "outputs" : [
202+ {
203+ "name" : " stdout" ,
204+ "output_type" : " stream" ,
205+ "text" : [
206+ " a = Value(data=2.0, grad=0.0)\n " ,
207+ " b = Value(data=3.0, grad=0.0)\n " ,
208+ " c = a + b = Value(data=5.0, grad=0.0)\n " ,
209+ " c의 부모 노드들: {Value(data=2.0, grad=0.0), Value(data=3.0, grad=0.0)}\n "
210+ ]
211+ }
212+ ],
135213 "source" : [
136214 " # 간단한 덧셈 예제\n " ,
137215 " a = Value(2.0)\n " ,
158236 },
159237 {
160238 "cell_type" : " code" ,
161- "execution_count" : null ,
239+ "execution_count" : 38 ,
162240 "metadata" : {},
163241 "outputs" : [],
164242 "source" : [
175253 " \n " ,
176254 " def _backward() -> None:\n " ,
177255 " # Product rule 적용\n " ,
256+ " print(\" backward is called, self.grad = \" , self.grad, \" other.grad = \" , other.grad, \" out.grad = \" , out.grad)\n " ,
178257 " self.grad += other.data * out.grad # d(a*b)/da = b\n " ,
179258 " other.grad += self.data * out.grad # d(a*b)/db = a\n " ,
180259 " \n " ,
194273 },
195274 {
196275 "cell_type" : " code" ,
197- "execution_count" : null ,
276+ "execution_count" : 45 ,
198277 "metadata" : {},
199- "outputs" : [],
278+ "outputs" : [
279+ {
280+ "name" : " stdout" ,
281+ "output_type" : " stream" ,
282+ "text" : [
283+ " x = Value(data=3.0, grad=0.0)\n " ,
284+ " y = Value(data=4.0, grad=0.0)\n " ,
285+ " z = x * y = Value(data=12.0, grad=0.0)\n " ,
286+ " w = z * 2 = Value(data=24.0, grad=0.0)\n "
287+ ]
288+ }
289+ ],
200290 "source" : [
201291 " # 곱셈 예제\n " ,
202292 " x = Value(3.0)\n " ,
225315 },
226316 {
227317 "cell_type" : " code" ,
228- "execution_count" : null ,
318+ "execution_count" : 46 ,
229319 "metadata" : {},
230320 "outputs" : [],
231321 "source" : [
260350 },
261351 {
262352 "cell_type" : " code" ,
263- "execution_count" : null ,
353+ "execution_count" : 47 ,
264354 "metadata" : {},
265355 "outputs" : [],
266356 "source" : [
295385 },
296386 {
297387 "cell_type" : " code" ,
298- "execution_count" : null ,
388+ "execution_count" : 48 ,
299389 "metadata" : {},
300390 "outputs" : [],
301391 "source" : [
344434 },
345435 {
346436 "cell_type" : " code" ,
347- "execution_count" : null ,
437+ "execution_count" : 49 ,
348438 "metadata" : {},
349439 "outputs" : [],
350440 "source" : [
430520 " self.grad = 1.0\n " ,
431521 " for v in reversed(topo):\n " ,
432522 " v._backward()\n " ,
523+ " \n " ,
524+ " def __hash__(self) -> int:\n " ,
525+ " return id(self)\n " ,
526+ " \n " ,
527+ " def __eq__(self, other) -> bool:\n " ,
528+ " return self is other\n " ,
433529 " \n " ,
434530 " def __repr__(self) -> str:\n " ,
435531 " return f\" Value(data={self.data:.6f}, grad={self.grad:.6f})\" "
448544 },
449545 {
450546 "cell_type" : " code" ,
451- "execution_count" : null ,
547+ "execution_count" : 51 ,
452548 "metadata" : {},
453- "outputs" : [],
549+ "outputs" : [
550+ {
551+ "name" : " stdout" ,
552+ "output_type" : " stream" ,
553+ "text" : [
554+ " === Forward Pass ===\n " ,
555+ " a = 1.300000\n " ,
556+ " b = -0.700000\n " ,
557+ " c = a * b = -0.910000\n " ,
558+ " d = c + a = 0.390000\n " ,
559+ " e = tanh(b) = -0.604368\n " ,
560+ " out = d * e = -0.235703\n " ,
561+ " \n " ,
562+ " === Backward Pass ===\n " ,
563+ " ∂out/∂a = -0.181310\n " ,
564+ " ∂out/∂b = -0.538130\n " ,
565+ " (Value(data=-0.235703, grad=1.000000), -0.18131033313514905, -0.5381296701591537)\n "
566+ ]
567+ }
568+ ],
454569 "source" : [
455570 " # 복잡한 함수 예제\n " ,
456571 " def test_complex_function():\n " ,
481596 " \n " ,
482597 " return out, a.grad, b.grad\n " ,
483598 " \n " ,
484- " result = test_complex_function()"
599+ " result = test_complex_function()\n " ,
600+ " print(result)"
485601 ]
486602 },
487603 {
495611 },
496612 {
497613 "cell_type" : " code" ,
498- "execution_count" : null ,
614+ "execution_count" : 25 ,
499615 "metadata" : {},
500- "outputs" : [],
616+ "outputs" : [
617+ {
618+ "name" : " stdout" ,
619+ "output_type" : " stream" ,
620+ "text" : [
621+ " \n " ,
622+ " 테스트 케이스: a=1.3, b=-0.7\n " ,
623+ " 자동미분: ∂f/∂a = -0.18131033, ∂f/∂b = -0.53812967\n " ,
624+ " 수치미분: ∂f/∂a = -0.18131033, ∂f/∂b = -0.53812967\n " ,
625+ " 상대오차: a = 9.15e-13, b = 1.26e-11\n " ,
626+ " 통과: True\n " ,
627+ " \n " ,
628+ " 테스트 케이스: a=0.5, b=0.5\n " ,
629+ " 자동미분: ∂f/∂a = 0.69317574, ∂f/∂b = 0.82089438\n " ,
630+ " 수치미분: ∂f/∂a = 0.69317574, ∂f/∂b = 0.82089438\n " ,
631+ " 상대오차: a = 4.10e-12, b = 2.06e-11\n " ,
632+ " 통과: True\n " ,
633+ " \n " ,
634+ " 테스트 케이스: a=-1.2, b=2.0\n " ,
635+ " 자동미분: ∂f/∂a = 2.89208274, ∂f/∂b = -1.41117607\n " ,
636+ " 수치미분: ∂f/∂a = 2.89208274, ∂f/∂b = -1.41117607\n " ,
637+ " 상대오차: a = 9.31e-11, b = 3.11e-10\n " ,
638+ " 통과: True\n "
639+ ]
640+ }
641+ ],
501642 "source" : [
502643 " import numpy as np\n " ,
503644 " \n " ,
564705 },
565706 {
566707 "cell_type" : " code" ,
567- "execution_count" : null ,
708+ "execution_count" : 26 ,
568709 "metadata" : {},
569- "outputs" : [],
710+ "outputs" : [
711+ {
712+ "name" : " stdout" ,
713+ "output_type" : " stream" ,
714+ "text" : [
715+ " \n " ,
716+ " === 연산 그래프 구조 ===\n " ,
717+ " 노드 개수: 5\n " ,
718+ " 엣지 개수: 5\n " ,
719+ " \n " ,
720+ " 노드 정보:\n " ,
721+ " Node 0: data=1.0000, grad=1.0000\n " ,
722+ " Node 1: data=3.0000, grad=0.0000\n " ,
723+ " Node 2: data=2.0000, grad=0.0000\n " ,
724+ " Node 3: data=6.0000, grad=0.0000\n " ,
725+ " Node 4: data=8.0000, grad=0.0000\n " ,
726+ " \n " ,
727+ " 연결 정보:\n " ,
728+ " 2.0000 -> 6.0000\n " ,
729+ " 6.0000 -> 8.0000\n " ,
730+ " 2.0000 -> 8.0000\n " ,
731+ " 3.0000 -> 6.0000\n " ,
732+ " 8.0000 -> 1.0000\n "
733+ ]
734+ }
735+ ],
570736 "source" : [
571737 " def trace_graph(root):\n " ,
572738 " \"\"\" 연산 그래프 추적\"\"\"\n " ,
728894 ],
729895 "metadata" : {
730896 "kernelspec" : {
731- "display_name" : " Python 3 " ,
897+ "display_name" : " ai " ,
732898 "language" : " python" ,
733899 "name" : " python3"
734900 },
742908 "name" : " python" ,
743909 "nbconvert_exporter" : " python" ,
744910 "pygments_lexer" : " ipython3" ,
745- "version" : " 3.11.0 "
911+ "version" : " 3.11.7 "
746912 }
747913 },
748914 "nbformat" : 4 ,
749915 "nbformat_minor" : 4
750- }
916+ }
0 commit comments