В публикацията си „Насоки за изследване на проект за машинно обучение“ обясних как да разделя всеки проект за машинно обучение на два етапа (изследване и развитие) и някои трикове за стимулиране на етапа на изследване.

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

Оформление на проекта

Това е оформлението на папката, което обикновено използвам в началото на всеки ML проект. Това оформление е отворено за разширение (като добавяне на папка tests, папка deploy и т.н.), веднага щом проектът трябва да порасне.

project          # project root
├── data         # data files
├── models       # machine learning models
├── notebooks    # notebook files
└── src          # helper functions

За разлика от обикновените проекти за разработка на софтуер, ML проектите имат 3 основополагащи камъка: изходния код (преносими компютри и src), данните, консумирани/произведени от кода, и моделизграден/консумиран от кода и данните.

📁 данни

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

data
├── raw        # original files
├── interim    # preprocessed files
└── processed  # result files

От това оформление можете да следвате потока на данните, като в конвейер: от raw до interim и след това до processed.

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

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

Въпреки че папката raw може да съхранява файлове в много формати (.csv, .json, .xls и т.н.), моята препоръка е да използвате някои често срещан формат в папката interim (например: двоични формати като .parquet, .feather или необработени формати като .csv , .png) и използвайте удобен за клиентите формат в папката processed (например: .csv или excel файл позволява на заинтересованите страни да прегледат резултатите от вашия модел). Понякога има смисъл да включите обобщени диаграми за резултатите от вашия модел (например: когато изграждате система за препоръчване, разпределението на вашите препоръки следва ли подобен модел като вашето разпределение на продажбите?)

📁 тетрадки

Докато работя в етапа на изследване, използвам Jupyter Notebooks като моя платформа за изпълнение/IDE. Това е причината повечето от кода, който поддържа жизнения цикъл на машинното обучение, да се хоства в Jupyter Notebooks

И така, папката с бележници наподобява (до известна степен) жизнения цикъл на ML:

notebooks
├── 1__ingestion                 # |-> data/raw
├── 1tests_eda
├── 2__preprocessing             # |<- data/raw  
│                                  |-> data/interim
├── 2tests_eda
├── 3tests_model_fit_variant_1     # |-> model/variant_1.pkl
├── 3deploy_model_fit_variant_2     # |-> model/variant_2.pkl
├── 3raw_models_validation       
└── 4__model_predict             # |<- data/interim, model/*.pkl  
                                   |-> data/processed

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

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

📁 модел

Резултатът от тетрадките за моделиране (моделът ML след обучение) може да се съхранява в тази папка. Повечето ML рамки (като scikit-learn, spacy, PyTorch) имат вградена поддръжка за сериализиране на модели (.pkl, .h5 и т.н.); в противен случай вижте великолепния пакет cloudpickle.

📁 src

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

WSL2

Подсистемата на Windows за Linux (v2) е новото дете в блока. Ако вече използвате Linux или MacOS, можете да пропуснете този раздел. В противен случай, ако попадате в категорията потребители на Windows, трябва да продължите да четете. Повечето от пакетите на Python са съвместими с Windows системи; но никога не знаете кога ще се сблъскате с трудностите на несъвместими операционни пакети (например: apache airflow не работи в среда на Windows). През тези времена ще се научите да обичате WSL, защото той се държи като напълно развита Linux система, без изобщо да напуска вашата Windows среда. Производителността е доста прилична и повечето IDE са съвместими с WSL.

Например, Visual Studio Code има собствена поддръжка за WSL. Това означава да заредите всеки проект/папка на Python, като използвате вашите обикновени плъгини и изпълните или коригирайте кода. Тъй като WSL монтира хост устройството в папката /mnt, вие все още ще имате достъп до папките на хоста на Windows. Ако в крайна сметка използвате един и същ проект както в Windows, така и в WSL, помислете, че може да срещнете някои проблеми с оперативната съвместимост. Например, git може неточно да открие файлове като променени поради разрешения за файлове или CRLF окончания на редове. За да коригирате тези проблеми, можете да изпълните следните команди в WSL:

