Redes neurais e a proporção áurea: segunda execução

Certa vez, escrevi um artigo no qual descrevi um modelo matemático simples da evolução de uma rede neural e sua seleção pela capacidade de adicionar números em sistemas numéricos com bases 2 e uma proporção áurea, e descobriu-se que a proporção áurea funciona melhor. Então, minha primeira experiência acabou sendo muito ruim, pois não levei em consideração várias nuances importantes relacionadas ao fato de que o erro não deveria ser levado em consideração para um neurônio, mas para um pouco de informação, então decidi melhorar meu experimento e apresentar mais algumas. ajustes.

  1. Decidi verificar 100 pares de amostras de 15 (amostra de treinamento) e 1000 (amostra de teste) vetores em sistemas numéricos com bases uniformemente distribuídas de 1,2 a 2 em vez de duas bases conhecidas anteriormente.
  2. Também fiz uma regressão linear não apenas da distância entre a base e a proporção áurea, mas também da própria base, o número de coordenadas no vetor e o valor médio da coordenada no vetor de resposta, para levar em consideração a dependência não linear do erro na base.
  3. Também verifiquei algumas amostras quanto à normalidade pelo critério Kolmogorov-Smirnov, ANOV, mas esses critérios mostraram que as amostras provavelmente se desviaram do gaussiano, então decidi fazer uma regressão linear ponderada em vez da usual. No entanto, a ANOVA, apesar de mostrar F um pouco menos do que antes (na região de 700-800 em vez de 800-900), mas ainda assim o resultado permaneceu mais do que estatisticamente significativo, o que significa que mais testes devem ser realizados. Como esses testes, fiz um histograma da densidade de distribuição dos resíduos de regressão e do QQ normal - um gráfico da função de distribuição desses resíduos.

Estes dois gráficos são:

imagem

imagem

Como pode ser visto, embora o desvio da distribuição normal na distribuição dos resíduos seja estatisticamente significativo (e à esquerda, até um pequeno segundo modo é visível no histograma), na verdade, é muito próximo do gaussiano, portanto, é possível (com cautela e intervalos de confiança maiores) contar com essa regressão linear .

Agora, sobre como eu gere amostras para testar redes neurais sobre elas.
Aqui está o código para gerar as amostras:
#define _CRT_RAND_S //     rand_s() #include "main.h" //   (    ) int main(void) { FILE *output,*test; int i; while (fopen("test.txt","w")==NULL) i=0; output=fopen("test.txt","w"); //       unsigned int p; p=0;//       rand_s(); rand_s(&p); double a; a=0; a = 1.6+((double) ((double) ((double)p/UINT_MAX)-0.5)*0.8);//    int n; n=0;//     . bool *t;//         . while (malloc(sizeof(bool)*1000)==NULL) n=0; t = (bool *) malloc(sizeof(bool)*1000); rand_s(&p); double s; s=0; s = (double)p/UINT_MAX;//    0  1. calculus(a,s,t,1000);// s  a-  . double mu; int q; mu=0; q=0; for (i=0;i<1000;i++) { if ((*(t+i))==true) mu =(double) mu+1; }//     , . . ,     . mu=(double) mu/1000; printf("%10.9lf\n",mu); n = (int) ((double) 14)/(log(mu)*mu/(log((double) 1/2))+log((double) 1-mu)*(1-mu)/log((double) 1/2)); //   ,     14    a-  . printf("%i\n",n); free(t); while (malloc(sizeof(bool)*n)==NULL) i=0; t = (bool *) malloc(n*sizeof(bool));//     ,      . double x,y,z; x=0; y=0; z=0; int j; j=0; int m; m=0; m=2*n; fprintf(output,"%i 1000\n",m);//         -. fprintf(output,"%lf\n",a); //    for (i=0;i<1000;i++) {//     ,  ,     ,   -  . rand_s(&p); x = (double) p/UINT_MAX; rand_s(&p); y = (double) p/UINT_MAX; z=x+y; calculus(a,x,t,n); for (j=0;j<n;j++) { if ((*(t+j))==true) fprintf(output,"1 "); else fprintf(output,"0 "); } calculus(a,y,t,n); for (j=0;j<n;j++) { if ((*(t+j))==true) fprintf(output,"1 "); else fprintf(output,"0 "); } fprintf(output,"\n"); calculus(a,z,t,n); for (j=0;j<n;j++) { if ((*(t+j))==true) fprintf(output,"1 "); else fprintf(output,"0 "); } for (j=0;j<n;j++) { fprintf(output,"0 "); } fprintf(output,"\n"); } //    ,     ,    15  . while (fopen("input.txt","w")==NULL) i=0; test = fopen("input.txt","w"); fprintf(test,"%i 15\n",m); fprintf(test,"%lf\n",a); for (i=0;i<15;i++) { rand_s(&p); x = (double) p/UINT_MAX; rand_s(&p); y = (double) p/UINT_MAX; z=x+y; calculus(a,x,t,n); for (j=0;j<n;j++) { if ((*(t+j))==true) fprintf(test,"1 "); else fprintf(test,"0 "); } calculus(a,y,t,n); for (j=0;j<n;j++) { if ((*(t+j))==true) fprintf(test,"1 "); else fprintf(test,"0 "); } fprintf(test,"\n"); calculus(a,z,t,n); for (j=0;j<n;j++) { if ((*(t+j))==true) fprintf(test,"1 "); else fprintf(test,"0 "); } for (j=0;j<n;j++){ fprintf(test,"0 "); } fprintf(test,"\n"); } free(t); fclose(output); fclose(test); }; 



