机器学习之第二部分:词向量 博客分类: 机器学习
程序员文章站
2024-03-22 10:46:40
...
第二部分:词向量
Code
第2部分的教程代码住在这里。
引入分布式词向量
这部分的教程将重点关注使用分布式Word2Vec创建的词向量算法。(深度学习的概述,以及一些额外的指针教程,看到“深度学习是什么?”页面)。
第2部分和第3部分比第1部分承担更多熟悉Python。我们开发了下面的代码在一个双核Macbook Pro,然而,我们还没有成功地在Windows上运行代码。如果你是一个Windows用户,你让它工作,请注意如何在论坛!更多细节,请参见“系统设置”页面。
Word2vec,谷歌于2013年出版,是一个学习的神经网络实现分布式表示单词。其他深或复发性神经网络架构提出了学习单词表示在此之前,但是这些主要问题是需要长时间训练模型。相对于其他模型Word2vec训练很快。
Word2Vec不需要标签为了创建有意义的陈述。这是非常有用的,因为在现实世界中大多数数据标记。如果网络是给予足够的训练数据(数百亿的话),它产生有趣的特色词向量。词的意思出现在集群和集群间距为这样一些词的关系,如类比,可以复制使用向量的数学。著名的例子是,训练有素的词向量,“国王-男+女=王后。”
看看Google的代码,那样,以及随之而来的论文。本课程也有帮助。原来的代码是在C语言中,但是它已经被移植到其他语言,包括Python。我们鼓励你玩原来的C工具,但警告说,它不是用户友好的开始,如果你是一个程序员(我们不得不手动编辑编译它的头文件)。
最近的工作的斯坦福大学也应用深度学习句子分析;他们的代码在Java中是可用的。然而,他们的方法,这依赖于句子解析,不能应用于一个简单的段落任意长度的方法。
分布式词向量是强大的,可用于许多应用程序,尤其是单词预测和翻译。在这里,我们将努力将它们应用于文本分析。
在Python中使用word2vec
在Python中,我们将使用优秀的实现word2vec实现包 gensim。如果你不已经安装了gensim,您将需要安装它。有一个很好的教程指导Python Word2Vec实现,在这里。
尽管Word2Vec不需要图形处理单元(gpu)和许多学习算法,它是计算密集型的。谷歌的版本和Python版本依赖多线程(并行运行多个进程在你的电脑上节省时间)。ln来训练你的模型在合理的时间内,您将需要安装cython(指令)。没有cython Word2Vec将运行安装,但需要几天跑而不是分钟。
准备训练模型
现在说清楚讲明白!首先,我们从pandas读到数据,正如我们在第1部分中所做的一样。在第1部分,我们现在使用unlabeledTrain.tsv,其中包含50000额外的评论没有标签。当我们建立了袋单词模型在第1部分中,额外的标记训练评论并不有用。然而,由于Word2Vec可以从无标号数据,现在可以使用这些额外的50000条评论。
import pandas as pd # Read data from files train = pd.read_csv( "labeledTrainData.tsv", header=0, delimiter="\t", quoting=3 ) test = pd.read_csv( "testData.tsv", header=0, delimiter="\t", quoting=3 ) unlabeled_train = pd.read_csv( "unlabeledTrainData.tsv", header=0, delimiter="\t", quoting=3 ) # Verify the number of reviews that were read (100,000 in total) print "Read %d labeled train reviews, %d labeled test reviews, " \ "and %d unlabeled reviews\n" % (train["review"].size, test["review"].size, unlabeled_train["review"].size ) |
我们写的清理data函数和part1部分类似,虽然现在有一些差异。首先,训练Word2Vec最好不要删除停止词因为算法依赖于更广泛的上下文句子为了生产高品质的词向量。出于这个原因,我们将停止词删除下面的功能可选。它还可能最好不要删除数据,但是我们离开它留给读者作为练习。
# Import various modules for string cleaning from bs4 import BeautifulSoup import re from nltk.corpus import stopwords def review_to_wordlist( review, remove_stopwords=False ): # Function to convert a document to a sequence of words, # optionally removing stop words. Returns a list of words. # # 1. Remove HTML review_text = BeautifulSoup(review).get_text() # # 2. Remove non-letters review_text = re.sub("[^a-zA-Z]"," ", review_text) # # 3. Convert words to lower case and split them words = review_text.lower().split() # # 4. Optionally remove stop words (false by default) if remove_stopwords: stops = set(stopwords.words("english")) words = [w for w in words if not w in stops] # # 5. Return a list of words return(words) |
接下来,我们想要一个特定的输入格式。Word2Vec预计单个的句子,每一个单词列表。换句话说,输入格式列表的列表。
它不是简单的如何一个段落分割成句子。有各种各样的陷阱在自然语言。英语句子结尾”吗?”、“!“”、“”.“。”,除此之外,间距和大小写也不是可靠的指导。出于这个原因,我们将使用NLTK的punkt记号赋予器对句子分割。为了使用它,您将需要安装NLTK和使用nltk.download()为punkt下载相关训练文件。
# Download the punkt tokenizer for sentence splitting import nltk.data nltk.download() # Load the punkt tokenizer tokenizer = nltk.data.load('tokenizers/punkt/english.pickle') # Define a function to split a review into parsed sentences def review_to_sentences( review, tokenizer, remove_stopwords=False ): # Function to split a review into parsed sentences. Returns a # list of sentences, where each sentence is a list of words # # 1. Use the NLTK tokenizer to split the paragraph into sentences raw_sentences = tokenizer.tokenize(review.strip()) # # 2. Loop over each sentence sentences = [] for raw_sentence in raw_sentences: # If a sentence is empty, skip it if len(raw_sentence) > 0: # Otherwise, call review_to_wordlist to get a list of words sentences.append( review_to_wordlist( raw_sentence, \ remove_stopwords )) # # Return the list of sentences (each sentence is a list of words, # so this returns a list of lists return sentences |
现在,我们可以将这个函数应用到我们的数据,准备输入到Word2Vec(这将需要几分钟):
sentences = [] # Initialize an empty list of sentences print "Parsing sentences from training set" for review in train["review"]: sentences += review_to_sentences(review, tokenizer) print "Parsing sentences from unlabeled set" for review in unlabeled_train["review"]: sentences += review_to_sentences(review, tokenizer) |
你可能会获得一些警告BeautifulSoup关于url的句子。这些都是没有什么可担心的(虽然你可能想考虑删除url来清洁文本)。
我们可以看一下输出,看看这不同于第1部分:
>>> # Check how many sentences we have in total - should be around 850,000+ ... print len(sentences) 857234 >>> print sentences[0] [u'with', u'all', u'this', u'stuff', u'going', u'down', u'at', u'the', u'moment', u'with', u'mj', u'i', u've', u'started', u'listening', u'to', u'his', u'music', u'watching', u'the', u'odd', u'documentary', u'here', u'and', u'there', u'watched', u'the', u'wiz', u'and', u'watched', u'moonwalker', u'again'] >>> print sentences[1] [u'maybe', u'i', u'just', u'want', u'to', u'get', u'a', u'certain', u'insight', u'into', u'this', u'guy', u'who', u'i', u'thought', u'was', u'really', u'cool', u'in', u'the', u'eighties', u'just', u'to', u'maybe', u'make', u'up', u'my', u'mind', u'whether', u'he', u'is', u'guilty', u'or', u'innocent'] |
一个小细节注意的区别是“+ =”和“append”,Python列表。在许多应用程序中这两个是可以互换的,但他们不是。如果你是apepnd列表到另一个列表,列表的列表,“append”只会添加第一个列表;您需要使用“+ =”为了加入所有的列表。
训练和保存您的模型
列表解析句子,我们准备训练模型。有很多影响运行时的参数选择和最终的质量模型。下面的算法细节,请参阅word2vec API文档以及谷歌文档。
Architecture: Architecture选项(默认) skip-gram或连续词袋。我们发现skip-gram略微慢一点但产生更好的结果。
Training algorithm:分层softmax(默认)或负面抽样。对我们来说,默认运行良好。
Downsampling of frequent words:谷歌文档推荐值是0.00001到0.001之间。对我们来说,值接近0.001似乎提高最终模型的准确性。
词向量维度(Word vector dimensionality):更多的特性导致长时间运行时,通常,但不总是,导致更好的模型。合理的值可以在数十到数百;我们使用300。
Context / window size:多少个单词的上下文应该训练算法考虑?10似乎适合层次softmax(越多越好,在一定程度上)。
工作线程(Worker threads):并行流程运行的数量。大多数系统上工作在4和6之间。
最低字数(Minimum word count):这有助于词汇的大小限制为有意义的单词。任何单词,至少不会发生这许多次在所有文件将被忽略。合理的值可能是介于10到100之间。在这种情况下,由于每个电影发生的30倍,我们设置了最低字数到40,避免过分重视个人电影标题。这导致了整体的词汇量的大小在15000字左右。更高的价值也有助于限制运行时。
选择参数并不容易,但是一旦我们选择参数,创建Word2Vec模型很直观:
# Import the built-in logging module and configure it so that Word2Vec # creates nice output messages import logging logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s',\ level=logging.INFO) # Set values for various parameters num_features = 300 # Word vector dimensionality min_word_count = 40 # Minimum word count num_workers = 4 # Number of threads to run in parallel context = 10 # Context window size downsampling = 1e-3 # Downsample setting for frequent words # Initialize and train the model (this will take some time) from gensim.models import word2vec print "Training model..." model = word2vec.Word2Vec(sentences, workers=num_workers, \ size=num_features, min_count = min_word_count, \ window = context, sample = downsampling) # If you don't plan to train the model any further, calling # init_sims will make the model much more memory-efficient. model.init_sims(replace=True) # It can be helpful to create a meaningful model name and # save the model for later use. You can load it later using Word2Vec.load() model_name = "300features_40minwords_10context" model.save(model_name) |
双核Macbook Pro,这花了不到15分钟运行使用4工作线程。然而,这将取决于你的电脑。幸运的是,有打印信息消息日志记录功能。
如果你在Mac或Linux系统上,您可以使用“top”命令从内部终端(不是在Python)您的系统是否成功的并行模型的训练。类型
> top -o cpu |
变成一个终端窗口,而模型的训练。4的worker,应该Python列表中的第一个进程,它应该显示300 - 400%的CPU使用率。
如果你的CPU使用率较低,这可能是因为cython并不在你的机器上正常工作。
探索模型的结果
祝贺使它成功地通过一切到目前为止!让我们看看我们创建我们的75000训练评估模型。
“doesnt_match”函数将试图推断出它在一组词是不是来自另外的组:
>>> model.doesnt_match("man woman child kitchen".split()) 'kitchen' |
我们的模型可以区分不同的意义!它知道,男人,妇女和儿童比他们更相似的厨房。更多勘探表明,该模型是敏感的细微差别的意义,比如国家和城市之间的差异:
>>> model.doesnt_match("france england germany berlin".split()) 'berlin' |
…虽然我们使用的相对较小的训练集,这当然不是完美:
>>> model.doesnt_match("paris berlin london austria".split()) 'paris' |
我们也可以使用“most_similar”功能来获得洞察集群模型的词:
>>> model.most_similar("man") [(u'woman', 0.6056041121482849), (u'guy', 0.4935004413127899), (u'boy', 0.48933547735214233), (u'men', 0.4632953703403473), (u'person', 0.45742249488830566), (u'lady', 0.4487500488758087), (u'himself', 0.4288588762283325), (u'girl', 0.4166809320449829), (u'his', 0.3853422999382019), (u'he', 0.38293731212615967)] >>> model.most_similar("queen") [(u'princess', 0.519856333732605), (u'latifah', 0.47644317150115967), (u'prince', 0.45914226770401), (u'king', 0.4466976821422577), (u'elizabeth', 0.4134873151779175), (u'antoinette', 0.41033703088760376), (u'marie', 0.4061327874660492), (u'stepmother', 0.4040161967277527), (u'belle', 0.38827288150787354), (u'lovely', 0.38668593764305115)] |
鉴于我们特定的训练集,这并不奇怪,“Latifah”是最高达到相似的“Queen”。
或者,更多文本相关分析:
>>> model.most_similar("awful") [(u'terrible', 0.6812670230865479), (u'horrible', 0.62867271900177), (u'dreadful', 0.5879652500152588), (u'laughable', 0.5469599962234497), (u'horrendous', 0.5167273283004761), (u'atrocious', 0.5115568041801453), (u'ridiculous', 0.5104714632034302), (u'abysmal', 0.5015234351158142), (u'pathetic', 0.4880446791648865), (u'embarrassing', 0.48272213339805603)] |
看来我们有相当好的模型语义——至少一样好袋的话。但是我们如何使用这些华丽的词分布向量为监督学习?下一节将尝试。