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);
}
각 연산과 노드 정의