E aqui está o código do arquivo de cabeçalho:
 #include <stdio.h> #include <stdlib.h> #include <math.h> int main(void); void calculus(double a, double x, bool *t, int n);//     x   a   t  n . void calculus(double a, double x, bool *t, int n) { int i,m,l; double b,y; b=0; m=0; l=0; b=1; int k; k=0; i=0; y=0; y=x; //  t   . for (i=0;i<n;i++) { (*(t+i))=false; } k=((int) (log((double)2))/(log(a)))+1;//    ,   . while ((l<=k-1)&&(m<nk-1)) //  x  a ( ),      { m=0; if (y>1) { b=1; l=0; while ((b*a<y)&&(l<=k-1)) { b=b*a; l++; } if (b<y) { y=yb; (*(t+kl))=true; } } else { b=1; m=0; while ((b>y)&&(m<nk-1)) { b=b/a; m++; } if ((b<y)||(m<nk-1)) { y=yb; (*(t+k+m))=true; } } } return; } 



Também decidi postar o código completo da rede neural:
 #include "main.h" //    ,   ,       main(void). int main(void) { FILE *input, *output, *test; int i,j,k,k1,k2,l,q,n,m,r; double *x,*y,*z,*a,s,s1,h,h1,d,mu,buffer; d=0; mu=0; r=0; unsigned int p; n=0; while (fopen("input.txt","r")==NULL) i=0; while (fopen("output.txt","w")==NULL) i=0; input = fopen("input.txt","r"); output = fopen("output.txt","w"); fscanf(input,"%i %i",&n,&m);//      . buffer=0; fscanf(input,"%lf",&buffer);//        . while (malloc(sizeof(double)*n*m)==NULL) i=0; x = (double *) malloc(sizeof(double)*n*m);//     while (malloc(sizeof(double)*n*m)==NULL) i=0; z = (double *) malloc(sizeof(double)*n*m);//       . while (malloc(sizeof(double)*n*m)==NULL) i=0; y = (double *) malloc(sizeof(double)*n*m);//    . for (k=0;k<m;k++) { for (i=0;i<n;i++) { fscanf(input,"%lf ",x+n*k+i);// . } for (i=0;i<n;i++) { fscanf(input,"%lf ",y+n*k+i);// . } for (i=0;i<n;i++) { (*(z+n*k+i))=0;//       . } } while (malloc(sizeof(double)*n*n)==NULL) i=0; a = (double *) malloc(sizeof(double)*n*n); //    . for (i=0;i<n*n;i++) { (*(a+i))=0; } k1 = 0; k2 = 0; s=1; s1=0; s1=s+1; d=0; h=0; q=0; mu=1; while (((d-mu)*(d-mu)>0.01)||(q<10))// ,           ,     ,     -  . { s=0; for (k=0;k<m;k++) { for (i=0;i<n;i++) { (*(z+k*n+i))=0; } for (i=0;i<n;i++) { for (j=0;j<n;j++) { (*(z+k*n+i))=(*(z+k*n+i))+(*(a+i*n+j))*(*(x+k*n+j));//     . } } for (i=0;i<n;i++) { s=s+((*(z+k*n+i))-(*(y+k*n+i)))*((*(z+k*n+i))-(*(y+k*n+i)));//         } } r=0; s1=s+1; while ((s<s1)&&(r<100))//,                     . { r++; s1=0; for (k=0;k<m;k++) { for (i=0;i<n;i++) { (*(z+k*n+i))=0; } } //      rand_s(&p); k1 = (int) (p/((int) (UINT_MAX/n))); rand_s(&p); k2 = (int) (p/((int) (UINT_MAX/n))); rand_s(&p); //   h=((double) p/UINT_MAX)-0.5; h1=1; rand_s(&p); l=((int) ((double) p/UINT_MAX)*20); // ,           . for (i=0;i<l;i++) { h1=h1/10; } h=h*h1; //      . for (k=0;k<m;k++) { for (i=0;i<n;i++) { for (j=0;j<n;j++) { if ((i==k1)&&(j==k2)) (*(z+k*n+i))=(*(z+k*n+i))+(*(a+i*n+j))*(*(x+k*n+j))+h*(*(x+k*n+j)); else (*(z+k*n+i))=(*(z+k*n+i))+(*(a+i*n+j))*(*(x+k*n+j)); } } //        . for (i=0;i<n;i++) { s1=s1+((*(z+k*n+i))-(*(y+k*n+i)))*((*(z+k*n+i))-(*(y+k*n+i))); } } } if (r<100) (*(a+k1*n+k2))=(*(a+k1*n+k2))+h; s1=0; d=0; for (k1=0;k1<n;k1++) { for (k2=0;k2<n;k2++) { for (k=0;k<m;k++) { for (i=0;i<n;i++) { (*(z+k*n+i))=0; } } for (k=0;k<m;k++) { for (i=0;i<n;i++) { for (j=0;j<n;j++) { if ((i==k1)&&(j==k2)) (*(z+k*n+i))=(*(z+k*n+i))+((*(a+i*n+j))+0.1)*(*(x+k*n+j)); else (*(z+k*n+i))=(*(z+k*n+i))+(*(a+i*n+j))*(*(x+k*n+j)); } } } s1=0; for (k=0;k<m;k++) { for (i=0;i<n;i++) { s1=s1+((*(z+k*n+i))-(*(y+k*n+i)))*((*(z+k*n+i))-(*(y+k*n+i))); } } d=d+(s1-s)*(s1-s)/(n*m); } } mu=mu*((double) q/(q+1))+((double) d/(q+1)); q=q+1; printf("%lf \n",mu); } for (k=0;k<m;k++) { for (i=0;i<n;i++) { (*(z+k*n+i))=0; } } //       . for (k=0;k<m;k++) { for (i=0;i<n;i++) { for (j=0;j<n;j++) { (*(z+k*n+i))=(*(z+k*n+i))+(*(a+i*n+j))*(*(x+k*n+j)); } } } free(x); free(y); free(z); while (fopen("test.txt","r")==NULL) i=0; test = fopen("test.txt","r"); fscanf(test,"%i %i",&n,&m); fscanf(test,"%lf",&buffer); while (malloc(n*m*sizeof(double))==NULL) i=0; x = (double *) malloc(n*m*sizeof(double)); while (malloc(n*m*sizeof(double))==NULL) i=0; y = (double *) malloc(n*m*sizeof(double)); while (malloc(n*m*sizeof(double))==NULL) i=0; z = (double *) malloc(n*m*sizeof(double)); for (k=0;k<m;k++) { for (i=0;i<n;i++) { (*(z+k*n+i))=0; } } for (k=0;k<m;k++) { for (i=0;i<n;i++) { fscanf(test,"%lf ",x+k*n+i); } for (i=0;i<n;i++) { fscanf(test,"%lf ",y+k*n+i); } } //      (  ). mu=0; for (k=0;k<m;k++) { for (i=0;i<n;i++) { mu=mu+(*(y+k*n+i)); } } mu=mu/((double) k*n); fprintf(output,"%lf\n\n",mu); for (k=0;k<m;k++) { for (i=0;i<n;i++) { for (j=0;j<n;j++) { (*(z+k*n+i))=(*(z+k*n+i))+(*(a+i*n+j))*(*(x+k*n+j)); } } } //     . for (k=0;k<m;k++) { s=0; for (i=0;i<n;i++) { s=s+((*(z+k*n+i))-(*(y+k*n+i)))*((*(z+k*n+i))-(*(y+k*n+i))); } s=(double) s/n; s=sqrt(s); s=(double) ((double) s*n)/14; fprintf(output,"%20.18lf \n",s); } free(a); free(x); free(y); free(z); fclose(input); fclose(output); return 0; }; 


