Darknet Softmax 출력 전체의 합이 1이 아니더라도 groups>1이거나 softmax_tree를 쓰고 있다면 정상일 수 있으며, 합은 각 group 안에서 따로 1이 되어야 합니다.
Softmax는 logit x_i를 확률로 바꾸지만 이 layer의 핵심은 공식 자체보다 어떤 원소를 한 분모로 묶는지입니다. 원문의 Softmax 설명과 코드를 함께 보면 group, tree 설정이 shape만큼 중요합니다.
Darknet Softmax 출력 전체의 합이 1이 아니더라도 groups>1이거나 softmax_tree를 쓰고 있다면 정상일 수 있으며, 합은 각 group 안에서 따로 1이 되어야 합니다.
Softmax는 logit x_i를 확률로 바꾸지만 이 layer의 핵심은 공식 자체보다 어떤 원소를 한 분모로 묶는지입니다. 원문의 Softmax 설명과 코드를 함께 보면 group, tree 설정이 shape만큼 중요합니다.
make_softmax_layer는 inputs % groups == 0을 assert하고 출력 크기를 입력과 같게 둡니다. Forward에서는 한 group의 크기를 inputs/groups로 계산해 softmax_cpu에 넘깁니다.
1
2
3
4
5
6
7
8
9
10
softmax_cpu(
net.input,
l.inputs/l.groups,
l.batch,
l.inputs,
l.groups,
l.inputs/l.groups,
1,
l.temperature,
l.output);
예를 들어 inputs가 12이고 groups가 3이면 12개 전체를 한 번에 정규화하는 것이 아니라 네 개씩 세 묶음을 계산합니다. 출력 전체 합은 3에 가까울 수 있습니다. 분류 class 전체가 하나의 배타적 집합이라면 groups를 1로 두어야 합니다.
temperature는 softmax에 들어가는 logit scale을 바꿉니다. 같은 logit에서도 값이 달라지므로 checkpoint를 비교할 때 temperature 설정을 함께 기록해야 합니다.
l.softmax_tree가 있으면 고정 크기 groups 대신 tree에 저장된 group_size를 순회합니다. count는 앞 group 크기를 누적해 다음 group의 시작점을 정합니다.
1
2
3
4
5
6
7
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;
}
이때 각 sibling group 안의 조건부 확률 합이 1입니다. 계층 전체 class 값을 평평한 확률 하나로 해석하려면 부모 경로 확률을 추가로 결합해야 하며, softmax layer만으로 그 작업까지 끝나지 않습니다.
Truth가 있고 noloss가 꺼져 있을 때 softmax_x_ent_cpu가 원소별 loss와 delta를 계산합니다. Cost는 평균이 아니라 batch*inputs 범위 loss의 합입니다.
Softmax와 one-hot cross-entropy를 결합하면 logit gradient는 보통 다음처럼 단순해집니다.
\[\frac{\partial L}{\partial x_i}=p_i-y_i\]Darknet의 부호 방향은 전체 optimizer 호출 계약과 함께 봐야 하지만, 중요한 구조는 backward 함수가 softmax Jacobian을 다시 계산하지 않는다는 점입니다. 이미 만들어진 l.delta를 앞 layer delta에 더하기만 합니다.
1
axpy_cpu(l.inputs*l.batch, 1, l.delta, 1, net.delta, 1);
Truth가 없거나 noloss가 켜져 있다면 이 forward 경로는 delta를 새로 만들지 않습니다. 다른 호출부가 delta를 제공하는지 확인하지 않고 backward만 호출하면 초기화된 0이 전달될 수 있습니다.
일반 mode에서는 batch와 group마다 출력 합을 계산하고, tree mode에서는 group_offset/group_size별로 합을 봅니다. 큰 양수, 음수 logit에서도 NaN이 없는지, temperature 변경이 분포를 예상 방향으로 바꾸는지 확인합니다. Loss를 켰다면 cost가 batch 평균이 아니라 합이라는 점도 비교 코드에 반영해야 합니다.
이 코드 조각은 Softmax layer의 메모리와 호출 흐름만 담고 있습니다. softmax_cpu의 수치 안정화, tree 구조 생성, optimizer의 delta 부호는 주변 구현을 함께 읽어야 정확히 포팅할 수 있습니다.
Inputs 6, groups 2에서 서로 다른 logit 세 개씩을 넣고 각 구간 합이 1인지 봅니다. Group stride와 batch stride를 다르게 드러내도록 batch 2를 사용합니다. Inputs가 groups로 나누어떨어지지 않거나 groups 0인 설정은 생성 전에 거부합니다.
Tree mode에서는 group_offset과 size가 전체 input을 범위 안에서 정확히 덮고 sibling마다 합이 1인지 확인합니다. 빠진 node와 겹친 group을 tree loader에서 검증합니다.
Sibling softmax 출력은 parent가 주어졌을 때의 조건부 확률입니다. Root부터 node까지 곱해 전체 class probability를 만들고 only-leaf 여부를 적용합니다. Softmax layer 출력만 threshold하면 깊은 node와 root node를 같은 의미로 비교하게 됩니다.
작은 root, child tree에서 sibling 합과 path product를 손으로 계산합니다. Parent-before-child 순서와 group offset이 틀리면 합은 1이어도 잘못된 sibling이 묶일 수 있습니다.
네. groups가 여러 개면 각 group 합이 1이고 전체 합은 group 수에 가까울 수 있습니다.
아닙니다. Sibling group 안 조건부 확률이며 최종 node 확률에는 부모 경로 확률을 결합해야 합니다.
이 forward 경로에서는 새 cross-entropy delta를 만들지 않으므로 backward 호출과 buffer 상태를 확인해야 합니다.
네. groups가 여러 개면 각 group 합이 1이고 전체 합은 group 수에 가까울 수 있습니다.
아닙니다. Sibling group 안 조건부 확률이며 최종 node 확률에는 부모 경로 확률을 결합해야 합니다.
이 forward 경로에서는 새 cross-entropy delta를 만들지 않으므로 backward 호출과 buffer 상태를 확인해야 합니다.
←→ 키와 좌우 스와이프를 지원합니다. 읽던 페이지는 이 기기에 저장됩니다.