2023.03.18 - [분류 전체보기] - implement_cnn (수정3)
implement_cnn (수정3)
2023.03.18 - [분류 전체보기] - implement_cnn (수정2) implement_cnn (수정2) 2023.03.17 - [분류 전체보기] - implement_cnn (수정1) implement_cnn (수정1) 코드 부분의 오류가 있어 수정, cnn 클래스의 same_padding_cnn 부분 기
teach-meaning.tistory.com
수정한 cnn 연산으로 인해 역전파 과정에도 수정이 필요
먼저 CNN 의 MLP 층에서의 접근 방식 수정
def mlp_forward_cal(self, node_count):
if(len(self.mlp.node_output) == 0):
self.mlp.node_output.append(self.layer_result[-1])
self.layer_result.append(self.mlp.forward_cal(self.layer_result[-1], node_count))
self.cnn_weight.append(self.mlp.weight[-1])
self.layer = self.layer +1
def mlp_forward_cal(self, node_count):
# 이전 레이어의 출력이 현재 층의 입력이 된다.
self.mlp.node_output.append(self.layer_result[-1])
# MLP 계산의 결과를 저장
self.layer_result.append(self.mlp.forward_cal(self.layer_result[-1], node_count))
self.cnn_weight.append(self.mlp.weight[-1])
조건문의 제거, 이전 레이어의 출력이 node_output 이 된다.
MLP 클래스의 forward_cal 함수 확인
#순전파 계산
def forward_cal(self, input, node_count):
# 가중치의 임의 생성, node_count 개수만큼의 은닉(또는 출력) 노드가 존재한다.
# (n,1) 개의 입력 값과 m 개의 노드 연결 (m, n) 크기의 가중치가 존재해야 한다.
weight = np.random.rand(node_count, input.shape[0])
#편향값의 임의 생성, 동일한 편향 값을 사용한다.
bias = np.random.rand(1)
#가중치와 노드 출력의 행렬곱연산, 편향값 덧셈
hidden_input = weight @ input + bias
#노드 입력과 활성화 함수 연산을 통한 노드 출력 계산
# cnn 에선 0과 1 사이의 결과를 출력해야 하기 때문에 시그모이드 활성화 함수를 사용용
output = self.activation.sigmoid(hidden_input)
# 가중치 값 저장
self.weight.append(weight)
# 편향 값 저장
self.bias.append(bias)
return output
해당 과정 반복을 통해 각 층의 입력(이전 층의 출력이) 저장된다.
해당 연산의 반복,
cnn = CNN()
cnn.same_padding_cnn(input, 7, 64)
cnn.pooling(2)
cnn.layer_cnn(3, 128)
cnn.pooling(2)
cnn.layer_cnn(3, 256)
cnn.pooling(2)
cnn.flatten()
cnn.mlp_forward_cal(128)
cnn.mlp_forward_cal(64)
cnn.mlp_forward_cal(10)
위 방식을 통해 layer 를 쌓는 모습,
10 개의 분류 결과 (0~1) 의 결과가 생성된다.
위 결과로 역전파 과정을 통해 delta 값의 계산 MLP 의 경우 기존에 구현했던 것과 동일, 호출 방식에만 수정을 해준다.
먼저 출력층에 대한 delta, 변화량 계산
비용 함수에 대한 미분값이 사용된다.
출력층 MLP 에 대한 delta 연산을 하는 cal_delta_result_layer 함수
# 출력층 MLP 에 대한 delta 연산
def cal_delta_result_layer(self):
self.delta.append(self.mlp.cal_delta_result(self.layer_result[-1], self.target))
delta 값에 mlp.col_delta_result 값을 추가시킨다. 건네주는 값은 마지막 층 출력의 결과와 타겟 값,
mlp 클래스의 cal_delta_result (수정 필요)
# 비용 함수에 대한 delta 값 계산
def cal_delta_result(self, predict, target):
#출력층 노드의 변화량에 대한 오차 함수의 변화량 계산
delta = (self.cost.diff_error_squared_sum(predict, target) * self.activation.sigmoid_diff(predict))
self.delta.append(delta)
return delta
비용 함수의 미분 함수와 활성화 함수의 미분 함수의 연산으로 각 노드별 델타 값을 계산한다.
여기서 잘못된 곳으로 시그모이드 함수의 미분 함수의 입력값으로 시그모이드 함수 연산 결과인 predict 값이 아닌, 활성화 함수 연산 전의 node_input 값을 넣어줘야 한다.
다시 MLP 의 forward_cal 부분 수정, 활성화 함수 입력 전의 값을 저장해야 한다.
#순전파 계산
def forward_cal(self, input, node_count):
# 가중치의 임의 생성, node_count 개수만큼의 은닉(또는 출력) 노드가 존재한다.
# (n,1) 개의 입력 값과 m 개의 노드 연결 (m, n) 크기의 가중치가 존재해야 한다.
weight = np.random.rand(node_count, input.shape[0])
#편향값의 임의 생성, 동일한 편향 값을 사용한다.
bias = np.random.rand(1)
#가중치와 노드 출력의 행렬곱연산, 편향값 덧셈
hidden_input = weight @ input + bias
# 노드 입력값의 저장 필요, 활성화 미분 함수의 값을 구하기 위해 필요
self.node_input.append(hidden_input)
#노드 입력과 활성화 함수 연산을 통한 노드 출력 계산
# cnn 에선 0과 1 사이의 결과를 출력해야 하기 때문에 시그모이드 활성화 함수를 사용용
output = self.activation.sigmoid(hidden_input)
# 가중치 값 저장
self.weight.append(weight)
# 편향 값 저장
self.bias.append(bias)
return output
node_input 에 해당 값을 저장해준다.
MLP 클래스의 수정된 cal_delta 부분
# 비용 함수에 대한 delta 값 계산
def cal_delta_result(self, predict, target):
#출력층 노드의 변화량에 대한 오차 함수의 변화량 계산
delta = (self.cost.diff_error_squared_sum(predict, target) * self.activation.sigmoid_diff(self.node_input[-1]))
self.delta.append(delta)
return delta
cnn.cal_delta_result_layer()
cnn.delta
>>>
[array([[-4.17621493e-12],
[-2.29150032e-13],
[-1.77635684e-15],
[-7.10542736e-15],
[-1.86517468e-14],
[-2.66453526e-15],
[-2.34479103e-13],
[-2.06057393e-13],
[-9.76996262e-15],
[-1.77635684e-15]])]
cal_delta_result_layer 의 실행 후 delta[0] 값의 확인,
이후 delta 값의 계산에서는 위 delta 값에 가중치 연산, 활성화 함수 미분 함수 연산을 통해 delta 값을 구할 수 있다.
CNN 클래스의 cal_delta_hidden_layer 에서의 구현
def cal_delta_hidden_layer(self):
# 노드 입력값을 넘겨준다.
self.delta.append(self.mlp.cal_delta_hidden(self.layer_result[self.layer - len(self.delta) - 1]))
mlp 클래스의 cal_delta_hidden 함수의 호출로 해당 delta 값을 계산, 넘겨주는 값으로 해당 층에 대한 가중치 연산으로 delta 값을 계산할 수 있다.
이전에 구한 delta 값과 가중치와의 연산, 활성화 함수 미분 함수 순으로 계산한다. 넘겨주는 값은 필요하지 않다.
MLP 클래스의 cal_delta_hidden 의 수정, 호출 방식의 변경
# 은닉층에 대한 delta 값 계산, 가중치 변화량이 누적된다.
def cal_delta_hidden(self, node_input):
# delta 값 호출
delta = self.delta[-1]
# 가중치와의 연산
delta = self.weight[-len(self.delta)].T @ delta
# 활성화 함수 미분 함수와의 연산
delta = delta * self.activation.sigmoid_diff(self.node_input[-(len(self.delta) + 1)])
self.delta.append(delta)
return delta
마지막으로 계산된 delta 값의 호출과 그에 해당하는 가중치와의 연산 수행
'implement_ml_models > CNN' 카테고리의 다른 글
implement_CNN(weight_update_mlp) (1) | 2023.03.19 |
---|---|
implement_cnn (수정3) (0) | 2023.03.18 |
implement_cnn (수정2) (1) | 2023.03.18 |
implement_cnn (수정1) (0) | 2023.03.17 |
implement_CNN(CNN_backpropagation_cnn) (0) | 2023.03.16 |