IT-инфраструктура для бизнеса и творчества

Обучение логистической регрессии

Привет, читатель. Сегодня у нас пост про обучение логистической регрессии с L1 и L2 регуляризациями с помощью метода Stochastic Gradient Descent (SGD).

Перед тем как приступить к статье и коду, беглым шагом пробежимся по основным понятиям L1 и L2 регуляризации, логистической регрессии и стахостического градиентного спуска (Stochastic Gradient Descent — SGD).

Итак, самое время поставить перед собой цели, которые к концу статьи должны быть достигнуты:

  • Реализовать обучение логистической регрессии с L1 и L2 регуляризациями с помощью метода стахостического градиентного спуска;
  • Для отладки работы алгоритма, реализовать возможность сохранения или вывода ошибки модели, после очередной итерации;
  • Запустить алгоритм на синтетических данных;
  • Вывести полученные веса и нарисовать разделяющую границу между классами;
  • Показать сходимость метода: изобразить графики зависимости значения функции потерь (по всей выборке) после очередной итерации/эпохи (выбрать одно) для разных alpha.

Поехали.

Реализация модели с L1 и L2 регуляризацией с методом SGD

import pandas as pd import numpy as np import matplotlib.pyplot as plt from sklearn.base import BaseEstimator, ClassifierMixin import numpy as np import math %matplotlib inline #Предположим, что в выборке всегда 2 класса class MySGDClassifier(BaseEstimator, ClassifierMixin): def __sigma(self, t): t = np.clip(t, -10, 10) return 1 / (1 + np.exp(-t)) #L1 регуляризация def __l1_penalty(self): return 1/self.C * np.sign(self.theta) #L2 регуляризация def __l2_penalty(self): return 1/self.C * self.theta def __none_penalty(self): return 0 def __init__(self, **kwargs): self.C = kwargs.get('C', 1) #Коэф. регуляризации self.alpha = kwargs.get('alpha', 1) # Скорость спуска self.max_epoch = kwargs.get('max_epoch', 10) #Максимальное количество эпох при обучении модели self.chunk_size = kwargs.get('chunk_size', 5) #Количество элементов в чанке (от 1 до общего числа точек) self.min_err = kwargs.get('min_err', 0.1) #Пороговое значение ошибки penalty = kwargs.get('penalty', 'none') #Способ расчета регуляризации if penalty == 'l1': self.penalty = self.__l1_penalty elif penalty == 'l2': self.penalty = self.__l2_penalty else: self.penalty = self.__none_penalty self.theta = None self.errors = None #Обучение модели def fit(self, X, y=None): import time np.random.seed(int(time.time())) eps = 1e-15 n, m = X.shape #n - число строк, m - столбцов sigma = self.__sigma chunk_size = self.chunk_size errors = np.empty(self.max_epoch) errors[:] = np.nan X_b = np.c_[X, np.ones(n)] self.theta = np.random.randn(m + 1, 1) Y = np.vstack(y) for epoch in range(self.max_epoch): lst = list(range(n)) np.random.shuffle(lst) chunks = [lst[i : i+chunk_size] for i in range(0, n, chunk_size)] for chunk in chunks: xi = X_b[chunk] yi = Y[chunk] gradients = xi.T.dot(sigma(xi.dot(self.theta)) - yi) self.theta = self.theta - self.alpha * (gradients + self.penalty()) p = sigma(X_b.dot(self.theta)) p = np.clip(p, eps, 1-eps) epoch_error = 1 / n * np.sum(-(Y * np.log(p) + (1 - Y)*np.log(1 - p))) errors[epoch] = epoch_error if epoch_error <= self.min_err: break self.errors = errors return self #Возвращение метки класса def predict(self, X): y_hat_proba = self.predict_proba(X) y_hat = np.where(y_hat_proba[0] >= 0.5, 0, 1) return y_hat #Возвращение вероятности каждого из классов def predict_proba(self, X): if self.theta is None: raise Exception("Model is not fitted yet. Use method 'fit'") n, m = X.shape X_b = np.c_[X, np.ones(n)] y1 = self.__sigma(X_b.dot(self.theta)) y0 = 1 - y1 y_hat_proba = np.c_[y0, y1] return y_hat_proba

Запуск алгоритма на синтетических данных и вывод полученных весов с нарисованной разделяющей границей между классами

max_epoch = 20 C1 = np.array([[0., -0.8], [1.5, 0.8]]) C2 = np.array([[1., -0.7], [2., 0.7]]) gauss1 = np.dot(np.random.randn(200, 2) + np.array([5, 3]), C1) gauss2 = np.dot(np.random.randn(200, 2) + np.array([1.5, 0]), C2) X = np.vstack([gauss1, gauss2]) y = np.r_[np.ones(200), np.zeros(200)] fig, ax = plt.subplots() fig.set_size_inches(20,10) ax.scatter(X[:,0], X[:,1], c=y) x_min, x_max = X[:, 0].min(), X[:, 0].max() y_min, y_max = X[:, 1].min(), X[:, 1].max() model = MySGDClassifier(alpha=.01, max_epoch=max_epoch, penalty = 'none', C = 100) model.fit(X, y) print("theta = ", model.theta) t0 = model.theta.item(0) t1 = model.theta.item(1) t2 = model.theta.item(2) x_ = np.array([x_min, x_max]) y_ = -(x_ * t0 + t2) / t1 ax.plot(x_, y_) ax.set_xlim(x_min - 1, x_max + 1) ax.set_ylim(y_min - 1, y_max + 1) plt.show()

