На 1 май 2017 г. си зададох въпроса: Мога ли да науча необходимата компютърна наука за изграждане на софтуерната част на самостоятелно управлявана кола за един месец?

На 22 май 2017 г. след 26 часа учене и кодиране разбрах, че отговорът е „да“.

През месец май аз документирах целия си учебен процес в поредица от 31 ежедневни блог публикации, които са събрани тук в един разказ. В тази статия можете да преживеете моя месец на прозрения, неудовлетвореност, изучаване на хакове и триумфи, тъй като се стремя към месечно овладяване.

Днес започвам нов месец и ново предизвикателство: Мога ли да науча необходимата компютърна наука за изграждане на софтуерната част на самостоятелно управлявана кола за един месец?

Определяне на успеха

За да изградя напълно самостоятелно управлявана кола, ще трябва да изградя 1. Софтуер за самостоятелно управление на автомобил и 2. Хардуер за самостоятелно управление на автомобил. Софтуерът ще използва сензорни и входни данни за алгоритмично генериране на инструкции за шофиране, а хардуерът ще изпълнява тези инструкции за шофиране в рамките на действителната кола.

Тъй като голяма част от техническото предизвикателство всъщност е в софтуерната част (а също и защото не притежавам автомобил), ще се фокусирам изключително върху софтуерната част за предизвикателството за този месец.

По-специално искам да създам самостоятелно управляващ софтуер, който може да направи две неща:

  1. Въз основа на видео входа на пътя софтуерът може да определи как безопасно и ефективно да управлявате автомобила.
  2. Въз основа на видео входа на пътя софтуерът може да определи как безопасно и ефективно да използва механизмите за ускорение и спиране на автомобила.

Може да се опитам да се справя с всяко от тези парчета поотделно или заедно. Все още не съм сигурен. Аз също не съм напълно сигурен в конкретните подробности за всяко от тези предизвикателства, но ще ги изясня по-сериозно, след като направя някои първоначални изследвания.

Възможно е да има и други важни съображения за софтуера за самостоятелно управление на автомобили, който не е включен в тези две кофи, но това са предметите, върху които ще се съсредоточа този месец. От тези елементи става ясно, че основно гледам да науча как да използвам машинно обучение / дълбоко обучение за решаване на проблеми с компютърното зрение (ще обясня какво означава всичко това в бъдеща публикация).

Моята отправна точка

Изграждането на софтуер за самостоятелно управление на автомобил очевидно изисква известно количество познания по компютърни науки и в тази връзка не започвам от нулата.

Първо, моята степен по Браун е по математика, което е много полезно за този конкретен клон на компютърните науки. Имам и общ фон за кодиране / компютърни науки, който със сигурност ще ми помогне.

Най-интересното е, че миналото лято публикувах няколко парчета фен-фантастика, които генерирах с помощта на подходяща техника за машинно обучение - като тази глава на Хари Потър, написана на AI - но това беше най-вече свидетелство за наличието на висококачествен отворен код код, а не моите знания за машинно обучение.

Миналото лято взех и математически базиран курс по задълбочено обучение (дълбокото обучение е подкатегория на машинно обучение ... което е подкатегория на изкуствения интелект ... което е подкатегория на компютърните науки). Този курс беше интересен, но беше чисто теоретичен, а не практичен.

Този месец съм съсредоточен силно върху приложението, а не теорията и компютърното зрение, с което имам нулев опит.

По принцип имам някакъв основополагащ опит, но не достатъчно опит, за да знам откъде да започна (това ще изисква някои изследвания през следващите няколко дни).

Както и да е, нямам разумна преценка колко трудно ще бъде това всъщност, така че това със сигурност ще бъде един завладяващ месец. Развълнуван съм да започна ...

Линейният метод на обучение

Когато се опитвате да разберете широк кръг от изследвания (като основната компютърна наука за самостоятелно шофиране на автомобили), често е трудно да разберете къде е правилната точка за влизане.

В резултат на това повечето хора приемат, че най-добрият път напред е да започнете с основите, да изградите обща основа на знанието и след това да продължите към по-фини и фини нива на детайлите.

Наричам това линеен метод на обучение.

Използването на линеен метод за научаване на компютърните науки за самостоятелно шофиране на автомобили би изглеждало така:

  1. Научете многопроменливо смятане
  2. Научете линейна алгебра
  3. Научете основни компютърни науки
  4. Научете за общи концепции за машинно обучение
  5. Научете за концепциите за компютърно виждане
  6. Научете как да кодирате в Python (кодиращ език, който обикновено се използва за машинно обучение)
  7. Научете как да използвате TensorFlow (специална библиотека за машинно обучение за Python)
  8. Научете как се прилага компютърно зрение за създаване на софтуер за самостоятелно управление на автомобил
  9. Научете как да напишете Python и TensorFlow код за изграждане на съответните програми
  10. И др ...

Въпреки че в крайна сметка този метод може да работи, той е неефективен и вероятно не е ефективен.

Първо, ако започна с изучаването на многоизмерно смятане, как да разбера кои части от многопроменливо смятане са подходящи за самостоятелно шофиране на автомобили и кои части не са? Аз не. Така че, ще трябва да науча всичко това. Същото за линейна алгебра и основи на компютърните науки и т.н.

С други думи, ако започна с най-общите части на знанието, няма начин да поставя приоритет на това, което уча, и така, в крайна сметка се принуждавам да науча всичко за всеки случай.

Освен това, тъй като за първи път усвоявам основополагащите концепции в общ, абстрактен смисъл, за мен е много по-трудно да свържа това, което уча, с неща, които вече знам. Тъй като ефективното обучение по същество е измислянето как да се прикачат по подходящ начин нови елементи към съществуващите към момента знания, Линейният метод на обучение също се проваля в това отношение.

Така че, докато повечето хора подхождат към ученето по този линеен начин, това е доста лош метод за научаване на каквото и да било в разумни срокове.

V-методът на обучение

Вместо това използвам различен метод, който наричам V-метод на обучение.

Ето как работи V-методът на обучение:

  1. Започвам с конкретен, добре документиран пример за моята крайна цел
  2. Опитвам се да разбера как работи този пример
  3. За всичко, което не разбирам от примера, изследвам основните понятия
  4. Ако не разбирам основните понятия, изследвам основните понятия на основните понятия, докато не почувствам, че съм изчерпал този път (или като постигна разбиране, или като достигна точка на намаляваща възвръщаемост)
  5. В крайна сметка аз пробивам достатъчно различни пътища, за да започна да виждам модели във важните основни понятия
  6. Изучавам тези съответни основни понятия, бавно си проправям път по веригата на знанието, докато не се върна на ниво детайлност на оригиналния пример
  7. И накрая, възпроизвеждам примера въз основа на новите си йерархични знания

Наричам това „V-метод“, защото започвам от най-финото ниво на детайла, гмуркам се дълбоко към директно приложимите основополагащи концепции и след това върна назад към най-финото ниво на детайлите - концептуален V.

V-методът е много по-ефективен от линеарния метод, тъй като аз съм в състояние да 1. Научавам се по реда на уместност за крайната ми цел, 2. Научете основополагащите концепции в контекста на нещо осезаемо и 3. Изграждайте и организирайте познанията ми по йерархичен, взаимосвързан начин.

В резултат на това този метод е много по-ефикасен, ефективен и ангажиращ.

И така, ето как смятам да прилагам метода V към предизвикателството за този месец:

  1. Потърсете примерен, отворен код на самоуправляващ се автомобилен код в Github (Github е популярно хранилище за код, което всъщност означава, че мога да намеря много софтуерни проекти на други хора там)
  2. Работете по пътя си ред по код
  3. За всеки ред код, който не разбирам на интуитивно ниво (което ще е повечето от тях), започнете спускането си през слоевете на основните понятия
  4. Определете модели в това, което постоянно търся / изследвам и определете най-важните основни концепции
  5. Проучете тези основополагащи концепции
  6. Изработете пътя си за архивиране на слоевете на основните понятия, докато не мога ефективно да си обясня всеки ред код от примерния проект на Github

Ако това все още звучи малко объркващо, надявам се, че ще започне да има повече смисъл, след като всъщност започна.

Първата ми стъпка е да потърся Github за добър пример на проект ...

Вчера въведох основния метод, който използвам за усвояване на нови технически умения, който наричам V-метод. Използвайки този метод, започвам проучванията си със силно специфичен пример (който трябва да симулира отблизо желания ми краен резултат) и го използвам като входна точка, за да науча съответните основни понятия по осезаем, организиран и йерархичен начин.

Ето защо, днес, целта ми беше да накарам някакъв код на моя компютър, който може би ще мога да използвам за моята самостоятелно управлявана кола.

Намиране на някакъв код

След като Googling малко наоколо, намерих проект на Github, който добре отговаря на нуждите ми. Кодът прави входно изображение на пътя и се опитва да идентифицира къде са линиите на лентата.

И така, от това ...

До това…

Целта ми за днес беше да се опитам да повторя този резултат с кода, изпълняван на моя собствен компютър.

Подготовка

Преди да успея да пусна някакъв код, трябваше да се уверя, че компютърът ми е настроен със съответните софтуерни библиотеки. По-специално трябваше да инсталирам numpy, matplotlib и OpenCV библиотеки за Python.

След като се ориентирах в Terminal (командния ред на Mac) и намерих някои инструкции онлайн, попаднах на първата си грешка ...

Вместо да се опитвам да разбера какво точно означава тази грешка или как да я поправя, използвах най-ефективната техника за отстраняване на грешки, която познавам: копирах и поставих цялото съобщение за грешка в Google.

Кликнах върху третата връзка и намерих този отговор:

След като стартирате тези няколко команди (като ги копирате и поставите в терминал и щракнете върху „Enter“), изглежда, че всичко работи правилно.

Официално всички бях създаден (поне засега).

Изпълнение на кода

Сега, когато бях настроен, беше време да пусна кода. След като отново използвах Google, за да увелича ограничените си познания за терминал, получих кода да стартирам и сякаш нищо не се счупи.

Получих този резултат ...

Готино! И така, тези числа са по същество математическото представяне на двете линии на лентата.

Дотук добре. Но, къде са визуалните изображения?

В проекта Github, който се опитвах да копирам, кодът изведе и тези хубави сюжети ...

Както и изображението с червените наслагвания ...

За съжаление кодът ми не извежда нито едно от тях, нито запазва изображения в моята локална директория.

И така, отново се обърнах към Google и потърсих „save image python“, с надеждата да разбера как да запазя изображение на изхода.

Google хубаво ми каза да използвам функцията cv2.imwrite (), така че аз го направих, и той работи. И под „работил“, имам предвид… успях да запазя изображение в сива скала на снимката с линиите на лентата, визуализирани в бяло.

И ето още ...

И още един ...

Сега какво?

Това е добро начало.

По принцип, след като мога ефективно да идентифицирам линиите на лентата, мога да използвам тази информация, за да науча моя самостоятелно управляван автомобил как да управлявам (в рамките на линиите на лентата). Освен това, тъй като видеото е само колекция от много снимки, обработката на видео трябва да работи по същия начин (стига да мога да разбера как да разделя видео в снимки в реално време за обработка).

Утре, тъй като кодът работи повече или по-малко, ще се опитам да премина през проекта линия по ред и да започна да разкривам как всъщност работи.

Дотогава урокът е следният: Ако сте готови да приемете, че често нямате всички отговори, но сте склонни да заобиколите Google и да експериментирате малко, можете да напреднете все пак.

Разбира се, все още нямам силно концептуално разбиране, но сега имам функционален пример, който мога да използвам като отправна точка.

Вчера измислих как да разпозная линиите на лентата в изображение, насочено напред към пътя. Е ... поне измислих как да стартирам код, който може да направи това.

Резултатът от вчера

Истина, не разбрах как действително работи кодът, затова днес се опитах да го променя.

По-долу е основният блок код, който използвах вчера. По-конкретно, копирах основната функция, която се нарича „draw_lane_lines“. По принцип функцията е блок от код, който взема някакъв вход (в случая снимка), манипулира входа по някакъв начин и след това извежда манипулацията (в случая линиите на лентата).

Тази основна функция използва някои други помощни функции, дефинирани другаде в кода, но тези помощни функции са най-вече само малко по-чисти начини за консумиране на предварително направените функции от библиотеките, които изтеглих вчера (като OpenCV, например).

