-
Notifications
You must be signed in to change notification settings - Fork 0
/
Model.py
134 lines (89 loc) · 4.36 KB
/
Model.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
import numpy as np
import math
class TwoLayerNet():
"""
2 Layer Network를 만드려고 합니다.
해당 네트워크는 아래의 구조를 따릅니다.
input - Linear - ReLU - Linear - Softmax
Softmax 결과는 입력 N개의 데이터에 대해 개별 클래스에 대한 확률입니다.
"""
def __init__(self, X, input_size, hidden_size, output_size, std=1e-4):
"""
네트워크에 필요한 가중치들을 initialization합니다.
initialized by random values
해당 가중치들은 self.params 라는 Dictionary에 담아둡니다.
input_size: 데이터의 변수 개수 - D
hidden_size: 히든 층의 H 개수 - H
output_size: 클래스 개수 - C
"""
# 사용될 weight와 bias들을 랜덤으로 초기화해주기
self.params = {}
self.params["W1"] = std * np.random.randn(input_size, hidden_size)
self.params["b1"] = np.random.randn(hidden_size)
self.params["W2"] = std * np.random.randn(hidden_size, output_size)
self.params["b2"] = np.random.randn(output_size)
def forward(self, X, y=None):
"""
X: input 데이터 (N, D)
y: 레이블 (N,)
Linear - ReLU - Linear - Softmax - CrossEntropy Loss
y가 주어지지 않으면 Softmax 결과 p와 Activation 결과 a를 return합니다. p와 a 모두 backward에서 미분할때 사용합니다.
y가 주어지면 CrossEntropy Error를 return합니다.
"""
W1, b1 = self.params["W1"], self.params["b1"]
W2, b2 = self.params["W2"], self.params["b2"]
N, D = X.shape
#N은 총 데이터의 개수, D는 feature 개수
# 여기에 p를 구하는 작업을 수행하세요.
h = np.dot(X, W1) + b1
a = np.maximum(0, h)
o = np.dot(a, W2) + b2
p = np.exp(o)/np.sum(np.exp(o),axis=1).reshape(-1,1)
if y is None: #Y가 없다 = 역전파! 따라서 중간 과정을 반환하여 역전파 시 이용, 이때는 따로 LOSS를 구하지 않고 여기서 함수 종료
return p, a
#Y가 있다 = 순전파이기 때문에 주어진 weight와 bias를 가지고 순전파를 진행하여 Loss 생성
# 여기에 Loss를 구하는 작업을 수행하세요.
Loss = 0
#크로스 엔트로피 공식에 따라 lOSS 계산
for i in range(y.shape[0]): #행
for j in range(p.shape[1]): #열
if y[i] == j:
Loss -= np.log(p[i][j])
# print('loss : ',Loss)
return Loss
def backward(self, X, y, learning_rate=1e-5):
"""
X: input 데이터 (N, D)
y: 레이블 (N,)
grads에는 Loss에 대한 W1, b1, W2, b2 미분 값이 기록됩니다.
원래 backw 미분 결과를 return 하지만
여기서는 Gradient Descent방식으로 가중치 갱신까지 합니다.
"""
W1, b1 = self.params["W1"], self.params["b1"]
W2, b2 = self.params["W2"], self.params["b2"]
N = X.shape[0] # 데이터 개수
grads = {}
#역전파에 이용할 중간 값들을 forward로부터 반환받음.
p, a = self.forward(X)
# 여기에 파라미터에 대한 미분을 저장하세요.
dp = p
for i in range(p.shape[0]):
for j in range(p.shape[1]):
if(j==y[i]):
dp[i][j]-=1
# Softmax 미분 값, p-y
da = np.heaviside(a,0)
# Relu를 미분하면 계단 함수처럼 생겼다 그리고 heaviside는 계단함수이다
#가중치를 업데이트 합시다, 풀이과정은 pdf에 필기로 첨부해놓았습니다
grads["W2"] = np.dot(a.T, dp)
grads["b2"] = np.sum(dp, axis=0)
grads["W1"] = np.dot(X.T, da*np.dot(dp, W2.T))
grads["b1"] = np.sum(da*np.dot(dp,W2.T), axis=0)
self.params["W2"] -= learning_rate * grads["W2"]
self.params["b2"] -= learning_rate * grads["b2"]
self.params["W1"] -= learning_rate * grads["W1"]
self.params["b1"] -= learning_rate * grads["b1"]
def accuracy(self, X, y):
p, _ = self.forward(X)
pre_p = np.argmax(p,axis=1)
return np.sum(pre_p==y)/pre_p.shape[0]