Почему Spark Word2Vec возвращает вектор? - PullRequest
0 голосов
/ 13 ноября 2018

Запустив пример Spark для Word2Vec , я понял, что он принимает массив строк и выдает вектор.Мой вопрос, не должен ли он вернуть матрицу вместо вектора?Я ожидал один вектор на входное слово.Но он возвращает один векторный период!

Или, возможно, он должен был принять строку вместо массива строк (одно слово) в качестве входных данных.Тогда, да, конечно, он может вернуть один вектор в качестве вывода.Но принимать массив строк и возвращать один-единственный вектор для меня не имеет смысла.

[ОБНОВЛЕНИЕ]

По запросу @ Shaido, вот код с моим второстепеннымизмените, чтобы напечатать схему для вывода:

public class JavaWord2VecExample {
    public static void main(String[] args) {
        SparkSession spark = SparkSession
                .builder()
                .appName("JavaWord2VecExample")
                .getOrCreate();

        // $example on$
        // Input data: Each row is a bag of words from a sentence or document.
        List<Row> data = Arrays.asList(
                RowFactory.create(Arrays.asList("Hi I heard about Spark".split(" "))),
                RowFactory.create(Arrays.asList("I wish Java could use case classes".split(" "))),
                RowFactory.create(Arrays.asList("Logistic regression models are neat".split(" ")))
        );
        StructType schema = new StructType(new StructField[]{
                new StructField("text", new ArrayType(DataTypes.StringType, true), false, Metadata.empty())
        });
        Dataset<Row> documentDF = spark.createDataFrame(data, schema);

        // Learn a mapping from words to Vectors.
        Word2Vec word2Vec = new Word2Vec()
                .setInputCol("text")
                .setOutputCol("result")
                .setVectorSize(7)
                .setMinCount(0);

        Word2VecModel model = word2Vec.fit(documentDF);
        Dataset<Row> result = model.transform(documentDF);

        for (Row row : result.collectAsList()) {
            List<String> text = row.getList(0);
            System.out.println("Schema: " + row.schema());
            Vector vector = (Vector) row.get(1);
            System.out.println("Text: " + text + " => \nVector: " + vector + "\n");
        }
        // $example off$

        spark.stop();
    }
}

И это напечатает:

Schema: StructType(StructField(text,ArrayType(StringType,true),false), StructField(result,org.apache.spark.ml.linalg.VectorUDT@3bfc3ba7,true))
Text: [Hi, I, heard, about, Spark] => 
Vector: [-0.0033279924420639875,-0.0024428479373455048,0.01406305879354477,0.030621735751628878,0.00792500376701355,0.02839711122214794,-0.02286271695047617]

Schema: StructType(StructField(text,ArrayType(StringType,true),false), StructField(result,org.apache.spark.ml.linalg.VectorUDT@3bfc3ba7,true))
Text: [I, wish, Java, could, use, case, classes] => 
Vector: [-9.96453288410391E-4,-0.013741840076233658,0.013064394239336252,-0.01155538750546319,-0.010510949650779366,0.004538436819400106,-0.0036846946126648356]

Schema: StructType(StructField(text,ArrayType(StringType,true),false), StructField(result,org.apache.spark.ml.linalg.VectorUDT@3bfc3ba7,true))
Text: [Logistic, regression, models, are, neat] => 
Vector: [0.012510885251685977,-0.014472834207117558,0.002779599279165268,0.0022389178164303304,0.012743516173213721,-0.02409198731184006,0.017409833287820222]

Пожалуйста, исправьте меня, если я ошибаюсь, но вход представляет собой массив строк ивывод представляет собой один вектор.И я ожидал, что каждое слово будет отображено в векторе.

Ответы [ 2 ]

0 голосов
/ 29 ноября 2018

Это попытка обосновать обоснование Spark здесь, и его следует читать как дополнение к хорошему программированию объяснению, уже предоставленному в качестве ответа ...

Для началас тем, как именно должны быть объединены отдельные вложения слов, в принципе не является особенностью самой модели Word2Vec (которая, в общем-то, отдельные слова), но является проблемой, касающейся моделей "более высокого порядка",такие как Sentence2Vec , Paragraph2Vec, Doc2Vec , Wikipedia2Vec и т. д. (я думаю, вы могли бы назвать еще несколько, я думаю ...).

Имеясказал, что, действительно, оказывается, что самый первый подход к объединению векторов слов для получения векторных представлений больших фрагментов текста (фраз, предложений, твитов и т. д.) действительно заключается в простом усреднении векторных представлений составляющих слов, как SparkML делает.

Исходя из сообщества практикующих, мы имеем:

Как объединить векторы слов для формирования вектора предложений (ответ SO):