git config --global core.filemode false
git config --global core.autocrlf true

Бъдещето пред WSL е обещаващо: собствен достъп до GPU (= обучение на модели за дълбоко обучение с помощта на GPU) и Linux GUI (= поддръжка не само за терминални приложения, но и за GUI приложения). И накрая, не пропускайте шанса си да използвате удивителния Windows Terminal заедно с WSL.

Тетрадка на Юпитер

Без съмнение Jupyter Notebooks е моят предпочитан инструмент за изследване и проучване. Но в същото време Jupyter Notebooks не е най-добрият инструмент, подходящ за производство на вашия модел. Между тези противоположни термини (изследване/разработка) има обща основа, където можете да подобрите начина, по който използвате Jupyter Notebooks.

Инсталация

Препоръчвам да инсталирате Jupyter Notebook с помощта на среди Anaconda и Conda. Но можете да използвате всеки друг инструмент за управление на пакети (като virtualenv, pipenv и т.н.). Но вие трябва да използвате някого и следователно го използвате и във вашите проекти.

Как да инсталирам Jupyter Notebook (или по-скоро как го инсталирах в моята машина):

Инсталирайте Jupyter Notebook с помощта на Anaconda (следователно първо трябва да инсталирате Anaconda); след това инсталирайте Jupyter Notebook в базовата/по подразбиране (conda) среда, като изпълните следните команди:

conda activate base
conda install -c conda-forge notebook

Това звучи против всички добри практики (Jupyter Notebook трябва да е зависимост от проекта), но смятам, че като код на Visual Studio (или назовете-предпочитаната-IDE-тук), Jupyter Notebook трябва да бъде зависимост на ниво машина, а не на ниво проект. Това прави последващите персонализации много по-лесни за управление: например, в случай на използване на Jupyter Extensions (повече за това в следващия раздел), вие ще конфигурирате разширенията само веднъж и след това те ще бъдат достъпни за всички ядра/проекти.

След като инсталирате Jupyter Notebook, идва ред на разширенията за Jupyter Notebook; изпълнете следните команди във вашата конзола:

conda install -c conda-forge jupyter_contrib_nbextensions
jupyter contrib nbextension install --user
conda install -c conda-forge jupyter_nbextensions_configurator

След това всеки път, когато създавате нова conda среда (трябва да създавате нова среда всеки път, когато стартирате нов проект), трябва да я направите достъпна като ядро ​​на Jupyter, като изпълните следната команда:

python -m ipykernel install --user --name retail --display-name "Python (retail)"

И накрая, за да стартирате Jupyter Notebook, трябва да сте в базовата среда и след това да изпълните:

project          # project root (launch jupyter notebook from here,
│                # using the base/default conda environment)
├── data
├── models
├── notebooks
└── src
conda activate base
jupyter notebook

След като Jupyter Notebook бъде стартиран във вашия уеб браузър, можете да изберете необходимата среда (ядро) за вашия бележник:

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

Разширения за бележник

Използвайте „Разширения за бележник на Jupyter“. Само за да активирам разширението Collapsing headers. Когато работите с големи преносими компютри, това е изключително полезно за организиране на информацията във вашия бележник и не губите ума си да прелиствате напред-назад в бележника. Считам го за задължително. МЕСЕЧЕН ЦИКЪЛ.

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

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

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

И накрая, препоръчвам ви да проверите други налични разширения (като scratchpad, autopep, сгъване на кодове, …). Ако сте следвали моята инсталационна настройка, трябва да има раздел с име Nbextensions, достъпен за вас, за да конфигурирате разширенията на Notebook:

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

Тестване на бележник и контрол на източника

