Cambia un poco y deja el resto
Un modelo grande tiene miles de millones de números. Entrenarlos todos exige mucha memoria y mucho tiempo. Un adaptador, como un LoRA, entrena unos pocos números extra junto a los grandes y no toca los grandes.
Esta lección cuenta esos números. Ningún laboratorio entrena un modelo, así que el trabajo es aritmética que ejecutas tú.
Al final de esta lección
Nota
Puedo explicar por qué un adaptador pequeño cambia barato un modelo grande.
Palabras clave
| Palabra | Qué significa |
|---|---|
| Parámetro | un número que el modelo ha aprendido |
| Congelado | que no cambia durante el entrenamiento |
| Adaptador | un pequeño conjunto de números nuevos entrenados |
| Rango | lo delgadas que son las dos tablas del adaptador |
| LoRA | un adaptador hecho de dos tablas delgadas |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Una capa es una tabla de números
Dentro de un modelo, una capa es sobre todo una tabla de números. Una tabla de 6 filas y 6 columnas guarda 6 por 6, es decir, 36 parámetros. Una tabla de 100 por 100 guarda 10 000.
El entrenamiento completo cambia todos los números de todas las tablas. Por eso es caro.
Dos tablas delgadas hacen un cambio completo
Multiplica una tabla de 6 por 1 por otra de 1 por 6 y obtienes una tabla de 6 por 6. Tiene la forma de la tabla congelada, así que se puede sumar a ella.
El adaptador guarda 6 más 6, es decir, 12 números, en lugar de 36. El rango es el lado delgado. Un rango mayor guarda más y cuesta más.
Ejemplo resuelto: una tabla de 100 por 100
| Rango | Números del adaptador | Parte de los 10 000 |
|---|---|---|
| 1 | 1 x (100 + 100) = 200 | 2 % |
| 4 | 4 x 200 = 800 | 8 % |
| 8 | 8 x 200 = 1600 | 16 % |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Un error frecuente
Advertencia
Mucha gente cree que un adaptador es una copia más pequeña del modelo. No lo es. El modelo grande se queda como está y el adaptador se suma a su salida. Quita el adaptador y recuperas el modelo original.
Escribe el ayudante del modelo, parte 1
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const base = process.env.AI_URL || \"http://ai:4000\";' '// Los tokens de una respuesta, o null si no trae ninguno.' 'function count(data, name) {' ' return data.usage && typeof data.usage[name] === \"number\" ? data.usage[name] : null;' '}' > model.js"Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Escribe el ayudante del modelo, parte 2
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function ask(messages, sample, max) {' ' try {' ' const res = await fetch(base + \"/v1/chat/completions\", {' ' method: \"POST\",' ' headers: { \"content-type\": \"application/json\", authorization: \"Bearer lab\" },' ' body: JSON.stringify({ model: \"lab\", messages: messages, max_tokens: max || 100 }),' ' signal: AbortSignal.timeout(30000),' ' });' ' if (res.ok === false) throw new Error(\"estado \" + res.status);' ' const d = await res.json();' ' return { text: d.choices[0].message.content, inTokens: count(d, \"prompt_tokens\"), outTokens: count(d, \"completion_tokens\"), recorded: false };' ' } catch (error) {' ' console.log(\"Muestra grabada: ningún modelo respondió (\" + error.message + \").\");' ' return { text: sample, inTokens: null, outTokens: null, recorded: true };' ' }' '}' 'module.exports = { ask };' >> model.js"Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Escribe el contador del adaptador, parte 1
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { ask } = require(\"./model\");' '// Una tabla W congelada de 6 por 6 y dos delgadas: B es de 6 por 1 y A es de 1 por 6.' 'const rows = 6, cols = 6, rank = 1;' 'const B = [1, 2, 0, 1, 0, 3];' 'const A = [2, 0, 1, 0, 1, 1];' > adapt4.js"Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Escribe el contador del adaptador, parte 2
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function delta(i, j) {' ' let sum = 0;' ' for (let k = 0; k < rank; k++) sum = sum + B[i * rank + k] * A[k * cols + j];' ' return sum;' '}' 'const full = rows * cols;' 'const adapter = rank * (rows + cols);' >> adapt4.js"Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Escribe el contador del adaptador, parte 3
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' ' console.log(\"tabla congelada: \" + rows + \" x \" + cols + \" = \" + full + \" números\");' ' console.log(\"adaptador: \" + rows + \" x \" + rank + \" más \" + rank + \" x \" + cols + \" = \" + adapter + \" números\");' ' const first = [];' ' for (let j = 0; j < cols; j++) first.push(delta(0, j));' ' console.log(\"cambio en la fila 0: \" + first.join(\" \"));' ' console.log(\"parte entrenada: \" + Math.floor((adapter * 100) / full) + \" %\");' ' const q = \"En una frase, ¿por qué entrenar un adaptador pequeño es más barato que entrenar todo el modelo?\";' ' const sample = \"Solo cambian las tablas pequeñas del adaptador, así que se guardan y se actualizan muchos menos números.\";' ' const reply = await ask([{ role: \"user\", content: q }], sample, 40);' ' console.log(\"el modelo dijo: \" + reply.text);' '}' 'main();' >> adapt4.js"Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Ejecuta el contador del adaptador
docker exec -w /home/node/project agent node adapt4.jsSe muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Lo que imprimió el contador
Imprime el tamaño de la tabla congelada, el del adaptador, una fila del cambio y la parte entrenada. Los números de A y B son inventados. Un adaptador real los aprende.
La última línea es una llamada corta al modelo, o una Muestra grabada.