1 Mayıs 2017'de kendime şu soruyu sordum: Bir ay içinde kendi kendine süren bir arabanın yazılım kısmını oluşturmak için gerekli bilgisayar bilimini öğrenebilir miyim?
22 Mayıs 2017'de 26 saat öğrenim ve kodlamanın ardından cevabın evet olduğunu öğrendim.
Mayıs ayı boyunca, tüm öğrenme sürecimi, burada tek bir anlatı halinde derlenmiş 31 günlük blog yazısı ile belgeledim. Bu makalede, aylık ustalık için çalıştığım gibi, ayın içgörüleri, hayal kırıklıklarını, öğrenme saldırılarını ve zaferleri tekrar yaşayabilirsin.
Bugün yeni bir ay ve yeni bir meydan okumaya başlıyorum: Kendi kendine süren bir arabanın yazılım bölümünü bir ay içinde oluşturmak için gerekli bilgisayar bilimini öğrenebilir miyim?
Başarıyı tanımlama
Kendi kendini süren bir araba tam olarak inşa etmek için, 1. Kendini süren otomobil yazılımı ve 2. Kendini süren otomobil donanımı. Yazılım algoritma olarak sürüş talimatlarını oluşturmak için sensör ve giriş verilerini kullanır ve donanım bu sürüş talimatını gerçek araç içinde yürütür.
Teknik zorlukların çoğu aslında yazılım bölümünde (ve aynı zamanda bir arabama sahip olmadığım için de) olduğu için, sadece bu ayki mücadelenin yazılım kısmına odaklanacağım.
Özellikle, iki şey yapabilen kendi kendini süren bir yazılım oluşturmak istiyorum:
- Yolun video girişine dayanarak, yazılım aracın nasıl güvenli ve etkili bir şekilde yönlendirileceğini belirleyebilir.
- Yolun video girişine dayanarak, yazılım aracın hızlanma ve fren mekanizmalarının güvenli ve etkin bir şekilde nasıl kullanılacağını belirleyebilir.
Bu parçaların her birini ayrı ayrı veya birlikte ele almaya çalışabilirim. Henüz emin değilim. Ayrıca, bu alt zorlukların her birinin özel ayrıntılarından da tam olarak emin değilim, ancak bazı ilk araştırmalar yaptıktan sonra bu detayları daha ciddiye alacağım.
Bu iki kovaya dahil edilmeyen kendi kendine sürüş otomobil yazılımı için başka önemli hususlar olabilir, ancak bunlar bu ay üzerinde yoğunlaşacağım öğeler. Bu öğelerden, bilgisayarla görme problemlerini çözmek için makine öğrenmeyi / derin öğrenmeyi nasıl kullanacağımı öğrenmeye çalıştığım belli (gelecek bir yazı için tüm bunların ne anlama geldiğini açıklayacağım).
Benim başlangıç noktam
Kendi kendine sürüş araç yazılımı oluşturmak açıkça bir miktar bilgisayar bilimi bilgisi gerektiriyor ve bu konuda sıfırdan başlamıyorum.
İlk olarak, Brown derecem matematiktedir ve bu bilgisayar bilimleri dalında oldukça faydalıdır. Ayrıca bana kesinlikle yardımcı olacak genel bir kodlama / bilgisayar bilimi geçmişim var.
En ilginç şekilde, geçen yaz, ilgili bir makine öğrenme tekniği kullanarak oluşturduğum birkaç hayran kurgusu yayınladım - bu AI yazılı Harry Potter bölümü gibi - ama bu çoğunlukla yüksek kaliteli açık kaynakların kullanılabilirliğinin bir kanıtıydı. kod, ve benim makine öğrenme bilgim değil.
Geçen yaz aynı zamanda derin öğrenme üzerine matematik temelli bir ders aldım (derin öğrenme, makine öğreniminin alt kategorisi… yapay zekanın alt kategorisi… bilgisayar biliminin alt kategorisidir). Bu kurs ilginçti, fakat tamamen teorikti, pratik değildi.
Bu ay, kesinlikle teoriye değil uygulamaya ve sıfır deneyime sahip olduğum bilgisayar vizyonuna odaklandım.
Temel olarak, bazı temel deneyimlerim var, ancak nereden başlayacağımı bilmek için yeterli deneyime sahip değilim (bu, önümüzdeki birkaç gün içinde biraz araştırma gerektirecektir).
Her neyse, bunun gerçekten ne kadar zor olacağına dair makul bir tahminim yok, bu yüzden kesinlikle büyüleyici bir ay olacak. Başlamak için heyecanlıyım…
Doğrusal Öğrenme Yöntemi
Geniş bir çalışma alanını anlamaya çalışırken (kendi kendini süren otomobillerin temel bilgisayar bilimi gibi), doğru giriş noktasının nerede olduğunu bilmek genellikle zordur.
Sonuç olarak, çoğu insan ileriye giden en iyi yolun temellerle başlamak, genel bir bilgi temeli oluşturmak ve ardından daha ince ve daha ince detay seviyelerine doğru devam etmek olduğunu varsaymaktadır.
Buna Doğrusal Öğrenme Yöntemi diyorum.
Kendi kendini süren otomobillerin bilgisayar bilimlerini öğrenmek için doğrusal yöntemi kullanmak şuna benzer:
- Çok değişkenli hesabı öğren
- Doğrusal cebir öğrenmek
- Temel bilgisayar bilimi temellerini öğrenir
- Genel makine öğrenmesi kavramları hakkında bilgi edinin
- Bilgisayarla görme kavramları hakkında bilgi edinin
- Python'da nasıl kodlanacağını öğrenin (genellikle makine öğrenmesi için kullanılan bir kodlama dili)
- TensorFlow'u (Python için özel bir makine öğrenme kütüphanesi) nasıl kullanacağınızı öğrenin
- Kendi kendine sürüş otomobil yazılımı oluşturmak için bilgisayarlı görmenin nasıl uygulandığını öğrenin
- İlgili programları oluşturmak için Python ve TensorFlow kodunu yazmayı öğrenin
- Vb…
Bu yöntem sonunda işe yarayabilir, ancak verimsiz ve muhtemelen etkili değil.
Öncelikle, çok değişkenli hesabı öğrenmeye başlarsam, çok değişkenli analizin hangi kısımlarının kendi kendini süren arabalarla ilgili olduğunu ve hangi parçaların uygun olmadığını nasıl bilebilirim? Yapmıyorum. Bu yüzden hepsini öğrenmek zorunda kalacağım. Doğrusal cebir ve bilgisayar bilimi temelleri, vb için aynı.
Başka bir deyişle, en genel bilgi parçalarıyla başlarsam, öğrendiklerimi öncelik sırasına koyabilirim ve bu yüzden, nihayetinde kendimi her şeyi öğrenmeye zorluyorum.
Ek olarak, ilk önce temel kavramları genel ve soyut anlamda öğrendiğim için, öğrendiklerimi zaten bildiğim şeylerle ilişkilendirmek çok daha zor. Etkili öğrenme, esasen mevcut bilgiye yeni bilgi parçalarının anlamlı bir şekilde nasıl ekleneceğini ortaya çıkardığı için, Doğrusal Öğrenme Yöntemi de bu konuda başarısız olur.
Bu nedenle, çoğu insan bu doğrusal biçimde öğrenmeye yaklaşırken, aslında makul bir zaman diliminde herhangi bir şeyi öğrenmek için oldukça zayıf bir yöntemdir.
Öğrenmenin V Yöntemi
Bunun yerine, Öğrenmenin V Yöntemi olarak adlandırdığım farklı bir yöntem kullanıyorum.
Öğrenmenin V Yöntemi şu şekilde çalışır:
- Son hedefimin belirli, iyi belgelenmiş bir örneğiyle başladım
- Bu örneğin nasıl çalıştığını anlamaya çalışıyorum
- Örnek hakkında anlamadığım her şey için, temel kavramları araştırıyorum
- Altta yatan kavramları anlamadığım takdirde, altta yatan kavramların altta yatan kavramlarını araştırıyorum, bu yolu tükettiğimi hissedene kadar (ya anlaşarak ya da azalan bir dönüş noktasına ulaşarak)
- Sonunda, altta yatan önemli kavramlarda kalıpları görmeye başlamak için yeterince farklı yollar arasında dolaşıyorum
- Bu ilgili temel kavramları inceliyorum, orijinal zincirin detay seviyesine gelinceye kadar yavaş yavaş bilgi zincirinde ilerliyorum.
- Sonunda, yeni hiyerarşik bilgilerime dayanarak örneği yeniden yapıyorum
Buna “V-Yöntemi” diyorum, çünkü en ince detay seviyesinden başlıyorum, doğrudan uygulanabilir temel kavramlara derinlemesine dalıyorum ve sonra en ince detay seviyesine geri dönüyorum - kavramsal bir V.
V-Yöntemi Doğrusal Yönteme göre çok daha etkilidir, çünkü yapabiliyorum: 1. Nihai hedefime uygunluk sırasına göre öğrenirim, 2. Somut bir şey bağlamında temel kavramları öğrenin ve 3. Oluşturun ve organize edin bilgimi hiyerarşik, birbiriyle ilişkili bir şekilde.
Sonuç olarak, bu yöntem çok daha verimli, etkili ve ilgi çekicidir.
Öyleyse, V-Yöntemi bu ayki mücadeleye nasıl uygulayacağımı aşağıda bulabilirsiniz:
- Github'da örnek, açık kaynak kodlu kendi kendine araba kodunu arayın (Github, kod için popüler bir depodur, bu da temelde birçok başka insanın yazılım projelerini burada bulabileceğim anlamına gelir)
- Kodumu satır satır çalışmak
- Her kod satırı için, sezgisel düzeyde (çoğu olacaktır) anlamadığım, inişlerimi, temel kavramların katmanları aracılığıyla başlat
- Sürekli aradığım / araştırma yaptığım örüntüleri tanımla ve en önemli temel kavramları belirle
- Bu temel kavramları inceleyin
- Örnek Github projesindeki her kod satırını kendime etkili bir şekilde açıklayana kadar temel kavramların katmanlarını yedekleyin.
Bu hala biraz kafa karıştırıcı geliyorsa, umarım gerçekten başladığımda daha anlamlı olmaya başlayacaktır.
İlk adımım Github'u iyi örnek bir proje aramak.
Dün, V-Yöntemi olarak adlandırdığım yeni teknik becerileri öğrenmek için kullandığım birincil yöntemi kullandım. Bu yöntemi kullanarak çalışmalarıma oldukça spesifik bir örnekle başlıyorum (istediğim sonucu neticesinde taklit etmeli) ve bunu ilgili temel kavramları somut, organize ve hiyerarşik bir şekilde öğrenmek için bir giriş noktası olarak kullanıyorum.
Bu nedenle, bugün hedefim, bilgisayarımda çalışan ve kendimi süren arabam için kullanabileceğim bazı kodlar elde etmekti.
Bazı kod bulma
Bir süre Googling’ten sonra Github’ta ihtiyaçlarıma uygun bir proje buldum. Kod yolun girdi görüntüsünü alır ve şerit çizgilerinin yerini belirlemeye çalışır.
Yani, bundan ...
Buna…
Bugün için hedefim bu sonucu kendi bilgisayarımdaki kodla çoğaltmaktı.
Kurulum almak
Herhangi bir kodu çalıştırmadan önce, bilgisayarımın uygun yazılım kitaplıklarıyla ayarlandığından emin olmam gerekiyordu. Özellikle, Python için numpy, matplotlib ve OpenCV kütüphanelerini kurmam gerekiyordu.
Terminal'de (Mac'te komut satırı) yönlendirildikten ve çevrimiçi olarak bazı talimatlar bulduktan sonra ilk hatamla karşılaştım…
Bu hatanın tam olarak ne anlama geldiğini veya kendimin nasıl düzeltileceğini anlamaya çalışmak yerine, bildiğim en etkili hata ayıklama tekniğini kullandım: tüm hata mesajını Google'a kopyaladım ve yapıştırdım.
Üçüncü bağlantıya tıkladım ve şu cevabı buldum:
Bu birkaç komutu çalıştırdıktan sonra (bunları Terminal'e kopyalayıp yapıştırarak ve “Enter” ı tıklatarak) her şey düzgün çalışıyor gibi görünüyordu.
Resmen tamamen kuruldum (en azından şimdilik).
Kod çalıştırılıyor
Artık kurulduğuma göre, kodu çalıştırmanın zamanı gelmişti. Sınırlı Terminal bilgimi artırmak için Google’ı tekrar kullandıktan sonra, çalıştırılacak kodu aldım ve hiçbir şey kırılmıyor gibiydi.
Bu çıktıyı aldım…
Güzel! Dolayısıyla, bu sayılar esasen iki şerit çizgisinin matematiksel gösterimidir.
Çok uzak çok iyi. Fakat görseller nerede?
Kopyalamaya çalıştığım Github projesinde, kod aynı zamanda bu hoş arsaların çıktısını aldı…
Kırmızı bindirmeli görüntünün yanı sıra…
Maalesef, kodum bunların hiçbirini çıkarmıyordu ya da görüntüleri yerel dizinime kaydetmiyordu.
Bu yüzden, bir kez daha, Google’a döndüm ve çıktının görüntüsünün nasıl kaydedileceğini bulmak umuduyla “resim pitonunu kaydet” i aradım.
Google cv2.imwrite () işlevini kullanmamı söyledi, bu yüzden yaptım ve işe yaradı. Ve “çalıştı” derken, demek istediğim… fotoğrafın gri tonlu görüntüsünü şerit çizgileri beyaz olarak göstererek kurtarabildim.
Ve işte bir başkası…
Ve bir tane daha ...
Şimdi ne olacak?
Bu iyi bir başlangıç.
Temel olarak, şerit çizgilerini etkili bir şekilde tanımladıktan sonra, bu bilgiyi kendi sürüş arabama nasıl yönlendirileceğini (şerit çizgileri içinde) öğretmek için kullanabilirim. Ayrıca, video yalnızca birçok fotoğrafın bir koleksiyonu olduğundan, video işlemek aynı şekilde çalışmalıdır (bir videonun işlenmek üzere gerçek zamanlı olarak nasıl fotoğraflara bölüneceğini bulabildiğim sürece).
Yarın, kod az ya da çok çalıştığı için, projeyi satır satır incelemeye çalışıp gerçekte nasıl çalıştığını ortaya çıkarmaya çalışacağım.
O zamana kadar, ders şudur: Sık sık tüm cevapların size ait olmadığını kabul etmeye istekliyseniz, ancak Google’a biraz daha ilgi göstermeye ve biraz deneyimlemeye razıysanız, yine de ilerleme kaydedebilirsiniz.
Tabii, henüz güçlü bir kavramsal anlayışa sahip değilim, ancak şimdi başlangıç noktam olarak kullanabileceğim işlevsel bir örneğim var.
Dün, yolun öne bakan bir görüntüsünde şerit çizgilerinin nasıl belirlendiğini anladım. Şey ... en azından bunu yapabilen kodun nasıl çalıştırılacağını öğrendim.
Gerçekten, kodun gerçekte nasıl çalıştığını anlamadım, bu yüzden bugün bunu değiştirmeye çalıştım.
Dün kullandığım ana kod bloğunu aşağıda bulabilirsiniz. Özellikle, “draw_lane_lines” adı verilen birincil işlevi kopyaladım. Temel olarak, bir işlev, bazı girdiler (bu durumda bir fotoğraf) çeken, girdiyi bir şekilde değiştiren ve daha sonra manipülasyonu (bu durumda şerit çizgileri) çıkaran bir kod bloğudur.
Bu birincil işlev, kodun başka bir yerinde tanımlanmış bazı yardımcı işlevleri kullanır, ancak bu yardımcı işlevler, dün indirdiğim kütüphanelerden (örneğin OpenCV gibi) önceden yapılmış işlevleri tüketmenin yalnızca biraz daha temiz yoludur.
def draw_lane_lines (resim):
imshape = image.shape # Gri tonlamalı resim greyscaled_image = gri tonlamalı (resim) # Gauss Bulanıklığı blurred_grey_image = gaussian_blur (greyscaled_image, 5) # Canny kenar tespiti edges_image = canny (blurred_grey_image, 50, 150) # Maske kenarları resmi sınır = 0 köşeler = np.array ([[(0, imshape [0])), (465, 320), (475, 320), (şekil [1], şekil [0])]], dtype = np.int32) edges_image_with_mask = region_of_interest (edges_image, köşe) # Hough çizgileri Rho = 2 theta = np.pi / 180 eşik = 45 min_line_len = 40 max_line_gap = 100 lines_image = hough_lines (edges_image_with_mask, rho, teta, eşik, min_line_len, max_line_gap)
# Ağırlıklandırmaya hazırlanmak için Hough'u tek kanaldan RGB'ye dönüştürün hough_rgb_image = cv2.cvtColor (lines_image, cv2.COLOR_GRAY2BGR) # Satır resmini orijinal resimle birleştir final_image = weighted_img (hough_rgb_image, resim) final_image döndür
Kalın yazılmış yorumlar, görüntü işleme boru hattının ana bölümlerinin açıklamalarıdır; bu, temel olarak bunların, şerit çizgilerini çıkarmak için giriş görüntüsünde sırayla gerçekleştirilen yedi manipülasyon olduğu anlamına gelir.
Bugün hedefim, bu yedi adımın her birinin ne yaptığını ve neden kullanıldığını anlamaktı.
Aslında, şerit çizgilerinin matematiksel gösterimini veren ilk beşe odaklandım. Son iki manipülasyon sadece görseller yaratır, böylece biz insanlar matematiği görsel olarak değerlendirebiliriz (başka bir deyişle, bu adımlar kendi kendini süren bir araba aslında çıktı verilerini tüketirken gerekli değildir).
Böylece, bugün yaptığım araştırmaya dayanarak, aşağıdaki görüntü işleme olaylarının sırasını açıklamaya çalışacağım: Giriş görüntüsü → 1. Gri tonlamalı görüntü, 2. Gauss Bulanıklığı, 3. Canny edge algılama, 4. Maske kenarları görüntüsü, 5. Sert çizgiler → Şerit çizgisi çıkışı
Giriş görüntü
İşte başlangıç giriş görüntüsü.
Bir görüntünün, dikdörtgen şeklinde düzenlenmiş bir grup pikselden başka bir şey olmadığını hatırlamak önemlidir. Bu özel dikdörtgen 960 piksel x 540 pikseldir.
Her pikselin değeri kırmızı, yeşil ve mavinin bir birleşimidir ve her sayının renklerden birinin değerine karşılık geldiği sayıların üçlüsü ile temsil edilir. Renklerin her birinin değeri 0 ile 255 arasında değişebilir; burada 0, rengin tamamen yokluğu ve 255,% 100 yoğunluktur.
Örneğin, beyaz renk (255, 255, 255) ve siyah renk (0, 0, 0) olarak temsil edilir.
Bu nedenle, bu girdi görüntüsü (0, 0, 0) ila (255, 255, 255) arasında değişen 999 x 540 = 518,400 üçlüsü sayılarla tanımlanabilir.
Şimdi bu görüntü sadece bir sayı koleksiyonudur, bu sayıları matematik kullanarak faydalı yollarla değiştirmeye başlayabiliriz.
1. Gri tonlamalı görüntü
İlk işlem adımı, renk görüntüsünü gri tonlamaya dönüştürerek, renk alanını üç boyuttan tek boyuta etkili bir şekilde indirir. Görüntüyü sadece bir boyutta değiştirmek çok daha kolay (ve daha etkili): Bu bir boyut, pikselin “kara” ya da “yoğunluğudur”, 0'ı siyah, beyazı temsil eden 255 ve bir miktar orta gri rengi temsil eden 126 .
Sezgisel olarak, bir gri tonlama filtresinin yalnızca gri tonlama çıktısına ulaşmak için kırmızı, mavi ve yeşil değerleri ortalayan bir işlev olacağını ummuştum.
Örneğin, orijinal fotoğraftaki gökten gelen bir renk:
RGB (kırmızı, yeşil, mavi) uzayda (120, 172, 209) olarak gösterilebilir.
Bu değerleri birlikte ortalamalarsam (120 + 172 + 209) / 3 = 167 veya bu rengi gri tonlamada alırım.
Ancak, yukarıdaki işlevi kullanarak bu rengi gri tonlamaya dönüştürdüğümde, gerçek çıktı renk, basit ortalama yöntemimi kullanarak oluşturduğumdan biraz farklı olan 164'dür.
Benim yöntemim aslında “yanlış” olmasa da, kullanılan ortak yöntem, gözlerimizin rengi algılayışına daha iyi uyan ağırlıklı bir ortalama hesaplamaktır. Başka bir deyişle, gözlerimiz kırmızı veya mavi alıcılardan çok daha fazla yeşil reseptöre sahip olduğundan, yeşil değerin gri tonlama işlevinde daha ağır olması gerekir.
Kolometrik dönüşüm adı verilen yaygın bir yöntem bu ağırlıklı toplamı kullanır: 0.2126 Kırmızı + 0.7152 Yeşil + 0.0722 Mavi.
Orijinal görüntüyü gri tonlamalı filtreden geçirdikten sonra, bu çıktının…
2. Gauss Bulanıklığı
Bir sonraki adım, bir Gauss Bulanıklığı kullanarak görüntüyü bulanıklaştırmaktır.
Hafif bir bulanıklık uygulayarak, en yüksek frekanslı bilgileri (a.k.a gürültüsü) görüntüden kaldırabiliriz; bu da analiz edebileceğimiz "daha yumuşak" renk blokları verir.
Bir kez daha, bir Gauss Bulanıklığı'nın altında yatan matematiği çok basit: Bulanıklık sadece daha fazla piksel ortalamaları alıyor (bu ortalama işlemi, açıklamak üzere olduğum şeyler için gereksiz bir şekilde süslü bir isim olan bir tür çekirdek evrişimidir).
Temel olarak, bulanıklık oluşturmak için aşağıdaki adımları tamamlamanız gerekir:
- Fotoğrafta bir piksel seçin ve değerini belirleyin
- Seçilen pikselin yerel komşularının değerlerini bulun (bu “yerel bölgenin” boyutunu rasgele tanımlayabiliriz, ancak genellikle oldukça küçüktür)
- Orijinal pikselin ve komşu piksellerin değerini alın ve bir miktar ağırlıklandırma sistemi kullanarak bunları ortalayın
- Orijinal pikselin değerini, çıkarılan ortalama değerle değiştirin
- Bunu tüm pikseller için yap
Bu süreç esasen “tüm pikselleri yakındaki piksellere daha benzer hale getir” diyor, sezgisel olarak bulanıklaştırma gibi geliyor.
Bir Gauss Bulanıklığı için, yukarıdaki 3. Adımdaki ağırlıkları belirlemek için sadece Gauss Dağılımını (yani bir çan eğrisi) kullanıyoruz. Bu, bir piksele seçilen piksele ne kadar yakınsa, ağırlığı da o kadar yüksek olur.
Neyse, görüntüyü çok fazla bulanıklaştırmak istemiyoruz, ancak fotoğraftaki gürültüyü gidermek için yeterli. İşte aldığımız şey…
3. Canny kenar algılama
Şimdi gri tonlamalı ve Gaussian Bulanıklaştırılmış bir resme sahip olduğumuza göre, bu fotoğraftaki tüm kenarları bulmaya çalışacağız.
Kenar, görüntüdeki değerde ani bir sıçrama bulunan bir alandır.
Örneğin, gri yol ile kesikli beyaz çizgi arasında net bir kenar vardır, çünkü gri yol 126 gibi bir değere sahip olabilir, beyaz çizgi 255'e yakın bir değere sahiptir ve bu değerler arasında kademeli bir geçiş yoktur. .
Yine Canny Edge Detection filtresi, kenarları bulmak için çok basit bir matematik kullanır:
- Fotoğrafta bir piksel seçin
- Seçilen pikselin sağındaki pikseller grubunun ve sağdaki pikseller grubunun değerini belirleyin
- Bu iki grup arasındaki farkı alın (yani birinin değerini diğerinden çıkarın).
- Seçilen pikselin değerini 3. Adımda hesaplanan farkın değerine değiştirin.
- Bunu tüm pikseller için yapın.
Öyleyse, seçilen pikselin yalnızca solundaki ve sağındaki bir piksele baktığımızı iddia edin ve bunların şu değerler olduğunu düşünün: (Sol piksel, seçilen piksel, sağ piksel) = (133, 134, 155). Ardından, sağ ve sol piksel arasındaki farkı 155–133 = 22 olarak hesaplar ve seçilen pikselin yeni değerini 22 olarak ayarlardık.
Seçilen piksel bir kenar ise, sol ve sağ pikseller arasındaki fark daha büyük bir sayı olacaktır (255'e yakın) ve bu nedenle çıkarılan resimde beyaz olarak görünecektir. Seçilen piksel kenar değilse, fark 0'a yakın olacak ve siyah olarak görünecektir.
Elbette, yukarıdaki yöntemin sadece dikey yönde kenarları bulacağını fark etmiş olabilirsiniz, bu nedenle, seçilen pikselin altındaki ve altındaki pikselleri yatay yönde adreslemek için karşılaştırdığımız ikinci bir işlem yapmalıyız.
Bu farklılıklar degradeler olarak adlandırılır ve dikey ve yatay degradelerden bireysel katkıları eklemek için temel olarak Pisagor Teoremi'ni kullanarak toplam degradeyi hesaplayabiliriz. Başka bir deyişle, toplam gradyan²² = dikey gradyan²² + yatay gradyan² diyebiliriz.
Örneğin, dikey gradyan = 22 ve yatay gradyan = 143, ardından toplam gradyan = sqrt (22² + 143²) = ~ 145 diyelim.
Çıktı böyle bir şeye benziyor…
Canny Edge Detection filtresi artık bir adım daha tamamlıyor.
Tüm kenarları göstermek yerine, Canny Edge Detection filtresi önemli kenarları belirlemeye çalışır.
Bunu yapmak için iki eşik belirledik: Yüksek eşik ve düşük eşik. Diyelim ki yüksek eşik 200 ve düşük eşik 150.
200 yüksek eşiğinden daha büyük bir değere sahip herhangi bir toplam degrade için, bu piksel otomatik olarak bir kenar olarak kabul edilir ve saf beyaza dönüştürülür (255). 155 düşük eşiğinden daha düşük bir değere sahip herhangi bir toplam degrade için, o piksel otomatik olarak "kenar değil" olarak kabul edilir ve saf siyaha (0) dönüştürülür.
150 ve 200 arasındaki herhangi bir degrade için, piksel yalnızca bir kenar olarak sayılan başka bir piksele doğrudan dokunuyorsa kenar olarak sayılır.
Buradaki varsayım, eğer bu yumuşak kenar sert kenara bağlıysa, muhtemelen aynı nesnenin bir parçası olduğu anlamına gelir.
Bu işlemi tüm pikseller için tamamladıktan sonra, şuna benzeyen bir görüntü elde ediyoruz…
4. Maske kenarları resmi
Bir sonraki adım çok basittir: Şerit çizgileri olmadığını varsaydığımız fotoğrafın tüm bölümlerini ortadan kaldıran bir maske oluşturulur.
Bunu anlıyoruz…
Bu oldukça agresif ve kibirli bir maske gibi görünüyor, ancak şu anda orijinal kodda yazılmış olan budur. Yani, devam ediyor…
5. Hough hatları
Son adım, şerit çizgileri için matematiksel ifadeyi bulmak üzere Hough dönüşümünü kullanmaktır.
Hough dönüşümünün arkasındaki matematik, yukarıda yaptığımız ağırlıklı ortalama işlerinden biraz daha karmaşık, ama ancak zorlukla.
İşte temel kavram:
Bir çizgi için denklem, y = mx + b'dir, burada m ve b, sırasıyla çizginin eğimini ve çizginin y-kesişimini temsil eden sabitlerdir.
Temel olarak, Hough dönüşümünü kullanmak için, m ve b’lerin bazı 2 boyutlu alanlarını belirleriz. Bu alan, m’lerin tüm kombinasyonlarını temsil eder ve b’nin, şerit çizgileri için en uygun hattı oluşturabileceğini düşünüyoruz.
Sonra, bu m’ler ve b’ler arasında dolaşıyoruz ve her çift için (m, b), y = mx + b formunun belirli bir satırı için bir denklem belirleyebiliriz. Bu noktada, bu çizgiyi test etmek istiyoruz, bu nedenle fotoğrafta bu çizgide kalan tüm pikselleri buluyoruz ve bunun şerit çizgisi için iyi bir tahmin olup olmadığını oylamalarını istiyoruz. Piksel beyaz ise (evet, bir kenarın bir parçası), evet ise “hayır”, siyah ise kullanır.
En çok oyu alan (m, b) çifti (veya bu durumda, en fazla oyu alan iki çift) iki şerit çizgisi olarak belirlenir.
İşte Hough Dönüşümünün çıktısı…
Hough dönüşümünün çizgiyi temsil etmek için y = mx + b formülünü kullanmak yerine, bunun yerine iki parametre olarak rho ve theta'yı kullanan kutupsal koordinatlar / / trigonometrik stil gösterimini kullandığı kısmı atlıyorum.
Bu ayrım çok önemli değil (anlayışımıza göre), çünkü alan hala 2 boyutlu olarak parametreleniyor ve mantık tamamen aynı, fakat bu trigonometrik gösterim tamamen dikey olarak ifade edemememize yardımcı oluyor y = mx + b denklemine sahip satırlar.
Neyse, bu yüzden rho ve theta yukarıdaki kodda kullanılıyor.
Son çıktı
Ve biz bitti.
Program iki şerit çizgisini tanımlamak için iki parametreyi çıkarır (ilginç bir şekilde, bu çıkışlar tekrar m, b parametrelerine dönüştürülür). Program ayrıca her şerit çizgisinin bitiş noktalarının koordinatlarını sağlar.
Şerit çizgisi 1
Eğim: -0.740605727717; Kesişme: 664.075746144
Birinci nokta: (475, 311) İkinci nokta: (960, 599)
Şerit çizgisi 2
Sığır eti: -0.740605727717; Kesişme: 664.075746144
Birinci nokta: (475, 311) İkinci nokta: (0, 664)
Bu çizgileri orijinal görüntünün üzerine yerleştirdiğinizde, temel matematik işlemlerini kullanarak şerit çizgilerini etkin bir şekilde tanımladığımızı görüyoruz.
Dün, yolun ileriye dönük görüntülerinde şerit çizgilerini tanımlayan bir kod parçası yaptım.
Bunun gibi…
Belki de resimden daha ilginç olan bu kod bloğu, sadece çok temel matematiksel işlemleri (esas olarak ağırlıklı ortalamaları bulan bir dizi fonksiyon) kullanarak şerit çizgilerinin matematiksel gösterimlerini oluşturur:
Şerit çizgisi 1 = Eğim: -0.740605727717; Kesişme: 664.075746144
Şerit çizgisi 2 = Coef: -0.740605727717; Kesişme noktası: 664.075746144.
Bu alıştırmanın içinden geçmek, artık kendi kendine süren bir arabanın mekaniğinin sezgisini daha iyi kavramamı sağladı.
Şu ana kadar deneyimlediklerime göre, kendi kendini süren otomobil yazılımı oluşturmanın iki ana adımı var gibi görünüyor:
Adım 1: Giriş görüntüsünü, sürüş ortamının (örneğin şerit çizgileri, diğer arabalar, trafik işaretleri, yayalar, vb.) Bir dizi yararlı sayısal gösterimi ile değiştirin.
Adım 2: Dünyanın bu nümerik temsilini, bu girdilere dayanarak, doğru direksiyon açısını ve ivmelenmeyi hesaplayan bir fonksiyonla besleyin.
2. Adımdaki fonksiyonun geliştiğinden şüpheliyim (gelecekte artan miktarda hesaplama gücünün mevcut olması nedeniyle), 1. Adımdaki işlem öncesi ve nesne kategorizasyonu giderek daha az önem kazanıyor.
Bu yüzden, dikkatimi, büyük ölçüde nesne tanıma ve sayısallaştırmaya odaklanan 1. Adımdan uzaklaştırmam gerektiği ve dikkatimin çoğunu, dünyadan gelen girdileri sürüş yönergelerine yönlendiren 2. Adımdaki fonksiyona odaklamam gerekiyor gibi görünüyor. Bu fonksiyona “Sihirli Fonksiyon” diyorum.
Bu, makul bir plan gibi gözüküyor, çünkü dün tarif ettiğim görüntü işleme teknikleri, Sihirli İşlev'in ancak yakın zamanda uygulanabilir hale geldiği on yıllar önce icat edildi.
Bu analizin doğru olup olmadığından veya bu yolun optimal olup olmadığından emin değilim, ancak şu ana kadar şimdiye kadar araştırdıklarım ve son birkaç gündeki alıştırmalara dayanarak benim sezgim.
Yarından itibaren, bir Magic Function'ın nasıl çalıştığını ve onu nasıl yapabileceğimi araştırmaya başlayacağım.
Dün, odağımı değiştirmek ve yolun girdi resimlerini kendi kendine süren araba için açık sürüş / direksiyon talimatlarına yönlendiren matematiksel bir algoritma olan Magic Function'ın bir versiyonunu oluşturma çabalarımı harcamam gerektiğini anladım.
Bugün, tam da ihtiyacım olanı içeren Udacity'nin (kendinden sürüş arabaları da dahil olmak üzere teknik konular hakkında çevrimiçi kurslar yapan bir şirket) açık kaynaklı bir 223 GB veri seti buldum:
Udacity ön camdan bir video çekti, ayrı ayrı karelere böldü ve ardından her kareyi insan sürücünün gerçekte gerçekleştirdiği karşılık gelen açı ile etiketledi.
Örneğin, çerçeve: 147942544493332893737; direksiyon açısı: -0.346924703940749
Sonuç olarak, bu veri seti Magic Function oluşturmak ve test etmek için mükemmeldir - Magic Function'tan video çerçevesine dayanarak direksiyon açısını tahmin etmesini isteyebilirim ve ardından tahminleri gerçek kaydedilen direksiyon açısı ile karşılaştırabilirim.
Tahmin gerçek değerden uzak ise, işlevi güncelleyebilir ve yeniden test edebilirim. Teorik olarak, bu işlemi binlerce kez yinelememe yardımcı olmak için bilgisayarı kullanabilir ve sonunda aracı doğru bir şekilde yönlendirmek için makul bir yol bulabilirim.
Şu an nasıl yapılacağını yalnızca “teorik olarak” bildiğim için, Udacity’nin veri kümesini bu şekilde kullanan birisini bulabilecek miyim diye görmek için bugün Github’a geri döndüm.
Birkaç proje buldum ve onları oldukça hızlı bir şekilde çalıştırıp çalıştırmalarını umuyordum. Yine de yaklaşık iki saat çalıştıktan sonra, Terminal'de ölümcül hatalar almaya devam ettim - hatta kodu çalıştırmaktan değil, bilgisayarımı ilk önce kodu çalıştırmak için gereken kütüphanelerle kurmaya çalışmaktan.
Birkaç gün önce, Terminal ne zaman bir hata yaparsa, Google’ın cevabını verip ilerlemek çok kolay. Birkaç gün önce bu benim deneyimim olsa da, bu deneyim muhtemelen normal değildir ve kesinlikle bugün değildi.
Tüm çabalarıma rağmen, bugün etkin bir şekilde sıfır ilerleme kaydettim, bu da sinir bozucu ama aynı zamanda oyunun bir parçası.
Yarın bu oyunu oynamaya devam edeceğim ve bilgisayarımın işbirliği yapıp yapamayacağını göreceğim. Şimdilik umutlu kalacağım…
Bazen, bina yazılımının en acımasız ceza biçimi olduğunu düşünüyorum. Bugün o günlerden biriydi.
Diğer uğraşlardan farklı olarak, işler zor olsa bile, bilgisayarımın birkaç kod satırını başarılı bir şekilde çalıştırmasını sağlamak için bilgisayarımın birkaç satır kodunu başarılı bir şekilde çalıştırmasını sağlamaya çalışmak duvar, umarım, eğer yeterince uzun süre yaparsam, sonunda bir şey değişecek.
Yeni kodlama bölgesine girerken, genel arsa yayını şu şekildedir: 1. Bazı rastgele kombinasyonların işe yarayıp yaramayacağını görmek için kod / ortam kurulumunun her olası permütasyonunu denemek için iki saat geçirin, 2. Hiçbir şey işe yaramaz ve daha ileride olduğunuzu fark edersiniz Hedefinizden başladığınız andan daha fazla (çünkü o kadar çok şeyle uğraşıyorsunuz ki), 3. Bir saat daha denemeye devam edin, 4. Büyülü bir şekilde yıldızlar hizalar ve açıklanamayan şeylerin birleşimi her şeyin çalışmasını sağlar.
Bu model ile ilgili sorun şu ki… 4. adımda sihirli bir şekilde nirvana ulaşana kadar dişlerinizi sıkmanız ve belli bir süre acı çekmeniz gerekiyor. Nirvananın ne zaman geleceğini bilmiyorsunuz ya da ne olacağına inanmıyorsunuz hiç gel, ama olabileceği ihtimaline karşı devam etmelisin. Kademeli bir ödeme yoktur, sihirli bir şekilde çalışana kadar sadece ruh emici hayal kırıklığı yaratmaz.
Ve sonra, işe yaradığında hiçbir şey daha keyifli olamaz. Tüm acılar bir an için buna değer, bir anın geldiğini varsayarsak.
Bugün zar zor dayanıyordum.
Çok az topraklandığım bir alanın derinindeyim ve bunun sonucunda günün büyük bir bölümünde kendimi kaybolmuş ve çaresiz hissettim.
Bu gibi durumlarda, video eğitimlerine veya çevrimiçi kurslara güvenmek genellikle yararlı olur, ancak henüz beni temel alan henüz erişilebilir bir öğretici (veya herhangi bir öğretici) bulamadım.
Bunun yerine, bugün yaklaşık 2.5 saatimi Çaresizlik Kodlama Çukuru'nda boğularak geçirdim. Acımasız ve güven tehdit edici bir şeydi ve bugün defalarca yenilgiyi kabul etmek istedim ama bekletebildim.
Her nasılsa, günün sonuna doğru yolumu buldum ve somut bir ilerleme kaydetmiş gibiyim. Yarın sabaha kadar kesin olarak söyleyemem: Bilgisayarım şu anda çalışıyor ve muhtemelen gece boyunca çalışmaya devam edecek.
Yarın, başarılı bir şekilde çalıştırılan bir programla uyandığımı umuyorum.
Dün gece, birkaç saat boyunca “Çaresiz Kodlama Çukuru” nda boğulduktan sonra, sonunda bir miktar ilerleme kaydettim.
Hatırlatmak gerekirse, son birkaç gün içinde yolun girdi resimlerine dayanarak direksiyon talimatlarını (kendi kendine süren arabam için) üretebilecek bir kod bulmaya ve çalıştırmaya çalışıyordum.
Araştırarak ve oynayıp saatlerce uğradıktan sonra, NVIDIA'da (diğerlerinin yanı sıra kendi kendini süren otomobil donanım ve yazılımını yapan bir şirket) araştırmacılar tarafından yazılmış bir akademik makale buldum.
Kağıdın Özetinde açıklandığı gibi, tasarlanan sistemleri “ham pikselleri doğrudan öne bakan bir kameradan doğrudan yönlendirme komutlarına eşleyebilir”.
Bu tam ihtiyacım olan şey!
Ardından, NVIDIA’nın Github’da bir TensorFlow uygulamasını buldum ve birkaç denemeden sonra, NVIDIA’nın bazı verilerine dayanarak “modeli eğitmeyi” başardım.
(Güncelleme: Bu aslında NVIDIA'nın verileri değil, Sully Chen tarafından üretilen bir veri kümesidir. Verileri, bir web kamerasını arabasının ön camına kanalını hafifçe vurarak ve arabasının CAN-BUS portundan 'sürücü verilerini' alarak yakaladı. ).
Bazı terimleri açıklığa kavuşturmak için hızlı bir şekilde: 1. “Model”, piksellerin direksiyon talimatlarına nasıl dönüştürüleceğini tanımlayan işlevdir ve 2. “Modeli eğitmek”, makine öğrenme tekniklerini kullanarak bu işlevi yinelemeli olarak geliştirmek anlamına gelir. Bu süreci gelecekteki bir gönderide daha ayrıntılı olarak açıklayacağım.
Her neyse, NVIDIA’nın veri kümesi, her karenin gerçek direksiyon açısı ile etiketlendiği 25 dakikalık videoyu kare kare ayırıyor (yani, insan sürücüsünün kullandığı direksiyon açısı).
Terminal'de, modeli eğitmek için program koştum ve bazı uyarılara rağmen çalışmaya başladı:
Bu ekran görüntüsünde, bir “Adım”, verilerin bir kısmı eğitim için sistemden her beslendiğinde açıklanmaktadır. Bir “Epoch”, birden fazla Adım içeren daha geniş bir kategoridir.
Bu modeli eğitmek için, Epoch başına birkaç düzine adım olan 30 Epoch kullandım.
Ekran görüntüsünde “Kayıp”, modelin (veya fonksiyonun) ne kadar doğru olduğunu açıklar. Kavramsal olarak, Kaybı hesaplamak için gerçek direksiyon açısı, model tarafından öngörülen direksiyon açısı ile karşılaştırılır. Fark ne kadar büyükse Kayıp da o kadar büyük olur.
Nihayet, modeli eğitirken, program, her yinelemeli adımda Kaybı azaltmaya çalışmak için (gelecekteki bir gönderide tarif edeceğim) birkaç matematik hilesi kullanır.
Dolayısıyla “modeli eğitmek” sadece “Kaybı azaltmak” dır.
İşte X ekseni üzerinde Adımlar ve Y ekseni üzerinde Kaybı olan bir komplo. (Dün gece, Tensorboard adlı bir şey kullanarak, bilgisayarım bunu antrenman sırasında çizdi).
Örneğin, Adım 126'da, Kaybın değeri 5.708'dir.
Neredeyse altı saat sonra, 3,241 Adımında, Kaybı, 0.1615'in anlamlı olarak daha iyi bir değerine sahipti.
Eğitim resmi olarak tamamlandığı için, model artık teorik olarak süper havalı olan bir aracı yönlendirmek için hazırdır.
Bugün işten eve geldiğimde, modeli test etmeye çalıştım (a.k.a. “araba yönlendirmek”) ve nasıl performans gösterdiğini gördüm. Ne yazık ki programı çalıştırmaya çalıştığımda bu hatayı aldım…
Bu sorunun üstesinden gelmek için iyi bir saat geçirdim, ancak indirdiğim kodun bir kısmı Mac'te çalıştırılamıyor gibi görünüyor (eğer yapabilirse, çalışmasını sağlayacak bir yol bulamadım).
Geçici bir çözüm için bir fikrim var, ancak yarına kadar beklemek zorunda kalacak.
Bu arada, kullanılmaya hazır, oldukça işlevsel, zaten eğitimli, kendi kendine sürüş bir araba modeline sahip olduğumu kutlayabilirim. Umarım, yarın, nasıl kullanılacağını çözebilirim…
Dün, kendi kendine sürüş arabamı nasıl eğiteceğimi öğrendim, ancak eğitimin gerçekten etkili olduğunu onaylamak için mücadele ettim.
Bugün, programın çalışmayan kısmının sadece görselleştirme ile ilgisi olduğunu hemen fark ettim. Başka bir deyişle, tüm görselleştirme kodunu silebildim ve hala otomobil için gerçek zamanlı direksiyon komutlarını başarıyla verebildim.
Bu rakamlar, talimatları uygulamak için kendi kendine süren bir arabaya sahip olmak için yeterliyken, insan gibi, bu çıktının anlaşılması zordur.
Neyse ki, birkaç gün önce, işlenmiş çerçeveleri nasıl yerel makineme kaydedeceğimi öğrendim.
Bu nedenle, programdan giriş videosunun bireysel karelerini ve öngörülen direksiyon simidi animasyonunu çıkarmaya karar verdim.
Daha sonra bireysel kareleri birleştirdim, iki videoyu üst üste getirdim ve oynat düğmesine bastım. İşte sonuç…
Bunun için gerçekten heyecanlıyım!
Neler olduğunu netleştirmek için: Program düşük kaliteli çizgi kamera görüntülerini izledi ve daha sonra dün çalıştığım kendi kendine sürüş modeline dayanarak direksiyon simidini otonom olarak canlandırdı. Başka bir deyişle, bilgisayar bu arabayı tamamen kullanıyor ve oldukça sağlam bir iş çıkarıyor.
Bir sonraki adım, temel kod hakkında daha fazla bilgi edinmek, genel kullanım için optimize etmek ve ardından farklı veri kümelerinde (örneğin farklı yollarda) nasıl performans gösterdiğini görmek. Udacity veri seti ile başlayacağım.
Henüz kendi sürüş arabamın arkasında uyumaya hazır olduğumdan hala emin değilim, ancak bugün kesinlikle ileriye doğru büyük bir adım attı.
Şimdi kendinden sürüşlü araba kodunu çalıştırdığımdan (dünden gelen videoya bakın), önümüzdeki birkaç gün içinde, kodu kaldırmayı ve tam olarak nasıl çalıştığını anlamaya çalışmayı planlıyorum.
Bugün, özellikle kodun etini düşünebilecek olan “modele” bakacağım: Model, giriş görüntülerinin direksiyon talimatlarına nasıl dönüştürüldüğünü tanımlar.
Bugün çok fazla zamanım olmadığından, kodun nasıl çalıştığını tam olarak açıklamayacağım (henüz bilmediğimden ve hala çok fazla araştırma yapmam gerektiğinden). Bunun yerine, kod satırlarının ne anlama gelebileceği hakkında bazı hipotezler yapacağım ve daha sonra araştırmam gereken açık soruları belgeleyeceğim.
Bu beni malzemeyi yapısal bir şekilde öğrenmeye hazırlayacaktır.
İşte bütünüyle kendini süren modelin kodu. Yalnızca 50 satırlık kod artı artı yorumlar ve boşluklar (araba kullandığı için oldukça çılgınca.)
tensorflow'u tf olarak içe aktar ithalat anlaşması
def weight_variable (şekil): initial = tf.truncated_normal (şekil, stddev = 0.1) tf.Variable (ilk)
def bias_variable (şekil): başlangıç = tf.constant (0.1, şekil = şekil) tf.Variable (ilk)
def conv2d (x, W, adım): tf.nn.conv2d döndürün (x, W, strides = [1, stride, stride, 1], dolgu = 'VALID')
x = tf.placeholder (tf.float32, shape = [Yok, 66, 200, 3]) y_ = tf.placeholder (tf.float32, shape = [Yok, 1])
x_image = x
#birinci evrişimli katman W_conv1 = ağırlık_ değişkenliği ([5, 5, 3, 24]) b_conv1 = bias_variable ([24])
h_conv1 = tf.nn.relu (conv2d (x_image, W_conv1, 2) + b_conv1)
#second evrişimli katman W_conv2 = ağırlık_ değişkenliği ([5, 5, 24, 36]) b_conv2 = bias_variable ([36])
h_conv2 = tf.nn.relu (conv2d (h_conv1, W_conv2, 2) + b_conv2)
# üçüncü evrişimli katman W_conv3 = ağırlık_ değişkenliği ([5, 5, 36, 48]) b_conv3 = bias_variable ([48])
h_conv3 = tf.nn.relu (conv2d (h_conv2, W_conv3, 2) + b_conv3)
# dördüncü evrişimli katman W_conv4 = ağırlık_ değişkenliği ([3, 3, 48, 64]) b_conv4 = bias_variable ([64])
h_conv4 = tf.nn.relu (conv2d (h_conv3, W_conv4, 1) + b_conv4)
# beşinci evrişimli katman W_conv5 = ağırlık_ değişkenliği ([3, 3, 64, 64]) b_conv5 = bias_variable ([64])
h_conv5 = tf.nn.relu (conv2d (h_conv4, W_conv5, 1) + b_conv5)
#FCL 1 W_fc1 = ağırlık_ değişkenliği ([1152, 1164]) b_fc1 = bias_variable ([1164])
h_conv5_flat = tf.reshape (h_conv5, [-1, 1152]) h_fc1 = tf.nn.relu (tf.matmul (h_conv5_flat, W_fc1) + b_fc1)
keep_prob = tf.placeholder (tf.float32) h_fc1_drop = tf.nn.dropout (h_fc1, keep_prob)
#FCL 2 W_fc2 = ağırlık_ değişkenliği ([1164, 100]) b_fc2 = bias_variable ([100])
h_fc2 = tf.nn.relu (tf.matmul (h_fc1_drop, W_fc2) + b_fc2)
h_fc2_drop = tf.nn.dropout (h_fc2, keep_prob)
#FCL 3 W_fc3 = ağırlık_ değişkenliği ([100, 50]) b_fc3 = bias_variable ([50])
h_fc3 = tf.nn.relu (tf.matmul (h_fc2_drop, W_fc3) + b_fc3)
h_fc3_drop = tf.nn.dropout (h_fc3, keep_prob)
#FCL 4 W_fc4 = ağırlık_ değişkenliği ([50, 10]) b_fc4 = bias_variable ([10])
h_fc4 = tf.nn.relu (tf.matmul (h_fc3_drop, W_fc4) + b_fc4)
h_fc4_drop = tf.nn.dropout (h_fc4, keep_prob)
#Çıktı W_fc5 = ağırlık_ değişkenliği ([10, 1]) b_fc5 = bias_variable ([1])
y = tf.mul (tf.atan (tf.matmul (h_fc4_drop, W_fc5) + b_fc5), 2)
Satır satır yorum
Şimdi, kodlardaki parçalarla çalışacağım ve her grubun ne anlama geldiğini / ne anlama geldiğini düşündüğümü açıklayacağım.
tensorflow'u tf olarak içe aktar ithalat anlaşması
İlk iki satır basit.
TensorFlow kitaplığını (kodun başka bir yerinde "tf" olarak adlandıracağımız) ve SciPy kitaplığını içe aktarıyoruz. TensorFlow, Google tarafından yazılmış, temel seviyedeki makine öğrenimi uygulamalarının çoğunu soyutlamaya yardımcı olacak bir piton kütüphanesidir. SciPy matematik işleri ile yardımcı olacaktır.
Burada öğrenmek için yeni bir şey yok.
def weight_variable (şekil): initial = tf.truncated_normal (şekil, stddev = 0.1) tf.Variable (ilk)
def bias_variable (şekil): başlangıç = tf.constant (0.1, şekil = şekil) tf.Variable (ilk)
Tamam, öyleyse burada yeni nesneler tanımladığımızı düşünüyorum, bu temel olarak kodumuzda başka bir yerde tekrar tanımlamak zorunda kalmadan başka bir yerde “weight_variable” ve “bias_variable” kavramlarını kullanabileceğimiz anlamına geliyor.
Makine öğrenmede, çözmeye çalıştığımız fonksiyon tipik olarak Wx + b = y olarak gösterilir, burada x (giriş görüntülerinin listesi) ve y (karşılık gelen yönlendirme talimatlarının listesi) verilir ve en iyisini bulmak isteriz denklem dengesini sağlamak için W ve b kombinasyonu.
W ve b aslında tek sayılar değil, katsayı koleksiyonlarıdır. Bu koleksiyonlar çok boyutludur ve bu koleksiyonların boyutu, makine öğrenme ağındaki düğüm sayısına karşılık gelir. (En azından şu an nasıl anladığımı anladım).
Bu nedenle, yukarıdaki kodda, weight_variable nesnesi W'yi ve bias_variable nesnesi genel anlamda b'yi temsil eder.
Bu nesneler temelde W ve b boyutlarını belirleyen “şekil” adlı bir girdi alır.
Bu W ve b nesneleri “normal” adı verilen bir işlevle başlatılır. Bunun bir W 've b' koleksiyonu oluşturulduğunda, bireysel katsayıların değerlerinin normal dağılıma (yani bir çan eğrisi) 0.1 standart sapma ile rastgele atanması gerektiğinden eminim. Standart sapma az ya da çok, başlangıç katsayılarının ne kadar rasgele olmasını istediğimizi tanımlar.
Yani, şaşırtıcı bir şekilde, çoğunlukla bu kodu anlıyorum. İlk bakışta ne olup bittiğinden emin değildim, ancak bunu yazmak düşüncelerimi toplamama yardımcı oldu.
Hala öğrenmem gerekenler: Wx + b = y yapısı, neden kullanıldığı, nasıl çalıştığı vb. Hakkında daha fazla şey öğrenmem gerekiyor, ancak kodun temellerini anlıyorum.
def conv2d (x, W, adım): tf.nn.conv2d döndürün (x, W, strides = [1, stride, stride, 1], dolgu = 'VALID')
Bu conv2d olayının bazı girdilerde çekirdek evrişimi gerçekleştiren bir işlev olduğuna inanıyorum. Çekirdek kıvrımları, birkaç gün önce öğrendiğim görüntü manipülasyonlarının daha genel bir sınıfıdır.
Endişelendiğim kadarıyla, bir çekirdek evrişimi, görüntünün kenarları, köşeleri vb. Olsun, görüntünün bir özelliğini vurgulamak için görüntüyü değiştirir.
Bu özel karakteristik, yukarıdan gelen basamaklar = [1, adım, adım, 1] kullanılarak tanımlanmış gibi görünen “çekirdek” ile tanımlanır. Yine de, adımların ne anlama geldiğini veya tam olarak nasıl çalıştığını bilmiyorum.
Bu görüntü işleme işlevine üç giriş var gibi görünüyor: 1. Çekirdek / adım (görüntünün nasıl işleneceğini söylemek için); 2. x (görüntünün kendisidir); ve 3. W (sanırım farklı görüntü manipülasyonlarını bazı kapasitelerde bir araya getirmek için kullanılan bir dizi katsayıdır).
Buradaki W’nin rolü hakkında daha fazla şey öğrenmek zorundayım.
Yine de, yüksek düzeyde, bu işlev, görüntüyü, modeli eğitmek için daha elverişli olan farklı özelliklere otomatik olarak düşürecek şekilde manipüle etmektir.
Hala öğrenmem gerekenler: Evrişim işlevi matematiksel olarak tam olarak nasıl tanımlanıyor ve W bu konuda nasıl bir rol oynuyor?
x = tf.placeholder (tf.float32, shape = [Yok, 66, 200, 3]) y_ = tf.placeholder (tf.float32, shape = [Yok, 1])
x_image = x
Bu sonraki birkaç satır oldukça basit görünüyor. Bir kez daha, Wx + b = y denklemine geri dönelim.
Burada esasen x ve y değişkenleri için yer tutucuları tanımlıyoruz. Bu yer tutucular değişkenlerin boyutlarını belirler (unutmayın: bu değişkenler yalnızca bir sayı değil, bir değer koleksiyonunu temsil eder).
Belirli boyutlarda bir görüntü almayı beklemek için x'i ayarlıyoruz ve çıktı olarak tek bir sayı bekleyecek şekilde y ayarlıyoruz (yani, direksiyon açısı).
Daha sonra, x'in bir resim olduğunu hatırlatmak için x'i “x_image” olarak yeniden adlandırıyoruz, çünkü… neden olmasın.
Burada öğrenmek için yeni bir şey yok.
#birinci evrişimli katman W_conv1 = ağırlık_ değişkenliği ([5, 5, 3, 24]) b_conv1 = bias_variable ([24])
h_conv1 = tf.nn.relu (conv2d (x_image, W_conv1, 2) + b_conv1)
Tamam, şimdi ilk evrimsel katmanımızın içindeyiz.
Yukarıda açıkladığım ağırlık değerinin sadece belirli bir örneği olan W_conv1'i tanımladık ([5, 5, 3, 24] şeklinde). Şeklin bu şekilde nasıl ve neden ayarlandığından emin değilim.
Daha sonra yukarıda açıkladığım bias_variable'ın özel bir örneği olan b_conv1'i tanımlarız ([24] şeklinde). Bu 24 olasılıkla W_conv1 şeklindeki 24'le eşleşmelidir, ancak neden olduğundan emin değilim (bunun dışında matris çarpımının çalışmasına yardımcı olacak).
h_conv1, evrişim işlevini x_image ve W_conv1 girişlerine uygulayan, evrişim çıktısına bconv1 ekleyen ve daha sonra her şeyi relu adı verilen bir işlevle işler.
Bu relu olayı tanıdık geliyor ama tam olarak ne yaptığını hatırlayamıyorum. Tahminim, bunun ne anlama geldiğine göre bir kapasitedeki her şeyi yumuşatan bir çeşit “ezici” veya normalleştirme işlevidir. Buna bakmak zorundayım.
Kodun çoğunu okuyabilsem de, neden bu şekilde bir "evrişim katmanı" kurulduğundan emin değilim.
Hala öğrenmem gerekenler: Konvolüsyon tabakası nedir, ne yapması gerekir ve nasıl yapar?
#second evrişimli katman W_conv2 = ağırlık_ değişkenliği ([5, 5, 24, 36]) b_conv2 = bias_variable ([36])
h_conv2 = tf.nn.relu (conv2d (h_conv1, W_conv2, 2) + b_conv2)
# üçüncü evrişimli katman W_conv3 = ağırlık_ değişkenliği ([5, 5, 36, 48]) b_conv3 = bias_variable ([48])
h_conv3 = tf.nn.relu (conv2d (h_conv2, W_conv3, 2) + b_conv3)
# dördüncü evrişimli katman W_conv4 = ağırlık_ değişkenliği ([3, 3, 48, 64]) b_conv4 = bias_variable ([64])
h_conv4 = tf.nn.relu (conv2d (h_conv3, W_conv4, 1) + b_conv4)
# beşinci evrişimli katman W_conv5 = ağırlık_ değişkenliği ([3, 3, 64, 64]) b_conv5 = bias_variable ([64])
h_conv5 = tf.nn.relu (conv2d (h_conv4, W_conv5, 1) + b_conv5)
İlk katmanla aynı şekilde çalışan dört evrişimli katmana geçiyoruz, ancak girdi olarak x_image kullanmak yerine, önceki katmandan (yani h_conv şeyi) çıktı kullanıyorlar.
Beş katman kullanmaya nasıl karar verdiğimizden ve her bir W_conv'un şekillerinin neden ve neden farklı olduğundan emin değilim.
Hala öğrenmem gerekenler: Neden beş katman ve her biri için şekilleri nasıl seçiyoruz?
#FCL 1 W_fc1 = ağırlık_ değişkenliği ([1152, 1164]) b_fc1 = bias_variable ([1164])
h_conv5_flat = tf.reshape (h_conv5, [-1, 1152]) h_fc1 = tf.nn.relu (tf.matmul (h_conv5_flat, W_fc1) + b_fc1)
keep_prob = tf.placeholder (tf.float32) h_fc1_drop = tf.nn.dropout (h_fc1, keep_prob)
#FCL 2 W_fc2 = ağırlık_ değişkenliği ([1164, 100]) b_fc2 = bias_variable ([100])
h_fc2 = tf.nn.relu (tf.matmul (h_fc1_drop, W_fc2) + b_fc2)
h_fc2_drop = tf.nn.dropout (h_fc2, keep_prob)
#FCL 3 W_fc3 = ağırlık_ değişkenliği ([100, 50]) b_fc3 = bias_variable ([50])
h_fc3 = tf.nn.relu (tf.matmul (h_fc2_drop, W_fc3) + b_fc3)
h_fc3_drop = tf.nn.dropout (h_fc3, keep_prob)
#FCL 4 W_fc4 = ağırlık_ değişkenliği ([50, 10]) b_fc4 = bias_variable ([10])
h_fc4 = tf.nn.relu (tf.matmul (h_fc3_drop, W_fc4) + b_fc4)
h_fc4_drop = tf.nn.dropout (h_fc4, keep_prob)
Daha sonra, “Tamamen Bağlantılı Katmanlar” anlamına geldiğine inandığım dört FCL'miz var.
Bu katmanlar için ayarlamalar evrişim adımlarına benzer, ancak burada ne olduğundan tam olarak emin değilim. Sanırım bu sadece vanilya sinir ağları (“vanilya sinir ağları” nı tamamen anlıyormuşum gibi yazdığım).
Her neyse, buna daha çok bakmak zorunda kalacağım.
Hala öğrenmem gerekenler: Bir FCL nedir ve her FCL adımında neler oluyor?
#Çıktı W_fc5 = ağırlık_ değişkenliği ([10, 1]) b_fc5 = bias_variable ([1])
y = tf.mul (tf.atan (tf.matmul (h_fc4_drop, W_fc5) + b_fc5), 2)
Son olarak, son FCL katmanının çıktılarını alıyoruz, çılgınca trigonometrik manipülasyonlar yapıyoruz ve sonra tahmin edilen direksiyon açısı y'yi veriyoruz.
Bu adım sadece “matematiği halletmek” gibi görünüyor, ama emin değilim.
Hala öğrenmem gerekenler: Çıktı bu şekilde nasıl ve neden hesaplanıyor?
Bitti.
Beklenenden daha uzun sürdü - çünkü beklediğimden daha fazla ayrıştırmayı başardım.
Uygulamanın ne kadarının TensorFlow kütüphanesi tarafından soyutlanması ve tamamen yetenekli bir kendi kendini süren araba modeli oluşturmak için temel matematik bilgisinin ne kadar azının gerekli olması çok çılgınca.
Model yapıcıları olarak bilmemiz gereken tek önemli şey, modelin derinliğinin (örneğin katman sayısı), her katmanın şekillerinin ve katman türlerinin nasıl ayarlanacağıdır.
Tahminime göre bu, bilimden ziyade bir sanat, fakat muhtemelen eğitimli bir sanat olabilir.
Yarın açık sorularımı aramaya başlayacağım.
Son on bir gündür bu ayki mücadelede büyük ilerleme kaydettim, bu yüzden bugün bir ara vermeye karar verdim.
Bu mola çoğunlukla, Konvolüsyonel Sinir Ağları ve çekirdeğindeki konvolüsyonlarla ilgili YouTube videolarını izlemeyi içeriyordu, bu da hala hedefime daha yakın olmamı sağladı, ancak daha pasif ve huzurlu bir şekilde.
Özellikle, bilgisayar bilimi ile ilgili konularda şahsen en sevdiğim kanal olan YouTube kanalı Computerphile'dan bir sürü video izledim.
İşte Konvolüsyonel Sinir Ağları hakkındaki Computerphile videosu…
Ve işte çekirdek konvolüsyonlarla ilgili bir serideki ilk Computerphile videosu…
Bu ayki zorlukla daha az alakalı olsa da, Computerphile genel olarak sayı teorisi ve matematikteki konuları tartışan, Numberphile adında bir kız kardeşi YouTube kanalına sahip.
İşte en sevdiğim Numberphile videolarımdan biri - pi'nin değerini belirlemek için harika bir yöntem.
Her neyse, bugün mola verdim, yarın işe döneceğim.
İki gün önce, kendi kendini süren araba kodunun eteğinden geçtim ve nasıl çalıştığıyla ilgili açık soruları belirledim.
Bu soruları kazmaya başladığımdan beri, tamamen uygulama açısından bakıldığında, etkili bir derin öğrenme sistemi oluşturmak için temel matematik / bilgisayar biliminin çoğunun anlaşılmasının çok gerekli olmadığını farketmeye başladım. Doğal olarak ilgileniyorum, bu yüzden ilerlediğim gibi öğrendim ama kesinlikle gerekli değil.
Temel olarak, işte bilmeniz gereken önemli şeyler:
- Bir Konvolüsyonel Sinir Ağı'nda, “yığının” tepesinde, hangi konvolüsyon işlemlerinin (yani görüntü manipülasyonları) öğrenilecek en iyi özellikleri vurguladığını öğrenen konvolüsyon katmanları vardır.
- Sonra, evrişimli katmanlar tarafından vurgulanan özelliklere dayanarak doğru çıktının nasıl üretileceğini öğrenmeye çalışan bazı Tam Bağlantılı Katmanlar vardır.
- Arada, öğrenme sürecini hızlandıran bazı matematiksel hileler (altörnekleme ve doğrultucular gibi) vardır.
- Katmanların şekillerini ve parametrelerini belirlemek genellikle ampirik olarak yapılır (yani farklı seçenekler deneyin ve en iyi sonuçları üreten konfigürasyonu seçin).
# 4 ile ilgili olarak, kullandığım derin öğrenme sistemini tanımlayan Nvidia’nın makalesinde, “evrişimsel katmanların özellik çıkarımı yapmak üzere tasarlandığını ve ampirik olarak çeşitli katman konfigürasyonlarını değiştiren bir dizi deney yoluyla seçildiğini” açıklıyorlar.
Öyleyse, işte yumruk noktası: Etkili bir Evrimsel Sinir Ağı kurmanın sırrı, normalde kullanılan bileşenlerin birkaç farklı kombinasyonunu denemek ve hangisinin en iyi işe yaradığını görmek.
Temel olarak, temel bileşenleri anladığınız sürece, etkili bir kendi kendine sürüş otomobil (Nvidia’nın% 98’i özerktir) oluşturmak, “tahmin et ve kontrol et” den daha fazla değildir. (Eğer arabayı% 98’den% 100’e otonom olarak almak istiyorsak, bugün tahmin edilen ve kontrol etmekten biraz daha fazlasını yapmamız gerekebilir, ki bu bugün doğrudur, ancak muhtemelen her zamanki gibi zamanla daha az gerçek olacağız. soruna giderek daha fazla işlem gücü uygulayın).
Elbette, kaputun altında, tüm bu “temel bileşenlerin” uygulamaları daha karmaşık, ama neyse ki TensorFlow kütüphanesi bu işlerin hepsini tamamen ortadan kaldırdı. Ayrıca, hobilerin GitHub'da tam açık kaynaklı kendi kendine sürüş araba modelleri yayınladıkları bir noktaya ulaştık.
18-24 aylarda, tek bir kod satırında kendi kendini süren bir otomobilin yaratılabileceği bir soyutlama seviyesine ulaşacağımızı tahmin ediyorum - sanırım bu ayın öğrenme zorluğunun iyi yaşamayacağı anlamına geliyor.
Bu bakımdan, bu ayki mücadelenin şu derse işaret ettiği görülüyor: Bazen “zor şeyleri öğrenmek” sadece belirsizliği veya korkutmayı ortadan kaldırıyor ve bunu yönlendirdiğinizde, yönlendirildikten sonra işler çok zor değil.
Şimdi odaklandığımdan beri, teoriyi kazmaya daha fazla zaman harcamam (en azından gelecek hafta ya da öylesine). Bunun yerine, odağımı saf uygulamaya geri döndüreceğim ve kendi kendine sürüş arabamın özelliklerini genişletip geliştiremeyeceğimi göreceğim.
Birkaç gün önce, bazı kodları koydum ve kendi aracımı sürdürebilen arabamın başarılı bir şekilde sokaklarda dolaşmalarını sağladım (en azından neredeyse NVIDIA’nın video görüntüsüne dayanarak).
Bugün, bir sonraki adımı atmak ve kendi kendine sürüş otomobil modelini farklı bir veri kümesi üzerinde kullanıp kullanamayacağımı görmek istedim. Ne de olsa, kendi kendini süren bir araba, sadece üzerinde eğitim aldığı yolları değil, herhangi bir yolda da sürülebilir.
Böylece, geçen hafta eğittiğim modelin, farklı yollar içeren Udacity’nin veri kümesi üzerinde performans gösterip göstermediğine karar verdim.
İlk adım Udacity veri setini biçimlendirmektı, böylece kendi kendini süren araba modelim tarafından işlenebiliyordu.
Farklı olarak, sıralı olarak numaralandırılmış karelere (0.jpg, 1.jpg, 2.jpg, 3.jpg, vb.) Ayrılan bir video klip içeren NVIDIA veri kümesi, Udacity veri kümesi kafa karıştırıcı olarak numaralandırılmış resimlerden oluşan bir koleksiyondur: Sayılar arasında tuhaf, tutarsız boyutta boşluklar var ve veri kümesi 1479425441182877835'te saymaya başlıyor.
Udacity'nin bu numaralandırma planı için muhtemelen bir mantığı vardı, ancak bu mantığın ne olduğunu çözemiyorum.
Bu nedenle, ilk adımım, tüm bu dosyaları NVIDIA tarzı numaralandırma düzenine uyacak şekilde yeniden adlandırmaktı (yani, sıfırdan başlayıp sayıları kadar).
İlk önce, kulaklıklarımı takmayı, sesli kitabı açmayı ve her dosyayı manuel olarak yeniden adlandırmayı düşündüm. Ardından, 5000'den fazla dosya olduğunu ve muhtemelen otomatik olarak bir kodla nasıl yapacağımı çözmem gerektiğini anladım (sonuçta, bu ay kodlama becerilerimi geliştirmeye çalışıyorum).
Etrafında yaklaşık 12 dakikalık bir erişte kaldıktan sonra, tüm Udacity dosyalarını yeniden adlandırmak için küçük bir Python betiği yazabildim.
ithal os
def rename (dizin):
i = 0
os.listdir'de (dizin) file_name için: new_file_name = str (i) + '.jpg' old_file_name = dosya_adı
os.rename (old_file_name, new_file_name)
i + = 1
PATH = os.path.abspath ('/ Kullanıcılar / maxdeutsch / Masaüstü / nvidia / udacity_data')
adlandırmak (yol)
Senaryoyu çalıştırdım ve birkaç dakika içinde tüm dosyalar yeniden adlandırıldı (elle yapmadığım için memnunum).
Daha sonra, hazırlanan veri seti ile modeli yeni veri seti üzerinde test etme, otonom olarak kontrol edilen direksiyon simidinin grafiklerini çıkarmanın ve ardından otomobilin nasıl performans gösterdiğini görmek için orijinal çekimlerin üstüne grafik kaplamanın zamanı gelmişti.
Ne yazık ki, performans çok kötü: Kendi kendine sürüş araba bu talimatları gerçek hayatta takip ediyorsa, neredeyse anında çarpacaktır.
Yarın, modeli deneyeceğim ve kendi kendine sürüş arabamı nasıl daha iyi bir şekilde genelleyeceğime karar vereceğim, böylece yeni bir sürüş ortamına her girişinde çarpışma olmaz.
Dün, kendi kendine sürüş arabamı yeni yollarda sürmeye çalıştım (Udacity veri kümesinden). Ancak, araba bunun için hazırlanmadı ve neredeyse tekrar tekrar çöktü.
Açıkçası, NVIDIA veri setinde eğitilen model Udacity veri kümesi için uygun değil.
Bu tutarsızlık için makul bir açıklama, her iki veri kümesinin de yolun öne bakan videolarına sahip olmasına rağmen, videoların görüş açısı, çerçeveleme ve mercek bozulma açısından farkedilir şekilde farklı olmasıdır. Sonuç olarak, bir bakış açısıyla eğitilmiş bir model de hiçbir şekilde iyi çalışmamalı (kamera taşındığından, yakınlaştırıldığından ve yeniden birleştirildiğinden).
İşte NVIDIA veri setinden hareketsiz bir çerçeve:
Ve işte hala bir Udacity’nin veri setinden:
Açıkçası, bir veri setinde eğitilmiş bir model diğerinden kullanılamıyorsa, yolun bu görüşleri yeterince farklıdır. (Her iki araç da aynı noktadan video çekiyorsa, model o zaman her iki veri kümesinde de kullanılabilir.
Bu nedenle, devam etmek için, kendi kendini süren otomobil modelini Udacity verilerinin bir bölümünde de eğitmeli ve sonra modelin yeni verilerin geri kalanında test edildiğinde nasıl bir performans gösterdiğini görmeliyim.
Bugünün görevi, Udacity’nin veri setini, eğitim için kullanılabilecek şekilde yeniden biçimlendirmekti.
Dün, Udacity JPEG'lerini uzun, rasgele sayılardan ardışık etiketli görüntülere yeniden adlandırdığımda bu yeniden biçimlendirme sürecinin bir kısmını tamamladım.
Bundan…
Buna…
Hazırlanan resimlerle ilgili Udacity veri kümesi için “data.txt” adında bir metin dosyası oluşturmam gerekti, ilgili görüntünün adının yanında doğru yönlendirme açısını listeledi.
NVIDIA’nın data.txt dosyası şöyle görünür:
Ancak, Udacity verileri şöyle bir elektronik tabloda derlendi:
Bu yüzden, Udacity veri kümesi için data.txt dosyasını oluşturmak için iki şeyi başarmam gerekiyordu: 1. Dünün numaralandırma düzeniyle eşleşmesi için frame_ids öğesini yeniden adlandırın; 2. Bir e-tabloyu, tablo tarzı formatlamadan herhangi biri olmadan bir metin dosyasına nasıl dönüştürebileceğinizi belirleyin.
Bir Python betiği kullanmak yerine, Google E-Tablolar içinde her iki adımı da nasıl yapacağınızı bulmaya çalıştım (muhtemelen daha verimli bir yol var).
İlk önce, ardışık sayıların küçük bir dizisini yazdım ve ardından diğer ~ 5000 hücrelerini doldurmak için diziyi aşağı çektim.
Daha sonra, tamsayıları dizgelere dönüştürmek ve sonra bu dizgileri .jpg dosya uzantısıyla birleştirmek için yerleşik fonksiyonlar olan TO_TEXT ve CONCATENATE işlevlerini kullandım.
Açık Adım 2 - Masayı biçimlendirilmemiş bir metin belgesine dönüştürme.
Resim isimlerini ve direksiyon açılarını tek bir hücrede bir boşluk ayırıcı ile birleştirmek için tekrar CONCATENATE kullandım.
Daha sonra, her bir hücreyi bir satır sonu için karakter kodu olan char (10) ile birleştirdim. Ve son olarak, tüm hücreleri tek bir hücreye birleştirdi.
Bu tek hücrenin içeriğini bir metin belgesine kopyaladım ve data.txt dosyam hazır olmaya hazırdı.
Tuhaf olan şey, Udacity’nin direksiyon açısı numaralarının NVIDIA’nın direksiyon açısı numaralarından çok farklı görünmesi.
Şirketlerin önemli ölçüde farklı direksiyon açısı gösterimleri kullandıkları görülüyor, ancak iki yöntemin matematiksel olarak nasıl bir ilişki kurduğundan emin değilim.
Bu matematiksel ilişkiyi öğrenmeden modeli başarılı bir şekilde eğitebilirim, ancak durumun şüphesi var.
Bunu daha yarın keşfedeceğim ve ardından modeli Udacity verileri üzerinde eğitmeye başlayacağım.
Dün yeni veri setini biçimlendirmeyi bitirdim, bu yüzden işten eve döndüğümde modeli eğitmeye başlamaya hazırdım.
Yine de, Terminal komutunda train komutunu çalıştırdığımda bilgisayarım bir saniye durdu ve sonra bir hataya yol açtı. Özellikle, bir “liste dizini aralık dışı” hatası.
Genellikle, program, gerçek şeyler listesinden daha uzun bir şeylerin listesini beklerken bu tür bir hata alırsınız.
NVIDIA veri kümesi Udacity veri kümesinden daha uzun / daha büyük olduğundan, liste uzunluğu için değerin sabit kodlanması gerektiğini düşündüm ve bu değeri buna göre ayarlayabilirim.
Ancak kodu okuduktan sonra sorunu bulamadım. Her şey çalışması gerektiği gibi görünüyordu.
Bu yüzden, birkaç baskı ifadesinde koda ekledim, bu da başlık altında neler olup bittiğini ve programın tam olarak nerede kırıldığını görmeme yardımcı olacak.
Programı print cümleleriyle çalıştırdım ve şu çıktıyı aldım:
Program, gerçek verilerdeki tüm satırlarda başarıyla yinelendi ve daha sonra varolmayan fazladan bir veri satırını ayrıştırmaya çalıştı.
Böylece, data.txt dosyasını açtım ve elbette ki… Dosya sonunda yanlışlıkla birkaç boş satır kopyaladım.
Bu üç boş satırı sildim ve programı Terminal'de yeniden sıraladım.
İşe yaradı ve model eğitime başladı.
Model eğitilirken (yarın kontrol edeceğiz), hızlı ve eğlenceli bir şekilde paylaşacağımı düşündüm:
Bugün işe gidip geldiğimde, Mountain View tren istasyonunun yakınında bir Google / Waymo kendiliğinden sürüş arabasını geçtim.
Sonra, gidip evimden, dairemden birkaç blok ötede, iki tane Uber'i arka arkaya gördüm.
İşte lider Uber'in biraz daha net bir resmi: Görünüşe göre şu anda insan güdümlü, muhtemelen eğitim amaçlı. Google otomobil kendisi kullanıyordu.
İşe giderken hemen hemen her gün birkaç kendi kendine sürüş araba görüyorum, ancak bugün yalnızca birkaç fotoğraf çekmeyi ve paylaşmayı düşündüm. Kendi kendini süren bir arabanın sitesine zaten uyuştuğum gerçeği oldukça çılgınca - her yerde gerçekliğe sahip olmaktan çok uzak değiller (düzenleme bir yana).
Her neyse, kişisel bilgisayarımda çalıştırdığım yazılımın bu gerçek arabaları kontrol edebilecek kadar güçlü olduğunu düşünmek çok güzel.
Bugün hüzünlü bir hata ve barikatlar koleksiyonu oldu (mutlu sonlar olmadan). Kendimi kurtarmaya çalıştığımda, tavşan deliğinden daha derine ve daha derine düşmeye devam ettim.
Dün başladı - Udacity verilerini başarıyla yeniden biçimlendirdim ve kendi kendine sürüş otomobil modelini eğitmeye başladım.
Modelin eğitimi bitiminden sonra, Loss grafiğine hızlıca baktım (Loss, modelin “doğruluğunu” ölçer - kayıp ne kadar düşükse, model o kadar iyi…).
30 eğitim döneminden sonra, Loss 1.00 değerinin altına düşmedi bile; NVIDIA verileri üzerine bir model geliştirdiğimde, Loss, ~ 0.16'ya dek, 1.00'ın altına düştü.
Neden farklı bir şey olmasını beklediğimden emin değilim - Kullandığım Udacity veri kümesi, NVIDIA veri kümesinin yalnızca 1 / 8'i kadardı.
Bu benim ilk hatamdı: Yanlışlıkla test veri setini modeli eğitmek için kullandım. Bunun yerine, daha büyük bir eğitim veri setini kullanmalı ve sonra da eğitim modelini test veri setinde test etmeliydim.
Çok büyük bir sorun değil: Udacity Github sayfasına gittim ve daha büyük veri setini eğitim için indirdim. Ya da en azından denedim.
İndirme işleminin yarısında bilgisayarım tamamen çıldırdı.
Bilgisayarımın yerel depolama / başlangıç diskinin tamamen dolu olduğu ortaya çıktı. Öyle dolu ki, bilgisayarım herhangi bir programı çalıştırmayı reddetti. Finder bile beklenmedik bir şekilde çöküyordu.
Harici sabit diskime taktım ve tüm Aylarımı yerel makinemden Master belgelerine aktarmaya başladım.
Bu arada, bir yana, bilgisayar ekranımın fotoğraflarını telefonumla çekmek zorunda kaldım, çünkü bilgisayarımda ekran görüntüsü almaya yetecek kadar yer yoktu.
Her neyse, M2M dokümantasyonunun ilk altı ayı, 70,8'i yerel makinemde olan 132 GB'lık tutuldu, bu yüzden transfer bittikten sonra, 70 GB'lık yerel eşyaları Çöp Kutusuna taşıdım.
Sonra çöpümü boşaltmaya çalıştığımda bilgisayarım dondu…
Bilgisayarımı birkaç kez yeniden başlattıktan sonra, Çöp Kutusu nihayet boşaldı ve 30 dakika sonra tekrar işime döndüm.
Bilgisayarımdaki boş alandan, eğitim veri setini indirmek için Udacity Github sayfasına geri döndüm.
Eğitim veri kümesi bir torrentde sıkıştırıldı, bu yüzden veri setini indirmek için BitTorrent'i kurmam gerekiyordu.
Torrent indirildikten sonra dosyayı açtım. Daha önce gördüğümüz gibi bir sürü JPEG görüntü ve data.txt dosyası görmeyi umuyordum, ama bunun yerine ...
Anlaşılan Udacity, verileri .bag dosyalarına paketlemenin iyi bir fikir olacağını düşündü. Asla .bag dosyalarını daha önce hiç duymamıştım, ancak kendi kendini süren arabaların (ya da diğer "robotların" veri kaydettiği) yerel yol gibi görünüyorlar.
Bu yüzden, JPEG ve CSV'lerin ayrı .bag dosyalarından nasıl çıkarılacağını bulmam gerekiyordu.
.Bag dosyalarıyla çalışması için ROS (Robot Operating System) isimli bir kütüphane var. Bu yüzden yüklemeye çalıştım.
Ancak, işte ROS kurulum sayfasında bulduğum şey…
Başka bir deyişle, ROS yapan insanlar temel olarak “Bu işe yaramayacak” diyor. Başarısız olacak. Afedersiniz."
Ve haklılardı, başarısız oldu.
Yine de hatayı çözmek için biraz daha zaman harcadım ve sonunda ihtiyacım olan her şeyi başarıyla kurduğum anlaşılıyor gibiydi. Ancak, sonra extripti komut dosyasını çalıştırmak için çalıştı ve bu hala başarısız oldu.
Bu noktada, gece için durmak zorunda kaldım.
Yarın, umarım biraz ilerleme kaydedebilirim.
Dün ciddi bir şekilde mücadele ettim: Udacity’nin ROSbag dosyalarını JPEG’lere ve CSV’lere dönüştürmeye çalışıyordum, bu yüzden verileri kendi kendine sürüş arabamı eğitmek için kullanabiliyordum, ancak çok fazla şansım olmadı.
Sonuçta, Robot İşletim Sisteminin Mac ile uyumlu olmadığını keşfettim ve bu yüzden dosyaları bilgisayarımda yerel olarak düzgün bir şekilde çıkaramadım.
Bugün, birçok deneme yanılma sonrasında, VirtualBox kullanarak Ubuntu 14.04 ve ROS'un sanal bir makinede nasıl çalıştırılacağını çözebildim.
Daha fazla deneme yanılma sonrasında, ROSbag dosyalarının içeriğini çıkarmak için sanal makinenin nasıl kullanılacağını öğrendim ...
Makul boyutlu bir kamera görüntü seti ve karşılık gelen direksiyon açısı için bir CSV bulmayı bekliyordum.
Bunun yerine, Udacity veri kümesi, üç farklı kamera açısından ~ 33.000 kare video sürüş ve direksiyon, fren, gaz, GPS, vb. İçin tüm verileri içerir.
Örneğin, direksiyon CSV'sinde veriler sadece zaman damgası ve açı değil, aynı zamanda tork (tekerleğin dönme kuvveti) ve hız (dönüş hızı) içerir.
Her neyse, bu veri seti süper harika ve beklediğimden çok daha kapsamlı. Daha işlevsel, uçtan uca otomatik sürüş bir otomobil yapmak için bu verileri nasıl kullanabileceğimi görmekten heyecan duyuyorum.
Dün, Udacity veri setini kırdım…
Bu nedenle, bugün plan, verileri yeniden biçimlendirmek / hazırlamak ve ardından kendi kendine sürüş otomobil modelini eğitmeye başlamaktı.
İlk adım olarak şimdilik sadece direksiyon açısını modellemeye karar verdim. Bu iyi giderse, modeli hem gaza hem de kırmaya dahil edecek şekilde genişletmeye çalışacağım.
Verileri hazırlamak için şuna benzeyen bir data.txt dosyası oluşturmam gerekiyordu:
Temel olarak, karşılık gelen direksiyon açısının yanındaki karenin adı olan ve boşlukla ayrılmış bir düz metin dosyası.
Bu yeterince basit görünüyordu - ama bir sorun vardı:
Steering.csv dosyasını açtığımda, dosyadaki zaman damgalarının hiçbiri JPEG çerçevelerinin zaman damgalarıyla eşleşmedi. Belki bir şeylere göz kulak olduğumu sanıyordum…
Böylece, JPEG'leri inceledim ve ilk çift kare sayısını kopyaladım.
Ardından, CSV’yi bu çerçeve numaraları için ayrı ayrı aradım, ancak olmadı…
Bu bir problemdi.
Görüntüleri sürüş verileriyle eşleştiremezsem, veri kümesi tamamen işe yaramaz hale gelir.
Neyse ki, Udacity veri kümesinde diğer CSV'leri açma (sadece başka bir şeyin ne olduğunu görmek için) hakkında çok parlak olmayan bir fikrim vardı ve sonunda tüm verileri tek bir yerde toplayan VE tüm bunlara uyan interpolated.csv'yi açtı. Görüntülerin zaman damgalarına mükemmel veri.
Böylece, şansa geri döndüm.
İhtiyacım olan verileri çıkardım, data.txt dosyasını yarattım ve modeli eğitmeye başladım.
Bu muhtemelen bütün gece sürecek, bu yüzden yarın kontrol edeceğiz.
Dün, Udacity’nin geniş veri setine dayanan kendinden sürüşlü araba modelini eğitmeye başladım.
Kayıp değeri (modelin doğruluğuna dolaylı olarak orantılı ölçü) 6.14783 'te başladı.
Birkaç saat sonra, model eğitimi bitirdi ve Kaybı sadece 0,000377398'e düşürdü.
İşte zaman içindeki kayıp grafiği:
Kayıptaki bu azalma oldukça dikkat çekicidir.
Daha da çarpıcı olanı, 5.000 veri noktası kullanırken (birkaç gün önce yaptığım gibi), ~ 1.00 Kaybı ile ve Udacity'nin 33.000 veri noktası kullanıldığında, yaklaşık 0.000377398 Kaybı ile Zarar arasındaki farktır.
Başka bir deyişle, veri kümesinin büyüklüğü ~ 7 faktörü artırılarak, kayıp ~ 2500 faktörü azaltılmıştır. Açıkçası, bu doğrusal bir ilişki değil: Biraz daha fazla veriyle, model gülünç bir şekilde daha iyi hale geliyor.
İşte bu yüzden Google, TensorFlow aracılığıyla makine öğrenme algoritmalarının ve kitaplıklarının tümünü / çoğunu vermeyi başarabilir: Verilerin miktarı farklıdır ve Google’ın en fazla özelliği (arama, e-posta, fotoğraf, YouTube videoları, vb.).
Aslında, daha geniş bir geliştirici topluluğunun algoritmaları daha hızlı bir şekilde geliştirmesini sağlamak için algoritmalarını açmak için Google’ın yararınadır. Ardından, Google bu gelişmiş algoritmaları alabilir, kendilerine ait verileri besleyebilir ve en iyi makine öğrenme modellerine önemli bir oranda sahip olabilir.
Bugün gerçekten verinin değerini rekabet avantajı olarak değerlendirmeme yardımcı oldum.
Veriler hakkında konuşmak… Kendi veri setimin oluşturulmasında bir dönüm noktasına ulaştım: Bugün, Master projesine Ay'ımın bir parçası olarak blog yazısı yazdığım 200. günü işaret ediyor.
Günlük giriş verilerim artık 85.000 kelime civarında. Belki, bir kere 365 gönderimle işim bittiğinde, bu veri kümesiyle ilgili ilginç bir şey bulacağım…
Dün, Udacity veri setinde kendi kendine süren araba modelimi eğitmeyi bitirdim. Bugünün işi sonucu görselleştirmeye çalışmaktı:
Sonuçların iyi olmasını beklememe rağmen, öngörülen yönlendirme oldukça doğal ve çok titiz değil. Sonuçtan çok memnunum.
Unutulmaması gereken birkaç şey:
- Başlangıçta iki Udacity veri kümesi olduğunu düşündüm: Bir eğitim veri kümesi (dün kullandım) ve test verileri (yanlışlıkla birkaç gün önce eğitim için kullandım). Bugün, test veri setinin aslında eğitim setinin bir alt kümesi olduğunu fark ettim, bu yüzden test için Nvidia verilerinin bazılarını kullanmaya karar verdim. Buradaki önemli şey, modelin Udacity veri kümesi üzerinde eğitildiği ve Nvidia veri kümesinden tamamen yeni bir arazide test edildiği. Başka bir deyişle, model eğitim setinin dışındaki yollarda iyi çalışır (evrensel olarak işlevsel bir kendi kendine sürüş araba istiyorsanız bu çok önemlidir).
- Udacity modelinin çıktısını uygun şekilde simüle etmek için iki şey yapmam gerekiyordu: 1. Udacity verilerini, Nvidia simülatörü tarafından kullanılabilecek bir değer aralığına eşleştirin (Nvidia modeli, Udacity veri kümesi arasında değişirken, birimler olarak derece kullanır) -1 ila 1) ve 2. Udacity modelini test etmek için Nvidia test setinde (yani kırpma) bazı küçük ön işlemler yapın.
- Test sırasında, senaryo, direksiyon simidinin görüntülerini öngörülen direksiyon açısına göre döndürülmüş hale getirdi ve daha sonra bu renderleri, biraz daha geniş bir görünüm için orijinal, açılmamış Nvidia görüntülerinin üzerine yerleştirdim.
- Videoya yaklaşık 40 saniye sonra, otomobil tamamen durur ve sonra keskin bir sağa dönüş yapar. Görünüşe göre, görseller doğru gitmeyi (araba dümdüz gidebilir) doğru olduğunu göstermeden önce otomobil dönmeye başlıyor gibi görünüyor, bu yüzden bunun nasıl olacağını tam olarak bilmiyorum. Udacity veri kümesi bu özel dönüş hakkında hiçbir bilgiye sahip değildir. Makul bir açıklama, modelin sıra şeridinde olduğunu fark etmesi veya modelin bir insandan daha öngörücü olduğudur. Her iki durumda da, bu biraz şaşırtıcı, ama görmek çok güzeldi.
Neredeyse bu ayki zorlukla bitirdim: Sadece modeli boğulma ve kırılma konusunda eğitmem gerekiyor, ki, modelin direksiyon açısı konusunda nasıl eğitildiği ile neredeyse aynı olacak (şüphesiz, direksiyon açısı, azaltma ve kırma tüm sadece keyfi tanımlı sayılarla gösterilir).
Bu ayın çoğu için, kendi sürüş arabam için bir direksiyon açısı tercihcisi oluşturmaya odaklandım.
Bununla birlikte, arabamı bitirmek için, gaz / gaz kelebeği ve aracın frenini (yani “pedallar”) kontrol etmek için nasıl bir sistem inşa edeceğimi anlamam önemlidir.
Bu tamamen yeni bir sorun gibi görünse de, pedal sistemimi herhangi bir yeni satır kodu yazmadan oluşturabildiğim ortaya çıkıyor.
Sonuçta, direksiyon modelim 1 tarafından yapıldı. Bilgisayara bir sürü resim göstererek, 2. Her resme sayısal bir değer atama, 3. Bilgisayardan, görüntülerin piksellerinin sayısal değerlerle nasıl ilişkili olduğunu bulmalarını isteme, 4 Diğer görüntülere atanan sayısal değeri tahmin etmek için bu ilişkiyi kullanın.
Direksiyon modelinde, bu sayısal değer direksiyon açısını temsil ediyordu. Ancak, gaz kelebeği veya fren miktarını kolayca temsil edebilirdi.
Böylece, pedal sistemi oluşturmak için tek yapmam gereken her görüntüye doğru gaz miktarına veya fren miktarına karşılık gelen sayısal bir değeri yeniden atamak ve ardından bilgisayardan (aynı şekilde) arasındaki ilişkiyi belirlemesini istemek oldu. pikseller ve sayısal değerler.
Demek yaptığım buydu.
Örneğin, gaz olması durumunda, data.txt dosyasını, karşılık gelen gaz miktarlarıyla eşleşen 10.000 görüntüyle hazırladım ve daha sonra bu dosyayı tam olarak aynı makine öğrenme modelinde yürüttüm.
Beklendiği gibi, model zamanla öğrendi, Kaybı azalttı ve gaz miktarını tahmin etmenin etkili bir yolunu belirledi.
Fren sistemi için de aynısını yaptım.
Başka bir deyişle, kullanmakta olduğum makine öğrenme modeli tamamen geneldir. Girişlerin direksiyon açısı, gaz kelebeği değerleri veya fren değerleri olması önemli değildir. Model ayrımcılık yapmıyor.
Bu belki de antiklimaktiktir, fakat bir anlamda, başka bir deyişle, hayret verici bir şey: Makine öğrenimi teknolojisi, her uygulama için oldukça özel modeller oluşturmaya ihtiyaç duymadığımız bir noktaya geldi. Bunun yerine, tek bir model birçok alanda oldukça genişletilebilir - ve bu daha iyi olmaya devam edecek.
Mesele şu ki, bedava boğulma ve fren yapmak için gerçekten çok fazla iş yapmak zorunda değilim. Bu oldukça iyi bir anlaşma…
Bu ay, kendi kendini süren bir arabanın yazılımını oluştururken kendime meydan okudum. Özellikle, iki ana şey inşa etmek istedim: 1. Otomobilin direksiyon sistemi ve 2. Otomobilin pedal sistemi (örneğin gaz ve fren).
İki gün önce, yolun öne bakan bir video beslemesine dayanarak direksiyon açısını doğru bir şekilde tahmin edebilen direksiyon sistemini oluşturmayı bitirdim.
Direksiyon sisteminin başarılı sayılması için iki alt hedef belirledim:
- Kendi kendine sürüş otomobil modelini, özellikle tasarlanmadığı bir veri setine uyarlamam ve kullanmam gerekiyordu. NVIDIA’nın Udacity tarafından sağlanan bir veri setine uygulanan araştırma belgesine dayanan bir model kullandığım için, bu alt hedefin gerekliliklerini yerine getirdim.
- İkincisi, modeli bir veri setinde (yani, yol kümesi) ve tamamıyla farklı bir veri setinde (yani, yeni yollar kümesi) iyi performans göstermesini sağlamalıydım. Modeli Udacity veri kümesi üzerinde eğittiğim ve modeli NVIDIA veri kümesi üzerinde başarılı bir şekilde test ettiğimden, bu alt hedef için gerekli koşulları yerine getirdim.
Daha sonra, dün aynı modeli değiştirilmiş veri girişleriyle, yolun öne bakan bir video beslemesine dayanarak gaz miktarını veya fren miktarını doğru bir şekilde tahmin edebilen gaz ve fren sistemlerini başarılı bir şekilde oluşturmak için kullandım.
Tüm bu parçalar birleştirildiğinde, bu ayki zorluk resmen tamamlandı!
Dün, bu ayki mücadeleyi başarıyla tamamlayıp kendi kendini süren bir arabanın yazılım bölümünü başarıyla oluşturdum.
Şimdi, soru şu: Arabamı Kaliforniya yollarında çıkarmak için ne yapılabilir / inşa edilir?
En iyi yanıt, DIY araba sürme hareketine öncülük eden George Hotz'dan geliyor.
Bloomberg, 18 ay önce, garajında tam işlevli (az ya da çok) kendi kendine çalışan bir araba yapan 26 yaşındaki Hotz hakkında bir video yayınladı:
Videoda, George, aracı oluşturmak için yalnızca iki şey inşa etmesi gerektiğini açıklıyor: 1. Giriş verilerine dayanarak sürüş talimatlarını verebilecek bir sistem ve 2. Otomobilin fiziksel aktüatörlerini kontrol edebilecek bir sistem (örn. Dijital girişlere dayalı direksiyon simidi, gaz kelebeği).
Bu ayın başında # 1 “yazılım bölümü” ve # 2 “donanım bölümü” olarak adlandırdım ve enerjilerimi yazılım üzerine yoğunlaştırdım. Bu yüzden, # 1 tamamlandığında, arabamı geliştirmeyi bitirmek için # 2'ye ihtiyacım olacak.
Hotz'ın videoda açıkladığı gibi, otomobilin tüm fiziksel aktüatörlerini kontrol etmek için, bilgisayarını arabanın hata ayıklama portuna bağladı (tıpkı bir tamircinin yaptığı gibi). Elbette, daha sonra, yazılım sisteminin gerçek zamanlı olarak bu bağlantı noktasından araca talimatlarını doğru şekilde göndermesini nasıl sağladığını bulması gerekiyordu, ama aslında çok fazla donanım korsanlığı yapmak zorunda değildi: Araba zaten dijital olarak bu şekilde kontrol edilebilir.
Arabalar hakkında çok fazla şey bildiğimden değil, ancak bu çok yaklaşılabilir hissettiriyor (İnternet ve YouTube’a erişimim olduğu sürece). Başka bir ayım olsaydı ve daha da önemlisi bir araba olsaydı, bu bir sonraki adımda doğal olurdu.
Temel olarak, uçtan uca kendi kendine sürüş arabanın sonuçta efsanevi olmadığı anlaşılıyor. George Hotz, kendim de dahil herkese, kendi kendini süren araba alanının yalnızca Google gibi şirketler için erişilebilir olmadığını, aynı zamanda oldukça hobi hobileri için de uygun olduğunu gösterdi.
Bloomberg videosunun yayınlanmasından bu yana, birçok küçük ekip şu anda kendi kendine sürüş arabaları ve ilgili servisler üzerinde çalışıyor ve bunun gelecek yıl içinde önemli ölçüde hızlanması bekleniyor.
Umarım, bu hikayede çok küçük bir rol oynadım, bu teknolojinin erişilebilirliğini göstermeye devam ediyorum…
Bu ayın mücadelesi, önceki Master için altı aydan biraz daha farklı. Özellikle, çok iyi yaşlanmayacak…
Şubat 2017'de bir backflip indi. Şubat 2020 yerine, bir fark yaratmayacaktı.
Aralık 2016'da gerçekçi portreler çizmeyi öğrendim. Bunun yerine Aralık 2036 olsaydı, bir fark yaratmazdı.
Bu ay, Mayıs 2017'de, kendi kendini süren bir arabanın yazılımını yaptım. Eğer bu Mayıs 2020 ise, bu meydan okuma tamamen farklı olurdu.
Tabii ki, bu bir tahmin, ama yine de… Üç yıl içinde, bu ay yaptığım her şeyin bir satır kodla (muhtemelen her şeyden soyutlanacak şekilde) bir araya gelmesi muhtemel.
Sadece bu değil, kişisel bilgisayarım çok daha hızlı ve daha hızlı bir şekilde veri toplayabiliyor ve bu da kendi kendine süren araba için katlanarak daha iyi bir model üretiyor.
Temel olarak, demek istediğim, bu ayki mücadelenin birkaç yıl içinde zorluk olmayacağı yönünde.
Bu o kadar da önemli bir şey değil, ancak becerilerin eskimişliği ve “son teknolojinin” hızla “sıkıcı orta” hale gelmesi hakkında düşünmek ilginç.
Belki de, bu ayki “performans hobisi meraklılarının insanların araba kullandığı bir dünyada kendi kendini süren yazılımlar geliştirdiği” zorlu performans sanatını düşünmeliyim. Ardından, bu ayki bloglar yayın kümesi zaman içinde daha alakalı / ilgi çekici kalabilir. Sonuçta, sanat genellikle zaman içinde değer kazanır.
Neyse, sadece paylaşmaya değer olduğunu düşündüğüm bir gözlem.
Bugün beş günlük bir tatil için Seattle'a uçuyorum, bu yüzden bu ayki mücadeleyi biraz erken bitirmek için çalıştım.
Seattle’dayken, günlük gönderilerimi yazmaya devam edeceğim (hala süreçlerim ve öğrenme tekniklerim / içgörülerim hakkında düşünecek çok şeyim olduğundan), ancak daha fazla yazılım üzerinde çalışmayı planlamıyorum. .
Bu yüzden ölçülebilir hedefler belirlemenin önemi var: Başarmak için belirlediğim şeyi kesin olarak tamamladığımdan, tatile çıkmakta iyi hissedebiliyorum.
Birçok insan genellikle hedeflerini daha belirsiz terimlerle tanımlar - “İspanyolca konuşmayı öğrenmek istiyorum”, “Nasıl çizileceğini öğrenmek istiyorum”, “Piyano çalmayı öğrenmek istiyorum”. Bu gibi durumlarda, hedefi tamamlamak asla mümkün olmaz ve nasıl ilerlediğinizi gerçekten bilmek mümkün değildir.
Daha tanımlanmış bir hedef çok daha fazla tercih edilir.
Açık uçlu bir hedefin, hedefe değil peşine daha fazla önem verdiği, öğrenmeye çalışırken daha verimli bir zihniyet olduğu konusunda hemfikir olduğum söylenebilir. Ancak, iyi tanımlanmış bir hedef olmadan, neyin takip edilmekte olduğu bile belli değil.
Belirsiz bir amaç, bana göre, hedefin yaratıcısının gerçek bir temel amacı olmayan, tembel bir hedef. Sonuçta, belirsiz bir hedefle, başarısız olamazsınız (ki bu belki de çekicidir), ancak başarılı olamazsınız.
Ve… Kötü tanımlanmış bir amacın peşinden koşarsanız, ne zaman duracağınızı veya ne zaman duracağınızı bilmek zor (ve hayatınızın diğer önemli kısımlarına odaklanmak) zor.
Ama yine de, açıkça tanımlanmış hedefimi tamamladığımdan beri, Seattle suçluluk duymadan yolculuğumun tadını çıkarmaya tamamen hazırım.
Birkaç gün önce, kendi kendini süren araba yarışmasını tamamladığımı beyan ettim. Sonuçta bilgisayarımın bir otomobili yönlendirdiği bu video…
Bu ayın denemesinin çıktısı kesinlikle bir aracı özerk bir şekilde kontrol edebilen bir sistem olsa da, soru hala devam ediyor… Bu ay kişisel olarak ne başardım?
Ne de olsa, kendi kendine sürüş arabam birincil olarak başkasının açık kaynak koduna dayanıyordu (hafifçe uyarlayıp genelleştirdim). Bu açık kaynaklı kod, NVIDIA’nın kendi kendine sürüş otomobil araştırma ekibi tarafından yazılmış bir bildiriye dayanıyordu. Araştırmadan elde edilen model, NVIDIA laboratuvarları dışında, özellikle üniversite araştırma merkezlerinde icat edilen matematiksel tekniklere (geri yayılım vb.) Dayanıyordu. Ve devam edebilirim…
Bu matematiksel teknikler, yüzlerce yıl önce icat edilmiş olan matematiğin temel içgörüleri üzerine inşa edilmiştir.
Bunu farklı bir yöne de götürebilirim: Koştum kod, Google tarafından oluşturulan, başkaları tarafından oluşturulan bir üst düzey programlama dili üzerine kurulu bir makine öğrenme kütüphanesinin üzerine inşa edildi. Ek olarak, bu kodlardan herhangi birini çalıştırmak için gerekli kütüphaneleri bilgisayarıma kurmam gerekiyordu. Bu kütüphaneleri kurmak karmaşık olabilir, bu yüzden süreci kolaylaştırmak için diğer kişilerin kurdukları kurulum servislerini kullandım.
Hala devam edebilirim… ama olmayacak.
Peki, şu soruya dönersek: Bu ay şahsen ne başardım? Tam olarak belli değil.
Bir yandan, bilgisayarımda yerel olarak çalıştırmak için kendinden sürüşlü bir araba sistemi elde edebileceğimi ve sistemi yeni veri kaynaklarını etkin bir şekilde işlemesi için uyarlayabildiğimi söyleyebilirim.
Öte yandan, birçok insanın çalışmalarını alıp video oluşturmak için birleştirdiğimi söyleyebilirim.
Her ikisi de doğru.
Peki ben gerçekten kendi kendine sürüş bir araba mı yaptım? OnePlus veya Xiaomi gibi şirketler, yazılım Google tarafından ve donanım bileşenleri Samsung, Foxconn ve diğerlerini oluşturduğumda bile akıllı telefonlar ürettiğini söyleyebilir misiniz?
“Montaj” “bina” olarak sayılıyor ve “toplanma” “öğrenme” olarak sayılıyor mu?
Evet diyecektim ama önemli olduğunu sanmıyorum.
Daha ilginç paket servis şudur: Bazen, zorlu veya erişilemez görünen şeyler aslında göründüğünden çok daha acemi-dostu olurlar. Bu nedenle, “kendi kendini süren bir araba inşa etmek” ile fark değil, bunu çözebileceğime olan inancım ve bunu yapma girişimim oldu.
Başka bir deyişle, çoğu zaman, üstatlığın münhasırlığı sadece var olur çünkü çoğu insan asla “bir şeyi” takip edemez (yapamayacağı varsayımına dayanarak).
Bu yüzden, bu ay başarabildiğim şeyi yeniden düzenlemek istiyorum: Kendi kendine süren bir araba inşa etmenin delice zor problemini çözmedim. Bunun yerine, kendinden sürüş bir araba yapmanın (bugünden itibaren) aslında delice zor bir sorun olmadığını kanıtladım. Bu noktada, sıradan hobilerin çoğunun çözebileceğine inandığım bir şey.
Bence bu zaten daha ilginç bir sonuç.
Bu ay boyunca, kendi kendini süren otomobillerin gizemlerini gizlemeye çalıştığım için, bir sorumu diğerlerinden daha çok ele aldım: Şimdi teknolojiyi daha iyi anlayabildiğine, tamamen kendi kendine sürüş araba?
Daha güvenli diyebilirim ama karmaşık bir durum: Kendi kendine sürüş otomobil modelinin basitliği, daha fazla veri ve işlem gücüyle kendi kendine sürüş özelliklerinin katlanarak daha iyi olmaya devam edeceği konusunda bana güven veriyor. Bununla birlikte, beynimin irrasyonel kısmı, modelin sürüş görevi için çok basit ve spesifik olmamasından dolayı garip hissediyor.
Yine de, model ne kadar basitse, o kadar genelleştirilebilir ve eğitilebilirdir, bu yüzden tamamen özerk otomobillerin geleceği konusunda kendimi güvende hissediyorum (Eh, kendimi güvende hissettiğimi kendimi güvende hissediyorum. ezgimi değiştir…).
Genel rahatlığım karşısında cevap olarak duyduğum ortak bir soru şudur: “Hayatınızı kontrol etmeyi tercih etmez miydiniz? Tamamen özerk bir otomobil kullanmak bir bütün olarak istatistiksel olarak daha güvenli olsa bile, kendinizi hayatta tutmak için kişisel olarak yapabileceğiniz her şeyi yaptığınızı bilmek istemez miydiniz? ”
Sırala. Ama, gerçekten, bir arabaya sahip olmadığımdan ve hayatım boyunca yabancılara (Uber / Lyft sürücüleri) güvendiğimden beri, şu anda bu kontrole sahip olduğumdan emin değilim.
Kısa bir zeyilname olarak: İki gün önce, MIT yıllık araştırma raporunu kendi kendine süren otomobillere olan tüketici ilgisinin mevcut durumunu yayınladı ve çalışmanın 3.000 katılımcının% 48'i hiçbir zaman kendisini tamamen sürecek bir otomobil almayacaklarını söyledi.
Sadece bu değil, geçen yıl, 25-34 yaşındakilerin% 40'ı tamamen şöförsüz bir araba ile rahat olacaklarını söyledi ve henüz aynı grubun sadece% 20'si bu yıl aynı dedi.
Genel halk kendi kendine sürüş arabaları hakkında daha fazla şey öğrendikçe, rahatlıklarının azalmakta olduğunu görmek ilginç.
Dürüst olmak gerekirse, MIT belgesini okuduktan sonra, kamuoyu ile aynı fikirdeyim (en azından bugünden itibaren… Ama yine de oldukça iyimserim).
Şu anda Seattle’da bir arkadaşımı ziyaret ediyorum, bu bana iki gün önce yazdığım gönderi hakkında bana zor anlar yaşatıyor:
Bu yazıda, kendi kendini süren araba çabalarımı büyük ölçüde hızlandırmak için ortak bilgi birikiminden ve diğer birçok insanın çalışmalarından yararlanabileceğimi açıkladım. Özellikle, makine öğrenme modelini sıfırdan oluşturmam gerekmemişti, ama bunun yerine, zaten inşa edilmiş bir modeli sistemime entegre edebildim.
Sonuç olarak, çok fazla "Duyurduğum çekirdekli araba modelini kurmanız gerekmediyse, bu ayki zorluk aslında nasıl bir zorluktu?" Diye duydum.
Cuma günkü yazıya göre, algılanan zorlukların (kendi kendini süren bir araba mekanizması oluşturma) aslında meydan okuma olmadığını kabul ediyorum, ama bu hiç bir zorluk olmadığı anlamına gelmiyor.
Aslında, algılanan mücadelenin hiçbir zaman gerçek meydan okuma olmadığını iddia ediyorum.
Örneğin, kasım ayında, karıştırılmış bir iskambil destesinin sırasını ezberleyerek hafızanın büyük şefi olmaya çalışırken, zor kısım aslında hatırlamıyordu. Bunun yerine, önceki girişimler sırasında neyi ezberlediğimi unutuyordum (kendimi karıştırmamak için).
Şubat ayında geri tepmeyi öğrenirken, zor kısmın fiziksel veya atletik herhangi bir şeyle ilgisi yoktu, ama bunun yerine, kendini koruma ile ilişkili zihinsel engeller ve korku ile ilgiliydi.
Bu ay, meydan okuma kendi kendini süren araba modelini yaratmıyordu, ama bunun yerine, bu modeli gerçekten benim çalışmam için sistemime entegre ediyordu.
Bu şaşırtıcı değil - yazılım mühendisliğinin çoğu tamamen yeni bileşenler oluşturmak zorunda değil. Genellikle, bir sürü önceden var olan bileşenlerin nasıl alınacağını, hepsinin birbirine nasıl uyduğunu ve çıktı işlevinin beklendiği gibi nasıl yapıldığını çözer.
Aklımda, yazılım mühendisliği bir organ nakli yapmak gibi bir şeydir: İşin püf noktası yedek organı bulamamaktadır (bununla birlikte hala uzun bir süreç olabilir). İşin püf noktası, bedeni yeni organı reddetmemek.
Benzer şekilde, yazılım mühendisliğinin iki temel zorluğu vardır: 1. 'Organı' (yani oluşturmak istediğiniz bileşenin bir örneği) bulmak, 2. Bu 'organı' bütün yapıya entegre etmek (yani geliştirme ortamınızın uygun şekilde kurulmasını sağlamak; Bileşenin diğer bileşenlere ve hizmetlere bağlanması, böylece projenin geri kalanıyla düzgün bir şekilde etkileşime girmesi, bileşenin beklenen / ihtiyaç duyulan şekilde davranması için değiştirilmesi.
Ve böylece, bu ayki zorluk, otomobil kullanmanın algılanan zorluğundan dolayı zor olmasa da, 1'i denemek isteyen çaresizlik kodlama çukurunda hala çok fazla zaman harcadım. Başarıyla çalıştırabilirim, 2. Bilgisayarımın ortamını modeli destekleyecek şekilde ayarlayın, 3. Verileri modelin kullanabileceği şekilde biçimlendirin, 4. Modelden ilginç bir şey çıktısını alın, 5. Çalışacak modeli değiştirin farklı veri kümeleriyle ve farklı davranışların modellenmesi için.
Genel olarak, algılanan zorluk bir meydan okuma değildi, ama yine de çok sürtünme vardı.
Burada aslında önemli bir ders var: Çoğu zaman, insanlar yeni bir şeyler öğrenirken, “zor olacak” veya “ne olması gerektiği” hakkında önceden düşünülmüş bir fikre sahipler. Sonuç olarak, yol boyunca başka zorluklar olduğunda, insanlar bu zorlukları öğrenme sürecinin ek bölümleri yerine engeller olarak algılarlar.
Başka bir deyişle, insanlar mücadele etmeyi umdukları şey için mücadele ettiğinde, genellikle sebat etmeyi haklı kılar. Bununla birlikte, dikkat dağıtıcı gibi görünen bir şey için mücadele ediyorlarsa, insanlar pes etme eğilimindedirler (zamanlarını boşa harcadıklarını algıladıkları için).
Fakat açıkça, bu dikkat dağıtıcı şeyler genellikle öğrenme zorluğunun gerçek etidir ve çatlarsa hedefe yönelik en fazla ilerlemenin kilidini açar.
Ryan Holiday'in açıkladığı gibi: “Engel yol”
Engellerin, hedefine ulaşman için seni engellemiyor, ama aslında peşinde koşmanın kendisini tanımla.
Bu yüzden, bu ayki mücadeleye meydan okuma diyerek katılıyorum. Anlambilimin yine de önemi yok… Ancak, öğrenme ve azimle ilgili önemli bir ders ortaya koyuyor.
Yarın, uygulama kayıtlarımdan geçmeyi ve bu ayki mücadeleye ne kadar zaman harcadığımı hesaplamayı planlıyorum.
Ancak, bunu yapmadan önce, bu ay vaktimi nasıl harcadığımı ve daha da özellikle zamanımın nasıl dağıldığını not etmek önemlidir.
Önceki aylarda, uygulama sürem oldukça eşit bir şekilde dağıtılmıştı - 30 gün boyunca 30 saat geçirirsem, genellikle günde bir saat harcıyordum.
Ancak, bu ay, oturumlarımın uzunlukları genellikle anlamlı derecede daha uzun ve daha az üniformdu. Bu ayın farkını anlamak için, öğrenmenin iki aşamasını ve iki öğrenme türünü anlamak gerekir…
Öğrenmenin iki aşaması:
- Keşif Aşaması - Bu aşamada, öğrencinin görevi alanı araştırmak, en iyi yolu keşfetmek ve alıştırmaları bu en iyi yola göre tasarlamaktır.
- Eğitim Aşaması - Bu aşamada, öğrenci neye ihtiyaç duyduğunu zaten biliyor ve tüm zamanını bilinçli ve yoğun bir şekilde eğitimini bu en iyi yola odaklayarak geçiriyor.
Tüm öğrenme bu iki aşamayı gerektirir, ancak bu aşamalar farklı öğrenme türleri içinde farklı etkileşime girebilir.
İki tür öğrenme:
- Ayrık Öğrenim - Ayrık Öğrenmede, Keşif Aşaması ve Eğitim Aşaması tamamen ayrı olarak ya da ayrık bir şekilde takip edilebilir. Örneğin, bir deste desteyi ezberlemeyi öğrenirken, önce uygun tekniği keşfedebildim, sonra da bu tekniği ayrı ayrı uyguladım. Ayrık Öğrenme genellikle kısa ama etkili eğitim seanslarına izin verir (gerekli Keşif Aşamasından sonra)
- Eşzamanlı Öğrenme - Eşzamanlı Öğrenme'de, Keşif Aşaması ve Eğitim Aşaması aynı anda sürdürülmelidir. Genellikle, Eşzamanlı Öğrenme, henüz açıkça tanımlanmış bir yolun (dışarıdan keşfedilebilecek) olmadığı ve bu nedenle de eğitim sırasında ortaya çıkarılması ve şekillendirilmesi gerektiğinde mevcuttur. Bu süreç tipik olarak, ilerlemenin öngörülemez ve yapılandırılmamış olması koşuluyla, daha uzun oturumlar gerektirir.
Geçtiğimiz altı aylık zorluklar sırasında, eğitimimi ay boyunca kısa, yoğun seanslara eşit bir şekilde dağıtmamı sağlayarak, oldukça ayrık bir yaklaşım izleyebildim (ilk önce en iyi eğitim yöntemlerini araştırdım ve sonra eğitim aldım).
Ancak, bu ayki zorluk sırasında, açıkça tanımlanmış bir yolun lüksüne sahip değildim. Udacity’nin 2400 dolarlık çevrimiçi kursu (ödemeye hazır değildim) dışında, kendi kendini süren bir araba yapmak için izleyebileceğim açık bir plan yoktu. Bunun yerine, yolumu bulmadan önce bir sürü çıkmaz ve kavşağı keşfetmem gerekiyordu.
Sonuç olarak, bu ayki oturumlarım genellikle en az birkaç saat sürdü, ancak miktar olarak daha azdı.
Günlük 45 dakikalık seanslar boyunca kendinden sürüşlü bir araba yapmayı deneseydim, asla başaramazdım. Bu ay özellikli öğrenme türüne uyması için zamanımı yeniden yapılandırmam ve yeniden dağıtmam gerekti (yani, Eşzamanlı Öğrenme).
Dolayısıyla, genel paket şu şekildedir: Kendi kişisel öğrenme zorluğunuzu üstlenmeyi planlıyorsanız, hangi tür bir öğrenmenin gerekli olduğunu belirlemek ve zamanınızı buna göre yapılandırmak ve programlamak önemlidir.
Neredeyse Mayıs ayının sonundan bu yana, geriye bakma ve bu ayki mücadelede ne kadar zaman harcadığımı görme zamanı.
Zamanımın çoğu, aşağıdaki uzunluklarda dokuz uzun oturumda dağıtıldı: 1.5 saat, 2 saat, 2.5 saat, 1.5 saat, 1 saat, 3.5 saat, 2.5 saat, 1.5 saat, 1 saat, 3 saat.
Ayrıca 15 dakikalık dört seans boyunca bir saat daha geçirdim ve beş saat boyunca araştırma, okuma ve yazma (özellikle bir öğrenme aracı olarak kullanıldığı durumlarda sayıyorum).
Toplamda 26 saatimi kendi arabamı sürmek için harcadım.
Bu toplamı hesaplamadan önce, 35-40 saat civarında bir şeyler bekliyordum, bu yüzden kesinlikle bu sonuçtan biraz şaşırdım. Ama şimdi mantıklı geliyor: Zaman harcıyormuş gibi hissettiğim birkaç gün vardı, ama aslında bilgisayarımın kendi başına çalışmasına izin veriyordum veya normalden daha ayrıntılı bir günlük yazı yazıyordum (yani aslında kendisine meydan okumak).
İlginç bir şekilde, bu ay her şey yolunda giderse, tüm meydan okumayı birkaç saat içinde bitirebilirdim. Elbette, her şey yolunda gitmedi ve en başından beri tam olarak neyin doğru olduğunu bilmiyordum - ama yine de… Bu ayın zamanımın çoğunluğu yolumu bulmak için harcandı.
“Yol” un kendisi aslında çok uzun sürmedi.
Bugün kendi kendini süren araba mücadelesinin son günü ve bu ay boyunca aldığım en büyük sorulardan birine değinmek istiyorum: “Burada bir şeylerin olduğunu düşünüyorum… Bundan nasıl para kazanacaksın?”
Garip çünkü kart destesini ezberlemeyi ya da backflipi indirmeyi öğrendiğimde kimse bana bunu sormadı.
Bu yüzden, bu son yazı benim cevabımdır (buna rağmen, doğrudan soruyu doğrudan cevapladığımdan emin değilim)…
Çalışan çoğu yetişkin yeni beceriler öğrenmeye zaman ayırmanın zor olduğunu düşünüyor. Ve zaman bulanlar genellikle profesyonel odaklı yetenekler edinmeye odaklanırlar.
Başka bir deyişle, çoğu yetişkin yalnızca bunun uğruna ustalık peşinde koşmaz. Bunun yerine, arayışları ticari olarak haklı ya da kariyer odaklı olma eğilimindedir.
Bu motivasyonda yanlış olan bir şey yok. Aslında, kesinlikle motive olmayan öğrenmeyi kesinlikle öğrenmemeye teşvik ediyorum. Ancak, mesleki becerilerle ilgili bir sorun var: Çok uzun süre alakalı veya ilginç kalmıyorlar.
Bu ayki mücadelenin öncesinde, zamanımı (eğer Rubik’in Cubing’i ve çizim portreleri gibi), ticari değeri çok sınırlı olan becerilerimi geliştirmek için harcadım. İşin güzel yanı… Yaşadığım sürece, bu becerilerin tadını çıkarabilirim. Başka bir deyişle, ilk yatırımım teorik olarak sonsuz getiri sağlar.
Öte yandan, bu ay, benim mücadelem çok ticari odaklıydı (veya en azından olabilir). İstesem, yeni keşfedilen kendi kendine sürüş araç becerilerimi toparlayabilir ve büyük bir teknoloji firmasında kendi kendine sürüş otomobil mühendisi olmaya çalışabilirim. Veya, alternatif olarak, kendi kendine sürüş arabamı çalıştırmaya başlayabilirim. Veya, müfredatımı bu meslek hedefleri olan başkalarına paketleyip satmaya çalışabilirim.
Bu ay edindiğim becerilerle, ticari olarak ilginç birçok şey yapabilirim.
Ancak, işte asıl şey… 24 ay içinde (daha önce olmasa da), tüm bu ticari değer kayboluyor. Sadece bu değil, 24 ay içinde, bu zorluk artık alakalı olmayacak ya da entelektüel olarak hiç ilginç olmayacak: Zamanlama, hala makul derecede etken olmayan teknik detaylar ve kendi kendini süren otomobiller için mevcut heyecan nedeniyle ilginçti.
Bu yüzden, ticari bir araba sürüşü özlemim olmadığından, araba kullanmayla ilgili eğlencem Mayıs ayı ile birlikte bitecek. Mücadeleyi fethetmekten çok eğlendim ama yine de her zaman tekrar tekrar çözdüğüm Rubik Küpü için olduğu gibi, tekrarlanan eğlenceli olanakların olduğundan emin değilim.
Belki de aşırı dramatikleştiriyorum, ancak ticari yönelimli becerilerle karşılaştırıldığında, ebedi yetenekleri tercih etme eğilimindeyim.
Ticari motivasyonların, genel olarak öğrenmenin en verimli temeli olamayacağını nasıl düşündüğüm hakkında daha fazla yazabilirim, ancak şimdilik bu noktaya değineceğim.
Yapmak istediğim asıl nokta şudur: Şu anda kendinize yatırım yapıyor musunuz? Yeni bir şeyler öğrenmeye mi çalışıyorsun? Ve özellikle, eğlenceli olduğu için yeni bir şeyler öğrenmeye mi çalışıyorsunuz (finansal nedenlerle değil)?
Olmazsa, belki düşünmeye değer.
Zamansız öğrenmenin bir şekilde daha iyi ya da “daha seçkin” ya da böyle bir şey olduğunu düşündüğüm için değil. Sadece eğlenceli olduğunu düşünüyorum. Ve çoğu zaman kendimize eğlenme fırsatı vermeyiz, çünkü bunun pratik olduğunu düşünmüyoruz.
Ancak pratik olarak kısa ömürlü ve sürekli değişiyor gibi gözüküyor, bu yüzden bazı pratik olmayan eğlencelere biraz zaman ayırmanızı tavsiye ediyorum.