DarkNet 시리즈 - Softmax Layer
softmax_layer
softmax란?
참조 : https://ratsgo.github.io/deep%20learning/2017/10/02/softmax/
- 입력의 모든 합을 1로 만드는 함수 입니다.
- \[p_i = \frac{exp(x_i)}{\sum^{C}_{c=1} exp{x_c}}\]
softmax는 역전파의 시작점 입니다.
우리는 error를 통해서 softmax input의 gradient를 구해야합니다. (그래야 뒤로 쭉쭉 갈수 있겠죠?)
먼저 연산을 위해 미리 softmax를 미분한다면
\(i = j\) 일때
- \[\frac{\partial p_i}{\partial x_i} = \frac{\partial \frac{exp(x_i)}{\sum^{C}_{c=1} exp(x_c)}}{\partial x_i}\]
- \[\frac{\partial p_i}{\partial x_i} = \frac{exp(x_i) \sum^{C}_{c=1} exp(x_c) - exp(x_i) exp(x_i)}{(\sum^{C}_{c=1} exp(x_c))^2}\]
- \[= \frac{exp(x_i) [ \sum^{C}_{c=1} \left \{ \exp(x_c) \right \} - exp(x_i)]}{(\sum^{C}_{c=1} exp(x_c))^2}\]
- \[= \frac{exp(x_i)}{\sum^{C}_{c=1} exp(x_c)} \frac{\sum^{C}_{c=1} \left \{ exp(x_c) \right \} - exp(x_i) }{(\sum^{C}_{c=1} exp(x_c))}\]
- \[= \frac{exp(x_i)}{\sum^{C}_{c=1} exp(x_c)} \left ( 1 - \frac{exp(x_i)}{\sum^{C}_{c=1} exp(x_c)} \right )\]
- \[= p_i (1 - p_i)\]
\(i \neq j\) 일때
- \[\frac{\partial p_i}{\partial x_j} = \frac{0 - exp(x_i) exp(x_j)}{(\sum^{C}_{c=1} exp(x_c))^2}\]
- \[= - \frac{exp(x_i)}{\sum^{C}_{c = 1} exp(x_c)} \frac{exp(x_j)}{\sum^{C}_{c=1} exp(x_c)}\]
- \[= - p_i p_j\]
역전파
- \[\frac{\partial L}{\partial x_i} = \frac{\partial (- \sum_{j} y_j \log p_j )}{ \partial x_i }\]
- \[= - \sum_j y_j \frac{\partial \log p_j}{\partial x_i}\]
- \[= - \sum_j y_j \frac{1}{p_j} \frac{\partial p_j}{\partial x_i}\]
- \[= - \frac{y_i}{p_i} p_i (1 - p_j) - \sum_{i \neq j} \frac{y_j}{p_j} (- p_i p_j)\]
- \[= - y_i + y_i p_i + \sum_{i \neq j} y_j p_i\]
- \[= - y_i + \sum_j y_j p_i\]
- \[= - y_i + p_i \sum_j y_j\]
- \[p_i - y_i\]
softmax_layer.c
forward_softmax_layer
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void forward_softmax_layer(const softmax_layer l, network net)
{
if(l.softmax_tree){
int i;
int count = 0;
for (i = 0; i < l.softmax_tree->groups; ++i) {
int group_size = l.softmax_tree->group_size[i];
softmax_cpu(net.input + count, group_size, l.batch, l.inputs, 1, 0, 1, l.temperature, l.output + count);
count += group_size;
}
} else {
softmax_cpu(net.input, l.inputs/l.groups, l.batch, l.inputs, l.groups, l.inputs/l.groups, 1, l.temperature, l.output);
}
if(net.truth && !l.noloss){
softmax_x_ent_cpu(l.batch*l.inputs, l.output, net.truth, l.delta, l.loss);
l.cost[0] = sum_array(l.loss, l.batch*l.inputs);
}
}
함수 이름: forward_softmax_layer
입력:
- softmax_layer l: softmax 레이어의 정보를 담은 구조체
- network net: 뉴럴 네트워크의 정보를 담은 구조체
동작:
- softmax 레이어의 forward propagation을 수행한다.
- softmax_tree가 존재하면, softmax_tree를 이용하여 그룹화된 입력값들에 대해 softmax 연산을 수행한다.
- softmax_tree가 존재하지 않으면, 입력값에 대해 softmax 연산을 수행한다.
- 만약 net.truth가 존재하고, l.noloss가 false이면, softmax_cross_entropy_loss 를 이용하여 손실을 계산한다.
설명:
- softmax 레이어는 출력값을 확률값으로 변환해준다.
- softmax_tree는 계층 구조를 이용하여 그룹화된 노드를 softmax 연산하기 위해 사용된다.
- softmax_cpu 함수는 입력값에 대해 softmax 연산을 수행하고, 결과를 출력값으로 저장한다.
- softmax_x_ent_cpu 함수는 softmax_cross_entropy_loss 를 계산하고, 손실값을 loss 배열에 저장한다.
- 손실값은 l.cost[0]에 저장된다.
backward_softmax_layer
1
2
3
4
void backward_softmax_layer(const softmax_layer l, network net)
{
axpy_cpu(l.inputs*l.batch, 1, l.delta, 1, net.delta, 1); // network delta = layer delta
}
함수 이름: backward_softmax_layer
입력:
- softmax_layer l: softmax 레이어의 구조를 저장하는 구조체
- network net: 신경망 전체의 구조와 데이터를 저장하는 구조체
동작:
- 입력값에 대한 softmax 함수의 역전파 수행
- axpy_cpu 함수를 사용하여, 현재 레이어의 델타 값을 이전 레이어의 델타 값에 더해줌으로써, 역전파를 계속 진행할 수 있도록 함
설명:
- softmax 레이어의 역전파는, softmax 함수의 출력값과 레이어의 델타 값을 이용해 수행됨
- 이 함수에서는, 현재 레이어의 델타 값을 이전 레이어의 델타 값에 더해주는 과정을 수행함
- 이렇게 함으로써, 이전 레이어의 델타 값은 현재 레이어의 델타 값에 영향을 받도록 되어, 역전파를 계속 진행할 수 있음
- 이 함수는 델타 값을 직접 수정하므로, 반환값이 없음
make_softmax_layer
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
softmax_layer make_softmax_layer(int batch, int inputs, int groups)
{
assert(inputs%groups == 0);
fprintf(stderr, "softmax %4d\n", inputs);
softmax_layer l = {0};
l.type = SOFTMAX;
l.batch = batch;
l.groups = groups;
l.inputs = inputs;
l.outputs = inputs;
l.loss = calloc(inputs*batch, sizeof(float));
l.output = calloc(inputs*batch, sizeof(float));
l.delta = calloc(inputs*batch, sizeof(float));
l.cost = calloc(1, sizeof(float));
l.forward = forward_softmax_layer;
l.backward = backward_softmax_layer;
return l;
}
함수 이름: make_softmax_layer
입력:
- int batch: 배치 크기
- int inputs: 입력 뉴런 수
- int groups: 그룹 수
동작:
- 입력 받은 batch, inputs, groups 값으로 softmax 레이어를 생성한다.
- 출력 뉴런 수는 입력 뉴런 수와 같다.
- loss, output, delta, cost 배열을 초기화한다.
- forward, backward 함수를 할당한다.
설명:
- Softmax 레이어는 출력값을 확률로 변환하는 레이어로, 입력값의 지수 함수를 취한 후, 해당 값을 소프트맥스 함수의 분모로 사용해 출력값을 구한다.
- 이 함수에서는 입력으로 받은 batch, inputs, groups 값으로 Softmax 레이어를 생성한다.
- assert 문을 사용하여, 입력 뉴런 수(inputs)가 그룹 수(groups)로 나누어 떨어지지 않을 경우 에러 메시지를 출력한다.
- l.loss, l.output, l.delta, l.cost 배열을 초기화한다.
- forward, backward 함수를 할당한다.
- 생성된 Softmax 레이어(l)를 반환한다.
This post is licensed under CC BY 4.0 by the author.