이진분류 신경망은 출력층에 뉴런 1개
다중분류 신경망은 출력층에 뉴런이 여러개임
3개 클래스를 구분하는 경우(예 강아지, 고양이, 새) 3개의 뉴런을 둔다 = 분류하고자 하는 클래스 개수 만큼 뉴런을 배치한다.
출력층에서 출력하는 뉴런의 확률값은 각 클래스에 대한 확률값임
이진분류의 확률값은 양성 클래스에 대한 확률다
이진분류는 출력층에 시그모이드 함수를 사용함
확률 값은 전체가 더해서 1이 되어야 함 하지만 위 사진을 보면 합이 1이 아님
자동차를 가장 높게 예측했지만 각각 차이가 0.1밖에 안남 → 자동차 비행기 로켓을 좀 헷갈리고있음
2번째 뉴런은 큰 차이로 자동차인 것을 예측했음, 0.5이지만 오히려 출력이 더 잘 됨
각 출력층 뉴런에 시그모이드 함수를 적용하면 비교가 어렵다 정규화를 해야 함.
선형출력값 z1에서 z3까지를 지수함수에 적용한 후 각 세개 뉴런의 출력값을 분모에 두어서 각 출력의 합이 1이 되도록 만드는 방법
뉴런마다 각자 시그모이드 함수로 출력하는 것보단
소프트맥스 함수를 사용해 확률값을 정규화 해 합이 1이 되도록 해 출력하는 것이 더 공정하다 다중분류에서는 출력층에 항상 소프트맥스 함수 사용
크로스 엔트로피 손실 함수를 사용하는데, 각 클래스의 타깃과 출력값의 로그를 곱해서 더하면 됨 a는 소프트맥스의 출력
다중분류 시 타깃이 되는 답 클래스는 1, 나머지 클래스는 0으로 둠
크로스 엔트로피 손실 함수 L = -1 * log(a(y=1))
소프트 맥스 함수 구현
시그모이드 그대로 두고 소프트맥스 추가함
def sigmoid(self, z):
a = 1 / (1 + np.exp(-z)) #시그모이드 계산
return a
def softmax(self, z):
#소프트맥스 함수
exp_z = np.exp(z)
return exp_z / np.sum(exp_z, axis=1).reshape(-1, 1)
지수함수 적용 후 np.sum( axis=1)로 분모 계산 (각 행의 값을 열 따라 더함) 행벡터를 열벡터로 바꿈?.
def init_weights(self, n_features, n_classes):
...
self.w2 = np.random.normal(0, 1, (self.units, n_classes)) # 은닉층의 크기, 클래스 개수
self.b2 = np.zeros(n_classes)
가중치의 개수(출력 부분) 이진분류에서 1이였기 때문에 다중분류인 지금은 가중치의 크기를 출력 클래스 개수만큼으로 바꿔줌 n_classes
절편의 개수도 클래스 개수만큼.
def update_val_loss(self, x_val, y_val):
...
a = self.softmax(z) #활성화 함수를 적용합니다
...
#크로스 엔트로피 손실과 규제 손실을 더해 리스트에 추가
val_loss = np.sum(-y_val * np.log(a))
...
출력층의 뉴런은 10개임. 각각 이 값과 타깃을 비교해야 함 →타깃값도 10개가 필요함
첫 타깃값이 6일 경우, 10개의 배열 중 7번째 (인덱스 6) 값이 1이 되도록 만듦
은닉층과 출력층을 완전연결층, 밀집층이라 부름
케라스는 dense클래스에서 이것을 구현함
전체모델은 sequential 모델로 만들 수 있음