/prj_perceptron_multicamadas_CUDA

Implementação simples do Perceptron Multicamadas em CUDA.

Primary LanguageCBSD 2-Clause "Simplified" LicenseBSD-2-Clause

Perceptron Multicamadas

Implementação paralela do Perceptron Multicamadas na linguagem CUDA, com o objetivo de comparar a performance e eficiência entre outras implementações do Perceptron Multicamadas (OpenACC e sequencial), já que o treinamento da rede é uma operação altamente custosa.

A implementação

Como o foco do implementação não estava na eficiência do treinamento da rede, e sim no na comparação de perfromance para meu TCC, a implementação utiliza um modelo para o treinamento da mesma bem simples, utilizando o algoritmo backpropagation, já que a rede pode possuir mais de uma camada.

Como compilar

Para compilar, basicamente serão necessários o CUDA Toolkit (que contém o compilador nvcc_) e o nosso querido GNU make (lembrando que todo código foi compilado utilizando um SO Linux, em Windows não faço idéia do comportamento esperado :/ ) para fazer todo o processo de compilação automatizado. Lembrando que no arquivo Makefile há diversas variáveis para configuração do código gerado, como a arquitetura alvo e etc, onde o mesmo está configurado para adaptadores gráficos com Compute Capability 6.1 (o código-fonte é compatível com a grande maioria dos adaptadores mais antigos, pois não usa operações atômicas e etc).

make # Executar este comando na pasta raíz do projeto (e torcer para compilar!)

As etapas (básicas) para o treinamento da rede

Há uma estrutura específica para os armazenar os padrões de treinamento, onde a mesma consiste basicamente de dois vetores, um vetor com a amostra à ser apresentada à rede e outra com a saída desejada para rede:

/**
 * Estrutura que irá representar um padrão de treinamento
 * para ser apresentado à rede.
 */
typedef struct {
  /** A vetor com a amostra (entrada da rede). */
  const float * d_amostra;
  
  /** Vetor com os valores desejados para saída da rede (objetivo). */
  const float * d_alvo;

} PadraoTreinamento;	

Essa estrutura, pode ser populada tanto manualmente, ou através de dois arquivos no formato CSV (um com as amostras e outro com os vetores de objetivo), utilizando a função abaixo (lembrando que os dados serão carregados na memória do adaptador gráfico):

/**
 * Método que carrega os padrões de treinamento de dois arquivos, um com as
 * amostras (que são normalizadas pela função), onde cada linha do mesmo
 * representa uma amostra (com os valores separados por ponto e vírgula ";"), e
 * outro com o vetor de objetivos para cada amostra respectivamente
 * (com os valores separados por ponto e vírgula também).
 *
 * @param nome_arquivo_amostras Nome do arquivo (com extensão) com as amostras
 *                              dos padrões de treinamento ou de teste.
 *
 * @param nome_arquivo_objetivos Nome do arquivo (com extensão) com os
 *                               objetivos dos padrões de treinamento ou
 *                               de teste.
 *
 * @param menor_val_amostra Menor valor presente nas amostras
 *                          (para normalização)
 *
 * @param maior_val_amostra Maior valor presente nas amostras
 *                          (para normalização)
 *
 * @param qtd_itens_amostra Quantidade de itens por amostra.
 *
 * @param qtd_itens_v_objetivo Quantidade de itens por vetor de objetivo.
 *
 * @param qtd_padroes Quantidade de padrões nos arquivos.
 *
 * @return Vetor com os padrões de treinamento ou de teste carregados na memória
 *         do adaptador gráfico ou NULO caso não seja possível abrir os arquivos
 *         para leitura.
 */
PadraoTreinamento * carregar_padroes_arquivo(char * nome_arquivo_amostras,
					     char * nome_arquivo_objetivos,
					     float menor_val_amostra,
					     float maior_val_amostra,
					     int qtd_itens_amostra,
					     int qtd_itens_v_objetivo,
					     int qtd_padroes);

Também é necessário alocar a estrutura do Perceptron Multicamadas na memória utilizando a seguinte função:

/**
 * Método que aloca o Perceptron Multicamadas na memória do hospedeiro,
 * salvo os atributos das camadas que serão salvos no adaptador gráfico.
 *
 * @param qtd_neuronios_entrada Quantidade de neurônios da camada de
 *                              entrada.
 *
 * @param qtd_camadas Quantidade de camadas (em que há processamento).
 *
 * @param qtd_neuronios_camada Vetor com a quantidade de neuronios para cada
 *                             camada.
 * 
 * @param funcao_ativacao_rede Função de ativação da rede, ou seja, todas as
 *                             camadas da rede estarão atribuidas para serem
 *                             ativadas com tal função (usar a enumeração
 *                             "funcoes_ativacao_enum"). Lembrando que, caso se
 *                             deseje que as camadas tenham funções de ativação
 *                             diferente, estabelecer manualmente estes valores
 *                             nas respectivas camadas. 
 *
 * @return Referência para a estrutura alocada.
 */
PerceptronMulticamadas *
inicializar_PerceptronMulticamadas(int qtd_neuronios_entrada,
				   int qtd_camadas,
				   int * qtd_neuronios_camada,
				   int funcao_ativacao_rede);	

FINALMENTE, agora é a hora de iniciar o treinamento com a função abaixo (^_^):

/**
 * Método que realiza o treinamento da rede através do método "backpropagation"
 * utilizando os padrões passados por parâmetro. A rede irá ser treinada
 * até que o erro MSE da mesma seja menor ou igual ao "erro_desejado" OU
 * até que a rede atinja a quantida máxima de épocas (QTD_MAX_EPOCAS).
 *
 * @param pm Perceptron.
 *
 * @param padroes Padrões para treinamento.
 *
 * @param qtd_padroes_treinamento Quantidade de padrões de treinamento.
 *
 * @param taxa_aprendizagem Taxa de aprendizagem.
 *
 * @param erro_desejado Condição de parada para o treinamento
 * da rede.
 *
 * @param gerar_historico Se será necessário gerar o histórico ou não.
 *
 * @return Histórico de treinamento.
 */
HistoricoTreinamento *
treinamento_PerceptronMulticamadas(PerceptronMulticamadas * pm,
				   PadraoTreinamento * padroes,
				   int qtd_padroes_treinamento,
				   float taxa_aprendizagem,
				   float erro_desejado,
				   bool gerar_historico);

Para demais informações em relação as funções, basta olhar os arquivos de cabeçalho, pois as funções estão devidamente documentadas (acredito eu).