Em seguida, vamos falar sobre como eu conduzi uma regressão linear ponderada. Para fazer isso, simplesmente calculei os desvios padrão dos resultados da rede neural e, em seguida, dividi a unidade neles.
Aqui está o código fonte do programa com o qual eu fiz isso:
 #include <stdio.h> #include <stdlib.h> #include <math.h> int main(void) { int i; FILE *input,*output; while (fopen("input.txt","r")==NULL) i=0; input = fopen("input.txt","r");//         . double mu,sigma,*x; mu=0; sigma=0; while (malloc(1000*sizeof(double))==NULL) i=0; x = (double *) malloc(sizeof(double)*1000); fscanf(input,"%lf",&mu); mu=0; for (i=0;i<1000;i++) { fscanf(input,"%lf",x+i); } for (i=0;i<1000;i++) { mu = mu+(*(x+i)); } mu = mu/1000; while (fopen("WLS.txt","w") == NULL) i=0; output = fopen("WLS.txt","w"); for (i=0;i<1000;i++) { sigma = sigma + (mu - (*(x+i)))*(mu - (*(x+i))); } sigma = sigma/1000; sigma = sqrt(sigma); sigma = 1/sigma; fprintf(output,"%10.9lf\n",sigma); fclose(input); fclose(output); free(x); return 0; }; 