def draw_lane_lines (изображение):
imshape = image.shape
    
    # Сиво изображение
    greyscaled_image = сива скала (изображение)
    
    # Gaussian Blur
    blgged_grey_image = gaussian_blur (greyscaled_image, 5)
    
    # Кани откриване на ръба
    edge_image = canny (замъглено_грей_имидж, 50, 150)
    
    # Изображение на ръбовете на маската
    граница = 0
    vertices = np.array ([[(0, imshape [0]), (465, 320), (475, 320),
    (imshape [1], imshape [0])]], dtype = np.int32)
    edge_image_with_mask = region_of_interest (edge_image,
    върхове)
    
    # Hough линии
    rho = 2
    theta = np.pi / 180
    праг = 45
    min_line_len = 40
    max_line_gap = 100
    lines_image = hough_lines (edge_image_with_mask, rho, theta,
    праг, min_line_len, max_line_gap)
# Преобразуване на Hough от едноканален в RGB, за да се подготви за претеглено
    hough_rgb_image = cv2.cvtColor (линии_изображение, cv2.COLOR_GRAY2BGR)
 
    # Комбинирайте изображение на линии с оригинално изображение
    final_image = претеглено_имг (hough_rgb_image, изображение)
    
    върнете final_image

Удебелените коментари са описания на основните части на тръбопровода за обработка на изображения, което основно означава, че това са седемте манипулации, извършвани последователно върху входното изображение, за да се изведат линиите на лентата.

Днес целта ми беше да разбера какво прави всяка от тези седем стъпки и защо се използват.

Всъщност се съсредоточих само върху първите пет, които извеждат математическото представяне на линиите на лентата. Последните две манипулации просто създават визуалните изображения, така че ние хората да можем да оценим визуално математиката (с други думи, тези стъпки не са необходими, когато самостоятелно управляваната кола всъщност изразходва изведените данни).

По този начин, въз основа на днешното си изследване, сега ще се опитам да обясня следната последователност на събития за обработка на изображения: входно изображение → 1. изображение в сиви мащаби, 2. размиване на Гаус, 3. разпознаване на ръбовете на Кани, 4. изображение на ръбовете на маската, 5. хоуп линии → Изход на линия

Входно изображение

Ето началното входно изображение.

Важно е да запомните, че изображението не е нищо повече от куп пиксели, подредени в правоъгълник. Този конкретен правоъгълник е 960 пиксела на 540 пиксела.

Стойността на всеки пиксел е някаква комбинация от червено, зелено и синьо и е представена от триплета от числа, където всяко число съответства на стойността на един от цветовете. Стойността на всеки от цветовете може да варира от 0 до 255, където 0 е пълното отсъствие на цвета, а 255 е със 100% интензитет.

Например, белият цвят е представен като (255, 255, 255), а черният цвят е представен като (0, 0, 0).

И така, това входно изображение може да бъде описано с 960 x 540 = 518 400 тройни числа, вариращи от (0, 0, 0) до (255, 255, 255).

Сега, когато това изображение е само колекция от числа, можем да започнем да манипулираме тези числа по полезни начини с помощта на математика.

1. Сиво изображение

Първата стъпка на обработка е преобразуването на цветното изображение в сива скала, ефективно понижавайки цветовото пространство от триизмерни до едноизмерни. Много по-лесно (и по-ефективно) е да се манипулира изображението само в едно измерение: Това едно измерение е "тъмнината" или "интензивността" на пиксела, като 0 представлява черно, 255 представлява бяло и 126 представлява средно сив цвят ,

Интуитивно, очаквах, че филтърът в сиви мащаби ще бъде просто функция, която осреднява средно червените, сините и зелените стойности, за да стигне до изхода на сивия мащаб.

Например, ето един цвят от небето в оригиналната снимка:

Тя може да бъде представена в RGB (червено, зелено, синьо) пространство като (120, 172, 209).

Ако средно оценявам тези стойности, получавам (120 + 172 + 209) / 3 = 167, или този цвят в пространството в сиво.

Но се оказва, че когато преобразувам този цвят в сиво скала с помощта на горната функция, действителният изведен цвят е 164, което е малко по-различно от това, което генерирах с помощта на моя прост метод за усредняване.

Въпреки че методът ми всъщност не е „грешен“, често използваният метод е да изчислим претеглена средна стойност, която по-добре съответства на това как очите ни възприемат цвета. С други думи, тъй като очите ни имат много повече зелени рецептори, отколкото червени или сини рецептори, стойността за зелено трябва да бъде претеглена по-силно във функцията на сивите скали.

Един общ метод, наречен колометрична конверсия, използва тази претеглена сума: 0,2126 Червено + 0,7152 Зелено + 0,0722 Синьо.

След като обработим оригиналното изображение през сивия филтър, получаваме този изход ...

2. Gaussian Blur

Следващата стъпка е да размажете изображението с помощта на Gaussian Blur.

Прилагайки леко замъгляване, можем да премахнем информацията с най-висока честота (a.k.a шум) от изображението, което ще ни даде „по-гладки“ цветови блокове, които можем да анализираме.

За пореден път основната математика на Gaussian Blur е много основна: Размиването просто отнема повече средни пиксели (този процес на усредняване е вид навиване на ядрото, което е ненужно фантастично име за това, което ще обясня).

По принцип, за да генерирате размазване, трябва да изпълните следните стъпки:

  1. Изберете пиксел на снимката и определете стойността му
  2. Намерете стойностите за локалните съседи на избрания пиксел (можем произволно да определим размера на този „местен регион“, но той обикновено е сравнително малък)
  3. Вземете стойността на оригиналния пиксел и съседните пиксели и ги осреднете заедно с помощта на някаква система за претегляне
  4. Заменете стойността на оригиналния пиксел с изведената средна стойност
  5. Направете това за всички пиксели

Този процес по същество казва „направи всички пиксели по-подобни на пикселите наблизо“, което интуитивно звучи като замъгляване.

За Гаусово замъгляване ние просто използваме разпределението на Гаус (т.е. крива на звънеца), за да определим теглата в стъпка 3 по-горе. Това означава, че колкото по-близо е един пиксел до избрания пиксел, толкова по-голяма е теглото му.

Както и да е, не искаме да замъгляваме изображението твърде много, но просто достатъчно, за да можем да премахнем малко шум от снимката. Ето какво получаваме ...

3. Откриване на ръбовете на Canny

Сега, когато имаме изображение в сиво и размито Гаус, ще се опитаме да намерим всички краища на тази снимка.

Ръбът е просто област в изображението, където има внезапен скок на стойността.

Например, има силен ръб между сивия път и пунктираната бяла линия, тъй като сивият път може да има стойност от нещо като 126, бялата линия има стойност близка до 255 и няма постепенен преход между тези стойности ,

Отново филтърът за разпознаване на ръбове на Canny използва много проста математика, за да намери ръбове:

  1. Изберете пиксел на снимката
  2. Идентифицирайте стойността за групата пиксели вляво и групата пиксели отдясно на избрания пиксел
  3. Вземете разликата между тези две групи (т.е. извадете стойността на едната от другата).
  4. Променете стойността на избрания пиксел до стойността на разликата, изчислена в стъпка 3.
  5. Направете това за всички пиксели.

Така че се преструвайте, че гледаме само един пиксел отляво и отдясно на избрания пиксел и си представете, че това са стойностите: (Ляв пиксел, избран пиксел, десен пиксел) = (133, 134, 155). Тогава бихме изчислили разликата между десния и левия пиксел, 155-133 = 22, и да зададем новата стойност на избрания пиксел на 22.

Ако избраният пиксел е ръб, разликата между левия и десния пиксел ще бъде по-голямо число (по-близо до 255) и следователно ще се покаже като бяло в изведеното изображение. Ако избраният пиксел не е ръб, разликата ще бъде близка до 0 и ще се покаже като черна.

Разбира се, може би сте забелязали, че горният метод ще намери само ръбовете във вертикална посока, така че трябва да направим втори процес, при който сравняваме пикселите над и под избрания пиксел, за да адресираме краищата в хоризонтална посока.

Тези разлики се наричат ​​градиенти и можем да изчислим общия градиент, като по същество използваме Питагоровата теорема за сумиране на отделните приноси от вертикалния и хоризонталния градиент. С други думи, можем да кажем, че общият наклон² = вертикалният наклон² + хоризонталният наклон².

Така че, например, да кажем, че вертикалният наклон = 22 и хоризонталният градиент = 143, тогава общият градиент = sqrt (22² + 143²) = ~ 145.

Изходът изглежда нещо подобно ...

Филтърът за разпознаване на ръбове на Canny сега завършва още една стъпка.

Вместо да показва само всички краища, филтърът за разпознаване на ръбове на Canny се опитва да идентифицира важните ръбове.

За да направите това, ние задаваме два прага: висок и нисък праг. Нека да кажем, че високият праг е 200, а ниският - 150.

За всеки общ градиент, чиято стойност е по-висока от високия праг от 200, този пиксел автоматично се счита за ръб и се преобразува в чисто бяло (255). За всеки общ градиент, чиято стойност е по-ниска от ниския праг от 155, този пиксел автоматично се счита за „не е ръб“ и се преобразува в чисто черно (0).

За всеки градиент между 150 и 200, пикселът се отчита като ръб, само ако директно докосва друг пиксел, който вече е отчетен като ръб.

Допускането тук е, че ако този мек ръб е свързан с твърдия ръб, той вероятно е част от същия обект.

След приключване на този процес за всички пиксели, получаваме изображение, което изглежда така ...

4. Изображение на ръбовете на маската

Следващата стъпка е много проста: Създадена е маска, която елиминира всички части на снимката, за които предполагаме, че нямат линии на лентата.

Получаваме това ...

Изглежда, че това е доста агресивна и самонадеяна маска, но това е написаното в момента в оригиналния код. И така, да продължим ...

5. Линии на тежести

Последната стъпка е да се използва трансформацията на Hough, за да се намери математическият израз за линиите на лентата.

Математиката зад трансформацията на Hough е малко по-сложна от всички средно претеглени неща, които направихме по-горе, но само едва.

Ето основната концепция:

Уравнението за права е y = mx + b, където m и b са константи, които представляват съответно наклона на линията и y-прехващането на линията.

По същество, за да използваме трансформацията на Hough, ние определяме някакво двуизмерно пространство на m и b. Това пространство представлява всички комбинации от m и b, които смятаме, че би било възможно да генерира най-подходящата линия за линиите на лентата.

След това преминаваме в това пространство на m 'и b' и за всяка двойка (m, b) можем да определим уравнение за определен ред от формата y = mx + b. В този момент искаме да тестваме тази линия, така че намираме всички пиксели, които лежат на тази линия на снимката, и ги молим да гласуват дали това е добро предположение за линията на лентата или не. Пикселът гласува „да“, ако е бял (a.k.a част от ръба) и гласува „не“, ако е черен.

(M, b) двойката, която получава най-много гласове (или в този случай, двете двойки, които получават най-много гласове) се определят като двете линии на лентата.

Ето резултатите от Hough Transform ...

Прескачам частта, където вместо да използвам формулата y = mx + b за представяне на линията, преобразуването на Hough вместо това използва представяне на полярни координати / тригонометричен стил, което използва rho и theta като двата параметъра.

Това разграничение не е супер важно (за нашето разбиране), тъй като пространството все още се параметризира в двуизмерни и логиката е абсолютно същата, но това тригонометрично представяне помага за факта, че не можем да изразим напълно вертикално линии с уравнението y = mx + b.

Както и да е, затова rho и theta се използват в горния код.

Крайният резултат

И ние сме готови.

Програмата извежда двата параметъра, за да опише двете линии на лентата (интересното е, че тези изходи се преобразуват обратно в m, b параметризация). Програмата също така предоставя координатите на крайните точки на всяка линия на лентата.

Линия на лентата 1

Наклон: -0.740605727717; Прихващане: 664.075746144

Точка първа: (475, 311) Точка втора: (960, 599)

Линия на линия 2

Коеф: -0.740605727717; Прихващане: 664.075746144

Точка първа: (475, 311) Точка втора: (0, 664)

