Sign In
🌳

Técnica del árbol del pensamiento (ToT)

El Árbol de los Pensamientos (Tree of Thoughts) es una técnica de indicaciones para modelos de lenguaje propuesta por Yao y Long en el artículo <Tree of Thoughts (ToT): A Framework for Advanced Problem Solving> publicado en 2023, que resulta especialmente adecuada para tareas complejas donde se requiere pensamiento estratégico y exploración. ToT expande el concepto de las cadenas de pensamiento (Chain-of-Thought, CoT) aprovechando una estructura arborescente de ideas combinada con algoritmos de búsqueda sistemática para resolver problemas.
Large Language Model Guided Tree-of-Thought.pdf388.93KB
Tree of Thoughts- Deliberate Problem Solving with Large Language Models.pdf748.36KB

Cómo funciona ToT

En términos sencillos, la técnica Árbol de los Pensamientos (ToT) representa el proceso de explorar distintas posibilidades y encontrar la solución óptima de un problema a través de una estructura similar a un árbol. Esto permite que el modelo de lenguaje considere varias direcciones, como lo haría una persona, e incluso pueda retroceder y probar otras rutas cuando sea necesario.

Por qué ToT está atrayendo la atención

Estructura de árbol: ToT explora el proceso de resolución de problemas a través de múltiples caminos, como las ramas de un árbol. Cada 'rama' representa una idea o un paso hacia la resolución del problema. (Puedes imaginarlo como la estructura de carpetas que solemos ver en los exploradores de archivos).
Generación y evaluación de ideas: Del mismo modo que una persona considera diversas ideas y evalúa cuál es la mejor para resolver un problema, el modelo de lenguaje propone diferentes soluciones y elige la más óptima.
Exploración y retroceso: se exploran varios caminos para resolver un problema, y si es necesario, se puede volver a pasos anteriores para intentar otra dirección.

Aplicación práctica

El problema de CoT es que no permite retroceder. Si tienes que avanzar hasta el final para ver el resultado y luego continuar la cadena, la principal ventaja de ToT es que puedes retroceder en el proceso y corregirlo en el momento. Como mencionamos antes, supongamos que estamos tratando de resolver un problema matemático difícil para los LLM. Por ejemplo, digamos que se nos presenta un quiz como el siguiente.
"4x4 스도쿠 퍼즐의 빈 칸을 채워 넣으시오."
Método general
Proceso: De la manera común, se encuentran los números que faltan en cada fila, columna y cuadrícula de 2x2 y se rellenan los espacios vacíos uno por uno.
Resultado: Se completa el rompecabezas rellenando en orden los espacios vacíos.
🤖
El Sudoku 4x4 que creé tiene todas las casillas vacías. Por lo tanto, el tablero completo para resolver este rompecabezas sería así:
1 2 3 4
3 4 1 2
2 1 4 3
4 3 2 1
Técnica de ToT
Mensaje adicional del proceso ToT
Paso 1: El modelo de lenguaje sugiere un número para colocar en el primer espacio vacío.
Paso 2: Se determina el número para el siguiente espacio vacío.
Retroceso: Si en algún paso el modelo reconoce que el rompecabezas no tiene solución, vuelve al paso anterior para probar con otro número.
Resultado final: El modelo completa correctamente todos los espacios vacíos y resuelve el rompecabezas.
🤖
Se resolvió el Sudoku 4x4 paso a paso, llenando correctamente todos los espacios vacíos en un total de 14 pasos. El Sudoku completo es el siguiente:
1 2 3 4
3 4 2 1
4 3 1 2
2 1 4 3
A simple vista, puede parecer que no hay mucha diferencia. Pero si revisas el código que utilizó este método, entenderás la diferencia.
Método de indicación normal
# 4x4 Sudoku puzzle generator and solver
import numpy as np
import random

