Este proyecto pretende ser una reimplementación limpia y concisa de GPT-2. La implementación del modelo, contenida en src/model.rs
, tiene menos de 300 líneas de código. Si bien este fue un ejercicio divertido principalmente para (mis propios) fines educativos, demuestra la utilidad de Rust and Burn en el dominio del aprendizaje automático: todo el proyecto se compila en un único binario, lo que hace que la implementación sea relativamente sencilla.
Por el momento, solo se admite un tokenizador a nivel de personaje, por lo que aún no se pueden usar pesos oficiales que requieran un tokenizador BPE. Sin embargo, para divertirte, puedes probar el modelo de juguete pequeño que entrené (ver inferencia).
El proyecto también incluye una CLI sencilla para entrenamiento e inferencia.
Usage: gpt-burn <COMMAND>
Commands:
run Generate text using a pre-trained model
train Train a new model
Puedes instalar gpt-burn
con Nix:
nix run github:felix-andreas/gpt-burn
O instalar con cargo
:
cargo install --git https://github.com/felix-andreas/gpt-burn
Alternativamente, clone el repositorio y compílelo desde la fuente:
nix develop # optional
cargo run --release
Si no usas Nix y estás en una distribución basada en Ubuntu, necesitas instalar estas dependencias adicionales:
apt install pkg-config libssl-dev libvulkan1 mesa-vulkan-drivers vulkan-tools
Entrené un modelo de juguete con un tokenizador a nivel de personaje en el corpus de Wikipedia en alemán para 20.000 lotes (tamaño de lote de 128) con los siguientes parámetros:
Parámetro | Valor |
---|---|
parámetros | 83M |
longitud del contexto | 128 |
n_layers | 12 |
n_heads | 12 |
d_model | 768 |
Puede descargarlo aquí y extraerlo luego. O haga ambas cosas en un solo comando:
curl -s ' https://drive.usercontent.google.com/download?id=1GGLaPnmPQ8Z2B9vJQoI6-K128X9LJKG0&export=download&confirm=t ' | tar xzf -
Luego, ejecuta el modelo:
gpt-burn run ./model_83M
Deberías ver algo como esto:
So wurden bis 1977 679 nachhaltige Wörgler Torbauten vorgeworfen, die Einwohnerzahl Sirkes bestand 2015 bis 1998.
Sie war trotz weniger als 10.000 ausgedehnter Größen wahrscheinlich auf folgende Breitenauflagen mit 932 km.
2016 wurden rund 145 Händen nach Deutschland geladen.
Otras opciones de línea de comando son:
Usage: gpt-burn run [OPTIONS] <MODEL_PATH>
Arguments:
<MODEL_PATH>
Options:
-p, --prompt <PROMPT>
-n, --n-new-tokens <N_NEW_TOKENS> [default: 1000]
-s, --seed <SEED> [default: 0]
Para entrenar su propio modelo, ejecute:
gpt-burn train --context-length 128 --n-layers 12 --n-heads 12 --d-model 768 --batch-size 128 --learning-rate 0.0003 --seed 0 --text-corpus ./corpus.txt
Importante
¡Asegúrese de que corpus.txt
sea un archivo de texto codificado en utf-8!
Puede pasar la mayoría de los hiperparámetros como una opción de línea de comando:
Usage: gpt-burn train [OPTIONS]
Options:
-o, --output-path <PATH>
-c, --context-length <CONTEXT_LENGTH> [default: 64]
-d, --d-model <D_MODEL> [default: 64]
-l, --n-layers <N_LAYERS> [default: 2]
-h, --n-heads <N_HEADS> [default: 2]
-n, --n-steps <N_STEPS> [default: 50]
-b, --batch-size <BATCH_SIZE> [default: 32]
-r, --learning-rate <LEARNING_RATE> [default: 0.003]
-s, --seed <SEED> [default: 0]
-t, --text-corpus <TEXT_CORPUS> [default: .data/corpus.txt]
-m, --n-mega-bytes <N_MEGA_BYTES> Only use first <n> megabytes of dataset for training
-x, --no-save Don't save trained model (useful for debugging)
El modelo se puede utilizar con diferentes tokenizadores mediante el rasgo Tokenizer
. A continuación puedes ver cómo la siguiente frase
Albert Einstein war ein schweizerisch-US-amerikanischer theoretischer Physiker deutscher Herkunft.
está codificado por los diferentes tokenizadores.
CharTokenizer
divide cada carácter en un token separado:
Tokens: ["A", "l", "b", "e", "r", "t", " ", "E", "i", "n", "s", "t", "e", "i", "n", " ", "w", "a", "r", " ", "e", "i", "n", " ", "s", "c", "h", "w", "e", "i", "z", "e", "r", "i", "s", "c", "h", "-", "U", "S", "-", "a", "m", "e", "r", "i", "k", "a", "n", "i", "s", "c", "h", "e", "r", " ", "t", "h", "e", "o", "r", "e", "t", "i", "s", "c", "h", "e", "r", " ", "P", "h", "y", "s", "i", "k", "e", "r", " ", "d", "e", "u", "t", "s", "c", "h", "e", "r", " ", "H", "e", "r", "k", "u", "n", "f", "t", "."]
Values: [28, 13, 3, 6, 19, 21, 1, 32, 10, 15, 20, 21, 6, 10, 15, 1, 24, 2, 19, 1, 6, 10, 15, 1, 20, 4, 9, 24, 6, 10, 27, 6, 19, 10, 20, 4, 9, 66, 48, 46, 66, 2, 14, 6, 19, 10, 12, 2, 15, 10, 20, 4, 9, 6, 19, 1, 21, 9, 6, 16, 19, 6, 21, 10, 20, 4, 9, 6, 19, 1, 43, 9, 26, 20, 10, 12, 6, 19, 1, 5, 6, 22, 21, 20, 4, 9, 6, 19, 1, 35, 6, 19, 12, 22, 15, 7, 21, 67]
SimpleVowelTokenizer
divide las palabras antes de la siguiente vocal si el fragmento tiene más de tres caracteres, creando un resultado que se asemeja a las sílabas:
Tokens: ["Albert", " ", "Einst", "ein", " ", "war", " ", "ein", " ", "schw", "eizer", "isch", "-", "US", "-", "amer", "ikan", "isch", "er", " ", "theor", "etisch", "er", " ", "Phys", "iker", " ", "deutsch", "er", " ", "Herk", "unft"]
Values: [2, 0, 3, 9, 0, 19, 0, 9, 0, 16, 10, 15, 1, 6, 1, 7, 13, 15, 11, 0, 17, 12, 11, 0, 5, 14, 0, 8, 11, 0, 4, 18]