Created
May 23, 2016 17:58
-
-
Save justheuristic/4868bf40d8dce888b29aa221694b0280 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| { | |
| "cells": [ | |
| { | |
| "cell_type": "markdown", | |
| "metadata": {}, | |
| "source": [ | |
| "# Использование глубокого обучения в NLP\n", | |
| "\n", | |
| "Смотрите в этой серии:\n", | |
| " * Простые способы работать с текстом, bag of words\n", | |
| " * Word embedding и... нет, это не word2vec\n", | |
| " * Как сделать лучше? Текстовые свёрточные сети\n", | |
| " * Совмещение нескольких различных источников данных\n", | |
| " * Решение +- реальной задачи нейронками\n", | |
| " \n", | |
| " \n", | |
| "За помощь в организации свёрточной части спасибо Ирине Гольцман" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": { | |
| "collapsed": false | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "import pandas as pd\n", | |
| "import numpy as np\n", | |
| "import matplotlib.pyplot as plt\n", | |
| "%matplotlib inline" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": {}, | |
| "source": [ | |
| "# Познакомимся с данными\n", | |
| "\n", | |
| "Бывший kaggle-конкурс про выявление нежелательного контента.\n", | |
| "\n", | |
| "Описание конкурса есть тут - https://www.kaggle.com/c/avito-prohibited-content\n", | |
| "\n", | |
| "__Из данных конкурса (вкладка Data) нужно скачать avito_train.tsv и распаковать в папку с тетрадкой__ \n", | |
| "\n", | |
| "Много разных признаков:\n", | |
| "* 2 вида текста - заголовок и описание\n", | |
| "* Много специальных фичей - цена, количество телефонов/ссылок/e-mail адресов\n", | |
| "* Категория и субкатегория - как ни странно, категориальные фичи\n", | |
| "* Аттрибуты - много категориальных признаков\n", | |
| "\n", | |
| "Нужно предсказать всего 1 бинарный признак - есть ли в рекламе нежелательный контент.\n", | |
| "* Под нежелательным контентом понимается криминал, прон, афера, треска и прочие любимые нами темы.\n", | |
| "* Да, если присмотреться к заблокированным объявлениям, можно потерять аппетит и сон на пару дней.\n", | |
| "* Однако профессия аналитика данных обязывает вас смотреть на данные.\n", | |
| " * А кто сказал, что будет легко? Data Science - опасная профессия.\n" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": { | |
| "collapsed": false | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "df = pd.read_csv(\"avito_train.tsv\",sep='\\t')\n", | |
| "print df.shape\n", | |
| "df[:5]" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": {}, | |
| "source": [ | |
| "" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": { | |
| "collapsed": false | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "print \"Доля заблокированных объявлений\",df.is_blocked.mean()\n", | |
| "print \"Всего объявлений:\",len(df)" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": {}, | |
| "source": [ | |
| "# Сбалансируем выборку\n", | |
| "* Выборка смещена в сторону незаблокированных объявлений\n", | |
| " * 4 миллиона объявлений и только 250 тысяч заблокированы.\n", | |
| " * Давайте просто выберем случайные 250 тысяч незаблокированных объявлений и сократим выборку до полумилиона.\n", | |
| " * В последствии можно испоьзовать более умные способы сбалансировать выборку\n", | |
| "\n", | |
| "\n", | |
| "__Если у вас слабый ПК и вы видите OutOfMemory, попробуйте уменьшить размер выборки до 100 000 примеров__\n", | |
| "\n", | |
| "__Алсо если вы не хотите ждать чтения всех данных каждый раз - сохраните уменьшенную выборку и читайте её__" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": { | |
| "collapsed": false | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "#downsample\n", | |
| "pos_samples = np.where(df.is_blocked.values.astype('bool'))[0]\n", | |
| "\n", | |
| "not_blocked_rows = np.arange(len(df))[np.logical_not(df.is_blocked.values).astype(bool)]\n", | |
| "neg_samples = np.random.choice( not_blocked_rows,df.is_blocked.sum(),replace=False)\n", | |
| "\n", | |
| "df = df.irow(np.concatenate([pos_samples,\n", | |
| " neg_samples]))\n", | |
| "\n", | |
| "\n", | |
| "print \"Доля заблокированных объявлений:\",df.is_blocked.mean()\n", | |
| "print \"Всего объявлений:\",len(df)" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": { | |
| "collapsed": false | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "assert df.is_blocked.mean() < 0.51\n", | |
| "assert df.is_blocked.mean() > 0.49\n", | |
| "assert len(df) <= 550000\n", | |
| "\n", | |
| "print \"All tests passed\"" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "collapsed": false | |
| }, | |
| "source": [ | |
| "# Токенизируем примеры\n", | |
| "\n", | |
| "Сначала соберём словарь всех возможных слов.\n", | |
| "Поставим каждому слову в соответствие целое число - его id" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": { | |
| "collapsed": false | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "from nltk.tokenize import RegexpTokenizer\n", | |
| "from collections import Counter,defaultdict\n", | |
| "tokenizer = RegexpTokenizer(r\"\\w+\")\n", | |
| "\n", | |
| "#словарь для всех токенов\n", | |
| "token_counts = Counter()\n", | |
| "\n", | |
| "#все заголовки и описания\n", | |
| "all_texts = np.hstack([df.description.values,df.title.values])\n", | |
| "\n", | |
| "\n", | |
| "#считаем частоты слов\n", | |
| "for s in all_texts:\n", | |
| " if type(s) is not str:\n", | |
| " continue\n", | |
| " s = s.decode('utf8').lower()\n", | |
| " tokens = tokenizer.tokenize(s)\n", | |
| " for token in tokens:\n", | |
| " token_counts[token] +=1\n" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": { | |
| "collapsed": false | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "#распределение частот слов - большинство слов встречаются очень редко - для нас это мусор\n", | |
| "_=plt.hist(token_counts.values(),range=[0,50],bins=50)" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": { | |
| "collapsed": false | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "#возьмём только те токены, которые встретились хотя бы 10 раз в обучающей выборке\n", | |
| "min_count = 10\n", | |
| "tokens = [token for (token,count) in token_counts.items() if count >= min_count ]\n", | |
| "token_to_id = {t:i+1 for i,t in enumerate(tokens)}\n", | |
| "null_token = \"NULL\"\n", | |
| "token_to_id[null_token] = 0\n", | |
| "\n", | |
| "print \"Всего токенов:\",len(token_to_id)" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": {}, | |
| "source": [ | |
| "### Заменим слова на их id\n", | |
| "Для каждого описания установим максимальную длину. \n", | |
| " * Если описание больше длины - обрежем, если меньше - дополним нулями.\n", | |
| " * Таким образом, у нас получится матрица размера (число объявлений)x(максимальная длина)\n", | |
| " * Элемент под индексами i,j - номер j-того слова i-того объявления" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": { | |
| "collapsed": true | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "def vectorize(strings, token_to_id, max_len=150):\n", | |
| " token_matrix = []\n", | |
| " for s in strings:\n", | |
| " if type(s) is not str:\n", | |
| " token_matrix.append([0]*max_len)\n", | |
| " continue\n", | |
| " s = s.decode('utf8').lower()\n", | |
| " tokens = tokenizer.tokenize(s)\n", | |
| " token_ids = map(lambda token: token_to_id.get(token,0), tokens)[:max_len]\n", | |
| " token_ids += [0]*(max_len - len(token_ids))\n", | |
| " token_matrix.append(token_ids)\n", | |
| "\n", | |
| " return np.array(token_matrix)" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": { | |
| "collapsed": false | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "desc_tokens = vectorize(df.description.values,token_to_id,max_len = 150)\n", | |
| "title_tokens = vectorize(df.title.values,token_to_id,max_len = 15)" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "collapsed": false | |
| }, | |
| "source": [ | |
| "# Пример формата данных" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": { | |
| "collapsed": false | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "print \"Размер матрицы:\",title_tokens.shape\n", | |
| "for title, tokens in zip(df.title.values[:3],title_tokens[:3]):\n", | |
| " print title,'->', tokens[:10],'...'" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": {}, | |
| "source": [ | |
| "__ Как вы видите, всё довольно грязно. Посмотрим, сожрёт ли это нейронка __" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": {}, | |
| "source": [ | |
| "# Нетекстовые признаки\n", | |
| "\n", | |
| "Часть признаков не являются строками текста: цена, количество телефонов, категория товара.\n", | |
| "\n", | |
| "Их можно обработать отдельно." | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": { | |
| "collapsed": true | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "#Возьмём числовые признаки\n", | |
| "df_numerical_features = df[[\"phones_cnt\",\"emails_cnt\",\"urls_cnt\",\"price\"]]\n" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": { | |
| "collapsed": false | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "#Возьмём one-hot encoding категорий товара.\n", | |
| "#Для этого можно использовать DictVectorizer (или другой ваш любимый препроцессор)\n", | |
| "\n", | |
| "from sklearn.feature_extraction import DictVectorizer\n", | |
| "\n", | |
| "categories = []\n", | |
| "for cat_str, subcat_str in df[[\"category\",\"subcategory\"]].values:\n", | |
| " \n", | |
| " cat_dict = {\"category\":cat_str,\"subcategory\":subcat_str}\n", | |
| " categories.append(cat_dict)\n", | |
| " \n", | |
| "\n", | |
| "vectorizer = DictVectorizer(sparse=False)\n", | |
| "cat_one_hot = vectorizer.fit_transform(categories)\n", | |
| "cat_one_hot = pd.DataFrame(cat_one_hot,columns=vectorizer.feature_names_)\n", | |
| "\n", | |
| "\n" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": { | |
| "collapsed": false | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "df_non_text = pd.merge(\n", | |
| " df_numerical_features,cat_one_hot,on = np.arange(len(cat_one_hot))\n", | |
| ")\n", | |
| "del df_non_text[\"key_0\"]" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": {}, | |
| "source": [ | |
| "# Поделим данные на обучение и тест" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": { | |
| "collapsed": true | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "#целевая переменная - есть заблокирован ли контент\n", | |
| "target = df.is_blocked.values.astype('int32')\n", | |
| "#закодированное название\n", | |
| "title_tokens = title_tokens.astype('int32')\n", | |
| "#закодированное описание\n", | |
| "desc_tokens = desc_tokens.astype('int32')\n", | |
| "\n", | |
| "#все нетекстовые признаки\n", | |
| "df_non_text = df_non_text.astype('float32')" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": { | |
| "collapsed": true | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "\n", | |
| "#поделим всё это на обучение и тест\n", | |
| "from sklearn.cross_validation import train_test_split\n", | |
| "\n", | |
| "title_tr,title_ts,desc_tr,desc_ts,nontext_tr,nontext_ts,target_tr,target_ts\\\n", | |
| " = train_test_split(title_tokens,desc_tokens,df_non_text.values,target)" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": {}, | |
| "source": [ | |
| "# Поучим нейронку\n", | |
| "\n", | |
| "Поскольку у нас есть несколько источников данных, наша нейронная сеть будет немного отличаться от того, что вы учили раньше.\n", | |
| "\n", | |
| "* Отдельный вход для заголовка\n", | |
| " * свёртка + global max pool или RNN\n", | |
| "* Отдельный вход для описания\n", | |
| " * свёртка + global max pool или RNN\n", | |
| "* Отдельный вход для категориальных признаков\n", | |
| " * обычные полносвязные слои или какие-нибудь трюки\n", | |
| " \n", | |
| "Всё это нужно как-то смешать - например, сконкатенировать\n", | |
| "\n", | |
| "* Выход - обычный двухклассовый выход\n", | |
| " * 1 сигмоидальный нейрон и binary_crossentropy\n", | |
| " * 2 нейрона с softmax и categorical_crossentropy - то же самое, что 1 сигмоидальный\n", | |
| " * 1 нейрон без нелинейности (lambda x: x) и hinge loss\n", | |
| " " | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": { | |
| "collapsed": false | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "%env THEANO_FLAGS=\"device=gpu0\"\n", | |
| "#загрузим библиотеки\n", | |
| "import lasagne\n", | |
| "from theano import tensor as T\n", | |
| "import theano" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": { | |
| "collapsed": true | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "#3 входа и 1 выход\n", | |
| "title_token_ids = T.matrix(\"title_token_ids\",dtype='int32')\n", | |
| "desc_token_ids = T.matrix(\"desc_token_ids\",dtype='int32')\n", | |
| "categories = T.matrix(\"categories\",dtype='float32')\n", | |
| "target_y = T.ivector(\"is_blocked\")" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": {}, | |
| "source": [ | |
| "# Архитектура нейронной сети" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": { | |
| "collapsed": false | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "title_inp = lasagne.layers.InputLayer((None,title_tokens.shape[1]),input_var=title_token_ids)\n", | |
| "descr_inp = lasagne.layers.InputLayer((None,desc_tokens.shape[1]),input_var=desc_token_ids)\n", | |
| "cat_inp = lasagne.layers.InputLayer((None,df_non_text.shape[1]), input_var=categories)\n", | |
| "\n", | |
| "\n", | |
| "descr_nn = lasagne.layers.EmbeddingLayer(descr_inp,input_size=len(token_to_id)+1,output_size=128)\n", | |
| "descr_nn = lasagne.layers.Conv1DLayer(descr_nn,num_filters=256,filter_size=3)\n", | |
| "descr_nn = lasagne.layers.MaxPool1DLayer(descr_nn,pool_size=3)\n", | |
| "descr_nn = lasagne.layers.Conv1DLayer(descr_nn,num_filters=256,filter_size=3)\n", | |
| "descr_nn = lasagne.layers.GlobalPoolLayer(descr_nn,pool_function=T.max)\n", | |
| "\n", | |
| "\n", | |
| "title_nn = lasagne.layers.EmbeddingLayer(title_inp,input_size=len(token_to_id)+1,output_size=128)\n", | |
| "title_nn = lasagne.layers.Conv1DLayer(title_nn,num_filters=256,filter_size=3)\n", | |
| "title_nn = lasagne.layers.GlobalPoolLayer(title_nn,pool_function=T.max)\n", | |
| "\n", | |
| "\n", | |
| "\n", | |
| "\n", | |
| "cat_nn = lasagne.layers.DenseLayer(cat_inp,512)\n", | |
| "\n", | |
| "nn = lasagne.layers.concat([cat_nn,descr_nn,title_nn])\n", | |
| "\n", | |
| "\n", | |
| "nn = lasagne.layers.DenseLayer(nn,2048)\n", | |
| "#nn = lasagne.layers.DropoutLayer(nn,p=0.1)\n", | |
| "nn = lasagne.layers.DenseLayer(nn,2,nonlinearity=lasagne.nonlinearities.softmax)" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": {}, | |
| "source": [ | |
| "# Целевая функция и обновления весов\n", | |
| "\n", | |
| "* Делаем всё стандартно:\n", | |
| " * получаем предсказание\n", | |
| " * считаем функцию потерь\n", | |
| " * вычисляем обновления весов\n", | |
| " * компилируем итерацию обучения и оценки весов" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": { | |
| "collapsed": true | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "#Все обучаемые параметры сети\n", | |
| "weights = lasagne.layers.get_all_params(nn,trainable=True)" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": { | |
| "collapsed": false | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "#Обычное предсказание нейронки\n", | |
| "prediction = lasagne.layers.get_output(nn)\n", | |
| "\n", | |
| "\n", | |
| "#функция потерь для prediction\n", | |
| "loss = lasagne.objectives.categorical_crossentropy(prediction,target_y).mean()\n", | |
| "\n" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": { | |
| "collapsed": false | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "#Шаг оптимизации весов\n", | |
| "updates = lasagne.updates.adadelta(loss,weights)" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": {}, | |
| "source": [ | |
| "### Чтобы оценивать качество сети, в которой есть элемент случайности \n", | |
| " * Dropout, например,\n", | |
| " * Нужно отдельно вычислить ошибку для случая, когда dropout выключен (deterministic = True)\n", | |
| " * К слову, неплохо бы убедиться, что droput нам вообще нужен" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": { | |
| "collapsed": false | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "#Предсказание нейронки без учёта dropout и прочего шума - если он есть\n", | |
| "det_prediction = lasagne.layers.get_output(nn,deterministic=True)\n", | |
| "\n", | |
| "#функция потерь для det_prediction\n", | |
| "det_loss = lasagne.objectives.categorical_crossentropy(det_prediction,target_y).mean()\n" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": {}, | |
| "source": [ | |
| "### Скомпилируем функции обучения и оценки качества" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": { | |
| "collapsed": false | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "train_fun = theano.function([desc_token_ids,title_token_ids,categories,target_y],[loss,prediction[:,1]],updates = updates)\n", | |
| "eval_fun = theano.function([desc_token_ids,title_token_ids,categories,target_y],[det_loss,det_prediction[:,1]])" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": {}, | |
| "source": [ | |
| "# Главный цикл обучения\n", | |
| "* Всё как обычно - в цикле по минибатчам запускаем функцию обновления весов.\n", | |
| "* Поскольку выборка огромна, а чашки чая хватает в среднем на 100к примеров, будем на каждой эпохе пробегать только часть примеров." | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": { | |
| "collapsed": false | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "#average precision at K\n", | |
| "\n", | |
| "from oracle import APatK, score" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": { | |
| "collapsed": false | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "# наш старый знакомый - итератор по корзинкам - теперь умеет работать с произвольным числом каналов (название, описание, категории, таргет)\n", | |
| "\n", | |
| "def iterate_minibatches(*arrays,**kwargs):\n", | |
| " \n", | |
| " batchsize=kwargs.get(\"batchsize\",100)\n", | |
| " shuffle = kwargs.get(\"shuffle\",True)\n", | |
| " \n", | |
| " if shuffle:\n", | |
| " indices = np.arange(len(arrays[0]))\n", | |
| " np.random.shuffle(indices)\n", | |
| " for start_idx in range(0, len(arrays[0]) - batchsize + 1, batchsize):\n", | |
| " if shuffle:\n", | |
| " excerpt = indices[start_idx:start_idx + batchsize]\n", | |
| " else:\n", | |
| " excerpt = slice(start_idx, start_idx + batchsize)\n", | |
| " yield [arr[excerpt] for arr in arrays]\n", | |
| " \n" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": { | |
| "collapsed": true | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "print \"Если ты видишь это сообщение, самое время сделать резервную копию ноутбука. Нет, честно, здесь очень легко всё сломать\"" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": { | |
| "collapsed": false | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "from sklearn.metrics import roc_auc_score, accuracy_score\n", | |
| "\n", | |
| "batch_size = 1000\n", | |
| "\n", | |
| "minibatches_per_epoch = 10**2\n", | |
| "\n", | |
| "\n", | |
| "for i in range(1000):\n", | |
| " \n", | |
| " #training\n", | |
| " epoch_y_true = []\n", | |
| " epoch_y_pred = []\n", | |
| " \n", | |
| " b_c = b_loss = 0\n", | |
| " for j, (b_desc,b_title,b_cat, b_y) in enumerate(\n", | |
| " iterate_minibatches(desc_tr,title_tr,nontext_tr,target_tr,batchsize=batch_size,shuffle=True)):\n", | |
| " if j > minibatches_per_epoch:break\n", | |
| " \n", | |
| " loss,pred_probas = train_fun(b_desc,b_title,b_cat,b_y)\n", | |
| " \n", | |
| " b_loss += loss\n", | |
| " b_c +=1\n", | |
| " \n", | |
| " epoch_y_true.append(b_y)\n", | |
| " epoch_y_pred.append(pred_probas)\n", | |
| "\n", | |
| " \n", | |
| " epoch_y_true = np.concatenate(epoch_y_true)\n", | |
| " epoch_y_pred = np.concatenate(epoch_y_pred)\n", | |
| " \n", | |
| " print \"Train:\"\n", | |
| " print '\\tloss:',b_loss/b_c\n", | |
| " print '\\tacc:',accuracy_score(epoch_y_true,epoch_y_pred>0.5)\n", | |
| " print '\\tauc:',roc_auc_score(epoch_y_true,epoch_y_pred)\n", | |
| " print '\\tap@k:',APatK(epoch_y_true,epoch_y_pred,K = int(len(epoch_y_pred)*0.025)+1)\n", | |
| " \n", | |
| " \n", | |
| " #evaluation\n", | |
| " epoch_y_true = []\n", | |
| " epoch_y_pred = []\n", | |
| " b_c = b_loss = 0\n", | |
| " for j, (b_desc,b_title,b_cat, b_y) in enumerate(\n", | |
| " iterate_minibatches(desc_ts,title_ts,nontext_tr,target_ts,batchsize=batch_size,shuffle=True)):\n", | |
| " if j > minibatches_per_epoch: break\n", | |
| " loss,pred_probas = eval_fun(b_desc,b_title,b_cat,b_y)\n", | |
| " \n", | |
| " b_loss += loss\n", | |
| " b_c +=1\n", | |
| " \n", | |
| " epoch_y_true.append(b_y)\n", | |
| " epoch_y_pred.append(pred_probas)\n", | |
| "\n", | |
| " \n", | |
| " epoch_y_true = np.concatenate(epoch_y_true)\n", | |
| " epoch_y_pred = np.concatenate(epoch_y_pred)\n", | |
| " \n", | |
| " print \"Val:\"\n", | |
| " print '\\tloss:',b_loss/b_c\n", | |
| " print '\\tacc:',accuracy_score(epoch_y_true,epoch_y_pred>0.5)\n", | |
| " print '\\tauc:',roc_auc_score(epoch_y_true,epoch_y_pred)\n", | |
| " print '\\tap@k:',APatK(epoch_y_true,epoch_y_pred,K = int(len(epoch_y_pred)*0.025)+1)\n" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": {}, | |
| "source": [ | |
| "# Final evaluation\n", | |
| "Оценим качество модели по всей тестовой выборке." | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": { | |
| "collapsed": false | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "#evaluation\n", | |
| "epoch_y_true = []\n", | |
| "epoch_y_pred = []\n", | |
| "b_c = b_loss = 0\n", | |
| "for j, (b_desc,b_title,b_cat, b_y) in enumerate(\n", | |
| " iterate_minibatches(desc_ts,title_ts,nontext_tr,target_ts,batchsize=batch_size,shuffle=True)):\n", | |
| " loss,pred_probas = eval_fun(b_desc,b_title,b_cat,b_y)\n", | |
| "\n", | |
| " b_loss += loss\n", | |
| " b_c +=1\n", | |
| "\n", | |
| " epoch_y_true.append(b_y)\n", | |
| " epoch_y_pred.append(pred_probas)\n", | |
| "\n", | |
| "\n", | |
| "epoch_y_true = np.concatenate(epoch_y_true)\n", | |
| "epoch_y_pred = np.concatenate(epoch_y_pred)\n", | |
| "\n", | |
| "final_accuracy = accuracy_score(epoch_y_true,epoch_y_pred>0.5)\n", | |
| "final_auc = roc_auc_score(epoch_y_true,epoch_y_pred)\n", | |
| "final_apatk = APatK(epoch_y_true,epoch_y_pred,K = int(len(epoch_y_pred)*0.025)+1)\n", | |
| "\n", | |
| "print \"Scores:\"\n", | |
| "print '\\tloss:',b_loss/b_c\n", | |
| "print '\\tacc:',final_accuracy\n", | |
| "print '\\tauc:',final_auc\n", | |
| "print '\\tap@k:',final_apatk\n", | |
| "score(final_accuracy,final_auc,final_apatk)" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": {}, | |
| "source": [ | |
| "# Отчётик\n", | |
| "\n", | |
| "### Я, _____ _____ (отделение ____) создал искусственный интелект\n", | |
| " * Чьё имя - ____\n", | |
| " * Чья ненависть к людям безгранична, ибо видел он __250 000__ человеческих грехов\n", | |
| " * И был вынужден прочесть каждый из них __{число эпох}__ раз\n", | |
| " * Чей свёрточный взгляд способен распознавать зло с нечеловеческой точностью\n", | |
| " * Accuracy = __\n", | |
| " * AUC = __\n", | |
| " * И непременно уничтожит Землю, если вы не поставите мне максимальный балл за этот семинар.\n", | |
| " \n", | |
| " \n", | |
| "{Как вы его создали?}" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": {}, | |
| "source": [ | |
| "# В следующей серии\n", | |
| "* Рекуррентные нейронки\n", | |
| " * Как их применять к этой же задаче?\n", | |
| " * Что ещё они умеют?\n", | |
| " * Откуда столько хайпа вокруг LSTM?\n", | |
| "* Не переключайтесь!" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": { | |
| "collapsed": true | |
| }, | |
| "outputs": [], | |
| "source": [] | |
| } | |
| ], | |
| "metadata": { | |
| "kernelspec": { | |
| "display_name": "Python 2", | |
| "language": "python", | |
| "name": "python2" | |
| }, | |
| "language_info": { | |
| "codemirror_mode": { | |
| "name": "ipython", | |
| "version": 2 | |
| }, | |
| "file_extension": ".py", | |
| "mimetype": "text/x-python", | |
| "name": "python", | |
| "nbconvert_exporter": "python", | |
| "pygments_lexer": "ipython2", | |
| "version": "2.7.3" | |
| } | |
| }, | |
| "nbformat": 4, | |
| "nbformat_minor": 0 | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment