СТАТЬЯ

Развертывание моделей машинного обучения, часть 1: сохранение моделей

Из Книжного лагеря по машинному обучению Алексея Григорьева

В этой серии статей мы рассмотрим развертывание моделей: процесс использования моделей. В частности, мы увидим, как упаковать модель в веб-службу, чтобы другие службы могли ее использовать. Мы также покажем, как развернуть веб-службу в среде, готовой к работе.

Получите скидку 40% на Книжный лагерь по машинному обучению, введя fccgrigorev в поле кода скидки при оформлении заказа на manning.com.

Модель прогнозирования оттока

Чтобы начать развертывание, мы будем использовать модель, которая используется в книге. Вы можете загрузить исходный код здесь (модель и данные находятся в папке CH 03, а другой соответствующий код находится в папке Ch05). Сначала в этой статье мы рассмотрим, как можно использовать модель для прогнозирования, а затем посмотрим, как сохранить ее с помощью Pickle.

Использование модели

Давайте воспользуемся этой моделью, чтобы рассчитать вероятность ухода следующего клиента:

customer = {
     'customerid': '8879-zkjof',
     'gender': 'female',
     'seniorcitizen': 0,
     'partner': 'no',
     'dependents': 'no',
     'tenure': 41,
     'phoneservice': 'yes',
     'multiplelines': 'no',
     'internetservice': 'dsl',
     'onlinesecurity': 'yes',
     'onlinebackup': 'no',
     'deviceprotection': 'yes',
     'techsupport': 'yes',
     'streamingtv': 'yes',
     'streamingmovies': 'yes',
     'contract': 'one_year',
     'paperlessbilling': 'yes',
     'paymentmethod': 'bank_transfer_(automatic)',
     'monthlycharges': 79.85,
     'totalcharges': 3320.75,
 }

Чтобы предсказать, собирается ли этот клиент уйти, мы можем использовать функцию predict:

df = pd.DataFrame([customer])
 y_pred = predict(df, dv, model)
 y_pred[0]

Этой функции нужен фрейм данных, а это значит, что мы должны сначала создать фрейм данных с одной строкой - нашего клиента. Затем мы помещаем его в функцию predict. Результатом является массив NumPy с единственным элементом: прогнозируемая вероятность оттока для этого клиента:

0.061875

Это означает, что вероятность ухода этого клиента составляет шесть процентов.

Теперь давайте посмотрим на функцию predict. Мы написали его ранее для применения модели к клиентам в наборе для проверки. Вот как это выглядит:

def predict(df, dv, model):
     cat = df[categorical + numerical].to_dict(orient='rows')
     X = dv.transform(cat)
     y_pred = model.predict_proba(X)[:, 1]
     return y_pred

Использование его для одного клиента кажется неэффективным и ненужным: мы создаем фрейм данных из одного клиента только для того, чтобы преобразовать этот фрейм данных обратно в словарь позже внутри predict.

Чтобы избежать этого ненужного преобразования, мы можем создать отдельную функцию для прогнозирования вероятности оттока только для одного клиента. Назовем эту функцию predict_single:

def predict_single(customer, dv, model): #A
     X = dv.transform([customer]) #B
     y_pred = model.predict_proba(X)[:, 1] #C
     return y_pred[0] #D

#A Вместо передачи фрейма данных передайте одного клиента

#B Векторизовать клиента: создать матрицу X

#C Применить модель к этой матрице

#D Поскольку у нас только один клиент, нам нужен только первый элемент результата

Его использование становится проще: мы вызываем его у нашего покупателя (словаря):

predict_single(customer, dv, model)

Результат тот же: вероятность того, что у этого покупателя изменится, составляет шесть процентов.

Эта модель живет в записной книжке Jupyter, и как только мы ее останавливаем, обученная модель исчезает. Это означает, что теперь мы можем использовать его только внутри ноутбука и больше нигде. Далее мы посмотрим, как с этим справиться.

Использование Pickle для сохранения и загрузки модели

Чтобы иметь возможность использовать его вне нашей записной книжки, нам нужно сохранить его, а позже другой процесс сможет загрузить его и использовать (рисунок 1).

Pickle - это модуль сериализации / десериализации, который уже встроен в Python: с его помощью мы можем сохранить произвольный объект Python (за некоторыми исключениями) в файл. Когда у нас есть файл, мы можем загрузить модель оттуда в другом процессе.

ПРИМЕЧАНИЕ. «Pickle» также может использоваться как глагол: травление объекта в Python означает его сохранение с помощью модуля Pickle.

Сохранение модели

Чтобы сохранить модель, мы сначала импортируем модуль pickle, а затем используем функцию dump:

