dev_AI_framework

soft max backend 구현,

명징직조지훈 2024. 9. 9. 09:44

배치 데이터 입력

// Softmax 연산을 배치 데이터로 수행하도록 개별 노드로 분리하여 구현
std::pair<py::array_t<double>, std::vector<std::shared_ptr<Node>>> softmax(py::array_t<double> inputs) {
    py::buffer_info buf = inputs.request();
    if (buf.ndim != 2)
        throw std::runtime_error("Input should be a 2-D array");

    size_t num_rows = buf.shape[0];
    size_t num_cols = buf.shape[1];
    double* ptr = static_cast<double*>(buf.ptr);

    py::array_t<double> result({num_rows, num_cols});
    py::buffer_info buf_result = result.request();
    double* ptr_result = static_cast<double*>(buf_result.ptr);

    std::vector<std::shared_ptr<Node>> node_list;

    // 각 행에 대해 Softmax 연산 수행
    for (size_t row = 0; row < num_rows; ++row) {
        double* row_ptr = ptr + row * num_cols;
        double* row_result_ptr = ptr_result + row * num_cols;

        // 각 행 별 최댓값
        double max_val = *std::max_element(row_ptr, row_ptr + num_cols);

        double sum = 0.0;
        std::vector<std::shared_ptr<Node>> exp_nodes;

        for (size_t i = 0; i < num_cols; ++i) {
            double input_value = row_ptr[i];

            // Subtract 노드 생성 (각 입력에서 최대값을 뺌)
            double sub_output = input_value - max_val;
            std::shared_ptr<Node> sub_node = std::make_shared<Node>("subtract", input_value, max_val, sub_output);

            // Exponentiate 노드 생성 (exp(x))
            double exp_output = std::exp(sub_output);
            std::shared_ptr<Node> exp_node = std::make_shared<Node>("exp", sub_output, exp_output);
            exp_node->add_child(sub_node);
            sub_node->add_parent(exp_node);

            exp_nodes.push_back(exp_node);

            sum += exp_output;
        }

        for (size_t i = 0; i < num_cols; ++i) {
            // Divide 노드 생성 (exp(x) / sum)
            double div_output = exp_nodes[i]->output / sum;
            std::shared_ptr<Node> div_node = std::make_shared<Node>("divide", exp_nodes[i]->output, sum, div_output);
            
            div_node->add_child(exp_nodes[i]);
            exp_nodes[i]->add_parent(div_node);

            // 결과의 개수는 입력 데이터의 개수와 동일, 배치까지
            node_list.push_back(div_node);

            // 결과 저장
            row_result_ptr[i] = div_output;
        }
    }

    return std::make_pair(result, node_list);
}

각 행, 각 데이터에 대해 softmax 연산을 수행과 노드 저장

 

from dev.backend.activations import activations

import numpy as np

# 예시 입력
inputs = np.array([[-1.0, 0.5, 2.0], [1.0, -0.5, 0.0]])

# ReLU 연산
result, nodes = activations.relu(inputs)
print("ReLU Result:", result)

# Sigmoid 연산
result, nodes = activations.sigmoid(inputs)
print("Sigmoid Result:", result)

# Tanh 연산
result, nodes = activations.tanh(inputs)
print("Tanh Result:", result)

# Leaky ReLU 연산
result, nodes = activations.leaky_relu(inputs, alpha=0.01)
print("Leaky ReLU Result:", result)

# Softmax 연산
result, nodes = activations.softmax(inputs)
print("Softmax Result:", result)

"""
ReLU Result: [0.  0.5 2.  1.  0.  0. ]
Sigmoid Result: [0.26894142 0.62245933 0.88079708 0.73105858 0.37754067 0.5       ]
Tanh Result: [-0.76159416  0.46211716  0.96402758  0.76159416 -0.46211716  0.        ]
Leaky ReLU Result: [-0.01   0.5    2.     1.    -0.005  0.   ]
Softmax Result: [[0.03911257 0.17529039 0.78559703] [0.62853172 0.14024438 0.2312239 ]]
"""

배치단위 입력이 일차원 리스트로 출력됨 크기 조정이 필요하네