apache-spark machine-learning apache-spark-mllib word2vec

apache spark - Spark Word2vec vector mathics



apache-spark machine-learning (3)

Estaba viendo el ejemplo del sitio Spark para Word2Vec:

val input = sc.textFile("text8").map(line => line.split(" ").toSeq) val word2vec = new Word2Vec() val model = word2vec.fit(input) val synonyms = model.findSynonyms("country name here", 40)

¿Cómo hago el vector interesante como rey - hombre + mujer = reina. Puedo usar model.getVectors, pero no estoy seguro de cómo proceder.


Aquí está el pseudo código. Para la implementación completa, lea la documentación: https://spark.apache.org/docs/1.4.0/api/java/org/apache/spark/mllib/feature/Word2VecModel.html

  1. w2v_map = model.getVectors() # this gives ua map {word:vec}
  2. my_vector = w2v_map.get(''king'') - w2v_map.get(''man'') + w2v_map.get(''queen'') # do vector algebra here
  3. most_similar_word_to_vector = model.findSynonyms(my_vector, 10) # they have an api to get synonyms for word, and one for vector

edit: https://spark.apache.org/docs/1.4.0/api/java/org/apache/spark/mllib/feature/Word2VecModel.html#findSynonyms(org.apache.spark.mllib.linalg.Vector, % 20int)


Aquí hay un ejemplo en pyspark , que creo que es fácil de portar a Scala: la clave es el uso de model.transform .

Primero, entrenamos el modelo como en el ejemplo:

from pyspark import SparkContext from pyspark.mllib.feature import Word2Vec sc = SparkContext() inp = sc.textFile("text8_lines").map(lambda row: row.split(" ")) k = 220 # vector dimensionality word2vec = Word2Vec().setVectorSize(k) model = word2vec.fit(inp)

k es la dimensionalidad de los vectores de palabras: cuanto más alto mejor (valor predeterminado es 100), pero necesitará memoria, y el número más alto que pude obtener con mi máquina fue 220. ( EDITAR: los valores típicos en las publicaciones relevantes se encuentran entre 300 y 1000)

Después de haber entrenado el modelo, podemos definir una función simple de la siguiente manera:

def getAnalogy(s, model): qry = model.transform(s[0]) - model.transform(s[1]) - model.transform(s[2]) res = model.findSynonyms((-1)*qry,5) # return 5 "synonyms" res = [x[0] for x in res] for k in range(0,3): if s[k] in res: res.remove(s[k]) return res[0]

Ahora, aquí hay algunos ejemplos con países y sus capitales:

s = (''france'', ''paris'', ''portugal'') getAnalogy(s, model) # u''lisbon'' s = (''china'', ''beijing'', ''russia'') getAnalogy(s, model) # u''moscow'' s = (''spain'', ''madrid'', ''greece'') getAnalogy(s, model) # u''athens'' s = (''germany'', ''berlin'', ''portugal'') getAnalogy(s, model) # u''lisbon'' s = (''japan'', ''tokyo'', ''sweden'') getAnalogy(s, model) # u''stockholm'' s = (''finland'', ''helsinki'', ''iran'') getAnalogy(s, model) # u''tehran'' s = (''egypt'', ''cairo'', ''finland'') getAnalogy(s, model) # u''helsinki''

Los resultados no siempre son correctos. Te dejo experimentar, pero mejoran con más datos de entrenamiento y una mayor dimensionalidad del vector k .

El bucle for de la función elimina entradas que pertenecen a la consulta de entrada en sí, ya que noté que con frecuencia la respuesta correcta era la segunda en la lista devuelta, siendo el primero uno de los términos de entrada.


val w2v_map = sameModel.getVectors // esto le da a ua map {word: vec}

val (king, man, woman) = (w2v_map.get("king").get, w2v_map.get("man").get, w2v_map.get("women").get) val n = king.length //daxpy(n: Int, da: Double, dx: Array[Double], incx: Int, dy: Array[Double], incy: Int); blas.saxpy(n,-1,man,1,king,1) blas.saxpy(n,1,woman,1,king,1) val vec = new DenseVector(king.map(_.toDouble)) val most_similar_word_to_vector = sameModel.findSynonyms(vec, 10) //they have an api to get synonyms for word, and one for vector for((synonym, cosineSimilarity) <- most_similar_word_to_vector) { println(s"$synonym $cosineSimilarity") }

y el resultado de la ejecución como golpe:

mujeres 0.628454885964967 philip 0.5539534290356802 henry 0.5520055707837214 vii 0.5455116413024774 elizabeth 0.5290994886254643 reina 0.5162519562606844 hombres 0.5133851770249461 wenceslaus 0.512430255995107 viii 0.5104392579985102 más antigua 0.510425791249559