From 9927d6642cadf12eeb60cf2b87e9d819a82c5d07 Mon Sep 17 00:00:00 2001 From: fanasina Date: Thu, 13 Jun 2024 23:35:25 +0200 Subject: [PATCH] modify COMPARE_N in tool, modify attribute of vehicle by using tensor --- .../src/deepQlearning/learn_to_drive.c | 67 ++++++++++++++---- .../src/deepQlearning/learn_to_drive.h | 24 +++++-- deepQlearn_0/src/deepQlearning/vehicle.c | 4 +- deepQlearn_0/src/deepQlearning/vehicle.h | 47 ++++++------ deepQlearn_0/test/is_good.c | 6 +- neuron_t/src/neuron_t/neuron_t.c | 13 ++++ neuron_t/src/neuron_t/neuron_t.h | 2 +- neuron_t/test/is_good.c | 24 ++++++- tensor_t/src/tensor_t/tensor_t.c | 15 ++-- tensor_t/test/is_good.c | 52 ++++++++++++++ ytest_t/libytest.so | Bin 835448 -> 835656 bytes ytools_t/src/tools_t/tools_t.c | 19 ++++- 12 files changed, 217 insertions(+), 56 deletions(-) diff --git a/deepQlearn_0/src/deepQlearning/learn_to_drive.c b/deepQlearn_0/src/deepQlearning/learn_to_drive.c index 648eb47..958f9da 100644 --- a/deepQlearn_0/src/deepQlearning/learn_to_drive.c +++ b/deepQlearn_0/src/deepQlearning/learn_to_drive.c @@ -47,14 +47,16 @@ struct networks_qlearning * create_nework_qlearning( } -struct reward_lists * create_reward_lists (){ - struct reward_lists * rwrd_l = malloc(sizeof(struct reward_lists)); +struct status_qlearning * create_status_qlearning (){ + struct status_qlearning * status_ql = malloc(sizeof(struct status_qlearning)); - rwrd_l->list_main_cumul = create_var_list_TYPE_L_INT(); - rwrd_l->list_target_cumul = create_var_list_TYPE_L_INT(); - rwrd_l->progress_best_cumul = create_var_list_TYPE_L_INT(); + status_ql->list_main_cumul = create_var_list_TYPE_L_INT(); + status_ql->list_target_cumul = create_var_list_TYPE_L_INT(); + status_ql->progress_best_cumul = create_var_list_TYPE_L_INT(); + + status_ql->nb_training_after_updated_weight_in_target = 0; - return rwrd_l; + return status_ql; } struct delay_params * create_delay_params ( @@ -71,13 +73,16 @@ struct delay_params * create_delay_params ( struct qlearning_params * create_qlearning_params ( double learning_rate, double discount_factor, - double exploration_factor + double exploration_factor, + long int nb_training_before_update_weight_in_target ){ struct qlearning_params * qparams = malloc(sizeof(struct qlearning_params)); qparams->learning_rate = learning_rate ; qparams->discount_factor = discount_factor ; qparams->exploration_factor = exploration_factor ; + + qparams->nb_training_before_update_weight_in_target = nb_training_before_update_weight_in_target; return qparams; } @@ -85,7 +90,7 @@ struct qlearning_params * create_qlearning_params ( struct RL_agent * create_RL_agent ( struct networks_qlearning * networks, struct vehicle * car, - struct reward_lists * rewards, + struct status_qlearning * status, struct delay_params * delay, struct qlearning_params *qlearnParams ){ @@ -93,7 +98,7 @@ struct RL_agent * create_RL_agent ( rlagent->networks = networks ; rlagent->car = car ; - rlagent->rewards = rewards ; + rlagent->status = status ; rlagent->delay = delay ; rlagent->qlearnParams = qlearnParams ; @@ -101,18 +106,52 @@ struct RL_agent * create_RL_agent ( } void free_networks_qlearning (struct networks_qlearning * networks){ - + free_neurons_TYPE_FLOAT(networks->main_net); + free_neurons_TYPE_FLOAT(networks->target_net); + free_neurons_TYPE_FLOAT(networks->best_net); + free_config_layers(networks->config); + free(networks); } -void free_reward_lists(struct reward_lists *rwd_l){ - +void free_status_qlearning(struct status_qlearning *status_ql){ + free_all_var_list_TYPE_L_INT(status_ql->list_main_cumul); + free_all_var_list_TYPE_L_INT(status_ql->list_target_cumul); + free_all_var_list_TYPE_L_INT(status_ql->progress_best_cumul); + free(status_ql); } void free_delay_params (struct delay_params *dly_p){ - + free(dly_p); } void free_qlearning_params(struct qlearning_params *q_params){ - + free(q_params); } void free_RL_agent(struct RL_agent *rlAgent){ + free(rlAgent->qlearnParams); + free(rlAgent->delay); + free_status_qlearning(rlAgent->status); + free_networks_qlearning(rlAgent->networks); + free_vehicle(rlAgent->car); + free(rlAgent); } +void train_qlearning(struct RL_agent * rlAgent, + int action /* */, + tensor_TYPE_FLOAT * new_state /*input*/, + tensor_TYPE_FLOAT * state /*input*/, + long reward){ + tensor_TYPE_FLOAT * action_value = NULL; + tensor_TYPE_FLOAT * next_action_value = NULL; + neurons_TYPE_FLOAT * net_main = rlAgent->networks->main_net; + neurons_TYPE_FLOAT * net_target = rlAgent->networks->target_net; + calculate_output_by_network_neurons_TYPE_FLOAT(net_main, state, &action_value); + calculate_output_by_network_neurons_TYPE_FLOAT(net_target, state, &next_action_value); + tensor_TYPE_FLOAT * experimental_values = CREATE_TENSOR_FROM_CPY_DIM_TYPE_FLOAT(action_value->dim); + + struct game_status * car_status = rlAgent->car->status; + if( copy_tensor_TYPE_FLOAT(experimental_values, action_value) == 0 /* done */){ + if(status->done){ + + } + } + +} diff --git a/deepQlearn_0/src/deepQlearning/learn_to_drive.h b/deepQlearn_0/src/deepQlearning/learn_to_drive.h index 7cb9530..2c9dfae 100644 --- a/deepQlearn_0/src/deepQlearning/learn_to_drive.h +++ b/deepQlearn_0/src/deepQlearning/learn_to_drive.h @@ -17,15 +17,21 @@ struct qlearning_params { double learning_rate; + double factor_update_learning_rate; + double minimum_threshold_learning_rate; double discount_factor; double exploration_factor; + double factor_update_exploration_factor; + double minimum_threshold_exploration_factor; + long int nb_training_before_update_weight_in_target; }; -struct reward_lists { +struct status_qlearning { struct main_list_TYPE_L_INT * list_main_cumul; struct main_list_TYPE_L_INT * list_target_cumul; struct main_list_TYPE_L_INT * progress_best_cumul; + long int nb_training_after_updated_weight_in_target; }; struct delay_params { @@ -43,7 +49,7 @@ struct networks_qlearning { struct RL_agent { struct networks_qlearning * networks; struct vehicle * car; - struct reward_lists * rewards; + struct status_qlearning * status; struct delay_params * delay; struct qlearning_params *qlearnParams; @@ -53,7 +59,7 @@ struct networks_qlearning * create_nework_qlearning( struct config_layers * config, bool randomize, float minR, float maxR, int randomRange ); -struct reward_lists * create_reward_lists (); +struct status_qlearning * create_status_qlearning (); struct delay_params * create_delay_params ( size_t delay_between_episodes, size_t delay_between_games @@ -62,19 +68,20 @@ struct delay_params * create_delay_params ( struct qlearning_params * create_qlearning_params ( double learning_rate, double discount_factor, - double exploration_factor + double exploration_factor, + long int nb_training_before_update_weight_in_target ); struct RL_agent * create_RL_agent ( struct networks_qlearning * networks, struct vehicle * car, - struct reward_lists * rewards, + struct status_qlearning * status, struct delay_params * delay, struct qlearning_params *qlearnParams ); void free_networks_qlearning (struct networks_qlearning * networks); -void free_reward_lists(struct reward_lists *rwd_l); +void free_status_qlearning(struct status_qlearning *status_ql); void free_delay_params (struct delay_params *dly_p); void free_qlearning_params(struct qlearning_params *q_params); void free_RL_agent(struct RL_agent *rlAgent); @@ -82,5 +89,10 @@ void free_RL_agent(struct RL_agent *rlAgent); void copy_weight_in_networks_from_main_to_target(struct networks_qlearning * networks); void copy_weight_in_networks_from_main_to_best(struct networks_qlearning * networks); +void train_qlearning(struct RL_agent * rlAgent, + int action , + tensor_TYPE_FLOAT * new_state /*input*/, + tensor_TYPE_FLOAT * state /*input*/, + long reward); #endif /* __LEARNING_VEHICLE__C_H____ */ diff --git a/deepQlearn_0/src/deepQlearning/vehicle.c b/deepQlearn_0/src/deepQlearning/vehicle.c index 0b44486..fa97eaa 100644 --- a/deepQlearn_0/src/deepQlearning/vehicle.c +++ b/deepQlearn_0/src/deepQlearning/vehicle.c @@ -326,7 +326,7 @@ void print2D_blocks_indexOne_withPoint(struct blocks *blk, float scale_x, float if(in) printf("%d",in); else - printf(" "); + printf("."); //printf(" "); printf("\033[0;37m"); // white } printf("\n"); @@ -478,7 +478,7 @@ void step(struct vehicle *v, int action){ status->reward = 0; status->done =false; struct blocks * path = v->path; - printf(" center : %f vs %f direction: %f\n",v->sensor->value[CENTER], LIMIT_DISTANCE, v->direction); + //printf(" center : %f vs %f direction: %f\n",v->sensor->value[CENTER], LIMIT_DISTANCE, v->direction); if( v->sensor->value[CENTER]<= LIMIT_DISTANCE ){ status->reward = REWARD_STOP; status->done = true; diff --git a/deepQlearn_0/src/deepQlearning/vehicle.h b/deepQlearn_0/src/deepQlearning/vehicle.h index 10a3377..d6d1327 100644 --- a/deepQlearn_0/src/deepQlearning/vehicle.h +++ b/deepQlearn_0/src/deepQlearning/vehicle.h @@ -16,6 +16,7 @@ #include "tools_t/tools_t.h" #include "dimension_t/dimension_t.h" +#include "tensor_t/tensor_t.h" #define LOG_LENTH 128 @@ -35,10 +36,12 @@ struct game_status { int cur_log; }; -struct coordinate { - size_t dimension_size; - float *x; -}; +//struct coordinate { +// size_t dimension_size; +// float *x; +//}; + +typedef tensor_TYPE_FLOAT coordinate; /* +-----------------------+ <-- upper_bound_block (coordinate (6,5) for example) @@ -55,32 +58,34 @@ struct coordinate { */ struct blocks { size_t nb_blocks; - struct coordinate **lower_bound_block; - struct coordinate **upper_bound_block; - struct coordinate **bounds_all_blocks; + coordinate **lower_bound_block; + coordinate **upper_bound_block; + coordinate **bounds_all_blocks; bool all_updated; - size_t dimension_size; + dimension *dim; bool *marker; //float step: // size of subdivision of the lowest large }; -struct sensors { - size_t nb_values; - float *value; -}; +//struct sensors { +// size_t nb_values; +// float *value; +// tensor_TYPE_FLOAT * sensor; +//}; +typedef tensor_TYPE_FLOAT sensors; struct vehicle { - struct coordinate *coord; + coordinate *coord; float direction; float speed; - struct sensors *sensor; + sensors *sensor; struct blocks *path; struct game_status *status; }; struct game_status * greate_game_status(); -struct coordinate * create_coordinate(size_t dim_size); +coordinate * create_coordinate(size_t dim_size); struct blocks * create_blocks(size_t nb_blocks, size_t dim_size); struct sensors * create_sensors(size_t nb_values); @@ -89,18 +94,18 @@ struct vehicle * create_vehicle( ); void free_game_status(struct game_status *status); -void free_coordinate(struct coordinate *coord); +void free_coordinate(coordinate *coord); void free_blocks(struct blocks *blk); -void free_sensors(struct sensors *snsr); +void free_sensors(sensors *snsr); void free_vehicle(struct vehicle * vhcl); void update_bounds_limits_blocks(struct blocks * blk); -int is_in_blocks(struct blocks *blk, struct coordinate *coord); +int is_in_blocks(struct blocks *blk, coordinate *coord); -void copy_coordinate(struct coordinate *coord, float *x); +void copy_coordinate(coordinate *coord, float *x); void move_vehicle(struct vehicle *v); void read_sensor(struct vehicle *v); @@ -111,9 +116,9 @@ void reset(struct vehicle *v); void print2D_blocks_indexOne_withPoint(struct blocks *blk, float scale_x, float scale_y, struct coordinate *coordPoint); void print_vehicle_n_path(struct vehicle *v, float scale_x, float scale_y); -float distance2_coordinate(struct coordinate *c0, struct coordinate *c1); +float distance2_coordinate(coordinate *c0, coordinate *c1); void print2D_blocks(struct blocks *blk, float scale_x, float scale_y, char pad); -void print2D_blocks_withPoint(struct blocks *blk, float scale_x, float scale_y, char pad, struct coordinate *coordPoint); +void print2D_blocks_withPoint(struct blocks *blk, float scale_x, float scale_y, char pad, coordinate *coordPoint); #endif /* __VEHICLE__C_H__ */ diff --git a/deepQlearn_0/test/is_good.c b/deepQlearn_0/test/is_good.c index c81183f..a9f4a61 100644 --- a/deepQlearn_0/test/is_good.c +++ b/deepQlearn_0/test/is_good.c @@ -165,7 +165,7 @@ TEST(first_vehicle){ copy_coordinate(path->upper_bound_block[0], (float[]){2,7}); copy_coordinate(path->lower_bound_block[1], (float[]){2,0}); copy_coordinate(path->upper_bound_block[1], (float[]){4,2}); - copy_coordinate(path->lower_bound_block[2], (float[]){4,1}); + copy_coordinate(path->lower_bound_block[2], (float[]){4,0.5}); copy_coordinate(path->upper_bound_block[2], (float[]){8,3}); copy_coordinate(path->lower_bound_block[3], (float[]){8,0}); copy_coordinate(path->upper_bound_block[3], (float[]){16,2}); @@ -204,7 +204,9 @@ TEST(first_vehicle){ } TEST(reward_list){ - struct reward_lists * l_reward = create_reward_lists (); + struct status_qlearning * l_reward = create_status_qlearning(); + + free_status_qlearning(l_reward); } int main(int argc, char **argv){ diff --git a/neuron_t/src/neuron_t/neuron_t.c b/neuron_t/src/neuron_t/neuron_t.c index 4c1e1df..96e6fe5 100644 --- a/neuron_t/src/neuron_t/neuron_t.c +++ b/neuron_t/src/neuron_t/neuron_t.c @@ -747,6 +747,19 @@ size_t learning_online2_neurons_##type(neurons_##type *base, data_set_##type *da return nbreps;\ }\ \ +void calculate_output_by_network_neurons_##type(neurons_##type *base, tensor_##type *input, tensor_##type **output_link){\ + for(size_t i=0; i<(input->dim)->rank; ++i) (base->output)->x[i]=input->x[i];\ + neurons_##type * tmp=base->next_layer;\ + while(tmp){\ + calc_out_neurons_##type(tmp);\ + if(tmp->next_layer==NULL){\ + /*print_tensor_msg_##type(tmp->output,"retult");*/\ + *output_link = tmp->output;\ + }\ + tmp = tmp->next_layer;\ + }\ +\ +}\ void print_predict_by_network_neurons_##type(neurons_##type *base, tensor_##type *input){\ for(size_t i=0; i<(input->dim)->rank; ++i) (base->output)->x[i]=input->x[i];\ neurons_##type * tmp=base->next_layer;\ diff --git a/neuron_t/src/neuron_t/neuron_t.h b/neuron_t/src/neuron_t/neuron_t.h index 8a7f268..5b7b3ac 100644 --- a/neuron_t/src/neuron_t/neuron_t.h +++ b/neuron_t/src/neuron_t/neuron_t.h @@ -106,7 +106,7 @@ void print_data_set_msg_##type(data_set_##type *ds, char *msg);\ \ size_t learning_online_neurons_##type(neurons_##type *base, data_set_##type *dataset, bool (*condition)(type, size_t));\ size_t learning_online2_neurons_##type(neurons_##type *base, data_set_##type *dataset, bool (*condition)(type, size_t));\ -\ +void calculate_output_by_network_neurons_##type(neurons_##type *base, tensor_##type *input, tensor_##type **output_link);\ void print_predict_by_network_neurons_##type(neurons_##type *base, tensor_##type *input);\ void print_predict_by_network_with_error_neurons_##type(neurons_##type *base, tensor_##type *input, tensor_##type *target);\ \ diff --git a/neuron_t/test/is_good.c b/neuron_t/test/is_good.c index a9a43eb..4bfd506 100644 --- a/neuron_t/test/is_good.c +++ b/neuron_t/test/is_good.c @@ -21,6 +21,7 @@ #define VALGRIND_ 1 + float L(float t, float o){ return (o - t) * (o - t)/2; } @@ -356,13 +357,30 @@ TEST(copy_weight_in_neurons){ size_t reps = learning_online2_neurons_TYPE_FLOAT(bn,ds,cond); + setup_all_layers_functions_TYPE_FLOAT(cpyn, + tensorContractnProdThread_TYPE_FLOAT, + tensorProdThread_TYPE_FLOAT, + DL, + L, + f, + df); + + setup_all_layers_params_TYPE_FLOAT(cpyn, 5, 1 , 0.1); + + copy_weight_in_neurons_TYPE_FLOAT(cpyn, bn); char msg[256]; + tensor_TYPE_FLOAT * linked_tens = NULL; for(size_t i=0; isize; ++i){ - print_predict_by_network_with_error_neurons_TYPE_FLOAT(bn,ds->input[i],ds->target[i]); - print_predict_by_network_with_error_neurons_TYPE_FLOAT(cpyn,ds->input[i],ds->target[i]); - +// print_predict_by_network_with_error_neurons_TYPE_FLOAT(bn,ds->input[i],ds->target[i]); + // print_predict_by_network_with_error_neurons_TYPE_FLOAT(cpyn,ds->input[i],ds->target[i]); + calculate_output_by_network_neurons_TYPE_FLOAT(bn,ds->input[i],&linked_tens); + sprintf(msg," output base %ld ",i); + print_tensor_msg_TYPE_FLOAT(linked_tens,msg); + calculate_output_by_network_neurons_TYPE_FLOAT(cpyn,ds->input[i],&linked_tens); + sprintf(msg," output copy %ld ",i); + print_tensor_msg_TYPE_FLOAT(linked_tens,msg); } diff --git a/tensor_t/src/tensor_t/tensor_t.c b/tensor_t/src/tensor_t/tensor_t.c index 71068e1..604e61c 100644 --- a/tensor_t/src/tensor_t/tensor_t.c +++ b/tensor_t/src/tensor_t/tensor_t.c @@ -130,11 +130,16 @@ tensor_##type* CLONE_TENSOR_##type(tensor_##type *tens){\ return NULL;\ }\ \ -void copy_tensor_##type(tensor_##type * dst, tensor_##type * src){\ - if(dst!=NULL && src!=NULL && dst->dim->rank == src->dim->rank){ \ - for(size_t i=0; i<(dst->dim)->rank;++i)\ - dst->x[i]=src->x[i];\ - }\ +int copy_tensor_##type(tensor_##type * dst, tensor_##type * src){\ + if(dst!=NULL && src!=NULL){ \ + int diff = dst->dim->rank - src->dim->rank;\ + if(diff == 0) \ + for(size_t i=0; i<(src->dim)->rank;++i)\ + dst->x[i]=src->x[i];\ + return diff;\ + \ + }\ + return -1;\ }\ \ void free_tensor_##type(tensor_##type * tens){\ diff --git a/tensor_t/test/is_good.c b/tensor_t/test/is_good.c index 4164665..792d5ae 100644 --- a/tensor_t/test/is_good.c +++ b/tensor_t/test/is_good.c @@ -1705,6 +1705,58 @@ TEST(copy_tensor){ } +TEST(tensorContractnProd_TYPE_DOUBLE_2_2 ){ + dimension *d0=create_dim(3); + dimension *d1=create_dim(3); +#if VALGRIND_ + d0->perm[0]=1; + d0->perm[1]=2; //3; + d0->perm[2]=3; //3; + + d1->perm[0]=2; + d1->perm[1]=3; //3; + d1->perm[2]=1; //3; + +#else + + d0->perm[0]=1; + d0->perm[1]=22; //3; + d0->perm[2]=52; //3; + d1->perm[0]=52; + d1->perm[1]=22; //3; + d1->perm[2]=1; //3; + +#endif + + updateRankDim(d0); + updateRankDim(d1); + + + tensor_TYPE_DOUBLE *M0 = CREATE_TENSOR_TYPE_DOUBLE(d0); + tensor_TYPE_DOUBLE *M1 = CREATE_TENSOR_TYPE_DOUBLE(d1); + + for(size_t i=0; idim->rank;++i) M0->x[i]=2 ; + for(size_t i=0; idim->rank;++i) M1->x[i]=3; + + print_tensor_double(M0,"M0"); + print_tensor_double(M1,"M1"); + + tensor_TYPE_DOUBLE *M=NULL; + + tensorContractnProd_TYPE_DOUBLE(&M, M0,M1,2); + + print_tensor_double(M,"M"); + + // for(size_t i=0;idim->rank;++i) + // EXPECT_EQ_TYPE_DOUBLE(M->x[i],MnO->x[i]); + + + free_tensor_TYPE_DOUBLE(M); + free_tensor_TYPE_DOUBLE(M0); + free_tensor_TYPE_DOUBLE(M1); + +} + diff --git a/ytest_t/libytest.so b/ytest_t/libytest.so index 1b54d93b05b4514cd0b4ebf014199404e797e2bf..499526018e139f4513d24effddf718173732fb33 100644 GIT binary patch delta 21324 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 a2D|)utd&;IBcCs=o$>eJ1HQDr^uGXbRdzA} delta 19280 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 AumAu6 diff --git a/ytools_t/src/tools_t/tools_t.c b/ytools_t/src/tools_t/tools_t.c index 6c8a59a..879dc82 100644 --- a/ytools_t/src/tools_t/tools_t.c +++ b/ytools_t/src/tools_t/tools_t.c @@ -115,14 +115,29 @@ long int PRECISION_TYPE_L_DOUBLE = 100000000000000; #define GENERATE_FUNCTION_NUMERIC(type)\ int COMPARE_N_##type(const void *a, const void *b){ \ - type diff = (*(type*)a - *(type*)b) * PRECISION_##type; \ + type diff = 0;\ + if((*(type*)a > *(type*)b)){ \ + diff =(*(type*)a - *(type*)b) * PRECISION_##type; \ + /*char *str_diff = type##_TO_STR(diff), *str_a = type##_TO_STR(*(type*)a), *str_b = type##_TO_STR(*(type*)b);\ + PRINT_DEBUG_(" diff = %s a=%s b=%s PRECISION : %ld\n",str_diff, str_a, str_b, PRECISION_##type);\ + free(str_diff); free(str_a); free(str_b);\ + */ \ + if(diff >= 1) return 1;\ + return 0;\ + }else{\ + diff =(*(type*)b - *(type*)a) * PRECISION_##type; \ /*char *str_diff = type##_TO_STR(diff), *str_a = type##_TO_STR(*(type*)a), *str_b = type##_TO_STR(*(type*)b);\ PRINT_DEBUG_(" diff = %s a=%s b=%s PRECISION : %ld\n",str_diff, str_a, str_b, PRECISION_##type);\ free(str_diff); free(str_a); free(str_b);\ */\ - if (diff <= -1) return -1; \ + if(diff >= 1) return -1;\ + return 0;\ + }\ + \ + /*if (diff <= -1) return -1; \ if (diff >= 1) return 1; \ return 0; \ + */\ } \ \ void COPY_ARRAY_##type(type *dst, const type *src, size_t size){ \