Jupyter Notebooks не се справят добре нито с тестване, нито с контрол на източника. В случай на тестване, има известна помощ при използването на papermill и nbdev. Също така силно препоръчвам да използвате триковете от старата школа като командата assert, за да проверите допусканията на вашия код. Например, след всяко pd.merge винаги е добра практика да проверявате кардиналността на резултантната рамка от данни (първоначален брой редове == краен брой редове):

nrows_initial = df.shape[0]
df = pd.merge(df, df_sub, how="left")
assert nrows_initial == df.shape[0]

В случай на контрол на източника, можете да поставите отметка на nbdime, за различаване и сливане бележници. Обикновено git предлага лошо различаване изживяване за откриване на промени във файловете на бележника, но за разлика от това nbdime е мощен инструмент, който можете да използвате от командния ред (интеграцията с git, bash и PowerShell е предоставен) или от уеб интерфейс, който предоставя много по-богато изживяване (осигурена е и интеграция с Jupyter Notebook). Наистина оценявам факта, че nbdime класифицира актуализациите по промени във входните клетки, промените в изходните клетки и промените в метаданните на клетката.

Магически команди за тетрадка

Друга препоръка при използване на Jupyter Notebooks е да се възползвате от използването на вградените %magic commands. Любимите ми магически команди са:

%load_ext autoreload
%autoreload 2
%matplotlib inline

Магическата команда %autoreload се оказва много удобна при повторно зареждане на модули и пакети в паметта без рестартиране на ядрото. Например, ако работите с код, който се съхранява в класически .py файл, когато изходният файл се актуализира, веднага щом изпълните клетка в бележника, новият изходен файл ще се презареди в текущото ядро ​​и промените ще бъдат достъпни за използване. Друг плюс на тази техника е, че можете да инсталирате нови пакети в средата на бележника и (през повечето време) те ще станат достъпни за импортиране в текущия бележник (отново без рестартиране на ядрото). От друга страна, магическата команда %matplotlib се използва за пренасочване на изхода matplotlib към текущия бележник с платно.

Други по-малко известни магически команди са:

%%time когато трябва да профилирате времето, прекарано в изпълнение на клетка в бележник. Обичам да използвам тази команда със сложни клетки, които изискват дълго време за изпълнение, тъй като имам представа колко ще отнеме, за да завърши изпълнението. Ако искате повече информация за това, можете да прочетете отличната глава Код за профилиране и синхронизиране - Python Data Science Handbook.

Друг начин да профилирате кода си е като използвате tqdm, който показва хубава лента за напредъка при изпълнение на „партиди от код“. Резултатът се адаптира добре в зависимост от контекста на изпълнение (python, интерактивен или Jupyter Notebook).

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

%debug (да, можете да отстранявате грешки), след като дадена клетка не успее да се изпълни поради грешка, изпълнете магическата команда %%debug в следващата клетка. След това ще получите достъп до (великолепния [преднамерен сарказъм] ) pdb интерфейс за отстраняване на грешки; имайте предвид, че няма изискан потребителски интерфейс за задаване на точки на прекъсване, само „старомодни“ команди, уви, „s“ за стъпка, „q“ за излизане и т.н.; можете да проверите останалите pdb команди за собствено забавление.

Предварителна обработка

Тръбопроводи за данни

В последните ми проекти получих силно вдъхновение от тази публикация „Рамка за инженеринг на функции и тръбопроводи за машинно обучение“, която обяснява как да изградя тръбопроводи за предварителна обработка на машинно обучение. Най-важната идея е да НЕ отлагате това, което може да бъде направено преди това, и да трансформирате данните, като следвате този ред:

  1. Предварителен процес: операции по колони (т.е. map трансформации)
  2. Инженеринг на функции: операции по ред (т.е. group by трансформации)
  3. Обединяване: разумни операции с рамка за данни (т.е. merge трансформации)
  4. Контекстуално: операции между рамки с данни (т.е. map операции с кръстосан контекст)

Профилиране

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