Em seguida, adicionei os pesos resultantes à tabela, onde reduzi todos os dados obtidos como resultado do programa, bem como os valores das variáveis ​​para calcular a regressão e, em seguida, calculei-o no JASP. Aqui estão os resultados:

Resultados

Regressão linear

Resumo do Modelo







Modelo
R

R² ajustado
Rmse
1
0,175
0,031
0,031
0,396


Anova







Modelo

Soma dos quadrados
df
Quadrado médio
F
p
1
Regressão
494,334
4
123.584
789.273
<0,001
Residual
15657.122
99995
0,157

Total
16151.457
99999



Coeficientes







Modelo

Não padronizado
Erro padrão
Padronizado
t
p
0,5%
99,5%
1
(Interceptar)
-0,104
0,059
-1,751
0,080
-0,256
0,049
A distância entre a base e a proporção áurea
-0,113
0,010
-0,080
-11,731
<0,001
-0,138
-0,088
O número de medições no vetor
0,008
2.328e -4
0,529
32.568
<0,001
0,007
0,008
O valor médio da coordenada do vetor na resposta
-0,951
0,181
-0,332
-5,255
<0,001
-1,417
-0,485
Sistema de número base
0,489
0,048
0,687
10,252
<0,001
0,366
0,611



Em seguida, tenho um histograma da densidade de distribuição dos resíduos de regressão padronizados:
imagem
Bem como o gráfico quantil-quantil normal de resíduos de regressão padronizados:
imagem
Em seguida, apliquei as variáveis ​​dos coeficientes de regressão obtidos em seu curso às variáveis ​​e realizei minha análise estatística para encontrar o mínimo mais provável da função de erro a partir da base do sistema numérico (quanto está relacionado a essas variáveis) usando o lema de Fermat, o teorema de Bayes e o teorema de Lagrange da seguinte maneira:
O fato é que a distribuição das bases do sistema numérico na amostra era obviamente uniforme, portanto, se uma certa base no intervalo (1,2; 2) é o mínimo do erro quadrático médio, então, pelo lema de Fermat, ele terá uma derivada zero, então a densidade de probabilidade dos valores A função será infinita.
Agora, sobre como eu apliquei o teorema de Bayes. Calculei os intervalos de confiança da distribuição beta (esta é a distribuição de probabilidade de "sucesso" no experimento sob a condição de n "sucessos" e m "falhas" com densidade de probabilidade p(x)= frac(n+m+1)!n!m!xn(1x)m) os valores da função de distribuição (esta é a probabilidade de a variável aleatória não ser maior que o argumento) dos erros calculados, com base no fato de que, se a variável aleatória não for maior que o argumento, será "sucesso" e, se for mais, "falha". Então, usando o teorema bayesiano, aplicamos a distribuição beta da função de distribuição dos erros calculados e calculamos seus intervalos de confiança de [função de distribuição] de 99% em cada erro calculado.
Passamos para o teorema de Lagrange. O teorema de Lagrange afirma que, se a função f (x) é continuamente diferenciável no intervalo [a; b], pelo menos em um ponto desse intervalo, ela tem uma derivada igual a  fracf(b)f(a)ba. Como aplico esse teorema: o fato é que a densidade de probabilidade é uma derivada da função de distribuição; portanto, pego o valor máximo entre aqueles que são precisos em alguns intervalos, desde o erro mínimo até os erros restantes. Depois, calculo os intervalos de confiança desses valores em 98% (usando a correção de Bonferroni) usando a seguinte fórmula:

[ fracF1(xi)F2(x1)xix1; fracF2(xi)F1(x1)xix1]


onde F1 é a extremidade esquerda do intervalo de confiança para a função de distribuição e F2 é a direita, x_i, x_1 são os erros calculados como argumento para a função de distribuição. Em seguida, o programa procura por um intervalo com a maior extremidade esquerda e a maior extremidade direita (para que o valor no intervalo seja máximo) e, em seguida, procura o máximo e o mínimo nas bases que correspondem aos erros calculados nesse intervalo. Esses máximos e mínimos são os argumentos da função de erro de baixo para cima, entre os quais se encontra o mínimo da própria função, com uma probabilidade de 98%.
Aqui está o código do programa que conduzi esta análise estatística com explicações:
 #include "main.h" //  . int main(void) { FILE *input,*output; int i,n,k,dFmax; double *x,*y,*F1,*F2,*F,*dF,*dF1,*dF2,t1,t2,xmin,xmax,ymin,ymax; t1=0; t2=0; while ((input=fopen("input.txt","r"))==NULL) i=0; while ((output=fopen("output.txt","w"))==NULL) i=0; n=0; while (fscanf(input,"%i",&n)==NULL) i=0; while ((x = (double *) malloc(sizeof(double)*n))==NULL) //    . i=0; while ((y = (double *) malloc(sizeof(double)*n))==NULL) //  ,   . i=0; while ((F = (double *) malloc(sizeof(double)*n))==NULL) //   -   . i=0; while ((F1 = (double *) malloc(sizeof(double)*n))==NULL) //      -. i=0; while ((F2 = (double *) malloc(sizeof(double)*n))==NULL)//      -. i=0; for (i=0;i<n;i++) { while (fscanf(input,"%lf %lf",y+i,x+i)==NULL) k=0; } for (i=0;i<n;i++) { Bayesian_99CI(i,ni,*(F1+i),*(F2+i),*(F+i)); //     ,     (     ) printf("%lf %lf %lf\n",*(F+i),*(F1+i),*(F2+i)); } while ((dF = (double *) malloc(sizeof(double)*n))==NULL) i=0; while ((dF1 = (double *) malloc(sizeof(double)*n))==NULL) i=0; while ((dF2 = (double *) malloc(sizeof(double)*n))==NULL) i=0; for (i=0;i<n-1;i++) //  " -"     . { for (k=i+1;k<n;k++) { if ((*(y+k))<(*(y+i))) { t1=(*(x+i)); t2=(*(y+i)); (*(x+i))=(*(x+k)); (*(y+i))=(*(y+k)); (*(x+k))=t1; (*(y+k))=t2; } } } dFmax=1; //     98%   ,       1-  (i+1)-        : for (i=1;i<n;i++) { (*(dF2+i))=((*(F2+i))-(*(F1)))/((*(y+i))-(*(y))); (*(dF1+i))=((*(F1+i))-(*(F2)))/((*(y+i))-(*(y))); } for (i=1;i<n;i++) { if (((*(dF1+i))>(*(dF1+dFmax)))&&((*(dF2+i))>(*(dF2+dFmax)))) dFmax=i; } xmin=0; xmax=0; ymin=0; ymax=0; xmin=(*x); xmax=(*x); ymin=(*y); ymax=(*y); //  ,       ,    ,      : for (i=0;i<=dFmax;i++) { if ((*(x+i))>xmax) xmax=(*(x+i)); if ((*(x+i))<xmin) xmin=(*(x+i)); if ((*(y+i))>ymax) ymax=(*(y+i)); if ((*(y+i))<ymin) ymin=(*(y+i)); }     : fprintf(output,"x (- [%lf; %lf]\ny (- [%lf; %lf]",xmin,xmax,ymin,ymax); scanf("%i\n",&i); free(x); free(y); free(F); free(F1); free(F2); free(dF); free(dF1); free(dF2); fclose(input); fclose(output); return 0; }; 



