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

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