Класическият начин за проверка за липсващи данни е използването на pandas API, както в df.isna().sum(); по същия начин можете да правите заявки за честоти на данни, изпълнявайки df.species.value_counts(). Но резултатът от тези команди е „непълен“, тъй като връща само абсолютни числа. Добре дошли в странична таблица, която обогатява минали заявки по приятен табличен начин:

sidetable и pandas-profiling API са напълно интегрирани в pandas DataFrame API и имат поддръжка за Jupyter Notebooks.

PS: тази област е „гореща“ в настоящия момент, така че очаквайте да дойдат още пакети в бъдеще (klib)

Визуализации

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

Ако прочетете това, докато функцията все още не е публикувана, не забравяйте, че можете да инсталирате пакети за „разработка“ директно от GitHub, като използвате следната команда:

pip install  https://github.com/mwaskom/seaborn.git@4375cd8f636e49226bf88ac05c32ada9baab34a8#egg=seaborn

Можете също така да използвате този вид URL адреси във вашия requirements.txt или environment.yml файл, въпреки че препоръчвам да закрепите хеша на записа на хранилището (както е показано в последния фрагмент). В противен случай ще инсталирате „последната версия на хранилището, която е налична по време на инсталацията“. Освен това внимавайте да инсталирате „бета“ или „разработващи“ версии в производствената среда. Вие сте предупреден

[актуализирано] В момента е налична версия 0.11 на Seaborn, така че не е необходимо да инсталирате версията за разработка от GitHub. Въпреки това, ще оставя бележките относно инсталирането на версии за разработка в името на знанието.

По време на последния ми проект се запознах с наистина удобен пакет за визуализиране на карти заедно със статистическа информация: kepler.gl, оригинален модул node.js, който наскоро беше пренесен в Python и също получи удобно разширение за зареждане на карти в Jupyter notebooks.

Най-важните характеристики, които харесвам в kepler.gl са:

  1. Тясно интегриран с pandas API.
  2. Успях да направя впечатляваща визуализация на 3D карта, включително динамична времева линия, която беше автоматично анимирана за кратък период от време.
  3. Потребителският интерфейс има много ГИС функции (слоеве и други подобни), така че картите са силно интерактивни и персонализирани. Но най-добрата част е, че можете да запазите тези настройки на потребителския интерфейс и да ги експортирате като обект на Python (речник на Python, за да бъдем точни); следващия път, когато заредите картата, можете да предадете този обект на Python и да избегнете повторното настройване на картата от нулата.
from keplergl import KeplerGl
sales_map = KeplerGl(height=900, 
                     data={"company sales" : df,
                           "box info" : df.drop_duplicates(subset=["product_id"]), 
                           "kid_info" : df.drop_duplicates(subset=["user_id"]) },
                     config=config # configuration dictionary
                    )
sales_map

​​Благодарим ви за отделеното време в четенето на тази публикация.

  • Повечето от проблемите, които обясних в тази публикация, се основават на моя трудов опит в ML проекти. Но не е задължително да се поберат в работната ви среда, но поне се надявам, че могат да ви дадат храна за размисъл.
  • Имайте предвид, че тази публикация се фокусира върху експерименти по време на етапа на проучване, така че разрешавам някои лицензи около себе си, които няма да позволя в краен продукт. В същото време се опитах да наложа области, които лесно се покриват с правилните инструменти (например: просто тестване с помощта на assert, добри практики за тръбопроводи и т.н.).
  • Изглежда контрапродуктивно, че не описвам проблеми с моделите за машинно обучение (обучение, валидиране и внедряване). Но в началото ще прекарате много повече време в планиране на вашия проект, трансформиране на вашите данни и справяне с неудобства, свързани със софтуера, отколкото в изпълнение на методи за приспособяване/предсказване.
  • Моля, споделете своите бележки или опита си в коментарите. Както казах преди, оставих няколко области без повече подробности, но ако се интересувате от някоя от тях, моля, кажете го. Това ще помогне за развитието на тази невероятна общност.