Probando el código generado por distintos modelos de AI

Imagen de Probando el código generado por distintos modelos de AI

Acababa de leer de un nuevo modelo que permite, supuestamente, mejores resultados que ChatGPT 4o para código y dije "vamos a probarlo", es un modelo abierto, Qwen 2.5, pero en mi PC no hay memoria para usar la versión full, así que opté por una versión "recortada".

El resultado fue patético, no funcionaba ni podía corregirlo 😁🤷, pero vamos, en vez de usar el modelo con 30 billones de parámetros estaba con el de 3 billones, como que era una décima parte, me dije ¿y si le hago la misma pregunta a todos?

Le tiré algo fácil: 

"I need a complete script in PHP that loads a JPG, PNG or WebP image and converts it to a dithered two colour degraded picture of the same size"

Porque es algo que ya hago en la versión TXT de mi sitio así que ¿Por qué no? Veamos los resultados...

Está claro que un pedido de código en una sola línea no es un test serio, pero no me importa, estaba divirtiéndome, así que tómenlo con pinzas como corresponde.

Les di esta imagen como input y me deberían devolver una imagen "procesada" con dithering, que sirve para convertir a dos colores (blanco y negro) al viejísimo estilo de una vieja TXT monocromo 😁 ¿podrán?

Casi todos tomarán el camino del algoritmo Floyd-Steinberg para crear una imagen dithered, pero no siempre lo entienden...

Qwen 2.5 3B Instruct

Usé la versión más pequeña aceptable para mi GPU, sin embargo el código que me devolvió fallaba y nunca dio ni un resultado.

Es curioso que llama en medio del código a la función imagesetpixel() y en un caso le tira tres parámetros y en otro cuatro, fallaba en uno, le avisé, nunca pudo corregir el error.

Pero ese no es el problema real, el código que me devolvió  entra en loop infinito y come todos los recursos de PHP, onda, no va, ni me puse a debuguear más, simplemente lo que devuelve es basura.

<?php // Qwen 2.5 Coder 3B Instruct // Q8 3.62Gb // Function to load and convert an image to a dithered, two-color degraded version function convertToDitheredTwoColor($inputPath, $outputPath) { // Load the input image $image = imagecreatefromjpeg($inputPath); if (!$image) { $image = imagecreatefrompng($inputPath); if (!$image) { $image = imagecreatefromwebp($inputPath); } } if (!$image) { die("Failed to load the input image."); } // Get the dimensions of the image $width = imagesx($image); $height = imagesy($image); // Create a new blank image with the same dimensions $outputImage = imagecreatetruecolor($width, $height); if (!$outputImage) { die("Failed to create a new output image."); } // Define the colors: black and white $blackColor = imagecolorallocate($outputImage, 0, 0, 0); $whiteColor = imagecolorallocate($outputImage, 255, 255, 255); // Dithering algorithm: Floyd-Steinberg dithering for ($y = 0; $y < $height; $y++) { for ($x = 0; $x < $width; $x++) { // Get the current pixel color in RGB list($red, $green, $blue) = imagecolorsforindex($image, imagesetpixel($image, $x, $y)); // Calculate the average of red, green, and blue to determine the brightness level $brightness = round(($red + $green + $blue) / 3); // Assign the closest color (black or white) if ($brightness < 128) { imagefilledrectangle($outputImage, $x, $y, $x + 1, $y + 1, $whiteColor); } else { imagefilledrectangle($outputImage, $x, $y, $x + 1, $y + 1, $blackColor); } // Apply Floyd-Steinberg dithering $error = $brightness - (($brightness < 128) ? 0 : 255); // Distribute the error to neighboring pixels if ($x > 0 && $y > 0) { imagesetpixel($outputImage, $x - 1, $y - 1, imagecolorallocatealpha($outputImage, 0, 0, 0, (int)(255 * ($error / 16)))); } if ($y > 0) { imagesetpixel($outputImage, $x, $y - 1, imagecolorallocatealpha($outputImage, 0, 0, 0, (int)(255 * ($error / 16)))); } if ($x < $width - 1 && $y > 0) { imagesetpixel($outputImage, $x + 1, $y - 1, imagecolorallocatealpha($outputImage, 0, 0, 0, (int)(255 * ($error / 16)))); } if ($x > 0) { imagesetpixel($outputImage, $x - 1, $y, imagecolorallocatealpha($outputImage, 0, 0, 0, (int)(255 * ($error / 16)))); } if ($x < $width - 1) { imagesetpixel($outputImage, $x + 1, $y, imagecolorallocatealpha($outputImage, 0, 0, 0, (int)(255 * ($error / 16)))); } } } // Save the output image if (!imagejpeg($outputImage, $outputPath)) { die("Failed to save the output image."); } echo "Dithered two-color image saved to: " . $outputFilePath; } // Example usage $inputFilePath = 'input.jpg'; // Replace with your input image path $outputFilePath = 'output-qwen.jpg'; // Specify the output file path convertToDitheredTwoColor($inputFilePath, $outputFilePath); ?>

