Извлечение функций Vowpal Wabbit

Я запутался в том, как vw извлекает функции. Рассмотрим задачу классификации текста, в которой я хочу использовать символьные ngrams в качестве признаков. В простейшем случае, который иллюстрирует мой вопрос, входная строка «аа», и я использую только 1-граммовые функции. Таким образом, пример должен состоять из одной функции «a», которая имеет количество 2, как показано ниже:

$ echo "1 |X a:2" | vw --noconstant --invert_hash f && grep '^X^' f
Num weight bits = 18
learning rate = 0.5
initial_t = 0
power_t = 0.5
using no cache
Reading datafile = 
num sources = 1
average    since         example     example  current  current  current
loss       last          counter      weight    label  predict features
1.000000   1.000000            1         1.0   1.0000   0.0000        1

finished run
number of examples per pass = 1
passes used = 1
weighted example sum = 1
weighted label sum = 1
average loss = 1
best constant = 1
total feature number = 1
X^a:108118:0.196698

Однако, если я передам строку символов «аа» в vw (введя пробелы между символами), vw сообщит о двух функциях:

$ echo "1 |X a a" | vw --noconstant --invert_hash f && grep '^X^' f
Num weight bits = 18
learning rate = 0.5
initial_t = 0
power_t = 0.5
using no cache
Reading datafile = 
num sources = 1
average    since         example     example  current  current  current
loss       last          counter      weight    label  predict features
1.000000   1.000000            1         1.0   1.0000   0.0000        2

finished run
number of examples per pass = 1
passes used = 1
weighted example sum = 1
weighted label sum = 1
average loss = 1
best constant = 1
total feature number = 2
X^a:108118:0.375311

Фактическая модель содержит только одну функцию (как и следовало ожидать), но ее вес (0,375311) отличается от первой модели (0,196698).

При обучении на реальных наборах данных с n-граммами более высокого порядка можно наблюдать существенные различия в средних потерях в зависимости от того, какой формат ввода используется. Я просмотрел исходный код в parser.cc и, если бы у меня было больше времени, я, вероятно, смог бы понять, что происходит; но если бы кто-нибудь мог объяснить несоответствие между двумя вышеприведенными случаями (это ошибка?) и/или указать мне на соответствующие части источника, я был бы признателен за помощь.


person Ken    schedule 13.10.2014    source источник


Ответы (1)


Я полагаю, что значение общего числа признаков - это просто счетчик наблюдаемых признаков. Например, вы получите 10 за следующую команду:

$ echo "1 |X a" | vw --noconstant --passes 10 --cache_file f -k

Я также видел в коде vw, который делит значение регрессора функции на вес функции перед распечаткой. Это видно из следующего:

$ echo "1 |X a:1" | vw --noconstant --invert_hash f && grep '^X^' f
X^a:108118:0.393395
$ echo "1 |X a:2" | vw --noconstant --invert_hash f && grep '^X^' f
X^a:108118:0.196698
$ echo "1 |X a:3" | vw --noconstant --invert_hash f && grep '^X^' f
X^a:108118:0.131132
$ echo "1 |X a:10" | vw --noconstant --invert_hash f && grep '^X^' f
X^a:108118:0.039344

Я подозреваю, что функции являются эксклюзивными, и такие примеры, как «|X a» и «| X a», дадут одинаковый результат, но это не так:

$ echo "1 |X a" | vw --noconstant --invert_hash f && grep '^X^' f
X^a:108118:0.393395
$ echo "1 |X a a" | vw --noconstant --invert_hash f && grep '^X^' f
X^a:108118:0.375311
$ echo "1 |X a a" | vw --noconstant --invert_hash f && grep '^X^' f
X^a:108118:0.366083

Я действительно не знаю, почему. В этом должна быть логика. Но это работает, как и ожидалось (мной), если вы укажете --sort_features

$ echo "1 |X a" | vw --noconstant --invert_hash f && grep '^X^' f
X^a:108118:0.393395
echo "1 |X a a a a a" | vw --noconstant --invert_hash f --sort_features && grep '^X^' f
X^a:108118:0.393395

Интересен тот факт, что если вы укажете --sort_features, vw использует только первое вхождение свойства. Пример:

$ echo "1 |X a a:10" | vw --noconstant --invert_hash f --sort_features && grep '^X^' f
X^a:108118:0.393395
$ echo "1 |X a a:2" | vw --noconstant --invert_hash f --sort_features && grep '^X^' f
X^a:108118:0.393395
$ echo "1 |X a:10 a" | vw --noconstant --invert_hash f --sort_features && grep '^X^' f
X^a:108118:0.039344

Я надеюсь, что с помощью этих наблюдений вы сможете заставить vw работать так, как вам нужно. Но я не уверен, это баг или фича. Перешлю vw авторам комментарии.

person truf    schedule 17.10.2014
comment
Я не использовал --sort_features раньше и не ожидал, что это приведет к поведению в ваших примерах. В записи справки говорится, что включите это, чтобы игнорировать порядок, в котором были определены функции. Это приведет к уменьшению размера кэша. Но почему в первую очередь важен порядок, в котором определяются признаки? Может быть, это ключ к моему первоначальному вопросу. - person Ken; 20.10.2014
comment
Я понятия не имею. Я поднял этот вопрос на официальной странице github.com/JohnLangford/vowpal_wabbit/issues/425 - person truf; 21.10.2014
comment
Если вы не отслеживаете дискуссию с автором - его ответ: это, по сути, вычислительная проблема. Мы могли бы попытаться объединить все функции в уникальный набор или оставить дубликаты в системе. Выполнение второго, кажется, на самом деле быстрее, потому что большинство наборов функций не имеют коллизий внутри примера. - person truf; 07.11.2014
comment
Спасибо. Я чувствую, что это должно быть упомянуто в документации, поэтому я присоединюсь к разговору на официальной странице. - person Ken; 09.11.2014