Демонстрация сходимости метода с графиками зависимости значения функции потерь после очередной итерации/эпохи для разных alpha

alphas = [0.1, 0.01, 0.001] penalties = ['None', 'l1', 'l2'] penalty_coef = 10 x_min, x_max = X[:, 0].min(), X[:, 0].max() y_min, y_max = X[:, 1].min(), X[:, 1].max() for penalty in penalties: fig, ax = plt.subplots(1, 2, figsize=(20, 7)) ax[1].scatter(X[:,0], X[:,1], c=y) ax[0].set_xlim(0, max_epoch) ax[0].set_ylim(0.2, 1.5) ax[0].set_title('Метод штрафной функции {}'.format(penalty)) for alpha in alphas: model = MySGDClassifier(alpha=alpha, max_epoch=max_epoch, penalty = penalty, C = penalty_coef, min_err = 0.05) model.fit(X, y) ax[0].plot(range(max_epoch), model.errors, label=r'$\alpha$ = {}'.format(alpha)) t0 = model.theta.item(0) t1 = model.theta.item(1) t2 = model.theta.item(2) x_ = np.array([x_min, x_max]) y_ = -(x_ * t0 + t2) / t1 ax[1].plot(x_, y_, label=r'$\alpha$ = {}'.format(alpha)) ax[1].set_xlim(x_min - 1, x_max + 1) ax[1].set_ylim(y_min - 1, y_max + 1) ax[0].legend(loc='upper right') ax[1].legend(loc='lower right') plt.show()

На этом все наши цели, которые мы ставили перед собой в начале статьи, были достигнуты. Выводы по графикам каждый может сделать сам. Если у кого-то есть, что дополнить или поделиться — пишите в комментариях.

Всем знаний!

Подписывайтесь на «Нейрон» в Telegram (@neurondata) ― там свежие статьи и новости из мира науки о данных появляются каждую неделю. Спасибо всем, кто помогает с полезными ссылками и разработкой, особенно Игорю Мариарти и Михаилу Чумашеву.

