Created
June 27, 2019 21:25
-
-
Save pxpc2/c8a9115f9d6bccfc96119a4f746bff53 to your computer and use it in GitHub Desktop.
oi
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <math.h> | |
#include <time.h> | |
#include "glcm.h" | |
#define MAX 1025*1025 | |
/** | |
* código do PROJETO 2, nada foi alterado. | |
* Basta incluir o header deste .c na main do PROJETO 6 | |
* Lá chamamos o getFeaturesImg e o gerarNumerosAleatorio | |
*/ | |
void exec() | |
{ | |
int* nums = gerarNumerosAleatorio(); | |
double* media_grass = (double *) calloc(536, sizeof(double)); | |
double* media_asphalt = (double *) calloc(536, sizeof(double)); | |
double* features_grass = (double *) calloc(536, sizeof(double)); | |
double* features_asphalt = (double *) calloc(536, sizeof(double)); | |
// TREINAMENTO | |
for (int i = 0; i < 25; i++) | |
{ | |
features_grass = getFeaturesImg(nums[i], 0); | |
features_asphalt = getFeaturesImg(nums[i], 1); | |
for (int j = 0; j < 536; j++) | |
{ | |
*(media_grass + j) += (*(features_grass + j) / 25.0); | |
*(media_asphalt + j) += (*(features_asphalt + j) / 25.0); | |
} | |
} | |
double taxa_acerto = 0.0, taxa_Faceitacao = 0.0, taxa_Frejeicao = 0.0; | |
// TESTE | |
for (int i = 25; i < 50; i++) | |
{ | |
features_grass = getFeaturesImg(*(nums + i), 0); | |
features_asphalt = getFeaturesImg(*(nums + i), 1); | |
/* // comparar com as médias calculadas no treinamento | |
int dist_grass = compararImagem(media_grass, media_asphalt, features_grass); | |
if (dist_grass == 1) taxa_acerto++; | |
else if (dist_grass == 0) taxa_Frejeicao++; | |
int dist_asphalt = compararImagem(media_grass, media_asphalt, features_asphalt); | |
if (dist_asphalt == 1) taxa_Faceitacao++; | |
else if (dist_asphalt == 0) taxa_acerto++; */ | |
} | |
free(features_grass); | |
free(features_asphalt); | |
free(media_grass); | |
free(media_asphalt); | |
free(nums); | |
/* double acerto = (double) (taxa_acerto / 50.0) * 100.0; | |
double f_aceitacao = (double) (taxa_Faceitacao / 50.0) * 100.0; | |
double f_rejeicao = (double) (taxa_Frejeicao / 50.0) * 100.0; | |
printf("TAXA DE ACERTO = %.1lf%%\n", acerto); | |
printf("TAXA DE FALSA ACEITAÇÃO = %.1lf%%\n", f_aceitacao); | |
printf("TAXA DE FALSA REJEIÇÃO = %.1lf%%\n", f_rejeicao);*/ | |
} | |
/** | |
type 0 = grass | |
type 1 = asphalt | |
*/ | |
int* getMatriz(int num, int type) | |
{ | |
char rota[40] = {}; | |
if (type == 1) | |
sprintf(rota, "%s%02d%s", "DataSet/grass/grass_", num, ".txt"); | |
else if (type == 0) | |
sprintf(rota, "%s%02d%s", "DataSet/asphalt/asphalt_", num, ".txt"); | |
FILE *arq; | |
arq = fopen(rota, "r"); // r = somente leitura | |
if (arq == NULL) | |
{ | |
printf("Deu ruim\n"); | |
return NULL; | |
} | |
char texto[1025*4]; | |
int i = 0, j = 0; | |
int* matriz = (int *) calloc(2000*2000, sizeof(int)); | |
int count = 0; | |
while (fgets(texto, 1025*4, arq) != NULL) | |
{ | |
j = 0; | |
const char remover[2] = ";"; | |
char *token; | |
token = strtok(texto, remover); | |
int pixel = atoi(token); | |
matriz[i * 1025 + j] = pixel; | |
count++; | |
while (token != NULL) | |
{ | |
token = strtok(NULL, remover); | |
if (token == NULL) continue; | |
j++; | |
pixel = atoi(token); | |
matriz[i * 1025 + j] = pixel; | |
count++; | |
} | |
i++; | |
} | |
fclose(arq); | |
return matriz; | |
} | |
int* getVetorILBP(int* matriz) | |
{ | |
const int size = 1025; // tamanho da matriz do arquivo | |
int* vetorILBP = (int *) calloc(512, sizeof(int)); | |
for(int s = 0; s < size*size; s++) // a ideia é passar por todos os pixels e pegar seus vizinhos | |
{ | |
int mat[3][3] = {}; | |
int soma = 0; | |
int matBin[3][3]={}; | |
double media = 0.0; | |
int x_pixel, y_pixel; // posicao do pixel atual na matriz | |
if (s < size) | |
{ | |
x_pixel = 0; | |
y_pixel = s; | |
} | |
else | |
{ | |
x_pixel = s / size; | |
y_pixel = s % size; | |
} | |
if (x_pixel == 0 || y_pixel == 0 || x_pixel == 1024 || y_pixel == 1024) | |
continue; // não queremos trabalhar com os pixels das bordas | |
// cálculo dos vizinhos do pixel atual, jogando em mat[x][y] 3x3 | |
for (int i = -1; i < 2; i++) | |
{ | |
for (int j = -1; j < 2; j++) | |
{ | |
int dx,dy; | |
dx = x_pixel + i, dy = y_pixel + j; | |
mat[i+1][j+1] = *(matriz + dx * 1025 + dy); | |
soma += mat[i+1][j+1]; | |
} | |
} | |
int palavraBin[9]; | |
media = (double) soma / 9.0; | |
int d = 0; | |
for (int i = 0; i < 3; i++) | |
{ | |
for (int j = 0; j < 3; j++) | |
{ | |
if (mat[i][j] < media) | |
matBin[i][j] = 0; | |
else | |
matBin[i][j] = 1; | |
palavraBin[d] = matBin[i][j]; | |
d++; | |
} | |
} | |
// pegar o menor valor das rotações da palavra binária, o código ILBP | |
int menor = 9999999, j = 9; | |
int aux[9]; | |
while (j--) | |
{ | |
// 9 rotações possíveis | |
for (int i = 0; i < 9; i++) | |
{ | |
int auxx = palavraBin[i]; | |
if (i == 0) | |
aux[i] = palavraBin[8]; | |
else | |
aux[i] = palavraBin[i-1]; | |
if (i == 8) | |
aux[0] = auxx; | |
else | |
aux[i+1] = auxx; | |
} | |
// calcular valor decimal | |
int decimal = 0; | |
for (int i = 0; i < 9; i++) | |
decimal += aux[i] * pow(2, 8-i); | |
for (int i =0; i < 9; i++) | |
palavraBin[i] = aux[i]; | |
if (decimal < menor) menor = decimal; | |
} | |
*(vetorILBP + menor) += 1; // faz a contabilidade do vetor ILBP | |
} | |
return vetorILBP; | |
} | |
int repete(int* vetor, int num) | |
{ | |
for (int i = 0; i < 50; i++) | |
if (vetor[i] == num) | |
return 1; | |
return 0; | |
} | |
/** | |
Gerar 25 números aleatórios e preencher o resto com o que falta, pra | |
compor os conjuntos TESTE e TREINAMENTO | |
*/ | |
int* gerarNumerosAleatorio() | |
{ | |
int* nums = (int*) calloc(50, sizeof(int)); | |
srand(time(0)); | |
for (int i = 0; i < 25; i++) | |
{ | |
int n = rand() % 50 + 1; | |
if (repete(nums, n) == 1) | |
{ | |
i--; // repetir essa iteração | |
continue; | |
} | |
*(nums + i) = n; | |
} | |
int j = 25; | |
for (int i = 1; i <= 50; i++) | |
{ | |
if (repete(nums, i) == 1) continue; | |
nums[j] = i; | |
j++; | |
} | |
return nums; | |
} | |
/** | |
(dx, dy) | |
(0, 0) = pixel inicial | |
(0, 1) = acima | |
(0, -1) = abaixo | |
(1, 0) = direita | |
(1, 1) = diagonal direita cima | |
(1, -1) = diagonal direita baixo | |
(-1, 0) = esquerda | |
(-1, 1) = diagonal esquerda cima | |
(-1, -1) = diagonal esquerda baixo | |
*/ | |
double* getMatrizGLCM(int* matriz, int dx, int dy) | |
{ | |
double* glcm = (double *) calloc(256*256, sizeof(double)); | |
int size = 1025, x1, y1, x2, y2; | |
for (int s = 0; s < size*size; s++) // passar por todos os pixels | |
{ | |
if (s < size) | |
{ | |
x1 = 0; | |
y1 = s; | |
} | |
else | |
{ | |
x1 = s / size; | |
y1 = s % size; | |
} | |
x2 = x1 + dx; | |
y2 = y1 + dy; | |
if (x2 < 0 || y2 < 0 || x2 > 1024 || y2 > 1024) | |
continue; // pular esta iteração pois não há pixel nessa direção | |
int indice1 = matriz[x1 * 1025 + y1]; | |
int indice2 = matriz[x2 * 1025 + y2]; | |
*(glcm + (indice1 * 256) + indice2) += 1; | |
} | |
return glcm; | |
} | |
double* getMetricas(double* glcm, int* matriz, int dx, int dy) | |
{ | |
double contraste = 0.0, homog = 0.0, energia = 0.0; | |
double* metricas = (double *) calloc(3, sizeof(double)); | |
int size = 1025, x1, y1, x2, y2; | |
for (int s = 0; s < size*size; s++) // passar por todos os pixels | |
{ | |
if (s < size) | |
{ | |
x1 = 0; | |
y1 = s; | |
} | |
else | |
{ | |
x1 = s / size; | |
y1 = s % size; | |
} | |
x2 = x1 + dx; | |
y2 = y1 + dy; | |
if (x2 < 0 || y2 < 0 || x2 > 1024 || y2 > 1024) | |
continue; // pular esta iteração pois não há pixel nessa direção | |
int indice1 = *(matriz + x1 * 1025 + y1); | |
int indice2 = *(matriz + x2 * 1025 + y2); | |
double prob_glcm = (double) glcm[indice1*256 + indice2] / (1025*1025); | |
//printf("PROB = %lf\n", prob_glcm); | |
int mod = abs(indice1-indice2); | |
contraste += prob_glcm * pow(mod, 2); | |
homog += prob_glcm / (1 + mod); | |
energia += pow(prob_glcm, 2); | |
} | |
*(metricas + 0) = contraste; | |
*(metricas + 1) = homog; | |
*(metricas + 2) = energia; | |
return metricas; | |
} | |
double* getFeaturesImg(int num, int type) | |
{ | |
double* features = (double *) calloc(536, sizeof(double)); | |
int* matriz; | |
int* ilbp; | |
double* glcm[8]; | |
// Pegar a matriz da imagem atual | |
matriz = getMatriz(num, type); | |
// Realizar o ILBP da imagem atual | |
ilbp = getVetorILBP(matriz); // vetor de 512 posições | |
// Pegar os 8 GLCMs da imagem atual | |
// Cada métrica pra cada uma das 8 GLCMs | |
double* contraste = (double *) calloc(8, sizeof(double)); | |
double* homog = (double *) calloc(8, sizeof(double)); | |
double* energia = (double *) calloc(8, sizeof(double)); | |
int cont = 0; | |
for (int i = -1; i < 2; i++) | |
{ | |
for (int j = -1; j < 2; j++) | |
{ | |
if (i == 0 && j == 0) continue; // não precisa fazer GLCM pro próprio pixel atual | |
// faz o GLCM da direção atual i,j | |
glcm[cont] = getMatrizGLCM(matriz, i, j); | |
double* metricas = getMetricas(glcm[cont], matriz, i, j); | |
*(contraste + cont) = *(metricas + 0); | |
*(homog + cont) = *(metricas + 1); | |
*(energia + cont) = *(metricas + 2); | |
cont++; | |
} | |
} | |
int i = 0; | |
for (i = 0; i < 512; i++) | |
*(features + i) = (double) *(ilbp + i); | |
for (i = 512; i < 520; i++) | |
*(features + i) = (double) *(contraste + (i-512)); | |
for (i = 520; i < 528; i++) | |
*(features + i) = (double) *(homog + (i-520)); | |
for (i = 528; i < 536; i++) | |
{ | |
*(features + i) = (double) *(energia + (i - 528)); | |
// printf("ENERGIA=%lf\n", (double) *(energia + (i - 528))); | |
} | |
normalizar(features); | |
return features; | |
} | |
void normalizar(double* vetor) | |
{ | |
int maior = 0, menor = 9999999; | |
for (int i = 0; i < 536; i++) | |
{ | |
double element = *(vetor + i); | |
if (element == 0.0) continue; | |
if (element < menor) | |
menor = element; | |
if (element > maior) | |
maior = element; | |
} | |
for (int i = 0; i < 536; i++) | |
{ | |
double element = *(vetor + i); | |
*(vetor + i) = (double) (element - menor) / (maior - menor); | |
} | |
} | |
/** | |
* return 1 -> parece mais com grama | |
* return 0 -> parece mais com asfalto | |
*/ | |
int compararImagem(double* media_grass, double* media_asphalt, double* vetor) | |
{ | |
int result_grass = 0, result_asphalt = 0; | |
for (int i = 0; i < 536; i++) | |
{ | |
result_grass += pow(*(vetor + i) - *(media_grass + i), 2); | |
result_asphalt += pow(*(vetor + i) - *(media_asphalt + i), 2); | |
} | |
result_grass = sqrt(result_grass); | |
result_asphalt = sqrt(result_asphalt); | |
return (result_grass < result_asphalt) ? 1 : 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
int* getMatriz(int, int); | |
int* getVetorILBP(int*); | |
int repete(int*, int); | |
int* gerarNumerosAleatorio(); | |
double* getMatrizGLCM(int*, int, int); | |
double* getMetricas(double*, int*, int, int); | |
double* getFeaturesImg(int, int); | |
void normalizar(double*); | |
/** | |
* código do PROJETO 2, nada foi alterado. | |
* Basta incluir este header e seu .c na main do PROJETO 6 | |
* Lá chamamos o getFeaturesImg e o gerarNumerosAleatorio | |
*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <math.h> | |
#include <time.h> | |
#include "rede.h" | |
#include "glcm.h" | |
int main(int argc, char* argv[]) | |
{ | |
// gera os 50 numeros das imagens, onde os 25 primeiros sao pro treinamento e os ultimos pro teste. | |
int* nums = gerarNumerosAleatorio(); | |
// pega o valor definido pra qt de neuronios em runtime, se nada for definido o padrao serão 10 neuronios | |
int qt_oculta = (argc < 2? 10 : atoi(argv[1])); | |
// inicializa as camadas e seus neuronios | |
initRede(qt_oculta); | |
srand(time(NULL)); | |
double taxa_acerto = 0.0, taxa_falsa_rejeicao = 0.0, taxa_falsa_aceitacao = 0.0; | |
printf("Calculando...\n"); | |
int epoca = 0; | |
while (epoca < 1000) | |
{ | |
printf("Iniciando epoca #%d\n", epoca+1); | |
epoca++; | |
double mse = 0.0; | |
for (int i = 0; i < 25; i++) // conjunto treinamento | |
{ | |
int type = rand() % 2; // aleatoriamente escolhe se vai ser grass ou asphalt | |
if (type % 2) | |
type = 1; | |
else | |
type = 0; | |
double *feature = getFeaturesImg(nums[i], type); // 1 = grass, 0 = asphalt | |
double output_saida = feedForward(feature); | |
mse += pow(type - output_saida, 2); | |
backPropagate(type); // faz os ajustes dos pesos e biases | |
printf("...\n"); | |
} | |
printf("Fim epoca\n"); | |
mse /= 25; | |
if (mse < 0.2) | |
break; | |
} | |
printf("Iniciando o teste\n"); | |
for (int i = 25; i < 50; i++) // TESTE | |
{ | |
int type = rand() % 2; // aleatoriamente escolhe se vai ser grass ou asphalt | |
if (type % 2) | |
type = 1; | |
else | |
type = 0; | |
double *feature = getFeaturesImg(nums[i], type); // 1 = grass, 0 = asphalt | |
double output_saida = feedForward(feature); | |
if ((output_saida > 0.5 && type == 1) || (output_saida < 0.5 && type == 0)) | |
taxa_acerto++; | |
else if (output_saida > 0.5 && type == 0) | |
taxa_falsa_aceitacao++; | |
else if (output_saida < 0.5 && type == 1) | |
taxa_falsa_rejeicao++; | |
} | |
freeTodos(); // libera todos os ponteiros alocados da memoria | |
printf("Taxa acerto = %.1lf%%\n", (taxa_acerto / 25.0) * 100.0); | |
printf("Taxa falsa aceitacao = %.1lf%%\n", (taxa_falsa_aceitacao / 25.0) * 100.0); | |
printf("Taxa falsa rejeicao = %.1lf%%\n", (taxa_falsa_rejeicao / 25.0) * 100.0); | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <math.h> | |
#include "rede.h" | |
#define QT_ENTRADA 536 // quantidade de neurônios na camada entrada | |
#define LEARNING_RATE 0.3 // definida aleatoriamente | |
Rede* rede; | |
/** | |
* Aloca memoria e inicializa as camadas e seus respectivos neuronios, | |
* atribuindo já os pesos e bias aleatorios pras entradas dos neuronios. | |
* | |
* @param qt_oculta quantidade de neuronios na camada oculta (definida runtime) | |
*/ | |
void initRede(int qt_oculta) | |
{ | |
rede = (Rede*) malloc(sizeof(Rede)); | |
rede->entrada = (Camada*) malloc(sizeof(Camada)); | |
rede->entrada->neuronios = (Neuronio**) malloc(sizeof(Neuronio*) * QT_ENTRADA); | |
rede->entrada->qt_neuronios = QT_ENTRADA; | |
rede->entrada->qt_entradas = QT_ENTRADA; | |
rede->entrada->def = 0; | |
rede->entrada->sinal_saida = (double*) malloc(sizeof(double) * QT_ENTRADA); | |
initNeuronios(rede->entrada, qt_oculta); | |
rede->oculta = (Camada*) malloc(sizeof(Camada)); | |
rede->oculta->neuronios = (Neuronio**) malloc(sizeof(Neuronio*) * qt_oculta); | |
rede->oculta->qt_neuronios = qt_oculta; | |
rede->oculta->qt_entradas = QT_ENTRADA; | |
rede->oculta->def = 1; | |
rede->oculta->sinal_saida = (double*) malloc(sizeof(double) * qt_oculta); | |
initNeuronios(rede->oculta, qt_oculta); | |
rede->saida = (Camada*) malloc(sizeof(Camada)); | |
rede->saida->neuronios = (Neuronio**) malloc(sizeof(Neuronio*)); | |
rede->saida->qt_neuronios = 1; | |
rede->saida->def = 2; | |
rede->saida->qt_entradas = qt_oculta; | |
rede->saida->sinal_saida = (double*) malloc(sizeof(double) * 1); | |
initNeuronios(rede->saida, qt_oculta); | |
} | |
/** | |
* | |
* Inicializa os neuronios | |
* | |
* @param camada camada da qual inicializar os neuronios | |
* @param qt_oculta quantidade de neuronios na camada oculta da rede | |
*/ | |
void initNeuronios(Camada* camada, int qt_oculta) | |
{ | |
if (camada == NULL) | |
return; | |
for (int i = 0; i < camada->qt_neuronios; i++) | |
{ | |
// trocamos a seed a cada iteração pra não repetir os mesmos pesos e bias | |
srand(i); | |
double* pesos = gerarPesos(camada->qt_entradas); | |
camada->neuronios[i] = (Neuronio*) malloc(sizeof(Neuronio)); | |
// se for da camada oculta ou entrada, teremos 536 pesos e 536 entradas | |
// se for da camada saída, teremos "qt_oculta" pesos e entradas | |
int size = (camada->qt_neuronios == 1? qt_oculta : QT_ENTRADA); | |
camada->neuronios[i]->p = (double*) malloc(sizeof(double) * size); | |
camada->neuronios[i]->w = (double*) malloc(sizeof(double) * size); | |
camada->neuronios[i]->p_length = size; | |
for (int j = 0; j < camada->qt_entradas; j++) | |
camada->neuronios[i]->w[j] = pesos[j]; | |
camada->neuronios[i]->b = gerarBias(); | |
} | |
} | |
/** | |
* Gera um vetor de pesos aleatorios | |
* @param quantidade quantidade de pesos pra gerar (igual a quantidade de entradas que neuronio recebe) | |
* @return vetor de pesos gerados | |
*/ | |
double* gerarPesos(int quantidade) | |
{ | |
double* pesos = (double*) malloc(sizeof(double) * quantidade); | |
for (int i = 0; i < quantidade; i++) | |
{ | |
pesos[i] = rand() % 15000 + 1; | |
} | |
return pesos; | |
} | |
/** | |
* Gera um escalar aleatorio, bias. | |
* @return o bias | |
*/ | |
double gerarBias() | |
{ | |
return rand() % 15000 + 1; | |
} | |
/** | |
* Calcula o somatorio do produto dos pesos pelas entradas, e adiciona o bias | |
* @param n neuronio pra calcular o somatorio dele | |
* @return o valor que vai na funcao logistica | |
*/ | |
double getSomatorio(Neuronio* n) | |
{ | |
double sum = 0.0; | |
if (n == NULL) | |
return -1; | |
for (int i = 0; i < n->p_length; i++) | |
sum += (n->p[i]*n->w[i]); | |
return (n->b + sum); | |
} | |
/** | |
* Aplica a funcao logistica ao somatorio | |
* @param somatorio somatorio do produto dos pesos pelas entradas e o bias | |
* @return resultado da funcao logistica (sigmoid) | |
*/ | |
double funcaoLogistica(double somatorio) | |
{ | |
return 1 / (1 + exp(-somatorio)); | |
} | |
/** | |
* Aplica a derivada da função sigmoide | |
* @param input entrada | |
* @return resultado da função sigmoide derivada pra este input | |
*/ | |
double derivadaSigmoide(double input) | |
{ | |
double r = funcaoLogistica(input); | |
return (r * (1 - r)); | |
} | |
/** | |
* Aplica o processo de feedforward com os inputs especificados | |
* @param input entrada pro feedforward | |
* @return saída gerada pela rede após propagar pelas camadas | |
*/ | |
double feedForward(double* input) | |
{ | |
double* output_entrada = feed(rede->entrada, input); | |
double* output_oculta = feed(rede->oculta, output_entrada); | |
return feed(rede->saida, output_oculta)[0]; | |
} | |
/** | |
* Faz o processo de feedforward pra camada utilizando as features de entrada | |
* @param camada ponteiro pra camada a qual fazer o processo | |
* @param features entrada do feedforward | |
* @return o vetor de saída do feedforward dado a entrada, pra esta camada | |
*/ | |
double* feed(Camada* camada, double* features) | |
{ | |
double* out = (double*) malloc(sizeof(double) * camada->qt_neuronios); | |
if (features == NULL) | |
return NULL; | |
for (int i = 0; i < camada->qt_neuronios; i++) | |
{ | |
// para cada neuronio desta camada | |
for (int j = 0; j < camada->qt_entradas; j++) | |
{ | |
// para cada entrada deste neuronio, atribuimos ela a feature | |
camada->neuronios[i]->p[j] = features[j]; | |
} | |
double somatorio = getSomatorio(camada->neuronios[i]); | |
double logistic = funcaoLogistica(somatorio); | |
camada->neuronios[i]->s = logistic; | |
out[i] = logistic; | |
} | |
camada->sinal_saida = out; | |
return out; | |
} | |
/** | |
* Realiza o cálculo do custo, somatorio do resultado (esperado - saída)^2 pra cada | |
* neuronio de cada camada, e seta os erros pra cada neuronio | |
* @param expected resultado esperado | |
*/ | |
void setCusto(int expected) | |
{ | |
double custo = 0.0, error; | |
for (int i = 0; i < rede->entrada->qt_neuronios; i++) | |
{ | |
error = expected - rede->entrada->neuronios[i]->s; | |
rede->entrada->neuronios[i]->erro = error; | |
custo += pow(error, 2); | |
} | |
for (int i = 0; i < rede->oculta->qt_neuronios; i++) | |
{ | |
error = expected - rede->oculta->neuronios[i]->s; | |
rede->oculta->neuronios[i]->erro = error; | |
custo += pow(error, 2); | |
} | |
error = expected - rede->saida->neuronios[0]->s; | |
rede->saida->neuronios[0]->erro = error; | |
custo += pow(error, 2); | |
rede->custo = custo; | |
} | |
/** | |
* Realiza o cálculo dos gradientes de acordo com o referêncial bibliográfico | |
* Como o gradiente de cada neuronio da camada oculta depende dos gradientes da saída | |
* utilizamos recurssão | |
* @param c camada pra calcular os gradientes | |
* @return vetor de gradientes da camada c | |
*/ | |
double* getGradiente(Camada* c) | |
{ | |
double* gradientes = (double*) malloc(sizeof(double) * c->qt_neuronios); | |
if (c->def == 1 || c->def == 0) | |
{ | |
for (int i = 0; i < c->qt_neuronios; i++) | |
{ | |
// usamos recurssividade pra calcular os gradientes da camada oculta | |
for (int j = 0; j < (c->def == 1? rede->saida->qt_neuronios : rede->oculta->qt_neuronios); j++) | |
gradientes[i] += getGradiente((c->def == 1? rede->saida : rede->oculta))[j]* | |
c->def == 1? rede->saida->neuronios[j]->s : rede->oculta->neuronios[j]->w[j]; | |
gradientes[i] *= derivadaSigmoide(c->neuronios[i]->s); | |
c->neuronios[i]->gradiente = gradientes[i]; | |
} | |
} | |
else if (c->def == 2) | |
{ | |
for (int i = 0; i < c->qt_neuronios; i++) | |
{ | |
gradientes[i] = derivadaSigmoide(c->neuronios[i]->s) * c->neuronios[i]->erro; | |
rede->saida->neuronios[i]->gradiente = gradientes[i]; | |
} | |
return gradientes; | |
} | |
return gradientes; | |
} | |
void setGradientes() | |
{ | |
getGradiente(rede->entrada); | |
getGradiente(rede->oculta); | |
getGradiente(rede->saida); | |
} | |
/** | |
* Realiza o ajuste dos pesos após realizar o calculo dos gradientes | |
* @param camada camada dos pesos pra ajustar | |
*/ | |
void ajustarPesos(Camada* camada) | |
{ | |
if (camada->def == 0) | |
return; // não fazemos operações com a camada de entrada | |
for (int i = 0; i < camada->qt_neuronios; i++) | |
{ | |
for (int j = 0; j < camada->neuronios[i]->p_length; j++) | |
{ | |
double saida_anterior = 0.0; | |
if (camada->def == 1) | |
saida_anterior = rede->entrada->neuronios[j]->s; | |
else if (camada->def == 2) | |
saida_anterior = rede->oculta->neuronios[j]->s; | |
camada->neuronios[i]->w[j] = (camada->neuronios[i]->w[j]) + | |
(LEARNING_RATE * saida_anterior * camada->neuronios[i]->gradiente); | |
} | |
} | |
} | |
/** | |
* Realiza o ajuste do bias de cada neuronio | |
* @param camada camada pra ajustar | |
*/ | |
void ajustarBias(Camada* camada) | |
{ | |
if (camada->def == 0) | |
return; // não fazemos com a entrada | |
for (int i = 0; i < camada->qt_neuronios; i++) | |
camada->neuronios[i]->b = camada->neuronios[i]->b + (LEARNING_RATE * camada->neuronios[i]->gradiente); | |
} | |
void backPropagate(int type) | |
{ | |
setCusto(type); | |
setGradientes(); | |
ajustarPesos(rede->oculta); | |
ajustarPesos(rede->saida); | |
ajustarBias(rede->oculta); | |
ajustarBias(rede->saida); | |
} | |
/** | |
* Libera da memoria os neuronios da camada | |
* @param c camada pra liberar os seus neuronios | |
*/ | |
void freeNeuronios(Camada* c) | |
{ | |
for (int i = 0; i < c->qt_neuronios; i++) | |
{ | |
free(c->neuronios[i]->p); | |
free(c->neuronios[i]->w); | |
free(c->neuronios[i]); | |
} | |
free(c->neuronios); | |
} | |
/** | |
* Libera todos os ponteiros alocados dinamicamente na memoria | |
*/ | |
void freeTodos() | |
{ | |
freeNeuronios(rede->entrada); | |
freeNeuronios(rede->oculta); | |
freeNeuronios(rede->saida); | |
free(rede->entrada->sinal_saida); | |
free(rede->oculta->sinal_saida); | |
free(rede->saida->sinal_saida); | |
free(rede->entrada); | |
free(rede->oculta); | |
free(rede->saida); | |
free(rede); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
typedef struct neuronio | |
{ | |
double* p; // conjunto de entradas deste neuronio | |
double* w; // conjunto de pesos deste neuronio | |
double b; // bias deste neuronio | |
double s; // saida deste neuronio | |
int p_length; // quantidade de entradas | |
double erro; // erro para propagar deste neuronio | |
double gradiente; // gradiente deste neuronio para o backpropagation | |
} Neuronio; | |
typedef struct camada | |
{ | |
int def; | |
Neuronio** neuronios; // conjunto de ponteiros dos neuronios dessa camada | |
int qt_neuronios; // quantidade de neuronios presente na camada | |
int qt_entradas; // quantidade de entradas por neuronio da camada | |
double* sinal_saida; | |
} Camada; | |
typedef struct rede | |
{ | |
Camada* entrada; // primeira camada da rede, com 536 neuronios | |
Camada* oculta; // camada oculta, quantidade de neuronios definida runtime | |
Camada* saida; // ultima camada, com somente 1 neuronio | |
double custo; // custo da rede com pesos e bias atuais | |
} Rede; | |
// inicializa a rede e suas camadas | |
void initRede(int); | |
// inicializa cada neuronio de uma camada (gerando os pesos e bias aleatorios) | |
void initNeuronios(Camada*,int); | |
// gera pesos aleatorios | |
double* gerarPesos(int); | |
// gera um bias aleatorio | |
double gerarBias(); | |
// pega o somatorio do produto pesos por entradas, somando com o bias | |
double getSomatorio(Neuronio*); | |
// pega a saída de um neuronio usando a funcao logistica sigmoid | |
double funcaoLogistica(double); | |
// faz o processo de feedforward chamando a funcao feed | |
double feedForward(double*); | |
// realiza o processo de atribuir entradas ao neuronio e calcular sua saída | |
double* feed(Camada*,double*); | |
// faz o calculo do somatorio do custo de cada neuronio | |
void setCusto(int); | |
// joga o valor na derivada da fç sigmoide, para calculo do gradiente do neuronio | |
double derivadaSigmoide(double); | |
// chama as funcoes do backpropagation | |
void backPropagate(int); | |
// faz o processo de calcular os gradientes pra cada camada | |
void setGradientes(); | |
// realiza os calculos para pegar o gradiente de cada neuronio | |
double* getGradiente(Camada*); | |
// realiza o ajuste dos pesos com os novos gradientes | |
void ajustarPesos(Camada*); | |
// realiza o ajuste de cada bias com os novos gradientes | |
void ajustarBias(Camada*); | |
// libera da memoria todos os neuronios | |
void freeNeuronios(Camada*); | |
// libera da memoria o resto dos ponteiros | |
void freeTodos(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment