|
|
Neural Network Toolkit - Redes dinâmicas
Início
1. Introdução
Redes dinâmicas são aquelas em que as saídas não só dependem da rede inicial mas também das entradas,
das saídas, dos estados actuais ou dos anteriores da rede.
Note-se que, ao contrário, as rede estáticas não têm elementos de feedback nem atrasos.
Início
2. Exemplos de redes dinâmicas com atraso e feedback
Seja o vector de entrda:
p = {0 0 1 1 1 1 0 0 0 0 0 0};
e criemos a seguinte rede estática e visualemo-la:
net = linearlayer;
net.inputs{1}.size = 1;
net.layers{1}.dimensions = 1;
net.biasConnect = 0;
net.IW{1,1} = 2;
view(net);
a = net(p);
a -> {0 0 2 2 2 2 0 0 0 0 0 0}
Seja agora uma rede com um atraso na entrada (redes dinâmicas feedforward):
net = linearlayer([0 1]);
net.inputs{1}.size = 1;
net.layers{1}.dimensions = 1;
net.biasConnect = 0;
net.IW{1,1} = [1 1];
view(net);
a = net(p);
a -> {0 0 1 2 2 2 1 0 0 0 0 0}
Finalmente seja agora uma rede realimentação (feedback) com séries temporais [NARX]
(rede dinâmicas recorrentes).
A função que a cria é então narxnet
net = narxnet(0,1,[],'closed');
net.inputs{1}.size = 1;
net.layers{1}.dimensions = 1;
net.biasConnect = 0;
net.LW{1} = 0.5;
net.IW{1} = 1;
view(net);
a = net(p);
a -> {0 0 1 1.5 1.75 1.875 0.9375 0.4688 0.2344 0.1172 0.0586 0.0293}
Note-se que as redes dinâmicas recorrentes têm normalmente uma resposta mais longa do que as redes dinâmicas feedforward.
Para redes lineares, as redes dinâmicas feedforward são designadas por resposta ao impulso finita (FIR, Finite Impulse Response),
uma vez que ficam nulas num tempo finito; enquanto as redes dinâmicas recorrentes lineares são chamadas de resposta ao impulso infinita
(IIR, Infinite Impulse Response), pois, o valor vai apenas tendendo para zero.
As redes dinâmicas, como vimos, uma vez que têm realimentação, logo têm memória, assim são indicadas para analisar
padrões sequenciais ou séries variáveis no tempo.
Início
3. Rede Dinâmica Digital em Camadas (LDDN) - Definição
Uma Rede Dinâmica Digital em Camadas (LDDN, Layered Digital Dynamic Network) caracteriza-se
por, cada camada ser composta por:
- Conjunto de matrizes de pesos que entram na camada, regra de função de peso
utilizada para combinar a matriz dos pesos com a sua entrada (normalmente multiplicação "dotprod")
e linha de atraso de derivação associada;
- Um vector de viés (bias);
- Regra de função de entrada de rede que é utilizada para combinar as saídas das várias
funções de peso com o viés (bias) para produzir a entrada de rede (normalmente uma junção somadora
"netprod")
- Função de transferência
O software Neural Network Toolbox pode ser utilizado para treinar qualquer LDDN, desde que as
funções de peso, funções de entrada líquida e funções de transferência têm derivadas.
A eficiência do cálculo do gradiente depende fortemente do desempenho dos algoritmos.
Os pesos podem ter dois efeitos na saída, o directo e o indirecto, e isso complica mais o cálculo dos mínimos e. para
evitar cair em mínimos locais, é conveniente fazer vários testes de treino.
Início
4. Redes neurais de atraso temporal em séries temporais na primeira entrada (FTDNN)
Vamos começar pela rede dinâmica mais simples: uma rede de alimentação directa com uma linha
de atraso ligada à entrada, isto é, uma rede neural de atraso focalizada
(FTDNN, focused Time-Delay Neural Network).
Faz parte de uma classe mais geral de redes dinâmicas, denominadas redes focalizadas,
em que a dinâmica surge apenas na camada de entrada de uma rede de alimentação direta multicamada estática.
Como exemplo, sejam os dados de intensidade registados por um laser de infravermelho distante em estado caótico (dados normalizados)
[dados de "Competição de Séries Temporais de Santa Fé"]. O objectivo é, a partir dos 1000 primeiros pontos da série temporal,
prever os pontos seguintes. Vamos agora limitarmo-nos apenas ao ponto seguinte.
(Pode usar-se a rede resultante para previsões vários passos à frente.)
Comecemos por carregar os dados e convertê-los numa série temporal. Depois criar uma rede FTDNN
com a função timedelaynet que é uma função análoga a feedforwardnet
com uma entrada adicional para o vector de atraso. A seguir organizar as entradas, os atrasos e os alvos. Como
rede possui uma linha de atraso com derivação com um atraso máximo de 8, começa-se por prever o nono valor da série.
| y = laser_dataset; | Carregar os dados |
| y = y(1:600); | Escolher os primeiros 600 para os cálculos |
| net = timedelaynet([1:8],10); | Criação de uma rede FTDNN com linha de atraso com derivação
com atrasos de 1 a 8 e 10 neurónios na camada oculta; |
| net.trainParam.epochs = 1000; | Definir o número máximo de iterações; |
| net.divideFcn = ''; | Não se define função de divisão dos dados; |
| p = y(9:end); | Entradas do nono até ao fim; |
| t = y(9:end); | Alvos do nono até ao fim; |
| Pi=y(1:8); | Valores iniciais para o atraso; |
| net = train(net,p,t,Pi); | Treino da rede |
Note-se que a entrada para a rede é a mesma que a do alvo.
Como a rede tem um atraso mínimo de um passo de tempo,
isto significa que está a realizar uma previsão um passo à frente.
Pode-se agora o erro da previsão:
| yp = net(p,Pi); | Geração das saídas a partir das entradas; |
| e = gsubtract(yp,t) | Calculo o erro subtraindo as saídas aos lavos; |
| rmse = sqrt(mse(e)) | Cálulo da raiz quadrada do erro quadrático médio normalizado; |
| rmse -> 0.9740 | Resultado da operação anterior. |
Como se pode ver pelo cálculo que se segue, este resultado do erro é muito melhor do que se usasse a função
linearlayer:
| net1 = linearlayer([1:8]); | Criação a rede linear |
| net1.trainFcn='trainlm'; | Escolha da função de treino |
| [net1,tr] = train(net1,p,t,Pi); | Treino |
| yp1 = net1(p,Pi); | Geração das saídas a partir das entradas; |
| e1 = gsubtract(yp1,t); | Calculo o erro subtraindo as saídas aos lavos; |
| rmse1 = sqrt(mse(e1)) | Cálulo da raiz quadrada do erro quadrático médio normalizado; |
| rmse1 -> 21.1386 | Resultado da operação anterior. |
Uma característica importante das FTDNN é que não requerem retropropagação dinâmica para
calcular o gradiente da rede, porque a linha de atraso tocada aparece apenas na entrada da rede e não contém
loops de feedback ou parâmetros ajustáveis, assim, este tipo de rede treina mais rapidamente do que outras redes dinâmicas.
Como se pode ver por este exemplo simples, as redes dinâmicas exigem uma maior preparação na introdução dos dados, pois,
é necessário ter em conta as como os dados iniciais são organizados. Para o simplificar pode usar-se a função
preparets
(Ver: Funções de preparação dos dados).
Assim, as anteriores linhas de comandos:
| p = y(9:end); | Entradas do nono até ao fim; |
| t = y(9:end); | Alvos do nono até ao fim; |
| Pi=y(1:8); | Valores iniciais para o atraso; |
podem ser substituídas por
[p, Pi, Ai, t] = preparets (net, y, y);
em que Ai são as saídas iniciais da camada para carregar as linhas de atraso
derivadas para os pesos da camada.
Início
5. Redes neurais de atraso distribuído em séries temporais (TDNN)
Como se viu as FTDNN tem a memória da linha de atraso com derivação apenas na entrada da primeira camada.
Agora vanos ver as redes em que os atrasos podem ser encontrados em qualquer camada, isto é,
redes neurais de atraso distribuído em séries temporais (TDNN).
Este tipo de redes podem ser usados no reconhecimento de fonemas. Se uma rede simplicada que
procurará reconhecer o conteúdo de frequência de um sinal de entrada.
Esta rede pode ser utilizada para um problema simplificado semelhante ao reconhecimento de fonemas.
Seja então uma rede com duas camadas ambas com viés e atraso. A saída alvo é 1 quando a entrada
está abaixo e -1 quando a entrada está acima.
| time = 0:99; | Tempo de 0 a 99 |
| y1 = sin(2*pi*time/10); | Função seno de frequência 0.1 |
| y2 = sin(2*pi*time/5); | Função seno de frequência 0.2 |
| y = [y1 y2 y1 y2]; | Junção dos sinais anteriores |
| t1 = ones(1,100); | Alvo para 'y1' (frequência 0.1) |
| t2 = -ones(1,100); | Alvo para 'y2' (frequência 0.2) |
| t = [t1 t2 t1 t2]; | junção dos alvos anteriores |
Os atrasos vão ser de 0 a 4 na primeira camada e de 0 a 3 na segunda.
A função de treino irá ser trainbr.
| d1 = 0:4; | Atraso de 0 a 4 na primeira camada |
| d2 = 0:3; | Atraso de 0 a 3 na segunda camada |
| p = con2seq(y); | Converte o vector 'y' para um vector de células |
| t = con2seq(t); | Converte o vector 'y' para um vector de células |
| net = distdelaynet({d1,d2},5); | Cria a rede |
| net.trainFcn = 'trainbr'; | Define a função de treino a utilizar |
| net.divideFcn = ''; | Não se define função de divisão dos dados |
| net.trainParam.epochs = 100; | Define o número máximo de iterações |
| net = train(net,p,t); | Executa o treico da rede |
| yp = sim(net,p); | Simula a rede |
| plotresponse(t,yp); | Faz o gráfico dos alvos e respostas da rede |
Início
6. Redes Neurais de Feedback NARX de Séries Temporais
Uma rede autoregressiva não linear com entradas exógenas (NARX, Nonlinear AutoRegressive network
with eXogenous inputs) é uma rede dinâmica recorrente, com ligações de feedback envolvendo várias camadas da rede,
definida por uma função "f" que depende de atrasos e feedbacks.
Pode implementar-se o modelo NARX utilizando uma rede neural feedforward para aproximar a função "f".
Assim, uma vez que a saída de um sinal vai realimentar a entrada, podemos substituir a saída pelo sinal
corespondente na rede de entrada, tal torna o treino mais fiável e por outro lado torna a rede assim formada numa
rede feedforward. Ou seja, transformamos uma rede de arquitectura paralela num rede
de arquitectura série-paralela.
Como exemplo, vão se usados os dados de levitação magnética: posição do íman permanente "y(t)"
e tensão aplicada "u(t)". Criamos uma rede NARX série-paralela com 10 neurónios na camada
oculta e vamos fazer o treino com a função trainlm e dão-se os dados das entradas:
| load magdata; | Carrega os dados magnéticos |
| y = con2seq(y); |
Converte o vector num vector de células |
| u = con2seq(u); |
Converte o vector num vector de células |
| d1 = [1:2]; | Atrasos na entrada |
| d2 = [1:2]; | Atrasos no feedback |
| net = narxnet (d1, d2, 10); |
Cria rede neural 'NARX' |
| net.divideFcn = ''; | Não define função de divisão dos dados |
| net.trainParam.min_grad = 1e-10; | Valor mínimo do gradiente para parar o treino |
| [p, Pi, Ai, t] = preparets (net, u, {}, y); |
Prepara os dados |
| net = train (net, p, t, Pi); |
Executa o treino |
Note-se que y(t), que é o vector alvo, vai ser a entrada de
feedback. Depois do treino, a rede vai ser alterada para paralela
e passa a alimentda pelo valor de saída.
Feito o treino, podemos ver os erros da implementação série-paralelo.
| yp = sim (net,p,Pi); |
Simula a rede neural |
| e = cell2mat(yp) -
cell2mat(t); |
Calcula a diferença entre a saída e o alvo |
| plot (e); | Mostra o gráfico |
Pode ver-se que os erros são pequenos mas, atenção, estamos a usar a configuração série-paralelo. Para melhorar o
teste é preciso reorganizar a rede série-paralela (loop aberto) para paralela (loop fechado). A função
closeloop faz isso. Assim, passemos à rede paralela
e calculemos novamente os erros:
| view (net); | Visualiza a rede antes de a transformar |
| net_closed = closeloop (net); |
Converte a rede loop aberto em loop fechado |
| view (net_closed); | Visualiza a rede depois de transformada |
| |
| |
Em resumo, o treino de uma rede deste tipo deve ser feito em loop aberto incluindo validação e teste. Só depois é
que se deve passar à rede de loop fechado. Não esquecer que se deve usar a função
preparets
para fazer preparar os dados para esta nova configuração.
Note-se que se pode criar uma rede de loop fechado directamente a partir
narxnet, basta para isso por
acrescentar um quarto argumento: "close". Normalmente leva mais tempo e o resultado é pior...
Assim, por exemplo, se quisermos realizar uma previsão iterada de 900 passos de tempo:
| y1 = y(1700:2600); | |
| u1 = u(1700:2600); | |
| [p1, Pi1, Ai1, t1] =
preparets (net_closed, u1, {}, y1);
| |
| yp1 = net_closed(p1, Pi1, Ai1); | |
| TS = size(t1, 2); | |
| plot (1:TS, cell2mat(t1), 'b', 1:TS, cell2mat(yp1), 'r') | |
Aqui estudou-se o caso de um único valor de entrada. No entanto, não limita que possa haver múltiplos elementos.
A título de exemplo veja se um caso com dois elementos na entrada com os de PH:
| [X,T] = ph_dataset; | Lê os dados de PH |
| net = narxnet (10); |
Cria uma rede de loop aberto |
| [x, xi, ai, t] = preparets (net, X, {}, T); |
Prepara os dados |
| net = train (net,x,t,xi,ai); |
Executa o treino |
| y = net(x, xi, ai); | Obtém os saídas da rede |
| e = gsubtract (t,y); |
Calcula o erro na saída |
| plot (cell2mat(e)) | mostra o gráfico |
Início
7. Redes Neurais Recorrentes em Camadas
Uma Rede Recorrente em Camadas (LRN, Layer-Recurrent Network) é uma rede neural multicamada com um
loop de realimentação, com um único atraso, em cada camada excepto na última.
Estas redes podem ser usadas em aplicações de filtragem e modelagem.
Pode ser criação com o comando layrecnet.
Seja um exemplo com fonemas:
| |
| load phoneme; | Carrega os dados de fonemas |
| p = con2seq (y); |
Converte o vector num vector de células |
| t = con2seq (t); |
Converte o vector num vector de células |
| net = layrecnet (1, 8); | Cria rede neural 'LRN' |
| net.trainFcn = 'trainbr'; | Define a função de treino a utilizar |
| net.trainParam.show = 5; | Mostra os dados do treino de 5 em 5 iterações |
| net.trainParam.epochs = 50; | Define o número máximo de iterações |
| net = train (net, p, t); | Executa o treino |
| y = net(p); | Gera as saídas |
| plot(cell2mat(y)); | Faz o gráfico |
Início
8. Criar Controlador de Modelo de Referência
Vamos aqui ver como se pode criar uma rede personalizada.
Como se poderá ver mais à frente em "Projetar Controlador Neural de Referência de Modelo no Simulink", uma
arquitectura de controle pode ser representada por duas sub-redes: uma é o modelo a controlar; a outra é o controlador.
Esta arquitetura é o sistema de controle adaptativo de referência de modelo (MRAC).
Primeiro treina a rede modelo.
No exemplo aqui apresentado, são carregados os dados do braço robótico para criar e treinar uma rede NARX
(ver: nnet_04_07__MRAC.m).
| [u, y] = robotarm_dataset; |
Carrega os dados do braço robótico |
| d1 = [1:2]; | Atrasos na entrada |
| d2 = [1:2]; | Atrasos no feedback |
| S1 = 5; | Tamanho da camada oculta |
| narx_net = narxnet (d1, d2, S1); |
Cria rede neural 'NARX' em loop aberto |
| view (narx_net) | Visualiza a rede em loop aberto |
| narx_net.divideFcn = ''; | Não define função de divisão dos dados |
| narx_net.inputs{1}.processFcns = {}; | Não define função de pré-processamento
da camada "1" |
| narx_net.inputs{2}.processFcns = {}; | Não define função de pré-processamento
da camada "2" |
| narx_net.outputs{2}.processFcns = {}; | Não define função de pós-processamento
da camada "2" |
| narx_net.trainParam.min_grad = 1e-10; | Valor mínimo do gradiente para parar |
| [p, Pi, Ai, t] = preparets
(narx_net, u, {}, y); | Prepara os dados |
| narx_net = train (narx_net, p, t, Pi); |
Executa o treino |
| narx_net_closed = closeloop (narx_net);
| Converte a rede loop aberto em loop fechado |
| view (narx_net_closed) | Visualiza a rede em loop fechado |
Uma vez treinado o modelo NARX, vamos criar o sistema MRAC. Para tal é necessário criar o controlador, juntá-lo
com a rede do modelo treinada e treinar agora apenas o controlador.
Vamos agora criar o sistema MRAC com um controlador: cria-se uma rede feedforward com
três camadas ocultas em loop fechado com atrasos
| mrac_net = feedforwardnet ([S1 1 S1]); |
Cria rede neural feedforward |
| mrac_net.layerConnect = [0 1 0 1 ; 1 0 0 0 ; 0 1 0 1 ; 0 0 1 0]; |
Estabelece as ligações entre as camadas |
| mrac_net.outputs{4}.feedbackMode = 'closed'; |
Indica que a rede está em loop fechado |
| mrac_net.layers{2}.transferFcn = 'purelin'; |
Define a função de transferência da camada "2" |
| mrac_net.layerWeights{3,4}.delays = 1:2; |
Define os atrasos da camada "4" (output) para a "3" |
| mrac_net.layerWeights{3,2}.delays = 1:2; |
Define os atrasos da camada "2" para a "3" |
| mrac_net.layerWeights{3,2}.learn = 0; |
Marca-se para não alterar no treino o peso da camada "2" para a
"3" |
| mrac_net.layerWeights{3,4}.learn = 0; |
Marca-se para não alterar no treino o peso da camada "4" para a
"3" |
| mrac_net.layerWeights{4,3}.learn = 0; |
Marca-se para não alterar no treino o peso da camada "3" para a
"4" |
| mrac_net.biases{3}.learn = 0; |
Marca-se para não alterar no treino o peso do viés da camada "3" |
| mrac_net.biases{4}.learn = 0; |
Marca-se para não alterar no treino o peso do viés da camada "4" |
| mrac_net.divideFcn = ''; | Não define função de divisão dos dados |
| mrac_net.inputs{1}.processFcns = {}; |
Não define funções de pré-processamento na camada "1" |
| mrac_net.outputs{4}.processFcns = {}; |
Não define funções de pós-processamento na camada "4" |
| mrac_net.name = 'Model Ref. Adaptive Control'; | Atribui um nome à rede |
| mrac_net.layerWeights{1,2}.delays = 1:2; |
Define os atrasos da camada "2" para a "1" |
| mrac_net.layerWeights{1,4}.delays = 1:2; |
Define os atrasos da camada "4" para a "1" |
| mrac_net.inputWeights{1}.delays = 1:2; |
Define o atraso na camada inicial |
São necessários dados de treinamento para configurar a rede:
| [refin,refout] = refmodel_dataset; | |
| ind = 1:length(refin); | |
| plot (ind, cell2mat(refin), ind, cell2mat(refout)) | |
| mrac_net = configure (mrac_net, refin, refout); | |
Vamos agora inserir os pesos do modelo da planta treinada
("narx_net_closed"), ou seja, as camadas "3"
e "4" vão ser substituídas pelas camadas "1"
e "2" da rede do modelo. Por outras palavras: as camadas "3"
e "4" são a sub-rede do modelo e as camadas "1" e
"2" o controlador:
| mrac_net.LW{3,2} = narx_net_closed.IW{1}; | |
| mrac_net.LW{3,4} = narx_net_closed.LW{1,2}; | |
| mrac_net.b{3} = narx_net_closed.b{1}; | |
| mrac_net.LW{4,3} = narx_net_closed.LW{2,1}; | |
| mrac_net.b{4} = narx_net_closed.b{2}; | |
Podemos definir os pesos de saída da rede do controlador como "0"
o que dará à planta uma entrada inicial de zero:
| mrac_net.LW{2,1} = zeros(size(mrac_net.LW{2,1})); | |
| mrac_net.b{2} = 0; | |
Também se podem associar gráficos e funções de treino e visualizá-la:
| mrac_net.plotFcns = {'plotperform', 'plottrainstate', 'ploterrhist', 'plotregression', 'plotresponse'}; |
|
| mrac_net.trainFcn = 'trainlm'; | |
| view(mrac_net) | |
Falta fazer o treino do controlador:
| [x_tot, xi_tot, ai_tot, t_tot] = preparets
(mrac_net, refin, {}, refout); |
Preparação dos dados |
| mrac_net.trainParam.epochs = 50; | Número de iterações |
| mrac_net.trainParam.min_grad = 1e-10; | Valor mínimo do gradiente para parar |
| [mrac_net, tr] = train (mrac_net, x_tot, t_tot,
xi_tot, ai_tot); | Executa o treino |
O treino desta rede é mais demorado, pois, é uma rede é recorrente e a retropropagação dinâmica deve ser usada.
Isto é determinado automaticamente, pelo que não requer qualquer acção específica.
Podemos agora testar a rede:
| testin = skyline (1000, 50, 200, -.7, .7); | |
| testinseq = con2seq (testin); | |
| testoutseq = mrac_net(testinseq); | |
| testout = cell2mat (testoutseq); | |
| figure | |
| plot([testin' testout']) | |
Início
9. Redes Neurais Dinâmicas usando Várias Sequências
É, por vezes, conveniente fornecer diversas sequências de dados separados para treinar ou obter valores de uma rede.
Quando se treina uma rede como diversas sequências é necessário garantir que têm todas o mesmo tamanho. Para tal
acrescentam-se NaN (None a Number) para ficarem todas iguais. Vejamos como se podem organizar:
| load magmulseq; | % Carrega as sequências |
| y_mul = catsamples (y1, y2, y3, 'pad'); |
% Junta as sequências |
| u_mul = catsamples (u1, u2, u3, 'pad'); |
% Junta as sequências |
| d1 = [1:2]; | % Atrasos na entrada |
| d2 = [1:2]; | % Atrasos no feedback |
| narx_net = narxnet (d1, d2, 10); |
% Cria rede neural 'NARX' em loop aberto |
| narx_net.divideFcn = ''; | % Não define função de divisão dos dados |
| narx_net.trainParam.min_grad = 1e-10; | % Valor mínimo do gradiente para parar |
| [p, Pi, Ai, t] = preparets (narx_net, u_mul, {}, y_mul); |
% Prepara os dados |
| narx_net = train (narx_net, p, t, Pi); |
% Executa o treino |
Início
10. Como treinar redes neurais com pesos de erro
Na função de desempenho padrão de erro quadrático médio, cada erro quadrático (mse) contribui igualmente para a função de desempenho da seguinte:
\[F = mse = {1 \over N}\,\sum_{k=1}^N\,e_k^2 = {1 \over N}\,\sum_{k=1}^N\,(t_k - a_k)^2\]
mas, podemos querer ponderar cada erro quadrático individualmente:
\[F = mse = {1 \over N}\,\sum_{k=1}^N\,w_k^e\,e_k^2 = {1 \over N}\,\sum_{k=1}^N\,w_k^e\,(t_k - a_k)^2\]
Note-se, no entanto, que a ponderação do erro tem de manter as mesmas dimensões que os dados, isto é, na prática
os "\(\bf{\color{green}{w_k^e}}\)" têm de ser adimensionais.
Exemplo em que se ponderam os erros:
| y = laser_dataset; |
% Carrega a sequência de dados; |
| y = y(1:600); | % Escolhem-se as 600 primeiras entradas; |
| ind = 1:600; | % Cria-se um vector com os valores 1 a 600; |
| ew = 0.99.^(600-ind); | % Define o pesos de cada erro; |
| figure; | % Cria-se uma figura; |
| plot(ew); | % faz-se o gráfico dos pesos dos erros; |
| ew = con2seq (ew); |
% Converte o vector num vector de células; |
| ftdnn_net = timedelaynet ([1:8], 10); |
% Cria-se a rede com atraso; |
| ftdnn_net.trainParam.epochs = 1000; | % Definir o número máximo de iterações; |
| ftdnn_net.divideFcn = ''; | % Não se define função de divisão dos dados; |
| [p, Pi, Ai, t, ew1] = preparets (ftdnn_net, y, y, {}, ew); |
% Prepara os dados |
| [ftdnn_net1, tr] = train(ftdnn_net, p, t, Pi, Ai, ew1);
| % Executa o treino |
Início
11. Normalização dos erros de múltiplas saídas
A função de desempenho mais comum utilizada para treinar redes neuronais é o erro quadrático médio (EQM).
Quando há saídas com valores muito diferentes em valor absoluto, os erros dos valores pequenos são quase
ignorados. Por exemplo (Ver nnet_04_09__MRAC.m):
| x = -1:0,01:1; | |
| t1 = 100*sin(x); | |
| t2 = 0,01*cos(x); | |
| t = [t1; t2]; | |
| net = feedforwardnet(5); | |
| net1 = train(net,x,t); | |
| y = net1(x); | |
| figura(1); | |
| plot(x,y(1,:),x,t(1,:)); | |
| figure(2); | |
| plot(x,y(2,:),x,t(2,:)); | |
Para que os elementos de saída sejam tratados de igual modo, faz-se a sua normalização para o intervalo [-1, 1].
Tal é feito, definindo parâmetro de desempenho da normalização em 'standard' (net.performParam.normalization).
| net.performParam.normalization = 'standard'; | |
| net2 = train(net,x,t); | |
| y = net2(x); | |
| figura(3); | |
| plot(x,y(1,:),x,t(1,:)); | |
| figure(4); | |
| plot(x,y(2,:),x,t(2,:)); | |
Início
12. Previsão de Redes Neurais Multietapas
Como se viu, as rede dinâmicas com feedback (narxnet,
narnet, ...) podem ser transformadas em loop aberto ou fechado.
Por vezes, pode ser conveniente alterar entre as duas situações, por exemplo, em situações
em que se estar a receber um sinal em en que este último pode ser fiável ou não para a simulação.
Recapitulemos o que se viu sobre o treino em situação de loop aberto, com os dados da levitação magnética:
| [X,T] = maglev_dataset; | |
| net = narxnet (1:2, 1:2, 10); | |
| [x, xi, ai, t] = preparets(net, X, {}, T); | |
| net = train (net, x, t, xi, ai); | |
| y = net(x, xi, ai); | |
| view(net); | |
Podemos agora passá-la a rede de loop fechado, usar os dados para fazer previsões para uma
qualquer série de entrada e de estados iniciais:
| netc = closeloop (net); | |
| view (netc); | |
| [x, xi, ai, t] = preparets (netc, X, {}, T); | |
| yc = netc(x, xi, ai); | |
Também se pode desejar pegar nesta rede já treinada em loop aberto e, passá-la a modo fechado para continuar
a simulação. Note-se que openloop como closeloop
para além de alterarem a rede também convertem os estados da rede:
| [open_net, open_xi, open_ai] = openloop (closed_net, closed_xi, closed_ai); | |
| [closed_net, closed_xi, closed_ai] = closeloop (open_net, open_xi, open_ai); | |
Considere o caso em que pode ter um registo do comportamento do Maglev durante 20 passos de tempo
e pretende prever com antecedência mais 20 passos de tempo (em modo aberto):
| x1 = x(1:20); | |
| t1 = t(1:20); | |
| x2 = x(21:40); | |
| [x, xi, ai, t] = preparets (net, x1, {}, t1); | |
| [y1, xf, af] = net(x, xi, ai); | |
Agora, os estados finais de entrada e de camada devolvidos pela rede são convertidos para a forma
de loop fechado juntamente com a rede, os quais passam a ser os estados iniciais:
| [netc, xi, ai] = closeloop(net,xf,af); | |
| [y2, xf, af] = netc(x2, xi, ai); | |
então, pode definir-se uma sequência de entradas e testar a rede treinada:
| x2 = num2cell (rand(1, 10)); | |
| [y2, xf, af] = netc(x2, xi, ai); | |
pode-se agora voltar ao modo aberto (não é necessário converter a rede porque já a temos),
e obter as novas saídas:
| [~,xi,ai] = openloop(netc,xf,af); | |
| x3 = num2cell (rand(2, 10)); | |
| y3 = net (x3, xi, ai); | |
Início
|
|