web-dev-qa-db-fra.com

Convertir le fichier bin Word2vec en texte

À partir du Word2vec site, je peux télécharger GoogleNews-vectors-negative300.bin.gz. Le fichier .bin (environ 3,4 Go) est un format binaire qui ne m’est pas utile. Tomas Mikolov nous assure que "Il devrait être assez simple de convertir le format binaire au format texte (bien que cela prenne plus de place sur le disque). Vérifiez le code dans l'outil de distance, il est plutôt trivial de lire le fichier binaire. " Malheureusement, je ne connais pas suffisamment C pour comprendre http://Word2vec.googlecode.com/svn/trunk/distance.c .

Soi-disant gensim peut le faire aussi, mais tous les tutoriels que j'ai trouvés semblent concerner la conversion de texte from, et non l'inverse.

Quelqu'un peut-il suggérer des modifications au code C ou des instructions pour que le gensim émette un texte?

54
Glenn

Sur la liste de diffusion Word2vec-toolkit, Thomas Mensink a fourni un answer sous la forme d'un petit programme en C qui convertira un fichier .bin en texte. Ceci est une modification du fichier distance.c. J'ai remplacé la distance d'origine.c par le code de Thomas ci-dessous et j'ai reconstruit Word2vec (make clean; make), puis renommé la distance compilée en readbin. Ensuite, ./readbin vector.bin créera une version texte de vector.bin.

//  Copyright 2013 Google Inc. All Rights Reserved.
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//      http://www.Apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.

#include <stdio.h>
#include <string.h>
#include <math.h>
#include <malloc.h>

const long long max_size = 2000;         // max length of strings
const long long N = 40;                  // number of closest words that will be shown
const long long max_w = 50;              // max length of vocabulary entries

int main(int argc, char **argv) {
  FILE *f;
  char file_name[max_size];
  float len;
  long long words, size, a, b;
  char ch;
  float *M;
  char *vocab;
  if (argc < 2) {
    printf("Usage: ./distance <FILE>\nwhere FILE contains Word projections in the BINARY FORMAT\n");
    return 0;
  }
  strcpy(file_name, argv[1]);
  f = fopen(file_name, "rb");
  if (f == NULL) {
    printf("Input file not found\n");
    return -1;
  }
  fscanf(f, "%lld", &words);
  fscanf(f, "%lld", &size);
  vocab = (char *)malloc((long long)words * max_w * sizeof(char));
  M = (float *)malloc((long long)words * (long long)size * sizeof(float));
  if (M == NULL) {
    printf("Cannot allocate memory: %lld MB    %lld  %lld\n", (long long)words * size * sizeof(float) / 1048576, words, size);
    return -1;
  }
  for (b = 0; b < words; b++) {
    fscanf(f, "%s%c", &vocab[b * max_w], &ch);
    for (a = 0; a < size; a++) fread(&M[a + b * size], sizeof(float), 1, f);
    len = 0;
    for (a = 0; a < size; a++) len += M[a + b * size] * M[a + b * size];
    len = sqrt(len);
    for (a = 0; a < size; a++) M[a + b * size] /= len;
  }
  fclose(f);
  //Code added by Thomas Mensink
  //output the vectors of the binary format in text
  printf("%lld %lld #File: %s\n",words,size,file_name);
  for (a = 0; a < words; a++){
    printf("%s ",&vocab[a * max_w]);
    for (b = 0; b< size; b++){ printf("%f ",M[a*size + b]); }
    printf("\b\b\n");
  }  

  return 0;
}

J'ai supprimé le "\ b\b" de la printf

En passant, le fichier texte résultant contenait toujours le texte Word et des espaces inutiles que je ne souhaitais pas pour certains calculs numériques. J'ai supprimé la colonne de texte initiale et le blanc de fin de chaque ligne avec les commandes bash.

cut --complement -d ' ' -f 1 GoogleNews-vectors-negative300.txt > GoogleNews-vectors-negative300_tuples-only.txt
sed 's/ $//' GoogleNews-vectors-negative300_tuples-only.txt
17
Glenn

J'utilise ce code pour charger un modèle binaire, puis enregistre le modèle dans un fichier texte, 

from gensim.models.keyedvectors import KeyedVectors

model = KeyedVectors.load_Word2vec_format('path/to/GoogleNews-vectors-negative300.bin', binary=True)
model.save_Word2vec_format('path/to/GoogleNews-vectors-negative300.txt', binary=False)

Références: API et nullege

Remarque: 

Le code ci-dessus concerne la version new de gensim. Pour la version précédente, j'ai utilisé ce code

from gensim.models import Word2vec

model = Word2vec.Word2Vec.load_Word2vec_format('path/to/GoogleNews-vectors-negative300.bin', binary=True)
model.save_Word2vec_format('path/to/GoogleNews-vectors-negative300.txt', binary=False)
66
silo