E aqui está o código do arquivo de cabeçalho:
 #include <stdio.h> #include <stdlib.h> #include <math.h> int main(void); double Bayesian(int n, int m, double x);//   -  n ""  m "",     "    "  "   " ,     : double Bayesian(int n, int m, double x) { double c; c=(double) 1; int i; i=0; for (i=1;i<=m;i++) { c = c*((double) (n+i)/i); } for (i=0;i<n;i++) { c = c*x; } for (i=0;i<m;i++) { c = c*(1-x); } c=(double) c*(n+m+1); return c; } double Bayesian_int(int n, int m, double x);//   - (      ): double Bayesian_int(int n, int m, double x) { double c; int i; c=(double) 0; i=0; for (i=0;i<=m;i++) { c = c+Bayesian(n+i+1,mi,x); } c = (double) c/(n+m+2); return c; } //        : void Bayesian_99CI(int n, int m, double &x1, double &x2, double &mu); void Bayesian_99CI(int n, int m, double &x1, double &x2, double &mu) { double y,y1,y2; y=(double) n/(n+m); int i; for (i=0;i<1000;i++) { y = y - (Bayesian_int(n,m,y)-0.5)/Bayesian(n,m,y); } mu = y; y=(double) n/(n+m); for (i=0;i<1000;i++) { y = y - (Bayesian_int(n,m,y)-0.995)/Bayesian(n,m,y); } x2=y; y=(double) n/(n+m); for (i=0;i<1000;i++) { y = y - (Bayesian_int(n,m,y)-0.005)/Bayesian(n,m,y); } x1=y; } 


Aqui está o resultado do trabalho deste programa, quando dei a ela os fundamentos do sistema numérico e os resultados da regressão:

 x (- [1.501815; 1.663988] y (- [0.815782; 0.816937] 

("(-" nesse caso é apenas uma notação do sinal "pertence" à teoria dos conjuntos, colchetes indicam o intervalo.)

Assim, me ocorreu que a melhor base do sistema numérico em termos do menor número de erros na transmissão de informações está no intervalo de 1,501815 a 1,663988, ou seja, a proporção áurea cai completamente nele. É verdade que fiz uma suposição ao calcular o mínimo e mais uma vez ao calcular a quantidade de informações em diferentes sistemas numéricos: primeiro, assumi que a função de erro da base é continuamente diferenciável e, segundo, que a probabilidade de que o número distribuído uniformemente seja 1, 2 a 2 terá o número um em um dígito específico, será aproximadamente o mesmo depois de algum dígito após o ponto decimal.

Se fiz algo completamente errado, ou simplesmente errado, estou aberto a críticas e sugestões. Espero que essa tentativa tenha sido mais bem-sucedida.
UPD Editei o artigo duas vezes para esclarecer alguns lugares da parte "puramente científica" e também formatou o código.
UPD2. Depois de consultar uma pessoa que entende de bioinformática (um graduado do estudo de pós-graduação da FBB MSU no IPPI RAS), decidiu-se substituir a palavra "cérebro" por "rede neural", pois eles diferem bastante.

Source: https://habr.com/ru/post/pt480886/


All Articles