import pickle
  
 with open('churn-model.bin', 'wb') as f_out: #A
     pickle.dump(model, f_out) #B

#A Укажите файл, в котором мы хотим сохранить

#B Сохраните модель в файл с помощью pickle

Для сохранения модели используем функцию open. Требуется два аргумента:

  • Имя файла, который мы хотим открыть. Для нас это churn-model.bin.
  • Режим, в котором мы открываем файл. Для нас это wb, что означает, что мы хотим писать в файл (w), и файл должен быть двоичным (b).

Функция open возвращает f_out - дескриптор файла, который мы можем использовать для записи в файл.

Далее мы используем функцию дампа из Pickle. Также требуется два аргумента:

  • Объект, который мы хотим сохранить. Для нас это model
  • Дескриптор файла, указывающий на выходной файл, который для нас f_out

Наконец, мы используем конструкцию with в этом коде. Когда мы открываем файл с открытым, нам нужно закрыть его после того, как мы закончим писать. С with это происходит автоматически. Без with наш код выглядит так:

f_out = open('churn-model.bin', 'wb')
 pickle.dump(model, f_out)
 f_out.close()

В нашем случае сохранения модели недостаточно: у нас также есть DictVectorizer, который мы также «обучили» вместе с моделью. Нам нужно спасти обоих.

Самый простой способ сделать это - поместить их обоих в кортеж при мариновании:

with open('churn-model.bin', 'wb') as f_out:
     pickle.dump((dv, model), f_out) #A

# Сохраняемый нами объект представляет собой кортеж с двумя элементами

Загрузка модели

Чтобы загрузить его, мы используем функцию load из Pickle. Мы можем протестировать это в том же блокноте Jupyter:

with open('churn-model.bin', 'rb') as f_in: #A
     dv, model = pickle.load(f_in) #B

#A Откройте файл в режиме чтения

#B Загрузить кортеж и распаковать его

Мы снова используем функцию open, но на этот раз в другом режиме: rb, что означает, что мы открываем его для чтения (r), а файл является двоичным (b).

ВНИМАНИЕ: будьте осторожны при указании режима. Случайное указание неправильного режима может привести к потере данных: если вы откроете существующий файл в режиме w вместо r , содержимое будет перезаписано.

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

ВНИМАНИЕ! Распаковка объектов, найденных в Интернете, небезопасна: при этом может выполняться произвольный код на вашем компьютере. Используйте его только для того, чему доверяете, и для того, что спасли сами.

Давайте создадим простой скрипт Python, который загружает модель и применяет ее к клиенту.

Мы называем этот файл churn_serving.py. Это содержит:

  • predict_single функции, которые мы написали ранее
  • Код для загрузки модели
  • Код для применения модели заказчику

Во-первых, начнем с импорта. Для этого скрипта нам нужно импортировать Pickle и NumPy:

import pickle
 import numpy as np

Теперь давайте поместим туда функцию predict_single:

def predict_single(customer, dv, model):
     X = dv.transform([customer])
     y_pred = model.predict_proba(X)[:, 1]
     return y_pred[0]

Теперь мы можем загрузить нашу модель:

with open('churn-model.bin', 'rb') as f_in:
     dv, model = pickle.load(f_in)

И примените это:

customer = {
     'customerid': '8879-zkjof',
     'gender': 'female',
     'seniorcitizen': 0,
     'partner': 'no',
     'dependents': 'no',
     'tenure': 41,
     'phoneservice': 'yes',
     'multiplelines': 'no',
     'internetservice': 'dsl',
     'onlinesecurity': 'yes',
     'onlinebackup': 'no',
     'deviceprotection': 'yes',
     'techsupport': 'yes',
     'streamingtv': 'yes',
     'streamingmovies': 'yes',
     'contract': 'one_year',
     'paperlessbilling': 'yes',
     'paymentmethod': 'bank_transfer_(automatic)',
     'monthlycharges': 79.85,
     'totalcharges': 3320.75,
 }
  
 prediction = predict_single(customer, dv, model)

Наконец, давайте покажем результаты:

print('prediction: %.3f' % prediction)
  
 if prediction >= 0.5:
     print('verdict: Churn')
 else:
     print('verdict: Not churn')

После сохранения файла мы можем запустить этот скрипт с Python:

python churn_serving.py

Мы должны сразу увидеть результаты:

prediction: 0.062
 verdict: Not churn

Таким образом, мы можем загрузить модель и применить ее к клиенту, указанному в скрипте.

Мы не собираемся вручную помещать информацию о клиентах в скрипт. Во части 2 мы рассмотрим более практичный подход: размещение модели в веб-сервисе.

Это все для этой статьи.

Если вы хотите узнать больше о книге, посмотрите ее на нашей браузерной платформе liveBook здесь.