Qwen 2.5 Coder 14B Instruct

Le di powa a una versión mucho más grande a ver si me podía producir un código decente, el código resultante fue muy distinto, muy elegante, se nota que si vas subiendo en complejidad mejora mucho, pero era uno cuantizado en Q4 que es como sacarle unos cuantos ceros

<?php function loadImage($filePath) { $imageInfo = getimagesize($filePath); $mimeType = $imageInfo['mime']; switch ($mimeType) { case 'image/jpeg': return imagecreatefromjpeg($filePath); case 'image/png': return imagecreatefrompng($filePath); case 'image/webp': return imagecreatefromwebp($filePath); default: throw new Exception("Unsupported file format"); } } function saveImage($image, $outputPath) { if (file_exists($outputPath)) { unlink($outputPath); // Delete the existing file } imagepng($image, $outputPath); // Save as PNG imagedestroy($image); } function ditherImage($inputFilePath, $outputFilePath) { $originalImage = loadImage($inputFilePath); $width = imagesx($originalImage); $height = imagesy($originalImage); // Create a new blank image with the same size $ditheredImage = imagecreatetruecolor($width, $height); // Define colors (black and white) $black = imagecolorallocate($ditheredImage, 0, 0, 0); $white = imagecolorallocate($ditheredImage, 255, 255, 255); for ($y = 0; $y < $height; $y++) { for ($x = 0; $x < $width; $x++) { $rgb = imagecolorat($originalImage, $x, $y); $red = ($rgb >> 16) & 0xFF; $green = ($rgb >> 8) & 0xFF; $blue = $rgb & 0xFF; // Calculate luminance $luminance = (int)(0.299 * $red + 0.587 * $green + 0.114 * $blue); // Determine the pixel color based on luminance if ($luminance > 127) { imagesetpixel($ditheredImage, $x, $y, $white); } else { imagesetpixel($ditheredImage, $x, $y, $black); } // Calculate the error $error = $luminance - (imagesetpixel($ditheredImage, $x, $y, $white) ? 255 : 0); // Apply diffusion to neighboring pixels if ($x + 1 < $width) { imagesetpixel($originalImage, $x + 1, $y, imagecolorat($originalImage, $x + 1, $y) + (int)(7 / 16 * $error)); } if ($x > 0 && $y + 1 < $height) { imagesetpixel($originalImage, $x - 1, $y + 1, imagecolorat($originalImage, $x - 1, $y + 1) + (int)(3 / 16 * $error)); } if ($y + 1 < $height) { imagesetpixel($originalImage, $x, $y + 1, imagecolorat($originalImage, $x, $y + 1) + (int)(5 / 16 * $error)); } if ($x + 1 < $width && $y + 1 < $height) { imagesetpixel($originalImage, $x + 1, $y + 1, imagecolorat($originalImage, $x + 1, $y + 1) + (int)(1 / 16 * $error)); } } } saveImage($ditheredImage, $outputFilePath); } // Example usage $inputPath = 'input.jpg'; $outputPath = 'output-qwen10.png'; try { ditherImage($inputPath, $outputPath); echo "Dithered image saved to: $outputPath"; } catch (Exception $e) { echo "Error: " . $e->getMessage(); } ?>

Lamentablemente el resultado de este bello código es una imagen en blanco, no me sirve de nada 🤷 el error debe ser mínimo, pero si la idea era que el LLM produjera un resultado ejecutable de una, no funcionó

ChatGPT (free)

Creo que la versión libre de ChatGPT usa 3.5 o, cuando puede, 4o, no tengo idea porque tampoco te avisa, sin embargo me devolvió un código decente que funciona.

<?php function loadImage($filename) { $image = null; $imageInfo = getimagesize($filename); switch ($imageInfo['mime']) { case 'image/jpeg': $image = imagecreatefromjpeg($filename); break; case 'image/png': $image = imagecreatefrompng($filename); break; case 'image/webp': $image = imagecreatefromwebp($filename); break; default: die("Unsupported image format. Please use JPG, PNG, or WebP."); } return $image; } function ditherImage($image) { $width = imagesx($image); $height = imagesy($image); // Create a black and white palette for the output $black = imagecolorallocate($image, 0, 0, 0); $white = imagecolorallocate($image, 255, 255, 255); // Convert the image to grayscale and apply Floyd-Steinberg dithering for ($y = 0; $y < $height; $y++) { for ($x = 0; $x < $width; $x++) { // Get the current pixel's color value $rgb = imagecolorat($image, $x, $y); $gray = (int)((($rgb >> 16) & 0xFF) * 0.3 + (($rgb >> 8) & 0xFF) * 0.59 + ($rgb & 0xFF) * 0.11); // Decide if the pixel should be black or white based on a threshold $newColor = ($gray < 128) ? 0 : 255; $error = $gray - $newColor; // Set the new color imagesetpixel($image, $x, $y, ($newColor == 0) ? $black : $white); // Apply error diffusion (Floyd-Steinberg) if ($x + 1 < $width) { $nextPixel = imagecolorat($image, $x + 1, $y); imagesetpixel($image, $x + 1, $y, $nextPixel + ($error * 7 / 16)); } if ($x - 1 >= 0 && $y + 1 < $height) { $nextPixel = imagecolorat($image, $x - 1, $y + 1); imagesetpixel($image, $x - 1, $y + 1, $nextPixel + ($error * 3 / 16)); } if ($y + 1 < $height) { $nextPixel = imagecolorat($image, $x, $y + 1); imagesetpixel($image, $x, $y + 1, $nextPixel + ($error * 5 / 16)); } if ($x + 1 < $width && $y + 1 < $height) { $nextPixel = imagecolorat($image, $x + 1, $y + 1); imagesetpixel($image, $x + 1, $y + 1, $nextPixel + ($error * 1 / 16)); } } } return $image; } function saveImage($image, $outputFilename) { // Save the dithered image as a PNG to avoid further quality loss imagepng($image, $outputFilename); imagedestroy($image); } // Main execution $inputFile = 'input.jpg'; // Path to your input image $outputFile = 'output-chatgpt.png'; // Path to save the dithered image $image = loadImage($inputFile); $ditheredImage = ditherImage($image); saveImage($ditheredImage, $outputFile); echo "Dithered image saved as " . $outputFile; ?>

El resultado no está mal en sí, es un dither, pero el fondo lo mandó todo a negro sin efectos, de hecho, tiene muchas cosas mejorables para que no quede todo blanco y negro y emule una escala de grises, el que yo uso en mi blog txt es mejor que este.

Meta AI (Llama 3.2?)

En teoría Meta.ai utiliza Llama 3.2 en su versión más grande 405B, que es una barbaridad de tamaño, el código también funciona:

<?php /** * Dither an image to two colors. * * @param string $inputFile Input image file path. * @param string $outputFile Output image file path. * @param int $threshold Threshold value (0-255) for dithering. * @param int $color1 RGB value for first color (e.g., 0x000000 for black). * @param int $color2 RGB value for second color (e.g., 0xFFFFFF for white). */ function ditherImage($inputFile, $outputFile, $threshold = 127, $color1 = 0x000000, $color2 = 0xFFFFFF) { // Load image $image = loadImage($inputFile); // Convert image to grayscale imagefilter($image, IMG_FILTER_GRAYSCALE); // Apply dithering algorithm for ($y = 0; $y < imagesy($image); $y++) { for ($x = 0; $x < imagesx($image); $x++) { $pixelColor = imagecolorat($image, $x, $y); $grayLevel = ($pixelColor >> 16) & 0xFF; // Get gray level from RGB // Apply threshold $newColor = ($grayLevel > $threshold) ? $color2 : $color1; // Set new pixel color imagesetpixel($image, $x, $y, $newColor); } } // Save output image saveImage($image, $outputFile); } /** * Load image from file. * * @param string $file Image file path. * * @return resource GD image resource. */ function loadImage($file) { $ext = pathinfo($file, PATHINFO_EXTENSION); switch ($ext) { case 'jpg': case 'jpeg': return imagecreatefromjpeg($file); case 'png': return imagecreatefrompng($file); case 'webp': return imagecreatefromwebp($file); default: throw new Exception("Unsupported image format."); } } /** * Save image to file. * * @param resource $image GD image resource. * @param string $file Output image file path. */ function saveImage($image, $file) { $ext = pathinfo($file, PATHINFO_EXTENSION); switch ($ext) { case 'jpg': case 'jpeg': imagejpeg($image, $file); break; case 'png': imagepng($image, $file); break; case 'webp': imagewebp($image, $file); break; default: throw new Exception("Unsupported output format."); } imagedestroy($image); } // Example usage: $inputFile = 'input.jpg'; $outputFile = 'output-metaai.png'; ditherImage($inputFile, $outputFile);

El resultado es similar al de ChatGPT aunque se nota un poco más croto, no está mal, no sé cuánta diferencia hay en lo que hace, pero esto dio

Copilot (ChatGPT?)

En teoría Copilot de Microsoft utiliza ChatGPT de backend, el resultado es muy distinto en el código, menos detallado en los comentarios también.

<?php function ditherImage($inputPath, $outputPath, $color1, $color2) { // Load the image $info = getimagesize($inputPath); $mime = $info['mime']; switch ($mime) { case 'image/jpeg': $image = imagecreatefromjpeg($inputPath); break; case 'image/png': $image = imagecreatefrompng($inputPath); break; case 'image/webp': $image = imagecreatefromwebp($inputPath); break; default: die('Unsupported image type'); } $width = imagesx($image); $height = imagesy($image); // Create the output image $output = imagecreatetruecolor($width, $height); $color1 = imagecolorallocate($output, $color1[0], $color1[1], $color1[2]); $color2 = imagecolorallocate($output, $color2[0], $color2[1], $color2[2]); // Convert to dithered two-color image for ($y = 0; $y < $height; $y++) { for ($x = 0; $x < $width; $x++) { $rgb = imagecolorat($image, $x, $y); $r = ($rgb >> 16) & 0xFF; $g = ($rgb >> 8) & 0xFF; $b = $rgb & 0xFF; $gray = ($r + $g + $b) / 3; if ($gray < 128) { imagesetpixel($output, $x, $y, $color1); } else { imagesetpixel($output, $x, $y, $color2); } } } // Save the output image imagepng($output, $outputPath); // Free memory imagedestroy($image); imagedestroy($output); } // Example usage $inputPath = 'input.jpg'; // Path to the input image $outputPath = 'output-copilot.png'; // Path to the output image $color1 = [0, 0, 0]; // First color (black) $color2 = [255, 255, 255]; // Second color (white) ditherImage($inputPath, $outputPath, $color1, $color2);

El resultado es más bajo que el de Meta inclusive, aunque en términos generales se "entiende", pero la imagen es todo y no alcanza

Qwen 2.5 72B Instruct

Fuck it! dije! me busqué un servidor donde corrieran este nuevo modelo para ver si en su versión full era tan potente como decían, vamos, en algún lado debía estar y dónde mejor que en Hugginface, así que me decidí a probarlo allí y me dio esto:

<?php function load_image($filename) { $info = getimagesize($filename); if ($info === false) { die("Failed to get image information"); } switch ($info[2]) { case IMAGETYPE_JPEG: return imagecreatefromjpeg($filename); case IMAGETYPE_PNG: return imagecreatefrompng($filename); case IMAGETYPE_WEBP: return imagecreatefromwebp($filename); default: die("Unsupported image type"); } } function save_image($image, $filename, $type) { switch ($type) { case IMAGETYPE_JPEG: imagejpeg($image, $filename); break; case IMAGETYPE_PNG: imagepng($image, $filename); break; case IMAGETYPE_WEBP: imagewebp($image, $filename); break; default: die("Unsupported image type"); } } function dither_image($image) { $width = imagesx($image); $height = imagesy($image); // Create a new image with the same dimensions $new_image = imagecreatetruecolor($width, $height); // Allocate colors $black = imagecolorallocate($new_image, 0, 0, 0); $white = imagecolorallocate($new_image, 255, 255, 255); for ($y = 0; $y < $height; $y++) { for ($x = 0; $x < $width; $x++) { $rgb = imagecolorat($image, $x, $y); $r = ($rgb >> 16) & 0xFF; $g = ($rgb >> 8) & 0xFF; $b = $rgb & 0xFF; // Calculate the average color intensity $intensity = ($r + $g + $b) / 3; // Dithering using a simple threshold if ($intensity > 127) { imagesetpixel($new_image, $x, $y, $white); } else { imagesetpixel($new_image, $x, $y, $black); } } } return $new_image; } // Main script $filename = 'input.jpg'; // Change this to your input file $output_filename = 'output-qwen72b.jpg'; // Change this to your desired output file // Load the image $image = load_image($filename); // Dither the image $dithered_image = dither_image($image); // Save the dithered image $save_type = exif_imagetype($filename); save_image($dithered_image, $output_filename, $save_type); // Free up memory imagedestroy($image); imagedestroy($dithered_image); echo "Image processed and saved as $output_filename"; ?>

Ahora sí funcionó! 

El resultado es similar a ChatGPT y otros, no me puedo quejar, podría ser mejor, pero al menos, cuando vamos a la versión full de Qwen 2.5 estamos al mismo nivel de esta simple prueba.

Codellama 13B Instruct

Con esta versión del modelo de Meta conseguí el resultado más falopa, no en el código que se ve perfectamente normal aunque extremadamente pequeño comparado con el resto, sino en el resultado final que no cumple un cuerno con lo pedido

<html> <?php // Codellama 13B Instruct // Q4 // 7.37GB $image_filename = "input.jpg"; // Input Image $output_filename = "output-codellama.png"; // Output image function dither($img) { $size = getimagesize($img); $width = $size[0]; $height = $size[1]; $img = imagecreatefromstring(file_get_contents($img)); $img2 = imagecreatetruecolor($width, $height); for ($i=0; $i < $width; $i++) { for ($j=0; $j < $height; $j++) { $rgb = imagecolorat($img, $i, $j); $r = (($rgb >> 16) & 0xFF) / 255.0; $g = (($rgb >> 8) & 0xFF) / 255.0; $b = ($rgb & 0xFF) / 255.0; // Dithering calculation: if(round($r*2)/2 > round($g*2)/2 && round($r*2)/2 > round($b*2)/2) { $color = imagecolorallocate($img2, 255, 0, 0); } // Red elseif (round($g*2)/2 > round($b*2)/2) { $color = imagecolorallocate($img2, 0, 255, 0); } // Green else { $color = imagecolorallocate($img2, 0, 0, 255); } // Blue imagesetpixel ($img2, $i, $j, $color); } } return $img2; } $ditheredImage = dither($image_filename); imagepng($ditheredImage,$output_filename); ?> <body> <p><img src="<?php echo $output_filename ?>"></p> </body> </html>

Vean tan sólo el delirio psicodélico que me regaló, genial resultado, ejjeej

Claude 3.5

Y por último el que, yo considero o creo, es el mejor de todos para código en este momento, el gallo claudio, tiene limitaciones de tokens si querés usarlo para mucho, pero si pagás da bastante más (algunos se quejan hasta de la versión paga).

Para una función simple como esta va perfecto:

<?php function ditherImage($inputPath, $outputPath) { // Validate input file existence if (!file_exists($inputPath)) { throw new Exception("Input file does not exist"); } // Get image info and create appropriate image resource $imageInfo = getimagesize($inputPath); if ($imageInfo === false) { throw new Exception("Invalid image file"); } switch ($imageInfo[2]) { case IMAGETYPE_JPEG: $source = imagecreatefromjpeg($inputPath); break; case IMAGETYPE_PNG: $source = imagecreatefrompng($inputPath); break; case IMAGETYPE_WEBP: $source = imagecreatefromwebp($inputPath); break; default: throw new Exception("Unsupported image format"); } // Get dimensions $width = imagesx($source); $height = imagesy($source); // Create grayscale version $grayscale = imagecreatetruecolor($width, $height); imagefilter($source, IMG_FILTER_GRAYSCALE); // Create output image $output = imagecreatetruecolor($width, $height); // Define black and white colors $white = imagecolorallocate($output, 255, 255, 255); $black = imagecolorallocate($output, 0, 0, 0); // Array to store grayscale values $pixels = array(); // Get grayscale values for ($y = 0; $y < $height; $y++) { for ($x = 0; $x < $width; $x++) { $rgb = imagecolorat($source, $x, $y); $r = ($rgb >> 16) & 0xFF; $pixels[$y][$x] = $r; // Since it's grayscale, we only need one channel } } // Floyd-Steinberg dithering for ($y = 0; $y < $height; $y++) { for ($x = 0; $x < $width; $x++) { $oldPixel = $pixels[$y][$x]; $newPixel = ($oldPixel < 128) ? 0 : 255; imagesetpixel($output, $x, $y, ($newPixel == 0) ? $black : $white); $error = $oldPixel - $newPixel; // Distribute error to neighboring pixels if ($x + 1 < $width) { $pixels[$y][$x + 1] += ($error * 7/16); } if ($y + 1 < $height) { if ($x > 0) { $pixels[$y + 1][$x - 1] += ($error * 3/16); } $pixels[$y + 1][$x] += ($error * 5/16); if ($x + 1 < $width) { $pixels[$y + 1][$x + 1] += ($error * 1/16); } } } } // Save the output image imagepng($output, $outputPath); // Clean up imagedestroy($source); imagedestroy($output); return true; } // Example usage try { $inputPath = "input.jpg"; // Replace with your input image path $outputPath = "output-claude.png"; // Replace with your desired output path ditherImage($inputPath, $outputPath); echo "Image successfully dithered and saved!"; } catch (Exception $e) { echo "Error: " . $e->getMessage(); } ?>

El resultado en imagen es realmente lo que esperaba, a diferencia de los otros Claude implementó bien el algoritmo Floyd-Steinberg y el resultado es notablemente superior:

Opinología

Probé Gemma de Google, nada, imagen vacía, al menos no tiró error, también Llama 3.2 instruct 3B (Q8 de 3.42GB) para probar, cero resultado de imagen, así que no culpo a las versiones pequeñas de Qwen, la realidad es que si vas a usar un modelo de LLM para programar, por más que den código como resultado, si el LLM es pequeño ese código será una porquería que no funciona.

Con un poco de debug lo sacás funcionando, sí, está bien, pero la idea es que justamente todo funcione como debe ser, de una, con poco trabajo, aquí sólo pedí una función muy simple, nada alocado.

De todos el único que implementó correctamente el algoritmo Floyd-Steinberg fue Claude, el resto se acercó bastante salvo los fallidos que también lo intentaron pero no pasaron el filtro. En tamaño de imagen la versión de Meta.ai y la de Copilot fueron las más eficientes (35Kb), la de Claude la menos, pesa tanto (170Kb) como la original en color (180Kb). En todos los casos respetaron el tamaño original de 1024x1024, por eso la de Claude pesa mucho, es un algoritmo ineficiente para imágenes grandes.

En todos los casos el LLM explicó el uso de la función y qué hacía cada parámetro, inclusive algunos se excusaron de no implementar en detalle el algoritmo, como diciendo que se podía mejorar (por qué cuernos no lo hiciste mejor???), esto es muy útil si se está aprendiendo un nuevo lenguaje o framework.

En fin, si quieren probar su propia versión o corregir/encontrarle el error a estos algoritmos, bienvenidos sean 😋


Volver al inicio Ver original

copyright©2025 Fabio Baccaglioni - Fabio.com.ar - Versión simplificada Old School