수치미분을 사용했을 때보다 월등히 빠른 연산시간을 확인할 수 있다.

 

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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
 
import numpy as np
from keras.datasets import mnist
from keras.utils.np_utils import to_categorical
from datetime import datetime
 
 
# 오차역전파(Back Propagation)
# 수치미분을 사용하지 않고, 행렬로 표현할 수 있는 수학공식을 사용하기 때문에 빠른 연산이 가능함
# 가중치나 바이어스가 변할 때, 최종오차가 얼마나 변하는 지를 나타내는 편미분을,
# 체인룰을 사용하여 국소미분으로 분리한 후, 수학 공식으로 표현하여 계산하는 방법
 
 
# MNIST 데이터 불러오기
(x_train, t_train), (x_test, t_test) = mnist.load_data()
 
x_train = np.reshape(x_train, (60000-1))
x_test = np.reshape(x_test, (10000-1))
 
x_train = x_train/255.0
x_test = x_test/255.0
 
t_train = to_categorical(t_train)
t_test = to_categorical(t_test)
 
print()
 
# csv 파일인 겨우
# x_train = np.loadtxt("파일경로", delimiter=',', dtype=np.float32)
 
 
def sigmoid(x):
    return 1 / (1 + np.exp(-x))
 
 
class NN:
 
    def __init__(self, input_nodes, hidden_nodes, output_nodes):
 
        self.input_nodes = input_nodes
        self.hidden_nodes = hidden_nodes
        self.output_nodes = output_nodes
 
        # np.random.rand() 이걸 써주면 학습이 안된다. 이유는 잘 모르겠다.
        # Xavier/He 가중치 초기화 기법 적용
        self.W2 = np.random.randn(self.input_nodes, self.hidden_nodes) / np.sqrt(self.input_nodes / 2)
        self.b2 = np.random.rand(self.hidden_nodes)
 
        self.W3 = np.random.randn(self.hidden_nodes, self.output_nodes) / np.sqrt(self.hidden_nodes / 2)
        self.b3 = np.random.rand(self.output_nodes)
 
        # 입력층 선형회귀 값 Z1, 출력값 A1 정의 (행렬로 표시)
        self.Z1 = np.zeros([1, input_nodes])
        self.A1 = np.zeros([1, input_nodes])
 
        self.Z2 = np.zeros([1, hidden_nodes])
        self.A2 = np.zeros([1, hidden_nodes])
 
        self.Z3 = np.zeros([1, output_nodes])
        self.A3 = np.zeros([1, output_nodes])
 
        self.learning_rate = 0.3
 
    def feed_forward(self):
        delta = 1e-7  # log가 무한대로 발산하는 것을 막아준다
 
        self.Z1 = self.input_data
        self.A1 = self.input_data
 
        self.Z2 = np.dot(self.A1, self.W2) + self.b2
        self.A2 = sigmoid(self.Z2)
 
        self.Z3 = np.dot(self.A2, self.W3) + self.b3
        self.A3 = sigmoid(self.Z3)
 
        return -np.sum(self.target_data * np.log(self.A3 + delta) + (1 - self.target_data) * np.log((1 - self.A3) + delta))
 
    def train(self, input_data, target_data):
 
        self.target_data = target_data
        self.input_data = input_data
 
        loss_val = self.feed_forward()
 
        # 출력층 loss_3
        loss_3 = (self.A3 - self.target_data) * self.A3 * (1 - self.A3)
        self.W3 = self.W3 - self.learning_rate * np.dot(self.A2.T, loss_3)
        self.b3 = self.b3 - self.learning_rate * loss_3
 
        # 은닉층 loss_2
        loss_2 = np.dot(loss_3, self.W3.T) * self.A2 * (1 - self.A2)
        self.W2 = self.W2 - self.learning_rate * np.dot(self.A1.T, loss_2)
        self.b2 = self.b2 - self.learning_rate * loss_2
 
    def loss_eval(self):
        delta = 1e-7
 
        self.Z1 = self.input_data
        self.A1 = self.input_data
 
        self.Z2 = np.dot(self.A1, self.W2) + self.b2
        self.A2 = sigmoid(self.Z2)
 
        self.Z3 = np.dot(self.A2, self.W3) + self.b3
        self.A3 = sigmoid(self.Z3)
 
        return -np.sum(self.target_data * np.log(self.A3 + delta) + (1 - self.target_data) * np.log((1 - self.A3) + delta))
 
    def predict(self, input_data):
 
        Z2 = np.dot(input_data, self.W2) + self.b2
        A2 = sigmoid(Z2)
 
        Z3 = np.dot(A2, self.W3) + self.b3
        A3 = sigmoid(Z3)
 
        return np.argmax(A3)
 
    def accuracy(self, input_x, input_t):
 
        right_list = []
        wrong_list = []
 
        for idx in range(len(input_x)):
            pred = self.predict(input_x[idx])
 
            if pred == np.argmax(input_t[idx]):
                right_list.append(idx)
            else:
                wrong_list.append(idx)
 
        print("accuracy = "100*len(right_list)/len(input_x), "%")
 
 
# 모델 훈련
model = NN(78410010)
 
start_time = datetime.now()
 
for step in range(10001):
 
    idx = np.random.randint(0len(x_train)-1)  #총 6만개의 데이터중 임의로 2만개 선택
 
    model.train(np.array(x_train[idx], ndmin=2), t_train[idx])
 
    if step % 1000 == 0:
        print("step = ", step, ", error = ", model.loss_eval())
 
        end_time = datetime.now()
        print("elapsed time = ", end_time - start_time)
        start_time = datetime.now()
 
 
# 모델 테스트
model.accuracy(x_test, t_test)
 
 
 
 
 
cs

 

위의 소스코드를 실행시키면 아래와 같은 출력값을 얻을 수 있다.

반응형

'머신러닝_딥러닝 > Tensorflow + Keras' 카테고리의 다른 글

(Tensorflow 2.x) Regression 2탄  (0) 2021.10.23
(Tensorflow 2.x) Regression 1탄  (0) 2021.10.23
MNIST 1탄  (0) 2021.10.23
XOR 문제 (딥러닝으로 해결)  (0) 2021.10.23
XOR 문제  (0) 2021.10.23

+ Recent posts