anlak.com

Pragmatik Araştırmacı

, Saturday, 20 August 2011
Akademiye geçmeden önce bir süre özel bir şirkette çalışmıştım, orada çevik (agile) metodları benimsemiştik. Farkettim ki piyasadaki durum, öğrenci olarak yapılması gerekenlerle pek fazla örtüşmüyor. Bunun başlıca nedeni öğrenci iken bakımı yapılacak şekilde bir ürün üretmiyorsunuz. Örneğin yaptığınız ödevler tek seferlik; bir kere öyle ya da böyle çalışır birşey elde ettikten sonra sonuçlarınızı elde edip yazdığınız kodları bir daha yüzüne bakmamak üzere rafa kaldırıyorsunuz. Araştırma yaparken durum birazcık daha farklı, yazdığınız kod üzerinde biraz daha uzun süre uğraşıyorsunuz , kodları elinizde biraz daha uzun süre tutuyorsunuz, fakat tecrübe ettiğim kadarıyla sonuç pek fazla değişmiyor, kodlar iş bittikten sonra bir köşeye terk ediliyor. Bu yüzden akademideki kod kalitesi bazı istisnalar (ör. Zemberek) dışında oldukça düşük.

Uzun süren araştırmalar bu duruma pek uymuyor, tez gibi uzun soluklu çalışmalarda mecburen kodunuzun bakımını yapmanız gerekiyor. Kimse yapmıyor o ayrı mesele. Yazdığınız kodu güzel yazmadıkça, bakımını yapmadıkça teknik borç (technical debt) birikiyor. Bu borç kısa vadede ilerlemenizi sağlayan fakat orta vadede size ayakbağı olacak eylemlerinizi açıklayan bir kavram. Bugün az bir emek harcayıp kodunuzu güzelleştirmek, ya da bir şeyi doğru şekilde yapmak yerine günü kurtarırsanız, daha sonra atacağınız adımlar daha da güç olacaktır. Az evvel dediğim gibi akademide yazılan kodlar çok kısa ömürlü olduğu için bu pek sorun olmuyor.

En azından makro ölçekte bu böyle. Son dönemlerde deneyimlerim ödevlerin, projelerin kısa ömürlü olmasına rağmen güzel programlama pratiklerine ihtiyaç duyduğu yönünde. En son arkadaşımı benim 1 günde bitirdiğim yapay sinir ağı ödevi için 3-4 gün harcamasını gördüğüm zaman farkettim bu durumu. İşlerimizi kolaylaştıracak yöntemlerin başında temiz kod yazmak geliyor. Temiz kod yazmanın, kısa süreli projeler olsa dahi, hayatımızı nasıl daha güzel kılacağını bir örnekle tarif etmeye çalışayım.

Diyelim ki $w_{i2}x+w_{i1}$ gibi bir ifadenin sonucunu sigmoide sokacağız, bu işi halletmenin MATLAB'da en düz yolu:
   y = 1 ./ (1 + exp(-x.*w(i, 2) + w(i, 1)));

Benim tercih edeceğim yol:
   y = sigmoid(x.*w(i, 2) + w(i, 1))

   function ret = sigmoid(x)
      ret = 1 ./ (1 + exp(-x));
   end

Sigmoid'i fonksiyon olarak ayrıştırarak
  1. Yeniden kullanılabilirliğini arttırdık. Bu örnekte, yapay sinir ağlarıyla uğraştığımızdan, birden fazla yerde sigmoid'i gönül rahatlığıyla kullanabiliriz. Her defasında yeniden aynı ifadeyi yazmakla uğraşmayız.
    Sigmoid'i yazarken bir yanlışlık yaptıysak dahi, bu yanlışlığı her yerde düzeltmemiz gerekmez. Sadece bir yerde düzeltmemiz yeterli olur. Diğer türlü sigmoid ifadesinin geçtiği her yeri bulmaya çalışırken gözümüzden bir kaç tanesini kaçırmamız çok olası.
    Hatta bunun bir adım ötesi, yavaş yavaş kendi kullanacağınız kod parçacıklarını kütüphaneleştirme yoluna gitmek olur. İleride size avantaj sağlayacaktır. Doğrudan kendi deneyimimi paylaşayım. Bir dönem projesi için çeşitli uzaklık metriklerini ($\chi^2$, Bhattacharaya, Kolomogrov vs.) implement etmiştim. Bir sonraki dönem başka bir dersin hocası verilen ödevde kullanacağımız her farklı uzaklık metriği için bonus puan vereceğini söyledi. Hiç uğraşmadan elimdeki hazır yazılmış 3-5 metriği çaktım geçtim.

  2. İfade daha anlaşılır oldu. Anlaşılır olması tekrar geri dönüp baktığınızda ilgili ifadede ne olup bittiğini çabucak kavramanızı sağlar. Anlaşılır kılarken ayrıca bug oluşumunu da engellersiniz aslında. Verdiğim kötü örnekte aslında bug var, exp() içine alırken, "-" toplamın iki elemanını da negatiflemeliydi, yani ifade y = 1 ./ (1 + exp(-x.*w(i, 2) - w(i, 1))); olmalıydı. Gördüğünüz gibi  böylesi "obscure" durumda hata yapmak daha kolaylaşıyor, hatayı bulması da zorlaşıyor. Sigmoid'i ayrı bir fonksiyon olarak yazdığımız durumda hata çabucak gözümüze çarpardı.

Bazıları önerdiğim yöntemin, fonksiyon çağrıları ve pass-by-value yüzünden daha yavaş olduğunu söyleyecektir, hele ki akademide mikro optimizasyonlar oldukça önemli olabiliyorken. Pragmatik programcılığın altın kurallarından biri de
  1. Profile et

  2. Darboğazı bul

  3. Optimize et
der. Profile etmek, kodunuzdaki ifadelerin hangilerinin koşmasının ne kadar zaman aldığını ölçmektir. Yıllardır yazdığım kodların hiçbirinde (abartmıyorum, 1 tanesinde bile olmadı bu) darboğaz tahmin ettiğim yerde değildi, ve bu tip mikro optimizasyonlar performansa hiç katkıda bulunmadı. Ayrıca, modern diller, hatta hantal MATLAB, bile kodlarınızı sizin için derlediğinizde ya da hemen koşturmadan önce optimize edebiliyor. awesome engineerO yüzden mutlaka ilkin profile edin ve kodunuz en çok zamanı nerede harcıyormuş onu bulun ve orayı hızlandırmaya çalışın.

Son olarak MATLAB'a özel bir tüyo vereyim, yıllardır MATLAB yazan insanların kodlarında bile görüyorum bu kötü uygulamayı. Matris işlemleri yaparken for döngüsü kullanmayın, kodunuzu vektörize edin. Vektörize etmek kodunuzu daha anlaşılır kılar, çünkü matematiksel ifadeleri neredeyse aynı şekilde ifade etmiş olursunuz hem de kodunuz hızlanır. Çünkü MATLABda array elemanlarına erişim oldukça maliyetli. Gerçi son dönemki MATLABdaki değişiklikler (JIT-accelerator), döngüler ve vektörizasyon arasındaki farkı önemsiz kulabiliyor.Yine de benim önerim kodunuzun güzelliği ve aklınızın sağlığı açısından vektörizasyon kullanmanız.

No comments:

Post a Comment