def is_safe(grid, row, col, num):
    """
    Check if it's safe to place a number in a given position.
    """
    # Check if we find the same num in the similar row
    for x in range(4):
        if grid[row][x] == num:
            return False

    # Check if we find the same num in the similar column
    for x in range(4):
        if grid[x][col] == num:
            return False

    # Check if we find the same num in the particular 2x2 matrix
    start_row = row - row % 2
    start_col = col - col % 2
    for i in range(2):
        for j in range(2):
            if grid[i + start_row][j + start_col] == num:
                return False
    return True


def solve_sudoku(grid, row, col):
    """
    Solving the puzzle using backtracking
    """
    # Check if we have reached the 4x4 matrix end
    if row == 3 and col == 4:
        return True
    
    # Check if column value becomes 4, we move to next row
    if col == 4:
        row += 1
        col = 0

    # Check if the current position is filled
    if grid[row][col] > 0:
        return solve_sudoku(grid, row, col + 1)

    for num in range(1, 5):
        # Check if it is safe to place the num
        if is_safe(grid, row, col, num):
            grid[row][col] = num

            # Checking for next possibility with next column
            if solve_sudoku(grid, row, col + 1):
                return True

        # Removing the assigned num
        grid[row][col] = 0
    return False


def generate_sudoku():
    """
    Generate a 4x4 sudoku puzzle
    """
    grid = np.zeros((4,4), dtype=int)

    # Filling the diagonal 2x2 matrices
    for i in range(0, 4, 2):
        num = 1
        for j in range(i, i+2):
            for k in range(i, i+2):
                grid[j][k] = num
                num += 1

    # Removing random numbers to create the puzzle
    for i in range(4):
        remove = random.randint(1,2)  # Number of digits to remove from each row
        while remove > 0:
            col = random.randint(0,3)
            if grid[i][col] != 0:
                grid[i][col] = 0
                remove -= 1

    return grid

# Generate a 4x4 sudoku puzzle
puzzle = generate_sudoku()
puzzle_original = np.copy(puzzle)
# Solve the puzzle
solve_sudoku(puzzle, 0, 0)
puzzle, puzzle_original
Método ToT
# Function to find the next empty cell in the sudoku grid
def find_empty_location(grid):
    for row in range(4):
        for col in range(4):
            if grid[row][col] == 0:
                return row, col
    return -1, -1

# Function to check if a number can be placed in a specific cell
def is_valid(grid, row, col, num):
    # Row check
    if num in grid[row]:
        return False

    # Column check
    if num in [grid[i][col] for i in range(4)]:
        return False

    # 2x2 square check
    start_row, start_col = 2 * (row // 2), 2 * (col // 2)
    for i in range(start_row, start_row + 2):
        for j in range(start_col, start_col + 2):
            if grid[i][j] == num:
                return False

    return True

# Function to solve the sudoku using backtracking
def solve_sudoku_step_by_step(grid, step=0):
    row, col = find_empty_location(grid)
    
    # If there is no empty location, we are done
    if row == -1:
        return True, grid, step

    for num in range(1, 5):
        if is_valid(grid, row, col, num):
            grid[row][col] = num
            solved, final_grid, next_step = solve_sudoku_step_by_step(grid, step + 1)
            
            if solved:
                return True, final_grid, next_step

            # Undo the current cell for backtracking
            grid[row][col] = 0

    return False, grid, step

# Generate a 4x4 sudoku puzzle with some empty spaces
sudoku_puzzle = np.array([
    [1, 0, 0, 0],
    [0, 0, 0, 0],
    [0, 0, 0, 2],
    [0, 0, 0, 0]
])

# Solve the sudoku step by step
solved, final_sudoku, steps = solve_sudoku_step_by_step(sudoku_puzzle)
final_sudoku, steps
Si realizas este proceso con GPT-3.5, podrás verlo de la siguiente manera.
Como se puede ver en los resultados, lo que es posible hacer con GPT-4 también puede reproducirse bastante bien en modelos como GPT-3.5 o LLaMA2 utilizando estas técnicas de indicaciones. (De hecho, con GPT-4 simplemente se resuelve programando).
🧊
📖
ⓒ 2023. Haebom, todos los derechos reservados.
Puede utilizarse con fines comerciales con el permiso del titular de los derechos de autor y con la debida atribución.
👍