Припокривайки тези линии върху оригиналното изображение, виждаме, че ефективно сме идентифицирали линиите на лентата, използвайки основни математически операции.

Вчера деконструирах парче код, който идентифицира линиите на платна в изображения, насочени напред към пътя.

Като този…

Може би по-интересно от картината, този блок от кодове генерира математическите изображения на линиите на лентата, използвайки само много основни математически операции (по същество низ от функции, които намират средно претеглени):

Линия на лентата 1 = Наклон: -0.740605727717; Прихващане: 664.075746144

Линия на лентата 2 = Coef: -0.740605727717; Прихващане: 664.075746144.

Преминаването през това упражнение ми помогна по-добре да интуитирам основните механики на самостоятелно управлявана кола, която вече не изглежда толкова мистична.

Въз основа на това, с което съм експериментирал досега, изглежда, че има две основни стъпки за създаване на софтуер за самостоятелно управление на автомобила:

Стъпка 1: Манипулирайте входното изображение в набор от полезни цифрови изображения на средата за шофиране (т.е. линии на платна, други автомобили, пътни знаци, пешеходци и т.н.)

Стъпка 2: Подайте това числово представяне на света във функция, която въз основа на тези входове изчислява правилния ъгъл на управление и ускорението.

Подозирам, че функцията в Стъпка 2 се подобрява (с увеличаване на количествата изчислителна мощност стават достъпни в бъдеще), предварителната обработка и категоризирането на обекти в стъпка 1 стават все по-малко важни.

По този начин изглежда, че трябва да насоча вниманието си към стъпка 1, която се фокусира до голяма степен върху разпознаването и дигитализацията на обектите, и вместо това да насоча по-голямата част от вниманието си върху функцията от стъпка 2, която картографира входовете от света в инструкции за шофиране. Ще нарека тази функция „магическата функция“.

Това изглежда като разумен план, особено защото техниките за обработка на изображения, които описах вчера, са изобретени преди десетилетия, където като магическа функция изглежда е наскоро възможно.

Не съм сигурен дали този анализ е правилен или този път е оптимален, но това е моята интуиция в момента, базирана на това, което съм изследвала досега, и на упражнението от последните няколко дни.

От утре ще започна да проучвам как може да работи една магическа функция и как бих могъл да я изградя.

Вчера разбрах, че трябва да преместя фокуса си и да посветя усилията си за изграждането на някаква версия на магическата функция, която е математическият алгоритъм, който преобразува входните изображения на пътя в явни инструкции за шофиране / управление за самостоятелно шофиращата кола.

Днес намерих набор от данни от 223 GB, който беше отворен от Udacity (компания, която прави онлайн курсове по технически теми, включително самоуправляващи се автомобили), който съдържа точно това, от което се нуждая:

Udacity взе видео от камера на тире, разби го на отделни кадри и след това маркира всяка рамка със съответния ъгъл на управление, който всъщност изпълнява човешкият водач.

Например рамка: 1479425444933328937; ъгъл на управление: -0.346924703940749

В резултат на това този набор от данни е перфектен за създаване и тестване на Magic Function - мога да помоля Magic Function да отгатне ъгъла на кормилно управление въз основа на кадъра на видеото и след това мога да сравня предположението с действително записания ъгъл на управление.

Ако предположението е далеч от действителната стойност, мога да актуализирам функцията и да я тествам отново. Теоретично мога да използвам компютъра, за да ми помогнат да повторя този процес хиляди пъти и в крайна сметка да намеря разумен начин за точно управление на автомобила.

Тъй като само „теоретично“ знам как да направя това в момента, днес се върнах в Github, за да видя дали мога да намеря някой, който използва набора от данни на Udacity по този начин.

Намерих няколко проекта и се надявах, че ще мога да ги накарам и да стартират доста бързо. След около два часа опити обаче продължих да получавам фатални грешки в Terminal - дори не от пускането на кода, а просто от опитите да настроя компютъра си с библиотеките, необходими за стартиране на кода на първо място.

Преди няколко дни ми се стори, че винаги, когато Терминал хвърли грешка, тривиално лесно е просто да отговорите на Google и да продължите напред. Въпреки че това беше моят опит преди няколко дни, този опит вероятно не е норма и със сигурност не беше днес.

Така че въпреки всичките си усилия, днес ефективно постигнах нулев напредък, което е разочароващо, но също така и част от играта.

Утре ще продължа да играя тази игра и ще видя дали мога да накарам компютъра си да сътрудничи. Засега ще остана надежда ...

Понякога смятам, че изграждането на софтуер е най-жестоката форма на наказание. Днес беше един от онези дни.

За разлика от други занимания, при които, дори когато нещата са трудни, мога да постигна бавен стабилен напредък (или поне да науча нещо ценно от провалите ми), опитите да накарам компютъра ми да изпълни успешно няколко реда код е като да ударя главата си срещу стена, надявайки се, че ако го направя достатъчно дълго, в крайна сметка нещо ще се промени.

Когато се впускате в нова кодираща територия, тук е общата сюжетна дъга: 1. Прекарайте два часа, опитвайки всяка възможна пермутация на настройката на код / ​​среда, за да видите дали някоя случайна комбинация ще работи, 2. Нищо не работи и осъзнавате, че сте далеч от вашата цел, отколкото когато сте започнали (защото сте се забъркали с толкова много неща), 3. Продължавайте да се опитвате още един час, 4. Магически звездите се изравняват и някаква необяснима комбинация от неща прави всичко да работи.

Проблемът при този модел е, че ... трябва да скърцате със зъби и да страдате от болката за неизвестно количество време, докато магически достигнете нирвана на Стъпка 4. Не знаете кога идва нирвана, нито вярвате, че ще стане някога идват, но трябва да продължите да имате шанса, че това може да стане. Няма постепенно изплащане, просто смущаващо душевно неудовлетворение, докато магически не работи.

И тогава, когато работи, нищо не е по-блажено. Цялата болка си струва за този един момент, ако приемем, че идва този един момент.

Днес едва се мотаех.

В дълбочина съм в район, в който имам малко заземяване, и в резултат на това се чувствах изгубен и безпомощен през по-голямата част от деня.

В тези случаи често е полезно да се разчита на видео уроци или онлайн курсове, но все още не съм намерил достъпен урок (или какъвто и да е урок), който би ми помогнал да ме заземява.

Затова вместо това прекарах около 2,5 часа днес, като се удавих в кодиращата яма на отчаянието. Беше брутално и заплашително за доверието и днес много пъти исках да призная поражение, но успях да се задържа.

Някак си намерих път към края на деня и изглежда съм постигнал осезаем напредък. Не мога да кажа със сигурност обаче до утре сутринта: Моят компютър в момента работи и вероятно ще продължи да работи през нощта.

Утре се надявам да се събудя с успешно стартирана програма.

Снощи, след като се удавих за няколко часа в „Кодиращата яма на отчаянието“, най-накрая постигнах известен напредък.

Като напомняне, през последните няколко дни се опитвах да намеря и пускам код, който може да генерира инструкции за управление (за моя самостоятелно управляван автомобил) въз основа на входните изображения на пътя.

След дълги часове на търсене и игра, намерих академична книга, написана от изследователи от NVIDIA (компания, която прави самостоятелно шофиране на хардуер и софтуер за автомобили, наред с други неща).

Както е описано в резюмето на статията, тяхната разработена система може да „картографира сурови пиксели от една предна лицева камера директно към командите за управление“.

Точно от това ми трябва!

Тогава открих TensorFlow внедряване на системата на NVIDIA в Github и след няколко опита всъщност успях да „обуча модела“ въз основа на някои данни на NVIDIA.

(Актуализация: Това всъщност не са данни на NVIDIA, а по-скоро набор от данни, произведен от Sully Chen. Той събра данните, като закачи уеб камера на предното стъкло на колата си и заснема „данните за шофиране“ от порта CAN-BUS на колата си. ).

Бързо настрана за изясняване на някои термини: 1. „Моделът“ е функцията, която описва как да преобразувате пиксели в инструкции за управление и 2. „Да тренирате модела“ означава итеративно да подобрите тази функция, използвайки техники за машинно обучение. Ще обясня този процес по-подробно в бъдеща публикация.

Както и да е, наборът от данни на NVIDIA включва 25 минути видео, разбити кадър по кадър, където всеки кадър е етикетиран с истинския ъгъл на управление (т.е. ъгъла на управление, който е използвал човешкият водач).

Рамка 45 522

В Терминал пуснах програмата за обучение на модела и въпреки някои предупреждения, тя започна да работи:

В тази снимка „Стъпка“ описва всеки път, когато част от данните се подават през системата за обучение. Епохата е просто по-широка категория, която съдържа множество стъпки.

За да тренирам този модел, използвах 30 епохи с няколко десетки стъпки на епоха.

На екрана „Загубата“ описва колко точен е моделът (или функцията). Концептуално, за да се изчисли загубата, истинският ъгъл на управление се сравнява с предвидения от модела ъгъл на управление. Колкото по-голяма е разликата, толкова по-голяма е загубата.

В крайна сметка, когато тренира модела, програмата използва няколко математически трика (които ще опиша в бъдеща публикация), за да се опита да намали загубата чрез всяка итеративна стъпка.

По този начин „обучение на модела“ е просто „намаляване на загубата“.

Ето график със стъпки по оста X и загуба на оста Y. (Снощи, използвайки нещо, наречено Tensorboard, компютърът ми замисли това, докато тренираше).

На стъпка 126, например, загубата имаше стойност 5.708.

Докато на стъпка 3241, почти шест часа по-късно, Загубата има значително по-добра стойност от 0,1615.

Сега, когато обучението официално приключи, моделът вече е теоретично готов да управлява автомобил, което е супер готино.

Когато се прибрах днес от работа, се опитах да тествам модела (a.k.a. „управлявайте кола“) и да видя как се представя. За съжаление, когато се опитах да стартирам програмата, получих тази грешка ...

Прекарах добър час, опитвайки се да преодолея този проблем, но изглежда, че част от изтегления от мен код не може да бъде стартиран на Mac (и ако може, не можах да намеря начин да го направя).

Имам идея за решение, но ще трябва да изчакаме до утре.

Междувременно мога да отбележа факта, че (вероятно) имам доста функционален, вече обучен модел на самостоятелно управление на автомобил, готов да бъде използван. Дано утре мога да разбера как всъщност да го използвам ...

Вчера измислих как да тренирам моята самостоятелно шофираща кола, но се мъчих да потвърдя, че тренировката всъщност е ефективна.

Днес бързо разбрах, че частта от програмата, която не работи, е свързана само с визуализацията. С други думи, успях да изтрия всички кодове за визуализация и все пак успешно извеждах командите за управление в реално време за автомобила.

Въпреки че тези цифри са достатъчни, за да получите самостоятелно управляващ автомобил, който да изпълнява инструкциите, като човешки, този изход е труден за оценяване.

За щастие, преди няколко дни измислих как да запазя отделни обработени кадри на моята локална машина.

И така, реших да изведа от програмата отделните кадри на входното видео и прогнозираната анимация на волана.

След това комбинирах отделните кадри, наслагвах двата видеоклипа и натисках възпроизвеждане. Ето резултата ...

Много се вълнувам от това!

За да изясним какво се случва: Програмата гледаше нискокачествените кадри на тире и след това автономно анимира волана въз основа на модела за самостоятелно шофиране, който тренирах вчера. С други думи, компютърът изцяло управлява тази кола и върши доста солидна работа.

Следващата стъпка е да научите повече за основния код, да го оптимизирате за обща употреба и след това да видите как се представя на различни набори от данни (т.е. на различни пътища). Ще започна с набора от данни Udacity.

Все още не съм съвсем сигурен, че съм готов да спя в задната част на моята самоуправляваща се кола, но днес определено бележи голяма стъпка напред.

Сега, когато имам работещ автомобилен код за самоуправление (вижте видеото от вчера), през следващите няколко дни планирам да деконструирам кода и да се опитам да разбера как точно работи.

Днес ще разгледам конкретно „модела“, който може да се счита за месото на кода: Моделът определя как входните изображения се преобразуват в инструкции за управление.

Днес нямам много време, така че няма да описвам напълно как работи кодът (тъй като все още не знам и все още трябва да правя много изследвания). Вместо това ще направя някои хипотези за това какво могат да означават редовете на кода и ще документирам отворените въпроси, които ще ми трябват за по-нататъшно проучване.