le format est le format à virgule flottante binaire simple précision IEEE 754: binary32 http://en.wikipedia.org/wiki/Single-precision_floating-point_format Ils utilisent le petit-endian.

Prenons un exemple:

  • La première ligne est le format de chaîne: "3000000 300\n" (vocabSize & VecSize, getByte till byte == '\ n') 
  • La ligne suivante inclut le vocabulaire Word d’abord, puis (300 * 4 octets de valeur flottante, 4 octets pour chaque dimension ):

    getByte till byte==32 (space). (60 47 115 62 32 => <\s>[space])
    
  • alors chacun des 4 octets suivants représentera un nombre flottant

    octet suivant: 0 0 -108 58 => 0.001129150390625.

Vous pouvez vérifier le lien wikipedia pour voir comment, laissez-moi faire celui-ci à titre d'exemple:

(little-endian -> ordre inverse) 00111010 10010100 00000000 00000000

  • le premier est le bit de signe => signe = 1 (sinon = -1)
  • 8 bits suivants => 117 => exp = 2 ^ (117-127) 
  • 23 bits suivants => pre = 0 * 2 ^ (- 1) + 0 * 2 ^ (- 2) + 1 * 2 ^ (- 3) + 1 * 2 ^ (- 5)

valeur = signe * exp * pre

7
dbao50

Vous pouvez charger le fichier binaire dans Word2vec, puis enregistrer la version texte comme ceci: 

from gensim.models import Word2vec
 model = Word2vec.Word2Vec.load_Word2vec_format('Path/to/GoogleNews-vectors-negative300.bin', binary=True)
 model.save("file.txt")

`

5
batgirl

J'utilise gensim pour travailler avec GoogleNews-vectors-negative300.bin et j'inclus un indicateur binary = True lors du chargement du modèle.

from gensim import Word2vec

model = Word2vec.Word2Vec.load_Word2vec_format('Path/to/GoogleNews-vectors-negative300.bin', binary=True) 

Semble fonctionner bien.

4
zaytsev

J'ai eu un problème similaire, je voulais obtenir la sortie des modèles bin/non-bin (gensim) au format CSV.

voici le code qui fait ça sur python, cela suppose que vous avez installé le gensim:

https://Gist.github.com/dav009/10a742de43246210f3ba

2
David Przybilla

convertvec est un petit outil permettant de convertir des vecteurs entre différents formats de la bibliothèque Word2vec.

Convertir des vecteurs de texte binaire en texte brut:

./convertvec bin2txt input.bin output.txt

Convertir des vecteurs du texte brut en binaire:

./convertvec txt2bin input.txt output.bin

2
Hamed Ganji

Si vous obtenez l'erreur:

ImportError: No module named models.Word2vec

c'est parce qu'il y a eu une mise à jour de l'API. Cela fonctionnera:

from gensim.models.keyedvectors import KeyedVectors

model = KeyedVectors.load_Word2vec_format('./GoogleNews-vectors-negative300.bin', binary=True)
model.save_Word2vec_format('./GoogleNews-vectors-negative300.txt', binary=False)
1
Raphael Schumann

Voici le code que j'utilise:

import codecs
from gensim.models import Word2Vec

def main():
    path_to_model = 'GoogleNews-vectors-negative300.bin'
    output_file = 'GoogleNews-vectors-negative300_test.txt'
    export_to_file(path_to_model, output_file)


def export_to_file(path_to_model, output_file):
    output = codecs.open(output_file, 'w' , 'utf-8')
    model = Word2Vec.load_Word2vec_format(path_to_model, binary=True)
    print('done loading Word2Vec')
    vocab = model.vocab
    for mid in vocab:
        #print(model[mid])
        #print(mid)
        vector = list()
        for dimension in model[mid]:
            vector.append(str(dimension))
        #line = { "mid": mid, "vector": vector  }
        vector_str = ",".join(vector)
        line = mid + "\t"  + vector_str
        #line = json.dumps(line)
        output.write(line + "\n")
    output.close()

if __== "__main__":
    main()
    #cProfile.run('main()') # if you want to do some profiling
1
Franck Dernoncourt

Juste une mise à jour rapide car il existe maintenant un moyen plus simple.

Si vous utilisez Word2vec from https://github.com/dav/Word2vec il existe une option supplémentaire appelée -binary qui accepte 1 pour générer un fichier binaire ou 0 pour générer un fichier texte. Cet exemple provient de demo-Word.sh dans le référentiel:

time ./Word2vec -train text8 -output vectors.bin -cbow 1 -size 200 -window 8 -negative 25 -hs 0 -sample 1e-4 -threads 20 -binary 0 -iter 15

0
Yohanes Gultom