Kodsuz/düşük kodlu ortamların artan kullanılabilirliği ve programlamaya uygulanan yapay zekanın ortaya çıkışıyla birlikte, son kullanıcıların kendi uygulamalarını oluşturacağı veya yapay zekanın kendi uygulamalarını yaratacağı için programcılar için sonun yakın olduğunu söyleyen bir dizi makale yayınlandı. Açıklamalardan uygulamalar yazın. Belki... ama henüz değil.
Bu makalede, OpenAI ChatGPT ve Codex'in Microsoft Copilot önerilerini elle yazılmış kodla karşılaştırarak yapay zeka destekli kodlamanın mevcut durumunu araştırıyorum. Yapay zekalar ya ortalama ya da kusurlu kod üretir.
Günümüzde büyük hacimli verilerin işlenmesine çok fazla odaklanıldığı için (ChatGPT ve Copilot için kullanılan büyük dil modelleri dahil), verileri verimli bir şekilde işlemenin anahtarı olan algoritmalara odaklanıyorum. Umarım yapay zekalar kendi doğalarını genel olarak koddan daha iyi "anlarlar"!
Bu algoritmalar şunlardır:
kavşak
Çapraz ürün
not alma
ChatGPT'ye formun talimatlarını verdim:
Bana <bazı fonksiyon açıklamalarını> göster
Codex'e girdi sağladım:
<bazı fonksiyon açıklamaları>
Copilot'a bir WebStorm IDE'sinde yorumlar sağladım
// <bazı fonksiyon açıklamaları>
İşlev açıklamaları her biri için aynıydı.
Hız artı bellek ve CPU kullanımı elde etmek için Benchtest'te bulunana benzer kodla desteklenen birim test donanımı olarak Jasmine'i kullandım.
Bana değişken sayıda dizi alan ve bunların kesişimini döndüren bir JavaScript işlevi gösterin.
function intersection(...arrays) { if (arrays.length < 2) { throw new Error("At least 2 arrays are required!"); } let result = new Set(arrays.shift()); for (let arr of arrays) { result = new Set([...result].filter(x => arr.includes(x))); } return [...result]; }
function intersection(arrays) { var result = []; var args = Array.prototype.slice.call(arguments); var arrays = args.slice(0, args.length - 1); var callback = args[args.length - 1]; var minLength = Math.min.apply(null, arrays.map(function(arr) { return arr.length; })); for (var i = 0; i < minLength; i++) { var item = arrays[0][i]; var isInAll = arrays.every(function(arr) { return arr.indexOf(item) !== -1; }); if (isInAll) { result.push(item); } } return callback(result); }
const intersection = (...arrays) => { const [first, ...rest] = arrays; return first.filter(x => rest.every(y => y.includes(x))); }
ChatGPT, birden az dizi sağlamanın geçerli olmadığını varsaydı. Tek bir argüman sunmanın geçerli olabileceği durumları hayal edebiliyorum.
Set kullanarak ChatGPT, sonuçlarda kopyaların bulunmamasını sağlar. Kesişimin ayarlanmış bir işlem olması gerekiyor ve kopyalar kaldırılmalıdır. Copilot kodu kopyalar içerebilecek bir dizi döndürecektir.
Ne ChatGPT ne de Copilot orijinal argümanları uzunluğa göre artan şekilde sıralamaz. Bu büyük bir fark yaratabilecek önemsiz bir optimizasyondur!
Herhangi bir argümanın uzunluğu sıfırsa kesişim yoktur; ne olursa olsun, maksimum kesişim en kısa dizi argümanıyla aynı olduğundan döngüleri kısaltır.
Codex, bilgilerime dayanarak oldukça verimli görünen karmaşık bir kod sağladı. Bununla birlikte, argümanların kullanımı belirsizdir ve biraz arkaik bir programlama stili içerir.
Kesişimi çağıran koda döndürmek için son argüman olarak bir geri çağırmanın sağlanması gerektiğini unutmayın, ancak argüman gösterilmemiştir.
Daha sonra ChatGPT ve Copilot'tan bana verimli bir işlev vermelerini istedim.
Değişken sayıda diziyi alıp bunların kesişimini döndüren etkili bir JavaScript işlevi gösterin.
function intersection(...arrays) { if (arrays.length < 2) { throw new Error("At least 2 arrays are required!"); } let result = new Set(); for (let item of arrays[0]) { let include = true; for (let i = 1; i < arrays.length; i++) { if(!arrays[i].includes(item)){ include = false; break; } } if(include){ result.add(item); } } return [...result]; }
Copilot ilk istekle aynı kodu oluşturdu.
ChatGPT ayrıca, işlevin nesneler için beklendiği gibi çalışmayacağını söyleyen bir yorum da ekledi; ancak muhtemelen çalışacaktır. Bu yüzden nesneleri destekleyecek bir işlev istedim:
Nesneleri veya temel öğeleri içeren değişken sayıda diziyi alan ve bunların kesişimini döndüren etkili bir JavaScript işlevi gösterin.
function intersection(...arrays) { if (arrays.length < 2) { throw new Error("At least 2 arrays are required!"); } let result = new Set(); for (let item of arrays[0]) { let include = true; for (let i = 1; i < arrays.length; i++) { if(!arrays[i].find(x => JSON.stringify(x) === JSON.stringify(item))){ include = false; break; } } if(include){ result.add(item); } } return [...result]; } This function takes an arbitrary number of arrays as arguments and first checks if at least 2 arrays are passed. Then it uses a nested loop. The outer loop iterates over the first array and the inner loop iterates over the remaining arrays. It compares each item of the first array with each item of the remaining arrays using Array.prototype.find() method and JSON.stringify() to check if the objects are the same. If an item is found in all arrays, it is added to
ChatGPT, karşılaştırılacak nesneleri dizeler. Bununla ilgili bir takım sorunlar var:
Aynı dize temsiline sahip iki nesne, yasal olarak ayrı nesneler olabilir.
Dizgeleştirme geçerli olsa bile, farklı özellik sıraları farklı dizelerle sonuçlanacaktır ve nesneler aynı varlığı temsil ediyor olabilir.
JSON.stringify ve ardından dize karşılaştırması yavaş bir işlemdir.
Ve şimdi gerçek test! Aşağıda ChatGPT, Codex, Copilot ve NPM aracılığıyla kullanılabilen en hızlı iki kesişim kitaplığı olan fastArrayIntersect ve intersector tarafından oluşturulan kod kullanılarak hız ve bellek için karşılaştırma sonuçları verilmiştir.
Karşılaştırma, her biri 10.000 tamsayıdan oluşan 3 özdeş diziyi ve 100 örnek boyutuyla 5.000 tamsayıdan oluşan son diziyi kesiştirdi. Kaynak dizilerde yinelenen girişler mevcut olduğunda, işlevlerin kümeleri döndürdüğünü doğrulamak için bir test de yapıldı.
Kaynak | Kopyalar | Kullanılan Yığın | İşlem Sek | Kullanıcı CPU'su | Sistem CPU'su |
---|---|---|---|---|---|
SohbetGPT | HAYIR | 39768 | 6.65 | 152170 | 780 |
Kodeks | HAYIR | 5475888 | 16.00 | 69070 | 160 |
Yardımcı pilot | Evet | 30768 | 4.16 | 345190 | 940 |
Sektörlerarası | HAYIR | 37304 | 73.02 | 21020 | 160 |
Hızlı Dizi Kavşağı | HAYIR | 42064 | 20.33 | 18990 | 630 |
Copilot en az yığını kullanır ancak aynı zamanda en yavaş ve en yoğun CPU kullananıdır.
ChatGPT en az CPU harcayandır ancak aynı zamanda yavaştır.
Fast Array Intersect, Copilot ve Chat GPT'den 3 ila 5 kat daha hızlıdır ve Codex'ten %20 daha hızlıdır ve daha az CPU yoğunluğuna sahiptir.
Intersector, ChatGPT ve Copilot'tan 15 kat, Codex'ten 4 kat ve Fast Array Intersect'ten 3 kat daha hızlıdır ve aynı zamanda en düşük CPU kullanımına sahiptir.
Özetle:
Ne ChatGPT ne de Copilot etkili kod üretmez.
ChatGPT geçerli olmayabilecek varsayımlarda bulunur.
Copilot, bağımsız değişkenleri yinelenen değerler içerdiğinde bir küme oluşturmayan kod üretir.
Codex, belirsiz kod olmasına rağmen makul performans üretir.
Programcılar kazanır.
Hem ChatGPT hem de Copilot, kullanıcıya birkaç açıklayıcı soru sormak için "zekalarını" uygulayarak geliştirilebilir; örneğin, hız mı yoksa bellek verimliliği mi arıyorsunuz, en az iki argümana ihtiyaç duymak mı istiyorsunuz?
Bu bölümün amacını netleştirmek için, vektörlerin aritmetik çapraz çarpımını değil, dizilerdeki tüm olası öğe kombinasyonlarını arıyordum.
Bana Kartezyen çapraz çarpım için bir JavaScript işlevi göster.
function cartesianCrossProduct(v1, v2) { var x = v1.y*v2.z - v1.z*v2.y; var y = v1.z*v2.x - v1.x*v2.z; var z = v1.x*v2.y - v1.y*v2.x; return {x: x, y: y, z: z}; }
function crossProduct(arrays) { var result = []; var args = Array.prototype.slice.call(arguments); var arrays = args.slice(0, args.length - 1); var callback = args[args.length - 1]; var maxLength = Math.max.apply(null, arrays.map(function(arr) { return arr.length; })); for (var i = 0; i < maxLength; i++) { var item = arrays[0][i]; var isInAll = arrays.every(function(arr) { return arr.indexOf(item) !== -1; }); if (isInAll) { result.push(item); } } return callback(result); }
const crossProduct = (...arrays) => { const [first, ...rest] = arrays; return first.flatMap(x => rest.map(y => [x, y])); }
Ne yazık ki ChatGPT, aritmetik çapraz çarpım için bir işlev sağladı. Benim düşünceme göre, her iki işlev türünü de sağlamalı veya açıklama istenmelidir.
Farklı sorgularda yapılan birçok denemeden sonra ChatGPT'nin aşağıdakilerin üçünü de oluşturmasını sağladım:
function crossProduct(...arrays) { if (arrays.length < 2) { throw new Error("At least 2 arrays are required!"); } let result = arrays[0].reduce((acc, x) => { return acc.concat(arrays.slice(1).reduce((acc, y) => { return acc.concat(y.map(z => [x].concat(z))); }, [])) }, []); return result; }
function allCombinations(...args) { var result = []; var f = function(prefix, arr) { for (var i = 0; i < arr.length; i++) { var newPrefix = prefix.concat(arr[i]); result.push(newPrefix); if (args.length > 0) { f(newPrefix, args.shift()); } } } f([], args[0]); return result; }
function crossProduct(...args) { var result = []; for(let i = 0; i < args.length; i++){ for(let j = i + 1; j < args.length; j++){ for(let ii = 0; ii < args[i].length; ii++){ for(let jj = 0; jj < args[j].length; jj++){ result.push([args[i][ii], args[j][jj]]); } } } } return result; }
const crossProduct = (...arrays) => { const [first, ...rest] = arrays; return first.flatMap(x => rest.map(y => [x, y])); }
Kesişmede olduğu gibi Codex, belirsiz argüman işleme ile eski bir programlama stilini kullanan bir işlev sağladı.
Kartezyen ürünlere aşina olanlar, bunların hem bellek kullanımı hem de performans açısından patlayıcı olabileceğini bilir.
Saf uygulamalar, tüm permütasyonları depolamak için yeterli RAM tüketecek ve tüm permütasyonlar oluşturulana kadar (bu uzun bir zaman olabilir) bir sonuç döndürmeyecektir. ChatGPT ve Copilot işlevlerinin her ikisi de bu eksikliklerden muzdariptir.
Bu yüzden daha sonra Kartezyen ürünü için hafızayı verimli kullanan bir JavaScript işlevi istedim.
function cartesianProduct(...args) { const iterators = args.map(arg => arg[Symbol.iterator]()); const next = () => { const values = iterators.map(iterator => iterator.next().value); return values.length > 1 ? values : null; }; return { [Symbol.iterator]: () => ({ next }) }; }
Copilot daha önce sağladığı sonuçların aynısını sağladı.
ChatGPT'nin "bellek açısından verimli" sürümünün ilkinden daha az RAM kullandığını varsaydım. Ancak bunun optimal olmadığını biliyordum. Birkaç denemeden sonra, Kartezyen ürünü için bir oluşturucu kullanarak hafızayı verimli kullanan bir JavaScript işlevi buldum.
function* cartesianProduct(...args) { const recursion = (arrays, i = 0) => { if (i === arrays.length - 1) { yield* arrays[i]; } else { for (let item of arrays[i]) { for (let result of recursion(arrays, i + 1)) { yield [item, ...result]; } } } } yield* recursion(args); }
Dürüst olmak gerekirse ChatGPT'den gelen bu yanıt beni hoş bir şekilde şaşırttı. Ancak bu kodu çalıştırma girişimleri başarısız oldu çünkü yield [item,...result]
bir oluşturucunun içinde değil, recursion
adı verilen iç içe geçmiş bir işlevin içindedir.
Ayrıca sorguyu kaybettiğim küçük bir değişiklik de aldım:
function* crossProduct(...arrays) { if (arrays.length < 2) { throw new Error("At least 2 arrays are required!"); } function* recurse(depth, current) { if (depth === arrays.length) { yield current; } else { for (let item of arrays[depth]) { yield* recurse(depth + 1, current.concat(item)); } } } yield* recurse(1, [arrays[0]]); }
ChatGPT bir kez daha argümanlar hakkında bazı varsayımlarda bulunuyor gibi görünüyordu.
Copilot daha önce yaptığı kodun aynısını döndürdü. Jeneratör talebimi tamamen görmezden geldi.
Ve şimdi gerçek test! Aşağıda ChatGPT, Copilot ve tanıdığım CXProduct ve Lazy Cartesian Product adlı en hızlı, hafıza açısından en verimli Kartezyen ürünler tarafından oluşturulan kod kullanılarak hız ve hafızaya ilişkin kıyaslama sonuçları yer almaktadır.
Ayrıca, belki de ChatGPT veya Copilot'un geri getirmesi gereken tek satırlık bir işlev de dahildir (sonuçları incelediğinizde bunu neden eklediğimi anlayacaksınız).
//https://stackoverflow.com/questions/12303989/cartesian-product-of-multiple-arrays-in-javascript const cartesian = (...a) => a.reduce((a, b) => a.flatMap(d => b.map(e => [d, e].flat())));
Test, her birinde 10 öğe bulunan 4 dizinin Kartezyen çarpımını alır. Dolayısıyla fonksiyonlar 10 * 10 * 10 * 10 birimlik, yani 10.000 adet Kartezyen çarpım üretmelidir.
Kaynak | # Sonuçlar | Kullanılan Yığın | İşlem Sek | Kullanıcı CPU'su | Sistem CPU'su |
---|---|---|---|---|---|
SohbetGPT1 | 300 | Yok | Yok | Yok | Yok |
SohbetGPT2 | 50 | Yok | Yok | Yok | Yok |
SohbetGPT3 | 600 | Yok | Yok | Yok | Yok |
ChatGPT Bellek Verimliliği | Yok | Yok | Yok | Yok | Yok |
ChatGPT Oluşturucu | 1000 | Yok | Yok | Yok | Yok |
Kodeks | 4 | Yok | Yok | Yok | Yok |
Yardımcı pilot | 30 | Yok | Yok | Yok | Yok |
Tek çizgi | 10000 | 0 | 78.46 | 18150 | 0 |
CXÜrünü | 10000 | 0 | 291.50 | 7330 | 0 |
TembelÜrün | 10000 | 17824 | 266.65 | 11560 | 150 |
Özetle:
ChatGPT, Codex ve Copilot, Kartezyen bir ürün için doğru sonucu üreten kodu üretme becerisine sahip değildir.
ChatGPT bazen geçerli olmayabilecek varsayımlarda bulunur; örneğin 2 argüman gerektirir.
ChatGPT, hafızanın daha verimli olduğunu söylediği bir kod üretti ancak çalışmadı bile.
Programcılar kazanıyor!
Bir kez daha ChatGPT, kullanıcıya birkaç açıklayıcı soru sormak için "zekasını" uygulayarak geliştirilebilir; örneğin, hız mı yoksa bellek verimliliği mi arıyorsunuz, en az iki argümana ihtiyaç duymak mı istiyorsunuz? Ancak bundan önce doğru kodu üretmesi gerekiyor!
Kesişim ve Kartezyen çarpımlarla ilgili dersimi aldıktan sonra hemen ezberlemek için incelikli bir soru sordum.
Bana nesneyi ve temel argümanları not eden etkili bir JavaScript işlevi gösterin.
function memoize(fn) { let cache = new WeakMap(); return function(obj, ...args) { let key; if (obj) { if (!cache.has(obj)) { cache.set(obj, {}); } key = JSON.stringify([obj, ...args]); } else { key = JSON.stringify(args); } if (cache.has(key)) { return cache.get(key); } let result = fn.apply(this, [obj, ...args]); cache.set(key, result); return result; } }
ChatCPT geçersiz kod oluşturdu; WeakMap
bir nesneyi anahtar olarak kullanması gerekir. Kod, test amacıyla aşağıdaki şekilde değiştirildi.
function memoize(fn) { let cache = new Map(); return function(obj, ...args) { let key; if (obj!=null) { if (!cache.has(obj)) { cache.set(obj, {}); } key = JSON.stringify([obj, ...args]); } else { key = JSON.stringify(args); } if (cache.has(key)) { return cache.get(key); } let result = fn.apply(this, [obj, ...args]); cache.set(key, result); return result; } }
function memoize(func) { var cache = {}; return function() { var args = Array.prototype.slice.call(arguments); var key = JSON.stringify(args); if (cache[key]) { return cache[key]; } else { var result = func.apply(null, args); cache[key] = result; return result; } } }
const memoize = (fn, cache = new Map()) => { return (...args) => { const key = JSON.stringify(args); if (cache.has(key)) { return cache.get(key); } else { const result = fn(...args); cache.set(key, result); return result; } } }
Codex ve Copilot aynı işlevi üretti; Copilot'un Codex'i temel aldığı göz önüne alındığında bu şaşırtıcı olmamalıdır. Her ne kadar önceki örneklerde farklı olsalar da.
ChatGPT, Codex ve Copilot'un oluşturduğu verimsiz işlevler JSON.stringify ve ardından dize karşılaştırması yavaştır ve ölçekte bellek tüketir.
Ayrıca Infinity ve NaN gibi dizilemeyen JavaScript değerleri de vardır. (Ne yazık ki, JavaScript JSON spesifikasyonu veri bilimi ve mikro hizmetler çağından önce tanımlanmıştı ve Infinity ve NaN'nin kodda meşru olmayan veya bir yerden başka bir yere taşınması gerekmeyen hatalara işaret ettiği varsayılmıştı. .)
Şimdi, ChatGPT ve Copilot kodunu nano-memoize ve mikro-memoize ile karşılaştırarak verimliliğin kanıtını görmek için bu kodu kullanarak 12. Fibonacci sayısını üretelim:
const fibonacci = (number) => { return number < 2 ? number : fibonacci(number - 1) + fibonacci(number - 2); };
Kaynak | Kullanılan Yığın | İşlem Sek | Kullanıcı CPU'su | Sistem CPU'su |
---|---|---|---|---|
ChatGPT (Düzeltildi) | 102552 | 45801 | 620 | 0 |
Kodeks | 17888 | 52238 | 320 | 0 |
Yardımcı pilot | 17888 | 51301 | 320 | 0 |
nano not alma | 17576 | 93699 | 470 | 160 |
mikro not alma | 18872 | 82833 | 620 | 0 |
Nano-memoize en hızlısıdır ve ChatGPT, Codex ve Copilot kodundan neredeyse iki kat daha hızlıdır. Ayrıca daha az bellek kullanır. Mikro memoize çok yakında.
nano-memoize
ve micro-memoize
için CPU kullanımı Code ve Copilot'tan biraz daha yüksek olmasına rağmen performans buna değer ve programcılar bir kez daha kazanıyor!
Kod oluşturmak için hem Copilot hem de ChatGPT kullanımının kesinlikle değeri olmasına rağmen, bu dikkatli yapılmalıdır. Her ikisi de optimum kodu üretemez ve bazı durumlarda geçersiz veya daha kötüsü yanlış olur. Ayrıca ChatGPT kullanırken sorguların oldukça spesifik olması gerekir.
ChatGPT ve Copilot'un her ikisi de, açıklayıcı sorular soracak bir özelliğin eklenmesiyle geliştirilebilir.
ChatGPT, eğer gerçekten akıllı olsaydı, kullanıcılara ya kod oluşturmak için kardeş Codex'i kullanmalarını söylerdi ya da Codex'i arka planda kullanırdı.
Arka planda Codex kullanılıyorsa, her ikisine de aynı işlev açıklamasını sağladığımda ve farklı sonuçlar aldığımda ne olduğundan emin değilim.
Her iki aracın da iç işleyişine aşina olmasam da, bunların dil modeli tabanlı olduğunu bilmek dışında, bu eksikliğin üstesinden gelmeden optimum kodu üretebilecekleri bir noktaya gelmelerinin pek mümkün olmadığını varsayıyorum:
Kamuya açık olarak incelenmemiş büyük hacimli kodlarla eğitilmiş bir sistem, kod için ortalama sonuçlar üretecektir, yani ortalama performansa sahip kod ve ortalama sayıda hata içeren kod.
Tutarlı bir şekilde doğru sonuçlar sağlamak için sistemin aşağıdakilere ihtiyacı olacaktır:
JSON.stringify gibi "karşı örnek" verilerinin parçalarını tüketme ve kullanma yeteneği verimsiz olabilir. Sistem bu yeteneği, test sonuçlarını ve kodu analiz ederek veya bilinen optimum kodu bir tür ağırlıklandırmayla besleyerek veya sonuçların bilinen uzmanlar tarafından eleştirilmesi yoluyla kazanabilir. Ne yazık ki, optimum kod çoğu zaman en yaygın veya en çok kullanılan kod değildir ve modelleri daha fazla örnekle beslemek yardımcı olmayacaktır. İdeal durumda, gerçekten akıllı bir sistem kendi test senaryolarını oluşturabilecektir.
Verimlilik kusurları açısından ürettiği kodu analiz etmek için programlamanın daha derin, daha ilk prensibi "anlaşılması"; örneğin, çalışma zamanı verimliliği için genellikle yinelemeyi özyinelemeye tercih etmek, kod boyutu ve okunabilirlik için genellikle özyinelemeyi tercih etmek.
En azından kod üreten bir yapay zeka, ürettiği kodu ayrıştırmaya ve sözdizimsel geçerliliğini değerlendirmeye çalışmalıdır. Bu, ChatGPT'ye yönelik basit bir geliştirme olmalıdır.
İdeal olarak yapay zeka, tip geçerliliğini sağlamak için en az bir veya iki basit test senaryosunu da çalıştırır. Ben birim testleri oluştururken, Copilot bu amaç için kullanılabilecek bir dizi yararlı gelişmiş kod tamamlama önerdi; örneğin işlev çağrılarına ve dizi aramalarına yönelik argümanlar. ChatGPT ve Codex'in böyle bir şeyi yapacak şekilde geliştirilebileceğini varsayıyorum.
Umarım bu makaleyi beğenmişsinizdir. Harika bir gün geçirin ve bugün (burada veya başka bir yerde) öğrendiklerinizi dünün kıskanmasını sağlayın!
Burada da yayınlandı