Това ще ме накара да науча материала структурирано.

Ето кода за самоуправляващия се модел в неговата цялост. Това е само 50 реда код плюс коментари и интервали (което е доста ядки, тъй като той кара кола и други неща ...)

внос tensorflow като tf
внос на шпион
def weight_variable (форма):
  начална = tf.truncated_normal (форма, stddev = 0,1)
  връщане tf.Variable (първоначален)
def bias_variable (форма):
  начален = tf.констант (0,1, форма = форма)
  връщане tf.Variable (първоначален)
def conv2d (x, W, крачка):
  върнете tf.nn.conv2d (x, W, стъпки = [1, крачка, крачка, 1], padding = 'VALID')
x = tf.placeholder (tf.float32, форма = [Няма, 66, 200, 3])
y_ = tf.placeholder (tf.float32, форма = [Няма, 1])
x_image = x
# първи конволюционен слой
W_conv1 = тегло-променлива ([5, 5, 3, 24])
b_conv1 = bias_variable ([24])
h_conv1 = tf.nn.relu (conv2d (x_image, W_conv1, 2) + b_conv1)
# втори второстепенен слой
W_conv2 = тегло-променлива ([5, 5, 24, 36])
b_conv2 = bias_variable ([36])
h_conv2 = tf.nn.relu (conv2d (h_conv1, W_conv2, 2) + b_conv2)
# третия светещ слой
W_conv3 = тегло-променлива ([5, 5, 36, 48])
b_conv3 = bias_variable ([48])
h_conv3 = tf.nn.relu (conv2d (h_conv2, W_conv3, 2) + b_conv3)
# четвърти спирален слой
W_conv4 = тегло-променлива ([3, 3, 48, 64])
b_conv4 = bias_variable ([64])
h_conv4 = tf.nn.relu (conv2d (h_conv3, W_conv4, 1) + b_conv4)
# пети спирален слой
W_conv5 = тегло_променливо ([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 = тегло_променливо ([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)
hold_prob = tf.placeholder (tf.float32)
h_fc1_drop = tf.nn.dropout (h_fc1, Keep_prob)
#FCL 2
W_fc2 = тегло-променливо ([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 = тегло_променливо ([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 = тегло-променливо ([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)
#Output
W_fc5 = тегло_променливо ([10, 1])
b_fc5 = bias_variable ([1])
y = tf.mul (tf.atan (tf.matmul (h_fc4_drop, W_fc5) + b_fc5), 2)

Редовен коментар

Сега ще работя чрез кода на парчета и ще опиша какво мисля всеки член.

внос tensorflow като tf
внос на шпион

Първите два реда са прави.

Ние импортираме библиотеката TensorFlow (която ще наричаме „tf“ другаде в кода) и библиотеката SciPy. TensorFlow е библиотека на python, написана от Google, която ще помогне да се абстрахират повечето от наземните приложения за машинно обучение. SciPy ще ви помогне с математическите неща.

Тук няма нищо ново да научите.

def weight_variable (форма):
  начална = tf.truncated_normal (форма, stddev = 0,1)
  връщане tf.Variable (първоначален)
def bias_variable (форма):
  начален = tf.констант (0,1, форма = форма)
  връщане tf.Variable (първоначален)

Добре, така че тук мисля, че дефинираме нови обекти, което в основата си означава, че можем да използваме понятието „weight_variable“ и „bias_variable“ другаде в нашия код, без да се налага да ги предефинираме някога еднократно.

При машинното обучение функцията, която се опитваме да решим, обикновено се представя като Wx + b = y, където ни се дават x (списъкът на входните изображения) и y (списъкът на съответните инструкции за управление) и искаме да намерим най-доброто комбинация от W и b, за да се направи балансът на уравнението.

W и b всъщност не са единични числа, а вместо това са колекции от коефициенти. Тези колекции са многоизмерни и размерът на тези колекции съответства на броя на възлите в мрежата за машинно обучение. (Поне така го разбирам в момента).

Така че в горния код обектът на тежестта на променливост представлява W, а обектът на пристрастимост вариращ представлява b, в обобщения смисъл.

Тези обекти приемат вход, наречен „форма“, който основно определя размерите на W и b.

Тези W и b обекти се инициират с функция, наречена „нормално“. Почти съм сигурен, че това означава, че ... когато първоначално се създават колекции от W и b, стойностите на отделните коефициенти трябва да се определят на случаен принцип въз основа на нормалното разпределение (т.е. крива на звънеца) със стандартно отклонение от 0,1. Стандартното отклонение повече или по-малко определя колко случайни искаме да бъдат първоначалните коефициенти.

И така, изненадващо, мисля, че най-вече разбирам този код. На пръв поглед не бях сигурен какво става, но писането на това ми помогна да събера мислите си.

Какво още трябва да науча: Трябва да науча повече за структурата Wx + b = y, защо се използва, как работи и т.н., но разбирам основите на кода.

def conv2d (x, W, крачка):
  върнете tf.nn.conv2d (x, W, стъпки = [1, крачка, крачка, 1], padding = 'VALID')

Вярвам, че това нещо conv2d е функция, която изпълнява сгъване на ядрото на някакъв вход. Съглашенията на ядрото са по-общ клас от манипулациите с изображения, за които научих преди няколко дни.

Що се отнася до мен, сгъването на ядрото манипулира изображението, за да подчертае някаква характеристика на това изображение, независимо дали това са краищата, ъглите на изображението и т.н.

Тази конкретна характеристика се дефинира от „ядрото“, което изглежда се дефинира с помощта на стъпки = [1, стъпка, крачка, 1] отгоре. Въпреки че, не знам какво означава крачките и как точно става това.

Изглежда, че има три входа към тази функция за манипулиране на изображението: 1. Ядрото / стъпките (за да кажете как да манипулирате изображението); 2. x (което е самото изображение); и 3. W (което предполагам е набор от коефициенти, които се използват за смесване на различни манипулации на изображението заедно в някакъв капацитет).

Трябва да науча повече за ролята на W във всичко това.

На високо ниво обаче тази функция е манипулиране на изображението по някакъв начин за автоматично намаляване на изображението в различни функции, които са по-благоприятни за обучението на модела.

Какво още трябва да науча: Как точно се определя математически функцията на светене и как W играе роля в това?

x = tf.placeholder (tf.float32, форма = [Няма, 66, 200, 3])
y_ = tf.placeholder (tf.float32, форма = [Няма, 1])
x_image = x

Следващите няколко реда изглеждат доста ясни. Отново се връщаме към уравнението Wx + b = y.

Тук по същество дефинираме заместители за променливите x и y. Тези заместители задават размерите на променливите (не забравяйте: тези променливи представляват съвкупност от стойности, а не само едно число).

Ние настройваме x, за да очакваме да получи изображение с определени размери, и ние настройваме y, за да очакваме едно число като изход (т.е. ъгъла на управление).

След това преименуваме x в „x_image“, за да си припомним, че x е изображение, защото… защо не.

Тук няма нищо ново да научите.

# първи конволюционен слой
W_conv1 = тегло-променлива ([5, 5, 3, 24])
b_conv1 = bias_variable ([24])
h_conv1 = tf.nn.relu (conv2d (x_image, W_conv1, 2) + b_conv1)

Добре, сега сме на първия си сложен слой.

Ние дефинираме W_conv1, което е само конкретен екземпляр от тежестта на променливата, която обясних по-горе (с формата [5, 5, 3, 24]). Не съм сигурен как или защо формата беше зададена по този конкретен начин.

След това дефинираме b_conv1, което е само специфичен екземпляр от bias_variable, който обяснявам по-горе (с формата [24]). Този 24 вероятно трябва да съответства на 24 от формата W_conv1, но не съм сигурен защо (освен това ще помогне на умножението на матрицата да работи).

h_conv1 е междинен обект, който прилага функцията на светене към входовете x_image и W_conv1, добавя bconv1 към изхода на конволюцията и след това обработва всичко чрез функция, наречена relu.

Това нещо с релу звучи познато, но не мога да си спомня какво точно прави. Моето предположение е, че това е някаква „сквошър“ или нормализираща функция, която изглажда всичко в някакъв капацитет, каквото и да означава това. Ще трябва да го разгледам.

Макар че мога да прочета по-голямата част от кода, не съм точно сигурен защо по този начин е създаден „спираловиден слой“.

Какво още трябва да науча: Какво е сложен слой, какво трябва да прави и как го прави?

# втори второстепенен слой
W_conv2 = тегло-променлива ([5, 5, 24, 36])
b_conv2 = bias_variable ([36])
h_conv2 = tf.nn.relu (conv2d (h_conv1, W_conv2, 2) + b_conv2)
# третия светещ слой
W_conv3 = тегло-променлива ([5, 5, 36, 48])
b_conv3 = bias_variable ([48])
h_conv3 = tf.nn.relu (conv2d (h_conv2, W_conv3, 2) + b_conv3)
# четвърти спирален слой
W_conv4 = тегло-променлива ([3, 3, 48, 64])
b_conv4 = bias_variable ([64])
h_conv4 = tf.nn.relu (conv2d (h_conv3, W_conv4, 1) + b_conv4)
# пети спирален слой
W_conv5 = тегло_променливо ([3, 3, 64, 64])
b_conv5 = bias_variable ([64])
h_conv5 = tf.nn.relu (conv2d (h_conv4, W_conv5, 1) + b_conv5)

Продължаваме да имаме още четири спираловидни слоя, които функционират по същия начин като първия слой, но вместо да използват x_image като вход, те използват изхода от предишния слой (т.е. нещо, което h_conv).

Не съм сигурен как решихме да използваме пет слоя и как и защо формите на всеки W_conv са различни.

Какво още трябва да науча: Защо пет слоя и как да изберем формите за всеки?

#FCL 1
W_fc1 = тегло_променливо ([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)
hold_prob = tf.placeholder (tf.float32)
h_fc1_drop = tf.nn.dropout (h_fc1, Keep_prob)
#FCL 2
W_fc2 = тегло-променливо ([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 = тегло_променливо ([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 = тегло-променливо ([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)

На следващо място, имаме четири FCL, което според мен означава „Напълно свързани слоеве“.

Настройката за тези слоеве изглежда подобна на стъпките на превъртане, но не съм точно сигурен какво се случва тук. Мисля, че това са просто ванилни невронни мрежи (за които пиша, че се преструвам, че напълно разбирам „ванилни невронни мрежи“).

Както и да е, ще трябва да разгледам повече това.

Какво още трябва да науча: Какво е FCL и какво се случва във всяка FCL стъпка?

#Output
W_fc5 = тегло_променливо ([10, 1])
b_fc5 = bias_variable ([1])
y = tf.mul (tf.atan (tf.matmul (h_fc4_drop, W_fc5) + b_fc5), 2)

И накрая, ние вземаме изходите на крайния FCL слой, правим няколко луди тригонометрични манипулации и след това извеждаме y, предвидения ъгъл на управление.

Изглежда, че тази стъпка е просто „да накара математиката да се отработи“, но не съм сигурен.

Какво още трябва да науча: Как и защо се изчислява продукцията по този начин?

Свършен.

Това отне повече време от очакваното - най-вече защото успях да разбера повече, отколкото очаквах.

Това е нещо като лудо колко голяма част от внедряването е отвлечено от библиотеката на TensorFlow и колко малко от основните математически знания са необходими за изграждането на напълно способен модел на самостоятелно управление на автомобил.

Изглежда, че единственото важно нещо, което знаем като конструктори на модели, е как да зададем дълбочината (например брой слоеве) на модела, формите на всеки слой и видовете слоеве.

Предполагам, че това може да е по-скоро изкуство, отколкото наука, но вероятно образовано изкуство.

Ще започна утре в откритите си въпроси.

Постигнах огромен напредък в предизвикателството за този месец през последните единадесет дни, така че днес реших да си отдъхна.

Тази почивка включваше най-вече гледане на видеоклипове в YouTube по Convolutional Neural Networks и ядра, които все още ми помогнаха да се доближа до целта си, но в по-пасивна и спокойна форма.

По-специално гледах куп видеоклипове от YouTube канал Computerphile, който лично е любимият ми канал по теми, свързани с компютърните науки.

Ето и видеоклипа на Computerphile в Convolutional Neural Networks ...

И ето първото видео от Computerphile от поредица за завъртанията на ядрото ...

Макар и по-малко уместен за предизвикателството за този месец, Computerphile има сестрински канал в YouTube, наречен Numberphile, който обсъжда теми от теорията на числата и математиката като цяло.

Ето един от любимите ми видеоклипове на Numberphile - той има супер готин начин за приблизително определяне на стойността на pi.

Както и да е, днес ми хареса почивката и утре ще се върна на работа.

Преди два дни минах през месото на кода на самоуправляващата се кола и идентифицирах откритите въпроси, които имах за това как работи.

Докато проучвах тези въпроси, започнах да осъзнавам, че от чисто гледна точка на приложението, не е супер необходимо да се разбере повечето основни математика / компютърни науки, за да се изгради ефективна система за дълбоко обучение. Естествено, аз се интересувам, така че аз се уча, като отида, но това със сигурност не е от съществено значение.

По принцип тук са важните неща, които трябва да знаете:

  1. В конволюционната невронна мрежа, в горната част на „стека“, има конволюционни слоеве, които научават кои операции на конволюция (т.е. манипулации с изображения) подчертават най-добрите характеристики, на които да се научите.
  2. След това има някои пълносвързани слоеве, които се опитват да научат как да генерират правилния изход въз основа на функциите, подчертани от слоените слоеве.
  3. Между тях има някои математически трикове (като понижаване на ток и изправители), които ускоряват процеса на обучение.
  4. Определянето на формите и параметрите на слоевете обикновено се извършва емпирично (т.е. опитайте различни опции и изберете конфигурацията, която дава най-добри резултати).

Що се отнася до №4, в статията на Nvidia, която описва системата за дълбоко обучение, която използвам, те обясняват, че „светещите слоеве са проектирани да извършват извличане на функции и са избрани емпирично чрез поредица от експерименти, които варират конфигурации на слоевете“.

И така, ето и ударната линия: Тайната за създаването на ефективна конволюционна невронна мрежа е да изпробвате куп различни комбинации от обикновено използвани компоненти и да видите какво работи най-добре.

По принцип, стига да разберете основните компоненти, изграждането на ефективен автомобил за самостоятелно управление (Nvidia е 98% автономен) не е много повече от „познайте и проверете“. (Може да се твърди, че ако искаме да получим колата от 98% до 100% автономна, трябва да направим малко повече от предположения и проверки, което е вярно днес, но вероятно ще стане по-малко вярно с времето, както някога - все по-често прилагайте повече мощност към проблема).

Разбира се, под капака реализациите на всички тези „основни компоненти“ са по-сложни, но за щастие библиотеката на TensorFlow по същество е абстрахирала цялата тази работа. Плюс това стигнахме до момент, в който любителите на GitHub публикуват пълни модели самоуправляващи се автомобили с отворен тип.

Предвиждам, че за 18–24 месеца ще стигнем до ниво на абстракция, при което може да се създаде самостоятелно управляващ автомобил в едноредов код - което предполагам означава, че предизвикателството за учене през този месец няма да остарее много добре.

Във връзка с това, предизвикателството за този месец изглежда сочи следния урок: Понякога „ученето на тежки неща“ просто отмива двусмислието или сплашването и установява, че след като се ориентирате, нещата не са твърде предизвикателни.

Тъй като сега съм ориентиран, няма да прекарвам повече време да се ровя в теорията (поне за следващата седмица или така). Вместо това ще прехвърля фокуса си обратно към чисто приложение и ще видя дали мога да разширя възможностите на моя самостоятелно управляван автомобил.

Преди няколко дни успях да пусна някакъв код и да накарам моята самоуправляваща се кола да се насочва успешно по улиците (поне практически въз основа на видеокадрите на NVIDIA).

Днес исках да направя следващата стъпка и да видя дали мога да използвам модела на самоуправляваща се кола на различен набор от данни. В крайна сметка автомобил със самостоятелно управление трябва да може да шофира по всеки път, а не само по пътищата, по които е бил обучен.

По този начин реших да видя дали моделът, който тренирах миналата седмица, може да изпълнява в набора от данни на Udacity, който разполага с различен набор от пътища.

Първата стъпка беше да форматирам набора от данни на Udacity, така че да може да се обработва от моя модел на самостоятелно управление на автомобил.

За разлика от набора от данни на NVIDIA, който съдържа видеоклип, добре разбит на последователно номерирани кадри (0.jpg, 1.jpg, 2.jpg, 3.jpg и т.н.), наборът от данни на Udacity е съвкупност от объркано номерирани изображения: Има нечетни, несъответстващи по големина празнини между числата и наборът от данни започва да се брои на 1479425441182877835.

Udacity вероятно имаше някаква обосновка за тази схема за номериране, но не мога да разбера каква е тази обосновка.

Следователно, първата ми стъпка беше да преименувам всички тези файлове, за да съответстват на схемата за номериране в стил NVIDIA (т.е. да започне от нула и да се брои от тях).

Отначало мислех да си сложа слушалките, да включа аудиокнига и да преименувам ръчно всеки файл. Тогава разбрах, че има над 5000 файла и вероятно трябва да измисля как да го направя автоматично с някакъв код (в края на краищата се опитвам да подобря уменията си за кодиране този месец).

След около 12 минути ноудлинг успях да напиша малък Python скрипт, за да преименувам всички файлове на Udacity.

import os
def rename (директория):
i = 0
за име на файл в os.listdir (директория):
      new_file_name = str (i) + '.jpg'
      old_file_name = име на файл
os.rename (old_file_name, new_file_name)
i + = 1
PATH = os.path.abspath ('/ Потребители / maxdeutsch / Desktop / nvidia / udacity_data')
преименуване (път)

Пуснах сценария и след няколко минути всички файлове бяха преименувани (радвам се, че не го направих на ръка).

На следващо място, с подготвения набор от данни, беше време да се тества моделът на новия набор от данни, да се изведе графиката на автономно управлявания волан и след това да се наслагва графиката отгоре на оригиналните кадри, за да се види как се справя колата.

За съжаление, представянето е много лошо: Ако самоуправляващият се автомобил действително следваше тези инструкции в реалния живот, той ще се срине почти веднага.

Утре ще експериментирам с модела и ще измисля как да обобщя по-добре моята самостоятелно управлявана кола, така че да не се срива всеки път, когато се въведе в нова среда за шофиране.

Вчера се опитах да карам моята самоуправляваща се кола по нови пътища (от базата данни на Udacity). Колата обаче не беше подготвена за това и на практика се срива многократно.

Ясно е, че моделът, обучен на база данни на NVIDIA, не е подходящ за набора данни от Udacity.

Едно разумно обяснение за това разминаване е, че макар и двата набора от данни да съдържат насочени към пътя видеоклипове, видеозаписите забележимо се различават по отношение на ъгъл на гледане, рамкиране и изкривяване на обектива. В резултат на това модел, обучен от един изглед, не трябва да работи добре нито от двете (тъй като камерата е била преместена, увеличена и прекроена).

Ето още кадър от набора от данни на NVIDIA:

И ето още от набора от данни на Udacity:

Ясно е, че тези изгледи на пътя са достатъчно различни, при което модел, обучен на един набор от данни, не е използваем от другия. (Ако и двата автомобила снимаха видео от една и съща гледна точка, теоретично моделът ще бъде използваем в двата набора данни).

По този начин, за да продължа напред, трябва да тренирам самоуправляващия се модел на автомобил също в част от данните на Udacity и след това да видя как се представя моделът, когато се тества върху останалите нови данни.

Днешната задача беше да преформатира набора от данни на Udacity, така че да може да се използва за обучение.

Вчера завърших част от това преформатиране, когато преименувах JPEG изображения на Udacity от дълги, произволни числа в последователно обозначени изображения.

От това…

До това…

С подготвените изображения, след това трябваше да създам текстов файл, наречен „data.txt“ за набора от данни на Udacity, който изброява правилния ъгъл на кормилно управление до името на съответното изображение.

Ето как изглежда файлът data.txt на NVIDIA:

Това не е най-убедителното хващане на екрана, тъй като първите 22 ъгли на кормилно управление са нулеви.

И все пак, данните на Udacity бяха събрани в електронна таблица по този начин:

И така, за да създам файла data.txt за набора данни от Udacity, трябваше да направя две неща: 1. Преименувайте frame_ids, за да съответства на схемата за номериране вчера; 2. Измислете как да конвертирате електронна таблица в текстов файл без форматиране в стил таблица.

Вместо да използвам скрипт на Python, се опитах да измисля как да направя и двете стъпки в Google Sheets (вероятно има по-ефективен начин).

Първо въведох малки поредици от последователни числа и след това разтеглих последователността, за да попълня останалите ~ 5000 клетки.

След това използвах вградените функции TO_TEXT и CONCATENATE, за да преобразувам целите числа в низове и след това да свържа тези низове с разширението на файла .jpg.

От стъпка 2 - Преобразуване на таблицата в неформатиран текстов документ.

Използвах CONCATENATE отново, за да комбинирам имената на изображения и ъглите на управление в една клетка (с един разделител за интервал).

След това обединих всяка клетка с char (10), който е кодът на символа за прекъсване на реда. И накрая, обединява всички клетки в една клетка.

Копирах съдържанието на тази единична клетка в текстов документ и файлът ми data.txt беше готов за стартиране.

Едното странно е, че номерата на ъглите на управление на Udacity изглеждат много по-различни от номерата на ъглите на кормилно управление на NVIDIA.

Изглежда, че компаниите използват значително различно представяне на ъгъла на управление, но не съм съвсем сигурен как математически се свързват двата метода.

Може да успея да тренирам успешно модела, без изобщо да открия тази математическа връзка, но съм скептичен, че това е така.

Ще проуча още това утре и след това ще започна обучението на модела върху данните на Udacity.

Вчера приключих с форматирането на новия набор от данни, така че, когато днес се прибрах от работа, бях готов да започна обучението на модела.

И все пак, когато изпълних командата на влака в Терминал, компютърът ми спря в продължение на секунда и след това изплю грешка. По-конкретно грешка „списък на индекс извън обхвата“.

Обикновено получавате този вид грешка, когато програмата очаква списък с неща, които са по-дълги от действителния списък с неща.

Тъй като наборът от данни на NVIDIA е по-дълъг / по-голям от набора от данни на Udacity, реших, че стойността за дължината на списъка трябва да бъде твърдо кодирана и мога да коригирам съответно тази стойност.

Но след като прегледах кода, не можах да намеря проблема. Всичко изглеждаше, че трябва да работи.

И така, в кода добавих няколко изявления за печат, които ще ми помогнат да видя какво се случва под капака и къде точно се чупи програмата.

Пуснах програмата с отчетите за печат и получих този изход:

Програмата успешно се повтаря през всички редове от реални данни и след това сякаш се опитва да анализира допълнителен ред данни, който не съществува.

И така, отворих файла data.txt и със сигурност ... случайно копирах няколко празни реда в края на файла.

Изтрих тези три празни реда и върнах програмата в Terminal.

Работи се и моделът започна да тренира.

Докато моделът тренира (ще го регистрираме утре), реших, че ще споделя едно бързо, забавно встрани:

Днес, когато пътувах на работа, минах покрай самоходен автомобил Google / Waymo близо до жп гарата Mountain View.

След това, в дома ми на пътуване, на няколко пресечки от апартамента ми, видях два самоуправляващи се Ubers подред.

Ето малко по-ясна картина на водещия Uber: Изглежда, че в момента се ръководи от хора, вероятно за тренировъчни цели. Автомобилът Google е шофирал сам.

Почти всеки ден по време на пътуването си виждам няколко самоуправляващи се автомобила, но днес мислех само за правене и споделяне на няколко снимки. Фактът, че вече съм изтръпнал до мястото на самоуправляваща се кола, е доста луд - те очевидно не са толкова далеч от повсеместна реалност (регламент настрана).

Както и да е, доста готино е да мисля, че софтуерът, който управлявам на моя личен компютър, е по същество достатъчно мощен, за да контролира тези реални автомобили.

Днес беше тъжна колекция от грешки и препятствия (без щастлив край). Докато се опитвах да откупя себе си, продължавах да падам все по-дълбоко и по-дълбоко надолу в заешката дупка.

Започна вчера - аз преформатирах успешно данните на Udacity и започнах да тренирам модела на самоуправляваща се кола.

След като моделът завърши обучение, хвърлих бърз поглед към графика на загубата (загубата измерва „точността“ на модела - колкото по-ниска е загубата, толкова по-добър е моделът в по-голямата си част).

След 30-те епохи на обучение, Загубата дори не потапяше под 1,00, където, когато тренирах модела по данни на NVIDIA, Загубата намаля значително под 1,00, чак до ~ 0,16.

Не съм сигурен защо очаквах да се случи нещо различно - Наборът от данни Udacity, който използвах, беше само 1/8 от размера на набора от данни на NVIDIA.

Това беше първата ми грешка: Случайно използвах данните за тестване, за да обуча модела. Вместо това трябваше да използвам много по-големия набор от данни за обучение и след това да тествам обучения модел на тестовата база данни.

Не е огромен проблем: Отидох на страницата на Udacity Github и изтеглих по-големия набор от данни за обучение. Или поне се опитах.

По средата на изтеглянето компютърът ми напълно се изплаши.

Оказва се, че локалният диск за съхранение / стартиране на моя компютър беше напълно пълен. Толкова пълен, че компютърът ми отказа да стартира всякакви програми. Дори Finder неочаквано се разби.

Свързах външния си твърд диск и започнах да прехвърлям цялата си Month в документация Master от моята локална машина.

Между другото, като настрана трябваше да снимам екрана на компютъра си с телефона си, тъй като нямаше достатъчно място на компютъра ми, за да направя снимки на екрана ...

Както и да е, първите шест месеца от документацията на M2M затъмниха 132 GB, 70,8 от които бяха на моята локална машина, така че след като прехвърлянето приключи, аз успях да преместя 70 GB местни неща в кошчето.

След това при опит да изпразня кошчето си компютърът ми замръзна ...

След като рестартирах компютъра си няколко пъти, кошът ми най-накрая се изпразни и 30 минути по-късно отново се заех с бизнеса.

С пространството сега на компютъра си се върнах на страницата на Udacity Github, за да изтегля учебния набор данни.

Учебният набор данни всъщност беше компресиран в торент, така че трябваше да инсталирам BitTorrent, за да изтегля набора от данни.

След изтегления торент разпаковах файла. Очаквах да видя куп JPEG изображения и файл data.txt, както видяхме преди, но вместо това видях това ...

Очевидно Udacity смята, че би било добра идея да пакетирате данните в .bag файлове. Всъщност никога не съм чувал за .bag файлове преди, но те изглежда са родният начин, по който самоуправляващите се автомобили (или други „роботи“ запазват данни).

И така, трябваше да разбера как да извлека JPEG и CSV от отделните файлове .bag.

Има библиотека, наречена ROS (Robot Operating System), която е необходима за работа с .bag файлове, така че се опитах да я инсталирам.

Но, ето какво открих на страницата за инсталиране на ROS ...

С други думи, хората, които правят ROS, основно казват „Това няма да работи. Ще се провали За съжаление ".

И те бяха прави, това се провали.

Въпреки това прекарах още малко време в опит да разреша грешката и в крайна сметка изглеждаше така, сякаш успешно инсталирах всичко необходимо. Но след това се опитах да пусна скрипта за извличане и това все още не успя.

В този момент трябваше да спра за през нощта.

Утре, надявам се, че ще успея да постигна известен напредък.

Вчера се заредих сериозно: опитвах се да преобразувам файловете на ROSbag на Udacity в JPEG и CSV файлове, за да мога да използвам данните за обучение на моята самостоятелно управлявана кола, но нямах голям късмет.

В крайна сметка открих, че операционната система Robot не е съвместима с Mac и затова не можах да извлека правилно файловете локално на компютъра си.

Днес, след много проби и грешки, успях да разбера как да стартирам Ubuntu 14.04 и ROS на виртуална машина, използвайки VirtualBox.

След още повече опити и грешки разбрах как да използвам виртуалната машина за извличане на съдържанието на файловете ROSbag ...

Очаквах да намеря изображение с размер на една камера с разумни размери и CSV за съответния ъгъл на управление.

Вместо това, наборът от данни на Udacity включва ~ 33 000 кадъра на шофиране на видео от три различни ъгли на камерата и всички данни за управление, спиране, газ, GPS и т.н.

В рамките на CSV за управление например, данните включват не само времева марка и ъгъл, но и въртящ момент (сила на въртене на колелото) и скорост (скорост на завъртане).

Както и да е, този набор от данни е супер готин и много по-задълбочен, отколкото очаквах. Развълнуван съм да видя как мога да използвам тези данни, за да направя по-функционална, самоцелна кола.

Вчера разбих набора от данни на Udacity ...

И така, днес планът беше да се преформатират / подготвят данните и след това да започне обучението на модела на самостоятелно шофиране на автомобили.

Реших засега просто да моделирам ъгъла на управление, като първа стъпка. Ако това върви добре, ще се опитам да разширя модела, така че да включва както дросела, така и счупване.

За да подготвя данните, трябваше да създам файл data.txt, който изглежда така:

По същество файл с незабележим текст с името на рамката до съответния ъгъл на управление, разделен с интервал.

Това изглеждаше достатъчно просто - но имаше проблем:

Когато отворих файла за управление.csv, никоя от времевите марки във файла не съответства на времевите марки на JPEG кадрите. Мислех, че може би пренебрегвам нещо ...

И така, преминах през JPEG и копирах първите няколко номера на рамката.

След това потърсих индивидуално CSV за тези конкретни номера на кадри, но те не съществуваха ...

Това беше проблем.

Ако не можах да сравня изображенията с данните за шофиране, наборът от данни става напълно безполезен.

За щастие имах не особено блестящата идея да отворя другите CSV файлове в набора от данни на Udacity (само за да видя какво още има) и в крайна сметка отворих interpolated.csv, който съдържа всички данни на едно място И съответства на всичко това данни перфектно към часовете на изображенията.

И така, аз отново имах късмет.

Извадих необходимите ми данни, създадох файла data.txt и започнах да тренирам модела.

Това вероятно ще отнеме цяла нощ, така че ние ще проверим за това утре.

Вчера започнах да тренирам модела на автомобил със самостоятелно управление, базиран на големия набор от данни на Udacity.

Стойността на загубата (мярката, косвено пропорционална на точността на модела) започва от 6.14783.

Много часове по-късно моделът завърши обучение, намалявайки загубата до само 0,000377398.

Ето сюжета на загубата във времето:

Това намаляване на загубата е доста поразително.

Още по-поразителна е разликата в загубата при използване на 5000 точки от данни (както преди няколко дни), със загуба от ~ 1,00 и при използване на 33 000 точки от данни на Udacity с загуба от около 0,000377398.

С други думи, чрез увеличаване на размера на набора от данни с фактор ~ 7, загубата е намалена с коефициент ~ 2500. Ясно е, че това не е линейна връзка: С малко повече данни, моделът става смешно по-добър.

Ето защо Google може да си позволи да раздаде всички / повечето от своите алгоритми за машинно обучение и библиотеки чрез TensorFlow: Количеството данни е диференциаторът, а Google има най-много (от търсене, имейл, снимки, видеоклипове в YouTube и т.н.)

Всъщност в интерес на Google е да отвори своите алгоритми, което позволява на по-голяма общност от разработчици да подобряват по-бързо алгоритмите. След това Google може да вземе тези подобрени алгоритми, да ги захрани с техните собствени данни и да има най-добрите модели за машинно обучение със значителен запас.

Днес наистина ми помогна да оценя стойността на данните като конкурентно предимство.

Говорейки за данни ... Достигнах крайъгълен камък в създаването на моя собствен набор от данни: Днес отбелязвам 200-ия ден подред, който написах в блог като част от моя проект "Месец към мастър".

Наборът ми от дневни записи вече наброява около 85 000 думи. Може би, след като свърша с всички 365 публикации, ще измисля нещо интересно за този набор данни ...

Вчера завърших обучението на моя модел самоуправляващ се автомобил на базата данни на Udacity. Днешната задача беше да се опитаме да визуализираме резултата:

Въпреки че очаквах резултатите да са добри, прогнозираното управление е съвсем естествено и не прекалено трептящо. Много съм доволен от резултата.

Няколко неща, които трябва да отбележите:

  • Първоначално мислех, че има два набора от данни Udacity: набор от данни за обучение (който използвах вчера) и данни за тестване (които случайно използвах за обучение преди няколко дни). Днес разбрах, че данните за тестване всъщност са подмножество на обучителния набор, затова реших вместо това да използвам някои от данните на Nvidia за тестване. Важното тук е, че моделът е обучен на базата данни на Udacity и е тестван на напълно нов терен от набора от данни на Nvidia. С други думи, моделът работи добре на пътища извън своя тренировъчен комплект (това е много важно, ако искате универсално функционален автомобил със самостоятелно управление).
  • За да симулирам правилно изхода на модела Udacity, трябваше да направя две неща: 1. Да картографирам данните на Udacity в диапазон от стойности, използваеми от симулатора на Nvidia (моделът Nvidia използва градуси като единици, докато наборът от данни на Udacity варира от -1 до 1) и 2. Извършете някаква незначителна предварителна обработка към тестовия набор Nvidia (т.е. изрязване), за да тествате модела Udacity.
  • По време на тестването сценарият показа изображенията на волана да се завъртят въз основа на прогнозирания ъгъл на волана, а след това покрих тези рендери на върха на оригиналните, непокрити кадри на Nvidia за малко по-широк изглед.
  • На около 40 секунди във видеото колата спира напълно и след това прави рязък десен завой. Изглежда, че колата започва да се върти, преди визуалните изображения да показват, че е предвидено да се движи правилно (колата може да се движи направо в края на краищата), така че не съм сигурен как става това. Наборът от данни Udacity няма познания за този конкретен завой. Единственото разумно обяснение е, че моделът разпозна, че е на лентата за завой, или моделът е просто по-предикативен от човека. Така или иначе, това беше малко изненадващо, но доста готино да се види.

Почти съм приключил с предизвикателството за този месец: просто трябва да обуча модела на дроселиране и счупване, което, подозирам, ще бъде почти идентично с начина, по който моделът е трениран на ъгъл на управление (в края на краищата, ъгъл на управление, дроселиране и т.н. разбиването са просто представени от произволно определени числа).

През по-голямата част от този месец бях съсредоточена върху създаването на предсказател на ъгъла на кормилно управление за моя самостоятелно управляван автомобил.

За да довърша колата си обаче е важно да разбера как да изградя система за управление на газта / дросела и спирачката на колата (т.е. „педалите“).

Въпреки че това може да звучи като напълно ново предизвикателство, се оказва, че мога да изградя педалната си система, без да пиша нов код на реда.

В крайна сметка моят модел за управление е конструиран от 1. Показване на компютъра куп изображения, 2. Присвояване на числова стойност на всяко изображение, 3. Питане на компютъра да разбере как пикселите на изображенията се свързват с числовите стойности, 4 Използвайки това отношение за прогнозиране на числовата стойност, присвоена на други изображения.

В случая на предвиждащия механизъм за управление тази цифрова стойност представлява ъгъл на управление. Но това може също толкова лесно да представи дросела или спирачната сума.

По този начин, за да изградя педалната система, всичко, което трябваше да направя, беше да присвоя на всяко изображение числова стойност, която съответства на правилното количество на дросела или спирачната сума, и след това помолете компютъра (по същия точен начин) да определи връзката между пикселите и числовите стойности.

Това е, което направих.

Например, в случая с дросела, подготвих data.txt с 10 000 изображения, съответстващи на съответното им количество на дросела, и след това пуснах този файл чрез точно същия модел на машинно обучение.

И както се очаква, моделът научи с течение на времето, намали загубата и определи ефективен начин за прогнозиране на количеството на дросела.

Направих същото за спирачната система.

С други думи, моделът на машинно обучение, който използвам, е напълно общ. Няма значение дали входовете са ъгли на управление, стойности на дросела или спирачни стойности. Моделът не дискриминира.

Това е може би антиклиматично, в някакъв смисъл, но в друг смисъл, доста невероятно нещо: Технологията на машинно обучение стигна до момент, в който не е необходимо да създаваме високоспециализирани модели за всяко приложение. Вместо това един модел е доста разширим в много области - и това просто ще се подобрява.

Въпросът е, че всъщност не ми се налага да работя много, за да получавам дроселиране и спиране безплатно. Това е доста добра сделка ...

Този месец предизвиках себе си да изградя софтуерната част на самоуправляваща се кола. По-специално исках да изградя две основни неща: 1. кормилната система на колата и 2. педалната система на колата (т.е. газта и спирачката).

Преди два дни завърших изграждането на кормилната система - която може точно да прогнозира ъгъла на кормилно управление въз основа на насочена към подаване на видеозапис на пътя.

За да се счита, че кормилната система е успешна, поставих две подцели:

  1. Трябваше да адаптирам и използвам модела на самостоятелно шофиране на автомобил върху набор от данни, за който той не е специално проектиран. Тъй като използвах модел, базиран на изследователския документ на NVIDIA, приложен към набор от данни, предоставен от Udacity, изпълних изискванията за тази подцел.
  2. Второ, трябваше да обучавам модела на един набор от данни (т.е. набор от пътища) и да го изпълнява добре на напълно различен набор от данни (т.е. набор от нови пътища). Тъй като обучих модела на базата данни на Udacity и след това успешно тествах модела на базата данни на NVIDIA, аз също изпълних изискванията за тази подцел.

След това, вчера, използвах същия модел, с модифицирани входове на данни, за да създам успешно дроселовата и спирачната система, която може точно да предвиди количеството на дросела или спирачната сума въз основа на насочена към подаване на видеозапис на пътя.

С всички тези парчета, събрани, предизвикателството за този месец е официално завършено!

Вчера завърших предизвикателството за този месец, като успешно изградих софтуерната част на самостоятелно управлявана кола.

Въпросът е ... Какво остава да направя / построя, за да мога действително да изкарам колата си по пътищата на Калифорния?

Най-добрият отговор идва от Джордж Хотц - който е пионер в движението за самостоятелно управление на автомобили „Направи си сам“.

Преди 18 месеца Bloomberg публикува видео за 26-годишния Хотц, който е построил напълно функциониращ (повече или по-малко) самоуправляващ се автомобил в гаража си:

Във видеото Джордж обяснява, че за създаването на колата му е било необходимо да изгради само две неща: 1. Система, която може да издава инструкции за шофиране въз основа на входни данни, и 2. Система, която може да контролира физическите задвижвания на автомобила (т.е. волан, дросел, спирачка) на базата на цифрови входове.

В началото на този месец нарекох №1 „софтуерната част“ и №2 „хардуерната част“, ​​като насочих енергията си към софтуера. И така, с завършен №1, за да завърша разработването на автомобила си, ще трябва да се обърна към номер 2.

Както Hotz обяснява във видеото, за да контролира всички физически задвижващи механизми на колата, той просто включи компютъра си в порта за отстраняване на грешки в колата (точно както би направил механикът). Разбира се, тогава той трябваше да измисли как да накара софтуерната му система да изпраща правилно инструкции до колата през този порт в реално време, но всъщност не трябваше да прави прекалено много хакерско хакване: Автомобилът вече е проектиран да се контролира цифрово по този начин.

Не че знам прекалено много за автомобилите, но това се чувства много достъпно (стига да имам достъп до интернет и YouTube). Ако имах още един месец и по-важното - кола, това би било естествената следваща стъпка.

По принцип изглежда, че автомобилът в края на края не е толкова митичен. Джордж Хотц помогна да покажа на всички, включително и на мен, че пространството за самостоятелно шофиране не е достъпно само за компании като Google, но и за непринудени любители.

След излизането на видеоклипа на Bloomberg, много малки екипи вече работят върху самостоятелно управлявани автомобили и свързаните с тях услуги и това вероятно ще се ускори значително през следващата година.

Надявам се, че съм изиграл много малка роля в тази история, като продължавам да демонстрирам достъпността на тази технология ...

Предизвикателността за този месец е малко по-различна от шестте предишни предизвикателства „Месец за магистър“. По-конкретно, няма да остарява много добре ...

През февруари 2017 г. кацнах заден ход. Ако беше вместо февруари 2020 г., нямаше да има значение.

През декември 2016 г. се научих да рисувам реалистични портрети. Ако беше вместо декември 2036 г., нямаше да има значение.

Този месец май 2017 г. създадох софтуерната част на самостоятелно управлявана кола. Ако това беше май 2020 г., това предизвикателство би било съвсем различно.

Е, разбира се, това е предположение, но все пак ... След три години е вероятно всичко, което построих този месец, да бъде изпълнено с един ред код (с всичко останало да се абстрахира).

Не само това, но моят личен компютър ще може да обработва много повече данни, много по-бързо, извеждайки експоненциално по-добър модел за самоуправляващата се кола.

По принцип това, което казвам, е, че предизвикателството през този месец няма да бъде предизвикателство след няколко години.

Не че това е толкова голяма работа, но е интересно да помислим за остаряването на уменията и как „режещият ръб“ бързо се превръща в „тъпата среда“.

Може би трябва да обмисля предизвикателното изкуство за този месец, където представянето е „случаен любител изгражда софтуер за самоуправление в свят, в който хората все още карат коли“. Тогава наборът от блогове за този месец може да остане по-подходящ / интересен с течение на времето. В крайна сметка изкуството обикновено набира стойност с времето.

Както и да е, само наблюдение, което мислех, че си струва да споделя.

Днес летя за Сиатъл за петдневна ваканция, поради което работих, за да завърша предизвикателството през този месец малко рано.

Докато съм в Сиатъл, ще продължа да пиша ежедневните си публикации (тъй като все още имам много да размишлявам, що се отнася до техния процес и учебни техники / прозрения), но не планирам да работя върху повече софтуер ,

Ето защо е важно да си поставим измерими цели: Тъй като окончателно изпълних онова, което съм си поставил за цел, мога да се чувствам добре да отида на почивка.

Много хора често определят целите си по-двусмислено - „Искам да се науча да говоря испански“, „Искам да се науча как да рисувам“, „Искам да се науча как да свиря на пиано“. В тези случаи никога не е възможно да постигнете целта, нито е възможно наистина да знаете как напредвате.

По-дефинираната цел е много по-предпочитана.

Може да се твърди, че отворената цел поставя по-голям акцент върху преследването, а не върху дестинацията, което, съгласен съм, е по-продуктивен начин на мислене, когато се опитвате да научите. Без ясно определена дестинация обаче не е ясно какво се преследва.

Нееднозначната цел според мен е малко мързелива цел, при която създателят на целта няма истински основни намерения. В крайна сметка с двусмислена цел не можете да се провалите (което е може би привлекателно), но също така не можете да успеете.

И ... Ако се заемете сериозно с преследването на неправилно определена цел, трудно е някога да сте доволни или да знаете кога да спрете (и да се съсредоточите върху другите важни части от живота си).

Но така или иначе, след като изпълних изрично дефинираната си цел, съм напълно готов да се наслаждавам на пътуването си до Сиатъл без вина.

Преди няколко дни декларирах, че съм изпълнил предизвикателството за самостоятелно управление на автомобил. Резултатът беше основно това видео на моя компютър, управляващ кола ...

Докато резултатът от експеримента от този месец със сигурност беше система, която може да управлява автономно автомобил, остава въпросът ... Какво лично постигнах този месец?

В края на краищата моята самоуправляваща се кола беше основана на нечий друг код с отворен код (който леко адаптирах и обобщих). Този код с отворен код се основава на хартия, написана от екипа на NVIDIA за самостоятелно управление на автомобили. Моделът от изследването се основаваше на математически техники (задно размножаване и др.), Измислени извън лабораторията на NVIDIA, главно в университетски изследователски центрове. И мога да продължа ...

Тези математически техники са изградени на основата на фундаментални прозрения от смятането, които са измислени преди стотици години и т.н.

Мога също да приема това в различна посока: Кодът, който пуснах, е построен върху библиотека за машинно обучение, построена от Google, която е изградена върху езика за програмиране на високо ниво, който е изграден от други. Освен това, за да изпълня някой от този код, трябваше да инсталирам необходимите библиотеки на моя компютър. Инсталирането на тези библиотеки може да бъде сложно, затова използвах инсталиращи услуги, които други хора са настроили, за да улеснят процеса.

Все още мога да продължа ... но няма да

И така, връщайки се към въпроса: Какво лично постигнах този месец? Не е съвсем ясно.

От една страна, мога да кажа, че успях да накарам система за самостоятелно управление на автомобили, която да работи локално на компютъра ми, и че бях в състояние да адаптирам системата, за да обработва ефективно нови източници на данни.

От друга страна, мога да кажа, че взех работата на много други хора и я комбинирах, за да направя видео.

И двете са верни.

И така, наистина ли построих самостоятелно шофираща кола? Можете ли да кажете, че компании като OnePlus или Xiaomi изграждат смартфони, дори ако софтуерът е изграден от Google и хардуерните компоненти са изградени от моя Samsung, Foxconn и други?

Дали „сглобяването“ се счита за „изграждане“ и „обобщаването“ се счита за „учене“?

Бих спорил с „да“, но не мисля, че това има значение.

По-интересното е това: понякога нещата, които изглеждат предизвикателни или недостъпни, всъщност са много по-удобни за начинаещи, отколкото изглеждат. По този начин разликата между „изграждането на самоуправляваща се кола“ и не беше моята вяра, че мога да го разбера и моя опит да го направя.

С други думи, често пъти, изключителността на майсторството съществува само защото повечето хора никога не преследват „нещото“ (въз основа на предположението, че не могат).

Така че, бих искал да преразкажа това, което постигнах този месец: не се пречупих с безумно трудния проблем с изграждането на самоуправляваща се кола. Вместо това доказах на себе си, че изграждането на самоуправляваща се кола (от днес) всъщност не е безумно труден проблем. В този момент, според мен, повечето случайни любители биха могли да разберат.

Мисля, че така или иначе това е по-интересен резултат.

През този месец, докато се опитвах да разкрия загадките на самостоятелно управляващите автомобили, получих един въпрос повече от всеки друг: Сега, когато имате по-добро разбиране на технологията, чувствате ли се повече или по-малко сигурни, когато влизате в напълно самоуправляваща се кола?

Бих казал по-сигурен, но е сложно: Простотата на модела на самоуправляваща се кола ми дава увереност, че с повече данни и мощност за обработка, способностите за самоуправление ще продължат да се подобряват експоненциално. Ирационалната част на мозъка ми обаче се чувства странна с факта, че моделът е толкова прост и неспецифичен за задачата за шофиране.

Независимо от това, колкото по-прост е моделът, толкова по-обобщаващ и обучаем е, така че се чувствам доста сигурен относно перспективата за напълно автономни автомобили (Е, чувствам се безопасно да напиша, че се чувствам в безопасност. Всъщност ме качи в колата и вижте дали променете мелодията си ...).

Един често срещан въпрос, който чувам в отговор на общата ми удобство, е: „Не бихте ли по-скоро да контролирате живота си? Дори ако е статистически по-безопасно като цяло да използвате напълно автономен автомобил, не бихте ли искали да знаете, че сте направили всичко възможно лично, за да запазите живота си? "

Нещо като. Но, честно казано, тъй като аз не притежавам кола и вече се доверявам на живота на непознати (шофьори на Uber / Lyft), не съм сигурен, че в момента имам такъв контрол.

Като кратко допълнение: Преди два дни MIT публикува своя годишен документ за изследване на настоящото състояние на интереса на потребителите към самоуправляващите се автомобили, а 48% от 3000 участници в проучването заявиха, че никога няма да закупят автомобил, който напълно се управлява сам.

Не само това, но миналата година 40% от 25–34 годишните са казали, че ще им е удобно с напълно без шофьор автомобил, но въпреки това само 20% от същата група са казали същото тази година.

Интересно е да се види, че когато широката общественост научава повече за самостоятелно шофиране на автомобили, тяхната удобство намалява.

Честно казано, след като прочетох доклада на MIT, бих могъл да се съглася с широката общественост (поне от днес ... Но все още съм доста оптимистичен).

В момента посещавам приятел в Сиатъл, който ме мъчи за публикацията, която написах преди два дни:

В този пост обяснявам, че успях да използвам колективните знания и работа на много други, за да ускоря значително усилията си за самостоятелно управление на автомобил. По-специално, нямах нужда да изграждам модела на машинно обучение от нулата, но вместо това можех да интегрирам вече изграден модел в моята система.

В резултат на това чувам много „Ако всъщност не сте имали нужда да изградите основния модел самоуправляваща се кола, как всъщност беше предизвикателството през този месец?“.

В публикацията в петък съм съгласен, че възприетото предизвикателство (създаване на механизъм за самостоятелно управление на автомобила) всъщност не е било предизвикателството, но това не означава, че изобщо нямаше предизвикателство.

Всъщност аз твърдя, че възприеманото предизвикателство никога всъщност не е истинското предизвикателство.

Например, през ноември, когато се опитвах да стана гросмайстор на паметта, като запаметявам реда на разбъркано тесте карти, трудната част всъщност не помнеше. Вместо това забравях това, което бях запомнил при предишни опити (за да не се объркам).

През февруари, когато се учех да въртя назад, тежката част нямаше нищо общо с нищо физическо или атлетично, а вместо това имаше общо с менталните блокове и страха, свързани със самосъхранението.

Този месец предизвикателството не беше създаването на модела на самоуправляваща се кола, а вместо това интегрирането на този модел в моята система, така че всъщност да работи.

Това не е изненадващо - по-голямата част от софтуерното инженерство не е задължително да изгражда напълно нови компоненти. Обикновено измисляме как да вземем куп от вече съществуващи компоненти, да ги монтираме заедно и да имат изходната функция, както се очаква.

Според мен софтуерното инженерство много прилича на извършване на трансплантация на органи: Номерът не е в намирането на органа за замяна (въпреки че това все още може да бъде дълъг процес). Номерът е да накарате тялото да не отхвърля новия орган.

По същия начин, софтуерното инженерство има две основни предизвикателства: 1. Намиране на „орган“ (т.е. пример за компонента, който искате да изградите), 2. Интегриране на този „орган“ в цялостното тяло (т.е. осигуряване на правилната ви среда за разработка; свързване на компонента с други компоненти и услуги, така че той да взаимодейства правилно с останалата част от проекта; модифицира компонента, така че да се държи по очаквания / необходим начин).

И така, макар предизвикателството през този месец да не беше трудно поради усещането на трудност да накарате една кола да управлява себе си, все пак прекарах много време в кодиращата яма на отчаянието, опитвайки се да 1. Намерете модел на автомобил със самостоятелно управление Бих могъл успешно да стартирам, 2. Настройте средата на моя компютър да поддържа модела, 3. Форматирайте данни, така че да могат да се използват от модела, 4. Измислете как да изведете нещо интересно от модела, 5. Променете модела да работи с различни набори от данни и за моделиране на различни поведения.

Като цяло, възприетото предизвикателство не беше предизвикателство, но все още имаше много триене.

Тук всъщност има важен урок: Често пъти, когато хората учат нещо ново, те имат предварително формулирана представа за това какво „ще бъде трудно“ или „какво трябва да учат“. В резултат на това, когато има други трудности по пътя, хората възприемат тези затруднения като препятствия, вместо допълнителни части от процеса на обучение.

С други думи, когато хората се борят за нещото, за което очакват да се борят, обикновено те могат да се оправдаят с постоянство. Ако обаче се борят за нещо, което изглежда разсейващо, хората са склонни да се отказват (тъй като смятат, че губят времето си).

Но ясно, че тези разсейвания често пъти са действителното месо на предизвикателството за учене и, ако бъдат напукани, отключват най-голям напредък към целта.

Както обяснява Райън Холидей: „Препятствието е пътят“

Вашите препятствия не ви пречат да постигнете целта си, но всъщност определете самото преследване.

Така че, аз заставам да нарека предизвикателство този месец предизвикателство. Не че семантиката има значение така или иначе ... Но тя разкрива всеки важен урок за ученето и постоянството.

Утре смятам да разгледам дневниците си и да изчисля колко време прекарах за предизвикателството за този месец.

Но преди да го направя, важно е да отбележа как прекарах времето си през този месец и по-специално как ми беше разпределено времето.

В предишните месеци времето ми за практикуване беше сравнително равномерно разпределено - ако прекарвах 30 часа над 30 дни, обикновено прекарвах един час на ден.

Този месец обаче продължителността на сесиите ми често беше значително по-дълга и не толкова равномерна. За да се разбере разликата през този месец, е необходимо да се разберат двете фази на обучение и двата типа учене ...

Двете фази на обучение:

  1. Фаза на откриване - В тази фаза задачата на обучаемия е да изследва полето, да открие най-добрия път и да проектира упражнения в съответствие с този най-добър път.
  2. Фаза на обучение - В тази фаза обучаемата вече знае какво трябва да практикува и прекарва цялото си време умишлено и интензивно, като фокусира обучението си върху този най-добър път.

Цялото обучение изисква тези две фази, но тези фази могат да си взаимодействат по различен начин в различните видове обучение.

Двата типа учене:

  1. Несвързано учене - при несъединено обучение фазата на откриване и фазата на обучение могат да бъдат преследвани напълно поотделно или по различен начин. Например, когато се учех да запаметявам тесте карти, успях първо да открия правилната техника, а след това отделно да практикувам тази техника. Разединеното обучение обикновено позволява кратки, но ефективни тренировки (след необходимата фаза на откриване)
  2. Едновременно обучение - при едновременно обучение фазата на откриване и фазата на обучение трябва да се преследват едновременно. Обикновено едновременно обучение съществува, когато все още няма ясно определен път (който може да бъде открит външно) и следователно трябва да бъде разкрит и оформен по време на обучение. Този процес обикновено изисква значително по-дълги сесии, като се има предвид, че напредъкът е непредсказуем и неструктуриран.

По време на предишните шест месеца предизвикателства успях да използвам доста разединен подход (първо проучих най-добрите начини да тренирам, а след това тренирах), което ми позволи да разпределя равномерно обучението си в кратки, интензивни сесии през целия месец.

Въпреки това, по време на предизвикателството през този месец, аз не бях лукс на ясно определен път. Освен онлайн курса на Udacity за 2400 долара (който не бях готов да платя), нямаше изричен план, който бих могъл да следвам, за да създам самоуправляваща се кола. Вместо това трябваше да проуча много задънена улица и кръгови кръгове, преди да намеря пътя си.

В резултат на това сесиите ми този месец продължиха поне няколко часа, но бяха по-малко в количеството.

Ако се опитах да построя самоуправляващ се автомобил чрез ежедневни 45-минутни сесии, никога нямаше да успея. Трябваше да преструктурирам и преразпределя времето си, за да отговаря на типа обучение, представен този месец (т.е. едновременно обучение).

Следователно, общият опит е следният: Ако планирате да се заемете с вашето лично предизвикателство за учене, важно е да определите кой тип обучение е необходимо и да структурирате и планирате времето си съответно.

Тъй като е почти края на май, време е да погледна назад и да видя колко време прекарах за предизвикателството за този месец.

По-голямата част от времето ми беше разпределено в девет по-дълги сесии, от следните продължителности: 1,5 часа, 2 часа, 2,5 часа, 1,5 часа, 1 час, 3,5 часа, 2,5 часа, 1,5 часа, 1 час, 3 часа.

Освен това прекарах още един час в четири 15-минутни сесии и още пет часа изследване, четене и писане (което отчитам в случаите, когато се използваше специално като средство за обучение).

И така, общо, прекарах 26 часа в изграждането на моя самостоятелно управляван автомобил.

Преди да изчисля тази сума, очаквах нещо около 35-40 часа, така че определено бях малко изненадан от този резултат. Но има смисъл сега: Имаше много дни, в които се чувствах, че инвестирам време, но всъщност или оставях компютъра си да работи самостоятелно, или писах по-подробна от обичайната ежедневна публикация (т.е. всъщност не работех върху предизвикателство себе си).

Интересното е, че ако този месец всичко вървеше както трябва, вероятно щях да завърша цялото предизвикателство за няколко часа. Разбира се, всичко не беше наред и от самото начало не знаех кое е напълно правилно - но все пак ... По-голямата част от времето си през този месец бях прекарала в търсене на пътя си.

Самият „пътят“ всъщност не отне много време.

Днес е последният ден от предизвикателството за самостоятелно шофиране на автомобили и искам да адресирам един от големите въпроси, които получавах през целия месец: „Мисля, че имате нещо тук… Как ще спечелите пари от това?“

Странно е, защото никой не ме е питал това, когато се научих да запаметявам тесте карти или да кацам заден ход.

И така, тази последна публикация е моят отговор на това (въпреки че всъщност не съм сигурен, че отговарям директно на въпроса) ...

Повечето работещи възрастни трудно отделят време за усвояване на нови умения. А тези, които намират време, обикновено са фокусирани върху придобиване на професионално ориентирани способности.

С други думи, повечето възрастни никога не преследват майсторството само заради него. Вместо това, техните стремежи са склонни да бъдат обосновани с търговска цел или кариера.

Няма нищо лошо в тази мотивация. Всъщност, аз със сигурност бих насърчил кариерно мотивирано учене без никакво обучение. Но има проблем с професионалните умения: те не остават уместни или интересни за дълго.

Преди предизвикателството на този месец прекарах времето си в овладяване на умения, които са с много ограничена търговска стойност, ако има такива (като кубирането и рисуването на портрети на Рубик). Готиното е ... Докато живея, ще мога да се наслаждавам на тези умения. С други думи, моята авансова инвестиция дава теоретично безкрайна възвръщаемост.

От друга страна, този месец предизвикателството ми беше много комерсиално (или поне може да бъде). Ако исках, вероятно бих опаковал моите новооткрити умения за самостоятелно шофиране на автомобили и да се опитам да стана самоуправляващ се автомобилен инженер в голяма технологична компания. Или, като алтернатива, бих могъл да направя опит за стартиране на собствен старт на автомобил. Или бих могъл да се опитам да опаковам и да продам учебната си програма на други, които имат тези кариерни амбиции.

С уменията, придобити този месец, мога да направя много интересни в търговската мрежа неща.

Но, ето реалното нещо ... След 24 месеца (ако не и по-рано) цялата тази търговска стойност изчезва. И не само това, но след 24 месеца това предизвикателство вече няма да е актуално или интелектуално интересно: интересно беше само заради времето, все още разумно меките технически детайли и настоящото вълнение за самостоятелно шофиране на автомобили.

Така че, тъй като нямам никакви амбиции за комерсиални автомобили за самостоятелно шофиране, моето забавление с самостоятелно управлявани автомобили вероятно ще приключи заедно с месец май. Определено се забавлявах, като се справях с предизвикателството, но не съм сигурен, че има възможности за многократно забавление (като има за кубчето на Рубик, което все още многократно решавам всеки ден).

Може би съм прекалено драматизирана, но в сравнение с ориентираните към търговски умения тенденции много предпочитам безвременни умения - умения, които могат да се ползват и непрекъснато да се работи завинаги.

Бих могъл да напиша много повече за това как също мисля, че комерсиалните мотиви може да не са най-продуктивната основа за учене като цяло, но засега ще прегледам тази точка.

Основното, което искам да отбележа, е това ... Инвестирате ли в момента в себе си? Опитвате ли се да научите нещо ново? И по-специално, опитвате ли се да научите нещо ново само защото е забавно (а не по финансови причини)?

Ако не, може би си струва да помислите.

Не защото смятам, че безвременното учене е някак по-добро или „по-елитно“ или нещо подобно. Просто мисля, че е забавно И често пъти не си даваме възможност да се забавляваме, защото не смятаме, че е практично.

Но практически изглежда така или иначе и непрекъснато се променя, така че бих ви препоръчал да инвестирате малко време в някое непрактично забавление.

Тази публикация е част от годишния ми проект за ускорено обучение „Месец до магистър“.

Ако искате да следвате моите ежедневни публикации, не забравяйте да следвате този среден акаунт.

За ексклузивно съдържание за ускорено учене, дисциплина и дизайн на начина на живот, абонирайте се за моя веднъж бюлетин.

Ако сте се радвали на тази подробна разбивка, уведомете ме, като щракнете върху сърцето по-долу. Винаги се оценява изключително много.