{ "author_name": "Рушан Сюрмаков", "author_type": "self", "tags": ["\u0441\u043f\u043e\u0441\u043e\u0431","\u043f\u0440\u0435\u0434\u043f\u043e\u043b\u043e\u0436\u0438\u043c","\u043f\u043e\u0440\u043e\u0433\u043e\u0432\u043e\u0435","\u043e\u0431\u0443\u0447\u0435\u043d\u0438\u0435","\u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0435","\u043a\u043e\u044d\u0444","\u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e","\u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0435\u043d\u0438\u0435","n","l2","l1"], "comments": 1, "likes": 4, "favorites": 9, "is_advertisement": false, "subsite_label": "dev", "id": 72964, "is_wide": true, "is_ugc": true, "date": "Tue, 25 Jun 2019 21:05:13 +0300", "is_special": false }
(function () { let cdnUrl = `https://specialsf378ef5-a.akamaihd.net/SelectelBranding/images/` let previousArticleNumber = null let currentArticleNumber = 0 let platform = 'Desktop' let articles = [ // { // name: 'camera', // url: `${cdnUrl}CameraCat`, // text: 'умную камеру для\u00A0наблюдения за\u00A0котиками', // link: '1', // }, { name: 'chill', url: `${cdnUrl}ChillCat`, text: 'трекер, который подскажет, когда пора отдохнуть', link: 'https://vc.ru/promo/288561-eye-tracker', }, // { // name: 'cloud', // url: `${cdnUrl}CloudCat`, // text: 'котика: даёшь ему «пять», а\u00A0он делает бэкап в облако', // link: '3', // } ] let buttonCycle = document.querySelector('.button--cycle') let textField = document.querySelector('.selectel-footer-subtitle') let imageAgent = document.querySelector('.image--agent') let banner = document.querySelector('.selectel-footer') buttonCycle.addEventListener('click', cycleClick) let media = window.matchMedia("(max-width: 570px)") media.addEventListener('change', matchMedia) function matchMedia() { if (media.matches) { platform = 'Mobile' } else { platform = 'Desktop' } update() } matchMedia() function cycleClick(event) { if (event) { event.preventDefault() event.stopPropagation() } window.open('https://vc.ru/tag/selectelDIY', '_blank') //cycle(event) } function cycle(event) { // incrementArticleNumber() textField.innerHTML = generatedText() imageAgent.src = articles[currentArticleNumber].url + platform + '.svg?5' imageAgent.setAttribute("class", "") imageAgent.classList.add('image--agent', articles[currentArticleNumber].name) banner.href = articles[currentArticleNumber].link } function update() { banner.href = articles[currentArticleNumber].link imageAgent.src = articles[currentArticleNumber].url + platform + '.svg?5' textField.innerHTML = generatedText() } function incrementArticleNumber() { previousArticleNumber = currentArticleNumber if (currentArticleNumber >= articles.length - 1) { currentArticleNumber = 0 } else { currentArticleNumber++ } } function generatedText() { let defaultText if (platform === 'Desktop') { defaultText = `Мы тут собрали %text%. Хотите почитать?` } else { defaultText = `Мы тут собрали %text%.` } return defaultText.replace('%text%', articles[currentArticleNumber].text) } function getRandom(min, max) { min = Math.ceil(min) max = Math.floor(max) return Math.floor(Math.random() * (max - min + 1)) + min } (function create() { currentArticleNumber = getRandom(0, articles.length - 1) cycle() let page = document.querySelector('.page--entry') if (page) { function insertAfter() { let parents = page.querySelectorAll('[data-id="7"]') let referenceNode = parents[0] referenceNode.parentNode.insertBefore(banner, referenceNode.nextSibling); loaded() } setTimeout(() => insertAfter(), 0) } }()) function loaded() { banner.classList.add('loaded') } loadImages([ `${cdnUrl}CameraCatDesktop.svg`, `${cdnUrl}ChillCatDesktop.svg`, `${cdnUrl}CloudCatDesktop.svg`, `${cdnUrl}CameraCatMobile.svg`, `${cdnUrl}ChillCatMobile.svg`, `${cdnUrl}CloudCatMobile.svg`, ]) function loadImages(urls) { return Promise.all(urls.map(function (url) { return new Promise(function (resolve) { var img = document.createElement('img'); img.onload = resolve; img.onerror = resolve; img.src = url; }); })); } }())
0
1 комментарий
Популярные
По порядку

gradients = xi.T.dot(sigma(xi.dot(self.theta)) - yi)
а усреднять по количеству примеров?

0
Читать все 1 комментарий
Подмосковное УФАС уличило «Магнит» и «Пятёрочку» в завышении цен на некоторые продукты Статьи редакции

Если ритейлеры не снизят цены, им грозит уголовное дело.

Как мы расслабили покупателей «Пятёрочки» с помощью ASMR. Кейс Cubic Music

Привет! Я Всеволод Кисляков, редактор и продюсер в музыкальном сервисе для бизнеса Cubic Music. Недавно мы сделали необычный проект — комплексное музыкальное решение для экспериментальных магазинов «Пятёрочка» без кассиров.

МТС перебил вводной кабель в квартиру, когда проводил интернет

Компания обесточила квартиру на несколько дней и отказывается компенсировать ремонт

Пять брендов, которые выпускают одежду, аксессуары и декор из мусора

Вещи, вышедшие из употребления, могут снова стать полезными — после переработки. Мы составили подборку брендов — от маленьких локальных до более крупных и известных за рубежом — которые производят товары из того, что другие просто выбрасывают.

Еду к деду
Кто такой конкурентный разведчик, чем он занимается и сколько зарабатывает Статьи редакции

Рассказ интернет-разведчика и руководителя компании «Интернет-Розыск» Игоря Бедерова — о том, как он раскрыл секретное подразделение МВД, искал киберпреступников и начал разрабатывать ПО для поиска информации в интернете.

Игорь Бедеров «Интернет-Розыск»
7 друзей планеты: как экологические стартапы спасают природу и зарабатывают деньги

Экологичность, устойчивое развитие и забота об окружающей среде — устойчивые тренды 2021 года. Предприятия-гиганты и быстрорастущие стартапы по всему миру тратят сотни миллионов долларов на спасение нашей планеты.

Как использовать облачные технологии для роста бизнеса в 2022 году: расскажем на Yandex Scale

А ещё представим новые продукты.

Задания от самого титулованного программиста в мире и 3,72 млн призовых: каким был VK Cup в этом году

Зачем в VK Cup ежегодно участвуют тысячи специалистов из разных стран и чем запомнится турнир в этом году? Отвечаем на главные вопросы.

Без сложных слов и длинных предложений: чем проще говорит директор, тем выше доходность акций компании Статьи редакции

Японская компания Nomura Holdings проанализировала речи руководителей 1000 фирм с самыми рентабельными акциями в США. Акции компаний, чьи директора использовали запутанные формулировки, приносили инвесторам на 6% меньше денег, рассказало Bloomberg.

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

Элизабет Холмс
основательница Theranos
Как облегчить планирование в редакции: опыт «Лайфхакера»
Банк России утвердил порядок тестирования неквалифицированных инвесторов

Банк России утвердил в новой редакции стандарт, который устанавливает порядок тестирования неквалифицированных инвесторов для допуска к совершению сделок со сложными финансовыми инструментами.

null