Para un ordenador, una foto son solo números
Un ordenador no puede mirar una foto. Guarda una cuadrícula de números, uno por cada punto. Un modelo que admite imágenes lee esos números.
Importa porque cuanto mayor es la cuadrícula, más cuesta enviarla. Esta lección te enseña la cuadrícula y lo que cuesta.
Al final de esta lección
Nota
Puedo explicar cómo una imagen se convierte en números que lee un modelo y qué efecto tienen su tamaño y sus mosaicos en el coste.
Palabras clave
| Palabra | Qué significa |
|---|---|
| Píxel | un punto de una imagen, guardado como número |
| Canal | una parte de color de un píxel: rojo, verde o azul |
| Redimensionar | cambiar el ancho y el alto de una imagen |
| Mosaico | un trozo cuadrado y pequeño de una imagen |
| Multimodal | que admite más de un tipo de entrada, como texto e imágenes |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Una imagen es una cuadrícula de números
Una imagen se divide en filas de puntos diminutos llamados píxeles. En una imagen en gris, cada píxel es un número de 0 (negro) a 255 (blanco).
Una imagen en color guarda tres números por píxel, uno por cada canal: rojo, verde y azul. Así que una imagen en color tiene el triple de números que una gris del mismo tamaño.
Una imagen gris y un píxel de color
| Fila | Píxel 1 | Píxel 2 | Píxel 3 |
|---|---|---|---|
| 1 | 0 | 128 | 255 |
| 2 | 64 | 128 | 192 |
| 3 | 255 | 128 | 0 |
| Un píxel de color | rojo 200 | verde 30 | azul 30 |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Las imágenes grandes se reducen primero
Un modelo solo acepta imágenes hasta cierto tamaño. Una mayor se redimensiona antes de leerla, o se rechaza.
La forma más simple de reducir una cuadrícula es hacer la media de cada bloque de píxeles. Un bloque de 2 por 2, con cuatro píxeles, pasa a ser un píxel. La imagen queda con la mitad de ancho y de alto.
Un error frecuente
Advertencia
Mucha gente cree que un archivo más pequeño es siempre una imagen más barata. El coste sigue al ancho y al alto en píxeles, no al tamaño en disco. Un archivo diminuto puede ser una cuadrícula enorme, así que cuenta siempre los píxeles.
Los mosaicos fijan el coste
Tras redimensionar, la imagen se corta en mosaicos cuadrados. Un mosaico del borde puede estar a medias, pero cuenta como uno entero.
En este laboratorio la regla es una cuota fija de 20 más 10 por cada mosaico de 16 por 16 píxeles. La regla está inventada para la lección. Un servicio real tiene la suya, así que lee siempre su página de precios.
Contar mosaicos de 16 por 16
| Imagen | Mosaicos a lo ancho | Mosaicos a lo alto | Mosaicos | Coste |
|---|---|---|---|---|
| 16 por 16 | 1 | 1 | 1 | 30 |
| 17 por 16 | 2 | 1 | 2 | 40 |
| 40 por 30 | 3 | 2 | 6 | 80 |
| 64 por 64 | 4 | 4 | 16 | 180 |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
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 script de la imagen, parte 1
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { ask } = require(\"./model\");' 'let seed = 7;' 'function next() { seed = (seed * 37 + 11) % 256; return seed; }' 'const image = [];' 'for (let y = 0; y < 6; y++) {' ' const row = [];' ' for (let x = 0; x < 6; x++) row.push(next());' ' image.push(row);' '}' > see1.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 script de la imagen, parte 2
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function shrink(img, f) {' ' const out = [];' ' for (let y = 0; y < img.length; y += f) {' ' const row = [];' ' for (let x = 0; x < img[0].length; x += f) {' ' let sum = 0;' ' for (let j = 0; j < f; j++) for (let i = 0; i < f; i++) sum += img[y + j][x + i];' ' row.push(Math.floor(sum / (f * f)));' ' }' ' out.push(row);' ' }' ' return out;' '}' 'function tiles(w, h, t) { return Math.ceil(w / t) * Math.ceil(h / t); }' >> see1.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 script de la imagen, parte 3
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' ' const small = shrink(image, 2);' ' console.log(\"grande \" + image[0].length + \"x\" + image.length + \" fila 1: \" + image[0].join(\" \"));' ' console.log(\"pequeña \" + small[0].length + \"x\" + small.length + \" fila 1: \" + small[0].join(\" \"));' ' console.log(\"mosaicos de 2: grande \" + tiles(6, 6, 2) + \", pequeña \" + tiles(3, 3, 2));' ' const q = \"En una frase corta, ¿por qué una imagen más pequeña cuesta menos enviarla a un modelo?\";' ' const reply = await ask([{ role: \"user\", content: q }], \"Una imagen más pequeña tiene menos mosaicos, y el precio sigue a los mosaicos.\", 40);' ' console.log(\"respuesta: \" + reply.text);' '}' 'main();' >> see1.js"Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Reduce una imagen y cuenta mosaicos
docker exec -w /home/node/project agent node see1.jsSe muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Las líneas que imprime
| Línea | Qué muestra |
|---|---|
| grande 6x6 fila 1: ... | La primera fila de la imagen inventada |
| pequeña 3x3 fila 1: ... | Cada bloque de 2 por 2 promediado en un píxel |
| mosaicos de 2: grande 9, pequeña 4 | Menos mosaicos tras reducir, así que menor precio |
| respuesta: ... | Una frase del modelo, o antes una línea de Muestra grabada |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.