Добрый день, уважаемые читатели. Сатирический заголовок говорит о том, что сегодняшней темой станут нейронные сети, а точнее «алгоритм» их обучения. Ведь обучить нейросеть не значит создать класс модели и вызвать метод fit (sklearn) или заполнить её слоями (keras). Это значит предобработать данные, подобрать гиперпараметры, сохранить её для дальнейшего использования и многое другое. Сегодня мы и сделаем это, исключив подбор гиперпараметров модели, это я доверяю вам, чтобы добавить интерактива.
Будет полезным:
Подпишись на группу Вконтакте и Телеграм-канал. Там еще больше полезного контента для программистов.
А на моем YouTube-канале ты найдешь обучающие видео по программированию. Подписывайся!
Импорт
В качестве примера мы будем использовать обычную реализацию нейросети из sklearn.
In[1]: import pandas as pd import pandas_profiling as pprf import numpy as np from sklearn.externals import joblib from sklearn.neural_network import MLPClassifier from sklearn.model_selection import train_test_split from sklearn.preprocessing import normaliz
Команды для установки пакетов:
pip install -U scikit-learn pip install pandas pip install numpy pip install pandas_profiling
В качестве датасета мы будем использовать набор сведений о людях, ключевым фактором которого является факт того, больше ли заработная плата персоны 50.000$. Загрузить и просмотреть его можно здесь, также в этом наборе имеются и другие наборы данных.
Предобработка (preprocessing) данных
In[2]: path = r'E:\datasets\mlcourse\adult_data.csv' df = pd.read_csv(path) df.head()
Загрузим данные с помощью pandas
, в частности функции read_csv.
Нам необходимо получше «узнать» датасет, чтобы продолжить с ним работу. В этом нам поможет профилирование.
In[3]: profiler = pprf.ProfileReport(df) profiler.to_file(r'C:\profiling.html')
Мы создали отчет по нашей таблице и загрузили его в отдельный файл. Не буду раскрывать карты и демонстрировать, что находится в нём, но могу сказать, что вы будете приятно удивлены, если ранее не сталкивались с pandas_profiling
.
У нас довольно много категориальных данных, которые мы будем кодировать с помощью One-Hot encoding.
Однако столбец education-num
является кодированием меток из столбца education
, потому он нам не нужен.
In[4]: df = df.drop('education-num', axis=1) df.head()
Также нам необходимо закодировать наш target
— столбец salary
. Для этого воспользуемся методом map
класса Series
. Он принимает словарь типа:
<value : coding>
Метод возвращает новый объект Series
, потому следующая наша команда выглядит так:
In[5]: df['salary'] = df['salary'].map({'<=50K': 0, '>50K': 1}) df.head()
По привычке, в качестве Out
в Jupyter Notebook
я выдаю первые 5 строк таблицы, дабы посмотреть, корректно ли сработала та или иная конструкция.
Далее нам необходимо закодировать категориальные переменные. Мы не будем делать это вручную: за нас это сделает функция get_dummies
из библиотеки pandas
.
In[6]: df = pd.get_dummies(df) df.values.shape Out[6]: (32561, 108)
Итого у нас получилось 108 столбцов — не так много, как могло казаться ранее. Теперь проверим информацию о таблице, чтобы точно убедиться, что всё верно.
In[7]: df.info() Out[7]: <class 'pandas.core.frame.DataFrame'> RangeIndex: 32561 entries, 0 to 32560 Columns: 108 entries, age to native-country_Yugoslavia dtypes: int64(6), uint8(102) memory usage: 4.7 MB
Отлично, мы имеем все столбцы в числовом виде, однако это ещё не всё.
Нам необходимо нормализировать данные: именно в таком виде лучше передавать числовые значения
Отделим нашу цель и образцы из общего набора:
In[8]: y = df['salary'] del df['salary'] X = normalize(df.values) X.shape, y.shape Out[8]: ((32561, 107), (32561,))
Теперь же разделим данные на тренировочные и тестовые с помощью train_test_split
:
In[9]: X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2) X_train.shape Out[9]: (26048, 107)
26 тысячи тренировочных образцов мы получили в итоге. Теперь начнём создавать наш классификатор.
Нейросеть (neural network)
In[10]: nntw = MLPClassifier(activation='logistic', hidden_layer_sizes=100, alpha=0.0001, learning_rate_init=0.2, shuffle=True, max_iter=300)
100 скрытых слоёв, сигмоидальная функция активации, штраф L2-регуляризации в 0.0001, перемешивание и т.д. указываем при создании экземпляра класса. Далее обучаем модель:
In[11]: nntw.fit(X_train, y_train) nntw.score(X_test, y_test), nntw.score(X_train, y_train) Out[11]: (0.7868877629356671, 0.7953777641277642)
Как вы можете заметить, мы столкнулись либо с недообучением, либо с недостатком обучающих данных. Однако цель сегодняшней статьи — не научить создавать идеальную нейросеть, а показать, что же делать с ней перед и после обучения.
Недавно от меня была статья про консервацию объектов Python с помощью pickle
и json
. Однако сегодня мы будем использовать joblib
— подмодуль sklearn
для сохранения модели в бинарный файл и её загрузки в объект Python.
Программный интерфейс joblib
, который нам необходим, такой же, как и у pickle
:
In[12]: with open(r'C:\model.pkl', 'wb') as f: joblib.dump(nntw, f)
In[13]: with open(r'C:\model.pkl', 'rb') as f: nntw = joblib.load(f) nntw Out[13]: MLPClassifier(activation='logistic', alpha=0.0001, batch_size='auto', beta_1=0.9, beta_2=0.999, early_stopping=False, epsilon=1e-08, hidden_layer_sizes=100, learning_rate='constant', learning_rate_init=0.2, max_iter=300, momentum=0.9, nesterovs_momentum=True, power_t=0.5, random_state=None, shuffle=True, solver='adam', tol=0.0001,validation_fraction=0.1, verbose=False, warm_start=False)
И далее, чтобы пользоваться моделью, нам ничего не нужно. Проверим равенство обобщающей способности до и после загрузки:
In[14]: nntw.score(X_test, y_test), nntw.score(X_train, y_train) Out[14]: (0.7868877629356671, 0.7953777641277642)
Отлично, всё сходится.
Заключение
Сегодня мы разобрали, как лучше предобработать данные для обучения на их основе нейронной сети, а так же как сохранить готовую модель в файл и её использовать без повторного обучения.
Документ .ipynb для полного его разбора вы можете найти здесь.
Также рекомендую прочитать статью Начальные функции NumPy. Подпишитесь на группу ВКонтакте, Telegram и YouTube-канал. Там еще больше полезного и интересного для разработчиков.