Skip to content

Instantly share code, notes, and snippets.

@justheuristic
Created May 23, 2016 17:58
Show Gist options
  • Select an option

  • Save justheuristic/4868bf40d8dce888b29aa221694b0280 to your computer and use it in GitHub Desktop.

Select an option

Save justheuristic/4868bf40d8dce888b29aa221694b0280 to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
{
"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": [
"![caption](https://kaggle2.blob.core.windows.net/competitions/kaggle/3929/media/Ad.png)"
]
},
{
"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