Существует как минимум три распространенных способа объединения векторов встраивания;(а) суммирование, (б) суммирование и усреднение или (в) объединение.[...] См. gensim.models.doc2vec.Doc2Vec, dm_concat и dm_mean - он позволяет использовать любой из этих трех вариантов

Sentence2Vec: Оценка популярных теорий - Часть I (Простое среднее векторов слов) (запись в блоге):

Итак, что первое, что приходит вам в голову, когда у вас есть векторы слов и вам нужно вычислить вектор предложения.

Просто усредните их?

Да, именно это мы и собираемся сделать здесь.enter image description here

Sentence2Vec (Github repo):

Word2Vec может помочь найти другие слова с похожим семантическим значением,Однако Word2Vec может занимать только 1 слово каждый раз, в то время как предложение состоит из нескольких слов.Чтобы решить эту проблему, я пишу Sentence2Vec, который на самом деле является оберткой для Word2Vec.Чтобы получить вектор предложения, я просто получаю усредненную векторную сумму каждого слова в предложении.

Очевидно, что, по крайней мере для практиков, это простое усреднение отдельных векторов словдалеко не неожиданно.

Ожидаемый контраргумент здесь заключается в том, что сообщения в блогах и ответы SO, возможно, не , что заслуживающие доверия источники;А как насчет исследователей и соответствующей научной литературы ?Что ж, получается, что это простое усреднение здесь тоже не редкость:

С Распределенные представления предложений и документов (Le & Mikolov, Google, ICML 2014):

enter image description here

Начиная с NILC-USP на SemEval-2017 Задание 4: Многоуровневый ансамбль для анализа настроений в Twitter (SemEval 2017, раздел 2.1.2):

enter image description here


К настоящему времени должно быть ясно, что конкретный выбор дизайна в Spark ML отнюдь не случаен или даже необычен;Я писал в блоге о том, что определенно выглядит как absurd выбор дизайна в Spark ML (см. Классификация в Spark 2.0: «Проверка ввода не удалась» и другие удивительные истории ), но кажется, что этоне такой случай ...

0 голосов
/ 13 ноября 2018

Чтобы увидеть вектор, соответствующий каждому слову, вы можете запустить model.getVectors.Для кадра данных в вопросе (с векторным размером 3 вместо 7) это дает:

+----------+-----------------------------------------------------------------+
|word      |vector                                                           |
+----------+-----------------------------------------------------------------+
|heard     |[0.14950960874557495,-0.11237259954214096,-0.03993036597967148]  |
|are       |[-0.16390761733055115,-0.14509087800979614,0.11349033564329147]  |
|neat      |[0.13949351012706757,0.08127426356077194,0.15970033407211304]    |
|classes   |[0.03703496977686882,0.05841822177171707,-0.02267565205693245]   |
|I         |[-0.018915412947535515,-0.13099457323551178,0.14300788938999176] |
|regression|[0.1529865264892578,0.060659825801849365,0.07735282927751541]    |
|Logistic  |[-0.12702016532421112,0.09839040040969849,-0.10370948910713196]  |
|Spark     |[-0.053579315543174744,0.14673036336898804,-0.002033260650932789]|
|could     |[0.12216471135616302,-0.031169598922133446,-0.1427609771490097]  |
|use       |[0.08246973901987076,0.002503493567928672,-0.0796264186501503]   |
|Hi        |[0.16548289358615875,0.06477408856153488,0.09229831397533417]    |
|models    |[-0.05683165416121483,0.009706663899123669,-0.033789146691560745]|
|case      |[0.11626788973808289,0.10363516956567764,-0.07028932124376297]   |
|about     |[-0.1500445008277893,-0.049380943179130554,0.03307584300637245]  |
|Java      |[-0.04074851796030998,0.02809843420982361,-0.16281810402870178]  |
|wish      |[0.11882393807172775,0.13347993791103363,0.14399205148220062]    |
+----------+-----------------------------------------------------------------+

Таким образом, каждое слово имеет свое представление.Однако при вводе предложения (массива строк) в модель происходит то, что все векторы слов в предложении усредняются вместе.

Из реализации github :

/**
  * Transform a sentence column to a vector column to represent the whole sentence. The transform
  * is performed by averaging all word vectors it contains.
  */
 @Since("2.0.0")
 override def transform(dataset: Dataset[_]): DataFrame = {
 ...

Это легко подтвердить, например:

Text: [Logistic, regression, models, are, neat] => 
Vector: [-0.011055880039930344,0.020988055132329465,0.042608972638845444]

Первый элемент вычисляется путем взятия среднего значения первого элемента векторовпять вовлеченных слов

(-0.12702016532421112 + 0.1529865264892578 -0.05683165416121483 -0.16390761733055115 + 0.13949351012706757) / 5

, что равно -0.011055880039930344.

...