Съдържание[Крия][Покажи]
Мозъкът е сравним с невронните мрежи. Това е аналогията, която обикновено се използва, за да помогне на някой нов в темата да разбере идеите зад машинното обучение и изкуствените невронни мрежи.
Тъй като има няколко слоя математически и статистически изчисления, които се извършват зад кулисите, дефинирането на тези мрежи като математическа функция е по-напреднал метод.
Това е за хората, които наистина се интересуват от машинно обучение и искат да видят как се пише кодът на невронната мрежа на Python.
В тази статия ще демонстрираме как да изградим напълно свързана дълбока невронна мрежа (DNN) от нулата в Питон 3.
Общ преглед на файловата структура за нашия код на невронна мрежа на Python
Тук ще бъдат създадени три файла. Първият е простият файл nn.py, който ще бъде обсъден в „Настройване на помощни функции“ и „Изграждане на невронната мрежа от нулата“.
Ще имаме също файл с име mnist loader.py за зареждане на тестовите данни, както е описано в „Зареждане на MNIST данни“.
И накрая, ще имаме файл с име test.py, който ще бъде стартиран в терминала, за да тества нашата невронна мрежа.
Този файл е описан подробно в „Изпълнение на тестове“.
Инсталация
Библиотеката NumPy Python трябва да бъде изтеглена, за да следвате този урок. Можете да постигнете това, като използвате следната команда на терминала:
Импортиране на модули и настройка на помощната функция
Единствените две библиотеки, от които се нуждаем, са random и NumPy, които ще импортираме веднага. За първоначалните тегла на нашата невронна мрежа ще ги разбъркаме с помощта на произволната библиотека.
За да ускорим нашите изчисления, ще използваме NumPy или np (по конвенция често се импортира като np). Нашите две помощни функции ще бъдат направени след нашия импорт. Две сигмоидни функции: едно и сигмоидно просто.
Логистичната регресия ще класифицира данните с помощта на сигмоидната функция, докато обратното разпространение ще изчисли делта или градиента с помощта на сигмоидната проста функция.
Създаване на мрежов клас
Изграждането на напълно свързана невронна мрежа е единственият фокус на този раздел. Класът на мрежата ще обхване всички функции, които идват след това. Функцията Object() { [native code] } ще бъде създадена първоначално в нашия мрежов клас.
Един аргумент, sizes, се изисква от функцията Object() { [роден код] }. Променливата sizes е набор от числови стойности, които представляват броя на входните възли, налични във всеки слой на нашата невронна мрежа.
Инициализираме четири свойства в нашия метод __init__. Входните променливи, sizes, се използват за задаване на списъка с размери на слоевете и съответно броя на слоевете, num layers.
Първата стъпка е да присвоим на случаен принцип началните отклонения на нашата мрежа към всеки слой, който следва входния слой.
И накрая, всяка връзка между входния и изходния слой има своите тегла, генерирани на случаен принцип. Np.Random.Randn() дава произволна извадка, извлечена от нормалното разпределение за контекст.
Функция за подаване напред
В невронна мрежа информацията се изпраща напред чрез функцията за препращане. Един аргумент, a, указващ текущия активиращ вектор, ще се изисква от тази функция.
Тази функция оценява активирането на всеки слой чрез итериране на всички отклонения и тегла в мрежата. Даденият отговор е прогнозата, която е активирането на последния слой.
Мини-партида Gradient Descent
Работният кон на нашия клас Network е Gradient Descent. В тази версия използваме минипартидно (стохастично) градиентно спускане, модифициран вариант на градиентно спускане.
Това показва, че малка партида точки от данни ще бъдат използвани за актуализиране на нашия модел. Към този метод се предават четири задължителни и един незадължителен аргумент. Четирите необходими променливи са наборът от данни за обучение, броят на епохите, размерът на мини-партидите и скоростта на обучение (ета).
Данните от тестовете са достъпни при поискване. Ще предоставим тестови данни, когато в крайна сметка оценим тази мрежа. Броят на пробите в тази функция първоначално е зададен на дължината на списъка, след като данните за обучението са били трансформирани в тип списък.
Също така прилагаме същия процес за тестване на дадени данни. Това е така, защото вместо да ни бъдат върнати като списъци, те всъщност са ципове от списъци. Когато заредим извадките от данни на MNIST по-късно, ще научим повече за това.
Ако можем да се уверим, че предоставяме и двата вида данни като списъци, тогава това преобразуване на типове не е непременно съществено.
След като имаме данните, преминаваме през епохите на обучение в цикъл. Един период на обучение е само един кръг от обучение на невронни мрежи. Първо разбъркваме данните във всяка епоха, за да гарантираме произволност, преди да направим списък с минипартиди.
Функцията за актуализиране на мини партида, която е обсъдена по-долу, ще бъде извикана за всяка мини партида. Точността на теста също ще бъде върната, ако данните от теста са налични.
Помощна функция за производна на разходите
Нека първо разработим помощна функция, наречена производна на разходите, преди наистина да създадем кода за обратно разпространение. Ако направим грешка в нашия изходен слой, функцията за производна на разходите ще го покаже.
Изисква два входа: масива за изходни активации и y-координатите на очакваните изходни стойности.
Функция за обратно разпространение
Нашият настоящ активиращ вектор, активиране, както и всички други активиращи вектори, активации и z-вектори, zs, трябва да се имат предвид. Първо се активира слой, наречен входен слой.
Ще прегледаме всяко отклонение и тегло, след като ги поставим. Всеки цикъл включва изчисляване на вектора z като точково произведение на теглата и активирането, добавянето му към списъка с zs, преизчисляване на активирането и добавяне на актуализираното активиране към списъка с активации.
И накрая, математиката. Делта, която е равна на грешката от предишния слой, умножена по сигмоидния прост номер на последния елемент от zs векторите, се изчислява, преди да започнем нашето преминаване назад.
Последният слой на nabla b е настроен да бъде делта, а последният слой на nabla w е зададен да бъде точковото произведение на делта и предпоследния слой от активации (транспонирани, за да можем всъщност да направим изчисленията) .
Продължаваме както преди, като започваме с втория слой и завършваме с последния, и повтаряме процеса, след като завършим тези последни слоеве. След това nablas се връщат обратно като кортеж.
Актуализиране на мини-партида градиентно спускане
Нашият SGD (стохастичен градиентен спускане) метод от преди включва минипартидно актуализиране. Тъй като се използва в SGD, но също така изисква backprop, обсъдих къде да поставя тази функция.
Най-накрая реших да го публикувам тук. Започва с генериране на 0 вектора на nablas на отклоненията и теглата, точно както направи нашата функция за бекпроп.
Той изисква мини-партида и eta скоростта на обучение като два входа. В мини-партията след това използваме функцията backprop, за да получим делта на всеки масив nabla за всеки вход, x, и изход, y. След това списъците с nabla се актуализират с тези делти.
И накрая, ние използваме скоростта на обучение и nablas, за да актуализираме теглата и отклоненията на мрежата. Всяка стойност се актуализира до най-новата стойност, минус скоростта на обучение, умножена по размера на минипартида и след това добавена към стойността на nabla.
Оценете функцията
Функцията evaluate е последната, която трябва да напишем. Тестовите данни са единственият вход за тази функция. В тази функция ние само сравняваме изходите на мрежата с очаквания резултат, y. Чрез подаване на входа x напред се определят изходите на мрежата.
Пълен код
Когато комбинираме целия код, изглежда така.
Тестване на невронна мрежа
Данните от MNIST се зареждат
- Данни на MNIST е във формат .pkl.gz, който ще отворим с помощта на GZIP и ще го заредим с pickle. Нека напишем бърз метод за зареждане на тези данни като кортеж с размер три, разделен на данни за обучение, валидиране и тест.
За да направим нашите данни по-лесни за управление, ще напишем друга функция за кодиране на y в масив от 10 елемента. Масивът ще бъде изцяло 0 с изключение на 1, която съответства на правилната цифра на изображението.
Ще използваме основните данни за зареждане и един метод за горещо кодиране, за да заредим нашите данни в четим формат. Ще бъде написана друга функция, която ще преобразува нашите x стойности в списък с размер 784, съответстващ на 784 пиксела на изображението, и нашите y стойности в тяхната единична горещо кодирана векторна форма.
След това ще комбинираме стойностите x и y така, че единият индекс да съвпада с другия. Това се отнася за наборите от данни за обучение, валидиране и тестове. След това връщаме променените данни.
Изпълнение на тестове
Ще направим нов файл, наречен „mnist loader“, който ще импортира невронната мрежа, която създадохме по-рано (просто nn), и MNIST зареждащия набор от данни, преди да започнем тестването.
В този файл всичко, което трябва да направим, е да импортираме данните, да изградим мрежа с размер на входния слой 784 и размер на изходния слой 10, да изпълним SGD функцията на мрежата върху данните за обучение, след което да я тестваме с помощта на тестовите данни.
Имайте предвид, че за нашия списък с входни слоеве няма значение какви са числата между 784 и 10. Можем да променим другите слоеве както желаем; само входните и изходните размери са фиксирани.
Не са необходими три слоя; можем да използваме четири, пет или дори само две. Забавлявайте се да експериментирате с него.
Заключение
Тук, използвайки Python 3, ние създаваме невронна мрежа от нулата. Наред с математиката на високо ниво, обсъдихме и спецификата на изпълнението.
Започнахме с внедряване на помощни функции. За да работят невроните, сигмоидната и сигмоидната основна функция са от решаващо значение. След това приложихме на практика функцията за предаване напред, която е основният процес за подаване на данни в невронната мрежа.
След това създадохме функцията за градиентно спускане в Python, двигателят, който управлява нашата невронна мрежа. За да локализира „локалните минимуми“ и да оптимизира техните тегла и отклонения, нашата невронна мрежа използва градиентно спускане. Създадохме функцията за обратно разпространение, използвайки градиентно спускане.
Чрез доставяне на актуализации, когато резултатите не съответстват на правилните етикети, тази функция позволява на невронната мрежа да се „учи“.
Най-накрая поставихме нашия чисто нов Python невронна мрежа към теста с помощта на набора от данни на MNIST. Всичко функционираше гладко.
Честито кодиране!
Оставете коментар