Beispiel #1
0
        public override Locomotion.MoveDirection GetNextMove(BoardInfo boardInfo, CellInfo currentPos, CellInfo[] goals)
        {
            if (!startedLearn)
            {
                if (File.Exists("qtable.csv") && !forgetPreviousLearning)
                {
                    qtable  = QTable.LoadFromCsv("qtable.csv", boardInfo);
                    episode = numberOfEpisodes;
                }
                else
                {
                    StartCoroutine(Learn(boardInfo));
                }

                startedLearn = true;
            }

            if (episode == numberOfEpisodes)
            {
                // Proxima celda aleatoria
                Locomotion.MoveDirection nextDirection = (Locomotion.MoveDirection)qtable.GetHighestQDirection(currentPos);
                return(nextDirection);
            }

            return(Locomotion.MoveDirection.None);
        }
Beispiel #2
0
        /// <summary>
        /// Lee un fichero csv para generar una QTable
        /// </summary>
        /// <param name="path">El fichero a leer</param>
        /// <param name="boardInfo">Información del tablero de juego</param>
        /// <returns>QTable con los valores almacenados en el fichero csv</returns>
        public static QTable LoadFromCsv(string path, BoardInfo boardInfo)
        {
            QTable       qtable       = new QTable(boardInfo);
            StreamReader streamReader = new StreamReader(path);
            string       line;

            float[] data;
            int     nLine = 0;

            qtable.table.Clear();
            streamReader.ReadLine();    // Saltar cabeceras

            while ((line = streamReader.ReadLine()) != null)
            {
                data = qtable.GetCsvValues(line);
                qtable.table.AddRange(data);
            }

            return(qtable);
        }
Beispiel #3
0
        /// <summary>
        /// Función para aprender mediante QLearning.
        /// </summary>
        /// <param name="boardInfo">Tablero de juego</param>
        /// <returns></returns>
        private IEnumerator Learn(BoardInfo boardInfo)
        {
            if (subTitle)
            {
                subTitle.text = String.Format(cultureInfo, "Número de episodios: {0:n0}", numberOfEpisodes);
            }
            if (loadingPanel)
            {
                loadingPanel.SetActive(true);
            }
            yield return(null);

            CellInfo nextState, currentState;                        // Estado actual y próximo

            Locomotion.MoveDirection direction;                      // Dirección proximo movimiento
            float Q, r;                                              // Valor Q y recompensa

            qtable = new QTable(boardInfo);                          // Nueva tabla Q
            float maxQValue   = float.MinValue;                      // valor máximo Q en toda la tabla
            float totalQValue = 0f;                                  // Suma de todos los valores Q de la tabla
            var   epsilon     = this.epsilon;                        // Epsilon clone

            for (episode = 0; episode < numberOfEpisodes; episode++) // Episodios
            {
                // Elección de una celda de inicio aleatoria para el episodio
                currentState = boardInfo.CellInfos[
                    Random.Range(0, boardInfo.NumColumns),
                    Random.Range(0, boardInfo.NumRows)
                               ];

                bool endOfEpisode = false;

                do
                {
                    // Elige una nueva dirección de forma aleatoria o mediante los valores Q del estado actual
                    // en función de epsilon, el ratio de aprendizaje-exploracion
                    if (Random.Range(0.0f, 1.0f) < epsilon)
                    {
                        // Elegimos una dirección aleatoria
                        direction = (Locomotion.MoveDirection)Random.Range(0, 4);
                    }
                    else
                    {
                        // Elegimos la mejor posición según la tabla Q
                        direction = (Locomotion.MoveDirection)qtable.GetHighestQDirection(currentState);
                    }

                    // Valor Q actual para la posición (estado) actual y la nueva dirección (accion) a tomar
                    Q = qtable[currentState, direction];

                    // Calculamos recompensa para la próxima posición (estado)
                    nextState = currentState.WalkableNeighbours(boardInfo)[(int)direction];
                    r         = GetReward(nextState);

                    // Máximo valor de Q para el próximo estado
                    float nextQMax = nextState != null?qtable.GetHighestQValue(nextState) : 0;

                    // Actualizamos tabla Q
                    float QValue = (1 - alpha) * Q + alpha * (r + gamma * nextQMax);
                    qtable[currentState, direction] = QValue;
                    totalQValue += QValue;
                    maxQValue    = QValue > maxQValue ? QValue : maxQValue;

                    // Nos desplazamos al siguiente estado
                    currentState = nextState;

                    // Condición de parada, hemos ido a una celda no navegable o hemos llegado al final
                    if (r == -1 || r == 100)
                    {
                        endOfEpisode = true;
                    }
                } while (!endOfEpisode);

                // Reducimos epsilon, para cada vez explorar menos y usar mas lo aprendido
                if (epsilon >= epsilonMinimumValue)
                {
                    epsilon *= epsilonDecayRate;
                }

                // Actualizamos avance
                float pct = (episode + 1.0f) / numberOfEpisodes;
                if (progressBar != null)
                {
                    progressBar.value = pct;
                }
                if (progressText != null)
                {
                    progressText.text = (int)(pct * 100) + "%";
                }
                if (iterationsText != null)
                {
                    iterationsText.text = "Episodios: " + (episode + 1);
                }

                if (episode % 100 == 0)
                {
                    yield return(null);
                }
            }

            if (loadingPanel)
            {
                loadingPanel.SetActive(false);
            }
            qtable.SaveToCsv("qtable.csv");
        }