dev_AI_framework

activation_functoin 의 노드 구현 softmax 남음

명징직조지훈 2024. 9. 5. 18:59

relu 의 경우 

// ReLU 연산의 구성 요소 노드와 결과 배열 반환
std::pair<py::array_t<double>, std::vector<std::shared_ptr<Node>>> relu_component_nodes(py::array_t<double> inputs) {
    // Numpy 배열의 버퍼 정보 가져오기
    py::buffer_info buf = inputs.request();
    double* ptr = static_cast<double*>(buf.ptr);

    // 결과 배열 생성
    py::array_t<double> result(buf.size);

    // result 배열 포인터 접근
    py::buffer_info buf_result = result.request();
    double* ptr_result = static_cast<double*>(buf_result.ptr);

    // 노드 리스트 생성
    std::vector<std::shared_ptr<Node>> node_list;

    // 각 요소에 대해 ReLU 연산을 수행하고, 노드 생성
    for (size_t i = 0; i < buf.size; ++i) {
        double input_value = ptr[i];

        // 비교 노드 생성 (x > 0)
        std::shared_ptr<Node> compare_node = std::make_shared<Node>("compare", input_value, input_value > 0 ? 1.0 : 0.0);

        // 선택 노드 생성 (x 또는 0 선택)
        double output_value = (compare_node->output > 0) ? input_value : 0.0;
        std::shared_ptr<Node> select_node = std::make_shared<Node>("select", input_value, output_value);

        // 노드 연결
        select_node->add_parent(compare_node);
        compare_node->add_child(select_node);

        // 결과 저장, 포인터 주소로 접근하기
        ptr_result[i] = output_value;

        // 노드 리스트에 추가
        node_list.push_back(compare_node); // 비교 노드를 리스트에 추가 (순서에 따라 필요할 수 있음)
    }
    // 결과 배열과 노드 리스트 반환
    return std::make_pair(result, node_list);
}

relu 의 경우 비교 노드 생성, 선택 노드 생성 후 자식, 부모 간 연결

compare 노드의 경우, 특정 값보다 큰지에 대한 값 1, 0 으로 큰 지 작은 지에 대한 판단 클 경우 1 출력, 

미분에 대해서 항상 생각하면

compare 의 gradient 를 볼 때, input_value, output_value 를 통해, 근데 단독으로 쓸 수 있는 일이 없는거 같은데

0,1일 상관없이 gra 값은 동일,

select 노드의 경우, 출력값에 따라 gra 값은 output / input 값으로 지정하는 방법

 

sigmoid

// Sigmoid 연산을 개별 노드로 분리하여 구현
std::pair<py::array_t<double>, std::vector<std::shared_ptr<Node>>> sigmoid(py::array_t<double> inputs) {
    // Numpy 배열의 버퍼 정보 가져오기
    py::buffer_info buf = inputs.request();
    double* ptr = static_cast<double*>(buf.ptr);

    // 결과 배열 생성
    py::array_t<double> result(buf.size);
    py::buffer_info buf_result = result.request();
    double* ptr_result = static_cast<double*>(buf_result.ptr);

    // 노드 리스트 생성
    std::vector<std::shared_ptr<Node>> node_list;

    // 각 요소에 대해 Sigmoid 연산을 수행하고, 노드 생성
    for (size_t i = 0; i < buf.size; ++i) {
        double input_value = ptr[i];

        // Negate 노드 (-x)
        double neg_output = -input_value;
        std::shared_ptr<Node> neg_node = std::make_shared<Node>("negate", input_value, neg_output);

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

        // Add 1 노드 (1 + exp(-x))
        // 상수 1 까지의 연산, add 하는 객체가 2개이므로
        double constant_value = 1.0;
        double add_output = constant_value + exp_output;
        std::shared_ptr<Node> add_node = std::make_shared<Node>("add", exp_output, constant_value, add_output);

        // 부모-자식 관계 설정
        add_node->add_child(exp_node);  // exp_node는 add_node의 자식 노드
        exp_node->add_parent(add_node);   // add_node는 exp_node의 부모 노드

        // Reciprocal 노드 (1 / (1 + exp(-x)))
        double constant_value = 1.0;
        double recip_output = constant_value / add_output;  // 1.0을 분자에 포함
        std::shared_ptr<Node> recip_node = std::make_shared<Node>("reciprocal", constant_value, add_output, recip_output);

        recip_node->add_child(add_node);
        add_node->add_parent(recip_node);

        // 결과 저장
        ptr_result[i] = recip_output;

        // 노드 리스트에 추가
        node_list.push_back(recip_node);
    }

    // 결과 배열과 노드 리스트 반환
    return std::make_pair(result, node_list);
}

각 연산에 대한 정의... 노드의 operation 값이 다르고, 입력, 출력값이 존재

두 개의 입력을 받는 연산의 정의

 

tanh

std::pair<py::array_t<double>, std::vector<std::shared_ptr<Node>>> tanh_activation(py::array_t<double> inputs) {
    py::buffer_info buf = inputs.request();
    double* ptr = static_cast<double*>(buf.ptr);

    py::array_t<double> result(buf.size);
    py::buffer_info buf_result = result.request();
    double* ptr_result = static_cast<double*>(buf_result.ptr);

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

    for (size_t i = 0; i < buf.size; ++i) {
        double input_value = ptr[i];

        // Exponentiate 노드 (exp(x))
        double exp_pos_output = std::exp(input_value);
        std::shared_ptr<Node> exp_pos_node = std::make_shared<Node>("exp", input_value, exp_pos_output);

        // Exponentiate 노드 (exp(-x))
        double exp_neg_output = std::exp(-input_value);
        std::shared_ptr<Node> exp_neg_node = std::make_shared<Node>("exp", -input_value, exp_neg_output);

        // Numerator 노드 (exp(x) - exp(-x))
        double numerator_output = exp_pos_output - exp_neg_output;
        std::shared_ptr<Node> numerator_node = std::make_shared<Node>("subtract", exp_pos_output, exp_neg_output, numerator_output);
        numerator_node->add_child(exp_pos_node);
        numerator_node->add_child(exp_neg_node);

        exp_pos_node->add_parent(numerator_node);
        exp_neg_node->add_parent(numerator_node);

        // Denominator 노드 (exp(x) + exp(-x))
        double denominator_output = exp_pos_output + exp_neg_output;
        std::shared_ptr<Node> denominator_node = std::make_shared<Node>("add", exp_pos_output, exp_neg_output, denominator_output);
        denominator_node->add_child(exp_pos_node);
        denominator_node->add_child(exp_neg_node);

        exp_pos_node->add_parent(denominator_node);
        exp_neg_node->add_parent(denominator_node);

        // Reciprocal 노드 (1 / (exp(x) + exp(-x)))
        double constant_value = 1.0;
        double reciprocal_output = constant_value / denominator_output;
        std::shared_ptr<Node> reciprocal_node = std::make_shared<Node>("reciprocal", constant_value, denominator_output, reciprocal_output);  // 두 입력: 상수 1과 분모
        reciprocal_node->add_child(denominator_node);
        denominator_node->add_parent(reciprocal_node);

        // Tanh 노드 (Numerator * Reciprocal)
        double tanh_output = numerator_output * reciprocal_output;
        std::shared_ptr<Node> tanh_node = std::make_shared<Node>("multiply", numerator_output, reciprocal_output, tanh_output);
        tanh_node->add_child(numerator_node);
        numerator_node->add_parent(tanh_node);

        ptr_result[i] = tanh_output;

        node_list.push_back(tanh_node);
    }

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

각 연산과 노드 정의