{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# BigARTM CLI\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Приложение `bigartm.exe`\n", "\n", "Приложение `bigartm.exe` (в Unix — просто `bigartm`) — самостоятельный бинарик, работающий по следующему алгоритму:\n", "\n", "1. Распарсить корпус и создать батчи\n", "2. Загрузить словарь, если он указан\n", "3. Инициализировать или загрузить модель\n", "4. Сделать определенное число итераций EM алгоритма\n", "5. При последнем проходе по корпусу вывести в файл тематические профили документов (вектора $\\theta$)\n", "6. Вывести модель/словарь в файлы\n", "\n", "#### Самостоятельный бинарник\n", "\n", "Бинарник не должен зависеть от динамически линкуемых библиотек. При переносе бинарника на другую машину он должен запускаться без дополнительных файлов и переменных окружения. Самостоятельность бинарика значительно упростит его использование на кластере для распределенного обучения модели и вывода тематических профилей документов. \n", "\n", "Для сборки самостоятельного бинарика `gcc` нужно передавать флаг `-static`. В `cmake` нужно прописать что-то такое:\n", "```\n", "SET(CMAKE_EXE_LINKER_FLAGS \"-static\")\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Ключи консольного приложения\n", "\n", "- `--rand-seed `: инициализация генератора случайных чисел, гарантируется что приложение отрабатывает с одинаковым результатом при одинаковом значении seed. По-умолчанию выбирается по таймеру (случайно).\n", "- `--response-file `: текстовый файл содержащий ключи коммандной строки данного бинарного файла (`bigartm.exe`). В отличии от коммандной строки, файл `response-file` может состоять из нескольких строк. Это может быть полезно при ограничениях операционной системы на длину коммандной строки, или для удобства редактирования параметров запуска." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 1. Corpus / Batches\n", "\n", "Парсинг корпуса и создание батчей:\n", "- `--read-vw-corpus `: источник, из которого поступает корпус в формате Vowpal Wabbit\n", "- `--read-uci-docword `: источник, из которого поступает корпус в формате UCI Bag-of-Words\n", "- `--read-uci-vocab `: источник, из которого поступает словарь формата UCI Bag-of-Words\n", "\n", "Минус (`-`) в `` означает stdin, может быть указан локальный файл; в дальнейшем хочется добавить поддержку hdfs и других сетевых протоколов.\n", "\n", "- `--batch-size `: число документов в одном батче\n", "\n", "Чтение батчей, подготовленных заранее:\n", "- `--use-batches `: путь к батчам, использовать заранее подготовленные батчи\n", "\n", "По умолчанию считается, что подготовленные батчи отсутствуют и сырой корпус читается из `stdin` в формате Vowpal Wabbit." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 2. Dictionary\n", "\n", "Использование существующего словаря:\n", "- `--use-dictionary `: использовать словарь, загруженный из файла в бинарном формате\n", "- настройки динамического словаря (в случае если он меняется), мин частота, макс число токенов\n", "\n", "Если не указана опция использования существующего словаря, то по-умолчанию создается новый словарь.\n", "\n", "Ключи фильтрации токенов при создании словаря. Основная идея: ключи ограничивают снизу (min) и сверху (max) либо частоту появления токенов (документная — df, токенная — tf), либо их квантили — (документная — dfq, токенная — tfq). Если ключу указано целое число >= 1 — значение воспринимается как ``, если ключу указано вещественное число < 1, либо число со знаком процента на конце — значение воспринимается как `

`.\n", "- `--dictionary-min-df `: фильтровать токены, встречающиеся в менее чем N документах / менее чем P% документов\n", "- `--dictionary-max-df `: фильтровать токены, встречающиеся в более чем N документах / более чем P% документов\n", "- `--dictionary-min-dfq `: фильтровать N токенов / P% токенов, встречающихся в наименьшем числе документов\n", "- `--dictionary-max-dfq `: фильтровать (#Tokens - N) токенов / (100 - P)% токенов, встречающихся в наибольшем числе документов\n", "- аналогичные ключи для term frequency: `--dictionary-min/max-tf/tfq`\n", "\n", "\n", "Примеры:\n", " - `--dictionary-min-tfq 20`\n", " - `--dictionary-max-df 30%`\n", " - `--dictionary-max-dfq 0.98`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 3. Model\n", "\n", "На этой фазе происходит создание модели: модель может быть загружена из файла, либо инициализирована по словарю.\n", "\n", "- `--load-model `: загрузить модель из файла\n", "\n", "Если не указана опция загрузки модели, то модель инициализируется.\n", "\n", "- `--topics `: создать N тем, имеющих названия `topic_0,...,topic_(N-1)`\n", "- `--topics :,...,:`: создать группы тем, для каждой группы создается соответствующее число тем с названиями вида `_`; если у группы не указан размер, то создается группа из одной темы\n", "- (\\*) `--initialize `: инициализировать матрицу $\\Phi$ одной из схем; _пока у нас только одна схема инициализации — команда не нужна_\n", "\n", "Пример: `bigartm ... --topics 100` — создать 100 тем; `bigartm ... --topics objective:100,background:3,thrash` — создать 100 целевых тем (objective), 3 фоновые темы (background) и 1 специальную трэш-тему.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 4. Learning Options\n", "\n", "Для обучения модели используется EM-алгоритм.\n", "\n", "- `-p ` или `--num-collection-passes `: число проходов по корпусу, по умолчанию N=1\n", "\n", "#### E-шаг\n", "\n", "На E-шаге оцениваются вектора $\\theta$\n", "- `--inner-iterations-count `: число итераций внутреннего цикла (оптимизация векторов theta)\n", "\n", "#### M-шаг\n", "\n", "На M-шаге производится обновление модели, в он-лайн алгоритме вес обновления берется из выражения $w = (\\tau_0 + \\text{update-count})^{-\\kappa}$, где параметр $\\text{update-count}$ равен числу обработанных батчей. Значения по-умолчанию для параметров обновления взяты из [статьи Хоффмана](https://www.cs.princeton.edu/~blei/papers/HoffmanBleiBach2010b.pdf).\n", "\n", "- `--update-every `: производить обновление модели каждые N батчей; если не указано, то используется офф-лайн алгоритм \n", "- `--tau0 `: параметр из выражения для веса обновления; по-умолчанию `tau0=1024`\n", "- `--kappa `: показатель степени в выражении для веса обновления; по-умолчанию `kappa=0.7`\n", "\n", "#### Модальности\n", "\n", "- `--use-modalities :,...,:`: использовать только указанные модальности, назначив им соответствующие веса; если опция не указана то используются все модальности с весом 1, у модальности может быть не указан вес — по-умолчанию считается равным 1\n", "\n", "Пример: `bigartm ... --use-modalities words,author:10,link:0.2` — будет обучена модель с модальностями `words` (вес 1.0), `author` (вес 10.0), `link` (вес 0.2).\n", "\n", "#### Регуляризаторы\n", "\n", "Резуляризаторы добавляются при помощи ключа, общий синтаксис которого:\n", "\n", "`--regularizer \" [#] [@] [!]\"`\n", "\n", "Кавычки обязательны: это два поля в массиве `argv` — ключ и его значение. Конструктор регуляризатора — название регуляризатора, которое может содержать параметры (если появятся регуляризаторы с параметрами). \n", "\n", "Регуляризатор `SparseSmooth(Phi/Theta)Regularizer` настоятельно предлагаю сделать двумя регуляризаторами, у которых веса действуют в разные (по знаку) стороны: `smoothPhi/sparsePhi`, `smoothTheta/sparseTheta`.\n", "\n", "Примеры:\n", "- `--regularizer \"0.1 smoothPhi\"`\n", "- `--regularizer \"25.0 sparseTheta\"`\n", "- `--regularizer \"10 decorrelation @words\"`\n", "- `--regularizer \"0.1 specific(x,y) #topic1,topic2 @words,author !dictionary\"`\n", "\n", "#### Функционалы качества\n", "\n", "Предустановленные наборы функционалов качества контролируются ключем ``--score-level ``.\n", "Возможны следующие варианты:\n", "- `--score-level 0` - функционалы качества не вычисляются\n", "- `--score-level 1` - на каждой итерации вычисляются и отображаются `Perplexity`, `ThetaSparsity` и `PhiSparsity`\n", "- `--score-level 2` - на последней итерации дополнительно выводятся функционалы `TopTokens` и `ThetaSnippet` \n", "- `--score-level 3` - на каждой итерации дополнительно выводятся функционалы группы `TopicKernel` (средний размер, чистота и контрастность тематических ядер)\n", "\n", "По умолчанию используется опция `--score-level 2`.\n", "\n", "Для более детельной настройки функционалов качества можно использовать ключи `--score` и `--final-score`, синтакс которых аналогичен ключу `--regularizer`:\n", "\n", "`--score \" [#] [@] [!]\"`\n", "\n", "`--final-score \" [#] [@] [!]\"`\n", "\n", "Функционалы качества, добавленные с помощью опции `--score`, будут отображаться после каждой итерации;\n", "функционалы качества, добавленные с помощью опции `--final-scores` --- лишь после последный итерации.\n", "\n", "Конструктор регуляризатора — название функционала качества, которое может содержать параметры. Например, в конструкторе `TopTokens` указывается желаемое количество слов каждой темы, в конструкторе `ThetaSnippet` — количество документов, в конструкторе `TopicKernel` — вещественный параметр `Probability Mass Threshold`.\n", "\n", "Использование любого из ключей `--score` или `--final-score` автоматически выключает все предустановленные функционалы качества (`--score-level 0`).\n", "\n", "Доступные типы функционалов качества: `Perplexity,SparsityTheta,SparsityPhi,TopTokens,ThetaSnippet,TopicKernel`.\n", "\n", "Примеры:\n", "- `--score \"Perplexity !dictionary\"`\n", "- `--score \"SparsityTheta #objective\"`\n", "- `--score \"SparsityPhi #background @words\"`\n", "- `--score \"TopTokens(7) @words \"`\n", "- `--score \"ThetaSnippet(7)\"`\n", "- `--score \"TopicKernel(0.2) #objective\"`\n", "\n", "#### Multicore Mode\n", "\n", "- `--threads `: число потоков в которых производить обучение, по умолчанию N=1\n", "\n", "#### Distributed Mode\n", "\n", "*Пока не нужно реализовывать.*" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 5. Output\n", "\n", "- `--save-model `: по окончанию обучения записать модель в файл\n", "- `--save-dictionary `: вывести словарь в файл\n", "- `--save-batches `: при первом чтении генерировать батчи и записывать по назначению; если не указано, то батчи пишутся во временный каталог, который удаляется перез завершением работы `bigartm`\n", "\n", "\n", "- `--write-predictions `: вывести тематические профили документов с последнего прохода по коллекции, в формате CSV. Возможность вывода в stdout!\n", "- `--write-model-readable `: по окончанию обучения записать модель в текстовый файл в формате CSV\n", "\n", "Ключам `--write-*` можно указывать значение `-` — это будет означать что писать нужно в stdout.\n", "\n", "#### Пояснение: принцип использования write/use/load\n", "\n", " - `--read` / `--write` призвано работать с некоторой потоковой информацией в текстовом формате, которую можно читать из stdin и записывать в stdout посредством специального значения `-` (минус)\n", " - `--use` / `--save` используется для работы со статичным объектом (словарь, набор батчей), который не изменяется в результате работы программы; статичный объект либо созается и потом сохраняется посредством `save`, либо он загружается из файла посредством `use`\n", " - `--load` / `--save` используется для объектов, которые меняются к концу выполнения программы; при помощи `load` мы загружаем такой объект, затем мы его меняем, сохраняем новую версию посредством `save`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Информационный вывод и логирование\n", "\n", "Информационный вывод должен производиться исключительно в stderr, поскольку в stdout может подаваться результат — тематические профили документов.\n", "\n", "#### Что выводить в stderr\n", "\n", "Пример вывода в stderr:\n", "```bash\n", "$ bigartm --read-corpus ... # (запуск команды)\n", "bigartm --read-corpus ... (исходная команда: склеенный полный argv[])\n", "\n", "Parsing corpus: -> (или tmp если не указано --save-batches), docs per batch\n", "Iter 1: batches=123 (сколько батчей обработали), update_weight=0.123 (какой вес был на этой итерации), perplexity=12312.123\n", "Iter 2: batches=246, update_weight=0.112, perplexity=9234.12\n", "...\n", "Iter 50: ...\n", "\n", "Topic snippet:\n", "\n", "```\n", "\n", "#### Идеи\n", "\n", "Что еще выводить в stderr:\n", "- число проходов\n", "- число обработанных документов\n", "- метрики качества\n", " - перплексия\n", " - разреженность по модальностям\n", "- способы подсчета метрик: hold-out / [progressive-validation](http://hunch.net/~jl/projects/prediction_bounds/thesis/mathml/thesisse44.xml) \n", "- логарифмический вывод (как в vw)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Форматы файлов" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Текстовые форматы\n", "\n", "#### Формат корпуса Vowpal Wabbit (`--read-vw-corpus`)\n", "\n", "#### Формат корпуса UCI Bag-of-Words (`--read-uci-docword`)\n", "\n", "#### Формат словаря UCI Bag-of-Words (`--read-uci-vocab`)\n", "\n", "#### Человекочитаемая модель (`--write-model-readable`)\n", "\n", "#### Предсказания (`--write-predictions`)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Бинарные форматы\n", "\n", "В бинарные файлы записыватюся protobuf-сообщения.\n", "\n", " - Модель\n", " - Словарь" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Примеры использования\n", "\n", "На этих примерах нужно протестировать новое CLI, а в конечном счете – сделать подробное описание этих примеров в документации.\n", "\n", "### 1. Эксперимент на датасетах UCI Bag-of-Words\n", "\n", "Предположим, что мы загрузили [данные с UCI](https://archive.ics.uci.edu/ml/datasets/Bag+of+Words) в каталог `data`.\n", "\n", "Обучение ванильной модели PLSA\n", "```bash\n", "bigartm \\\n", " --read-uci-docword data/docword.enron.txt \\\n", " --read-uci-vocab data/vocab.enron.txt \\\n", " --topics 50 \\\n", " --num-collection-passes 30 \\\n", " --save-model enron_50topics.model \\\n", " --write-predictions enron_50topics.theta.txt \\\n", " --write-model-readable enron_50topics.phi.txt \n", "```\n", "\n", "Инициализируем модель для корпуса `nytimes` несколькими итерациями без регуляризаторов, создадим 100 тем с префиксом `topic` (целевые темы) и 3 темы `noise` (шумовые):\n", "```bash\n", "bigartm \\\n", " --read-uci-docword data/docword.nytimes.txt \\\n", " --read-uci-vocab data/vocab.nytimes.txt \\\n", " --batch-size 1000 \\\n", " --topics \"topic:100,noise:3\" \\ # создает 103 темы: topic_0,topic_1,...,topic_99,noise_0,...,noise_2\n", " --num-collection-passes 5 \\\n", " --update-every 5 \\\n", " --save-model nytimes_100topics_3noise.init.model \\\n", " --save-batches nytimes.batches \\ # название каталога с батчами, который необходимо создать\n", " --save-dictionary nytimes.dict \\ # словарь в бинарном формате\n", " --threads 8\n", "```\n", "\n", "Продолжим обучение модели. Теперь включаем регуляризаторы; шумовые темы будут сглаживаться, а целевые — разреживаться и декоррелироваться:\n", "```bash\n", "bigartm \\\n", " --use-dictionary nytimes.dict \\\n", " --use-batches nytimes.batches \\\n", " --load-model nytimes_100topics_3noise.init.model \\\n", " --regularizer \"0.5 smoothPhi #noise\" \\\n", " --regularizer \"0.5 sparsePhi #topic\" \\\n", " --regularizer \"0.5 smoothTheta #noise\" \\\n", " --regularizer \"0.5 sparseTheta #topic\" \\\n", " --regularizer \"1000 decorrelation #topic\" \\\n", " --num-collection-passes 50 \\\n", " --update-every 3 # детальная настройка итераций\n", " --tau0 128 \\ \n", " --kappa 0.5 \\\n", " --save-model nytimes_100topics_3noise.model \\\n", " --write-predictions nytimes_100topics_3noise.theta.txt \\\n", " --write-model-readable nytimes_100topics_3noise.phi.txt \\\n", " --threads 32\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 2. Обучение модели мультиязычной Википедии и использование для разметки документов\n", "\n", "По корпусу статей Википедии построим многоязычную тематическую модель, которую затем сможем использовать для категоризации произвольных страниц.\n", "\n", "Для обучения тематической модели был подготовлен мультиязычный корпуc в построчном формате vw, его положили в партицированном виде в HDFS (как результат работы MapReduce задачи, к примеру):\n", "```bash\n", "hdfs -cat wikipedia_corpus/part_00001\n", "\n", " page_2342123 |en computer:2 device:3 mouse input |ru мышь:2 устройство компьютер |es ratón dispositivo:3 computadora:2\n", " page_5645623 |en crusade:4 heretics:2 jerusalem |fr croisades:3 hérétique:2\n", " ...\n", "```\n", "\n", "Инициализируем модель и словарь, корпус подается на вход через stdin:\n", "```bash\n", "hdfs -cat wikipedia_corpus/\\* | bigartm \\\n", " --dictionary-min-df 3 \\ # брать слово если оно нашлось не менее чем в 3х документах\n", " --dictionary-max-df 30% \\ # ... не более чем в 30% документов\n", " --read-vw-corpus - \\ # минус значит что читать из stdin\n", " --topics topic:1000 \\\n", " --use-modalities en,ru,fr,es,de,it \\\n", " --save-batches wikipedia.batches \\\n", " --save-dictionary wikipedia.dict \\\n", " --save-model wikipedia_1k_topics.initial.model\n", "```\n", "\n", "Теперь обучим хорошую модель, параллельно:\n", "```bash\n", "bigartm \\\n", " --use-batches wikipedia.batches \\\n", " --load-model wikipedia_1k_topics.initial.model \\\n", " --num-collection-passes 100 \\\n", " --regularizer \"0.5 sparsePhi #topic\" \\\n", " --kappa 0.8 \\\n", " --write-model wikipedia_1k_topics.model \\\n", " --write-model-readable wikipedia_1k_topics.phi.txt \\\n", " --threads 32\n", "```\n", "\n", "Ура, теперь можем использовать модель для разметки документов по темам:\n", "```bash\n", "echo \"new_document |ru пхнглуи мглвнафх рльех вгахнагл фхтагн ктулху\" | bigartm \\\n", " --load-model wikipedia_1k_topics.model \\\n", " --read-vw-corpus - \\ # прочитать корпус из stdin \n", " --write-predictions - # записать предсказания в stdout\n", " \n", " new_document 0 0 0 0.3 0 0 0 ... 0 0.1 0\n", "```\n", "В таком виде BigARTM можно использовать для разметки произвольно большого набора документов при помощи MapReduce." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 3. Позиционирование CLI и Python API\n", "\n", " - Командный интерфейс удобен для того чтобы запускать обучение. \n", " - Python API удобно для того чтобы работать с обученной моделью: посмотреть, повизуализировать, дообучить с хитрой траекторией регуляризаторов." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Пакетирование\n", "\n", "### Пакет для Debian\n", "\n", "В идеале BigARTM пользователь должен не собирать из исходников, а устанавливать вот таким образом:\n", "`apt-get install bigartm`\n", "\n", "Что нужно при этом установить:\n", "- SO: `/usr/lib/bigartm.so`\n", "- CLI: `/usr/bin/bigartm`\n", "- Python-пакет: `/usr/lib/python2.7/site-packages`\n", "\n", "[Руководство по созданию deb-пакетов](http://ubuntuforums.org/showthread.php?t=910717)" ] }, { "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.12" } }, "nbformat": 4, "nbformat_minor": 0 }