wrapper :封装,将现成的东西加一些自己的东西打包好来用
token(符号):包括单词和标点
tokenization(分词):我是中国人->['我', '是', '中国人']
numericaliz:将一个句子用数字进行标记,就是将一个句子变成一串代表其内容的数字。
https://mp.weixin.qq.com/s/Ta2Im4WCWq5eQ8SF-mNpuQ
什么是Embedding?用一个低维的向量表示一个物体、一个词、一部电影、一个商品。即将这个东西从现实的这个空间变换到一个向量空间(暂时如此称呼),而在这个向量空间中这些物体可能有一些联系。编码的思想是与one hot encoding相似,one hot是稀疏的。
word2vec,训练一个对word的语义表达,输入的是一个句子的集合。假设长度为T的句子是$w_1,w_2,···,w_T$,每个词与他相邻的词的关系最为密切。或者每个词都是由相邻的词决定的(CBOW模型的动机),每个词都决定了相邻的词(Skip-gram模型动机)。
文本中的滑动窗口,每次选择长度为2c+1(目标词前后各选c个词)的滑动窗口,从句子左边滑到右边,每一次滑动,就产生一个正样本。
有了样本后就是定义目标函数了,因为每个词$w_t$都决定了相邻$w_{t+j}$,采用极大似然,要使$p(w{t+j}|w_t)$之积最大,使用log对数
$ \frac{1}{T}\sum_{t=1}^{T}{\sum_{-c<j<c}{log p(w_{t+j}|w_t)}} $
想用向量$v_w$表示每个词w,用词之间的距离$v_i^Tv_j$表示语义接近程度,那么条件概率表示成
$p(w_O|w_I)=\frac{exp(v^{'T}{w_O}v{w_I})}{\sum_{w=1}^Wexp(v^{'T}{w_O}v{w_I})}$
我们有可能会忽略一个事实,我们用$w_t$去预测$w_{t+j}$,但其实这二者的向量表达并不在一个向量空间内。$v_{w_O}^{'}$和$v_{w_O}$分别是词w的输出向量表达和输入向量表达。什么是输出向量表达和输入向量表达?下图就可阐明
上图其实可以写成$y_V=x_V·W_{VN}·W^{'}_{NV}·$。权重矩阵$W_{VN}$就是输入向量表达,$W^{'}_{NV}$就是输出向量表达。感觉就是对向量进行了加工。
那么什么是词向量$v_w$呢?
就是我们上面所说的输入向量矩阵$W_{V*N}$中每一行对应的权重向量。下图中所表达的就是每个神经元多要处理所有的words(如左图),那么所有神经元组合在一起就表示了一个words的一个300维的features。
从word2vec到item2vec
那么进行扩展,既然可以对一个序列中的词进行embedding,那么自然可以对用户高迈序列中的一个商品,观影中的一个电影进行embedding,这就是item2vec
如果我们摒弃序列中item的空间关系,在原来的目标函数基础上,自然是不存在时间窗口的概念了,取而代之的是item set中两两之间的条件概率。
$ \frac{1}{K}\sum_{t=1}^{K}{\sum_{j≠i}^{K}{log p(w_{j}|w_i)}} $
上面讲了embedding的原理下面那就附上一个文本处理库的使用。gensim对多种NLP处理技术做了封装。
在Gensim中Word2vec模块中,模型的期望输入是进行过分词的句子列表。
from gensim.models import Word2Vec
raw_sentences = ["the quick brown fox jumps over the lazy dogs","yoyoyo you go home now to sleep"]
sentences = [s.encode("utf-8").split() for s in raw_sentences]
model = Word2Vec(sentences, min_count=1)
这里我们调用Word2Vec
创建模型实际上会对数据执行两次迭代操作,第一轮操作会统计词频来构建内部的词典数结构,第二轮操作会进行神经网络训练,而这两个步骤是可以分步进行的,这样对于某些不可重复的流(譬如 Kafka 等流式数据中)可以手动控制:
model = gensim.models.Word2Vec(iter=1)
model.build_vocab(some_sentences)
model.train(other_sentences)
参数设置
min_count 这个参数是设置预料库中要忽略出现次数很少的词的阈值,只有大于这个阈值的词才会进行运算。一般设置在0-100之间。
size 设置神经网络的层数,默认100.
workers 设置并发训练的线程数,只在Cython安装的情况下有用。
sg=1是skip-gram算法,对低频词敏感;默认sg=0为CBOW算法。
negative和sample可根据训练结果进行微调,sample表示更高频率的词被随机下采样到所设置的阈值,默认值为1e-3。
hs=1表示层级softmax将会被使用,默认hs=0且negative不为0,则负采样将会被选择使用。
将外部数据设置为迭代数据导入
class Mysentences(object):
def __init__(self, dirname):
self.dirname = dirname
def __iter__(self):
for fname in os.listdir(self.dirname):
for line in open(os.path.join(self.dirname,fname)):
yield line.split()
sentences = Mysentences("/some/directory")
model = gensim.models.Word2Vec(sentences)
模型的保存与读取
model.save("model2.model")
model2 = Word2Vec.load("model2.model")
model.save_word2vec_format('text.model.bin', binary=True)
model1 = word2vec.Word2Vec.load_word2vec_format('text.model.bin', binary=True)
词和向量的获取
vocab = model.wv.vocab.keys() #通过训练好的模型获得词的列表
vector = model.wv.vectors
##torchtext的使用
torchtext可以做什么?
- File Loading: 加载不同文件格式的
corpus
- Tokenization: 将句子 分解成 词列表。
- Vocab: 构建 当前 corpus 的词汇表
- Numericalize/Indexify: 将 词 映射成 index
- Word Vector: 词向量
- Batching: generate batches of training sample (padding is normally happening here)
不可以做什么?
- Train/Val/Test Split: 数据集切分
- Embedding Lookup:词嵌入
包含什么?
torchtext.data.Example:用来表示一个样本,数据+标签
torchtext.vocab.Vocab:词汇表
torchtext.dataDatasets:数据集类,**__ getitem __**返回Example实例。
torchtext.data.Field:用来定义字段的处理方法。1.创建Example时的预处理。2.batch时的一些处理操作。
torchtext.data.Iterator:迭代器,用来生成batch
torchtext.data.datasets:包含了常见数据集
####处理流程
-
定义要对样本进行何种操作。用torch.data.Field。
-
加载数据corpus(string类型)。用torchtext.data.Datasets
-
在Datasets中,torchtext将corpus处理成一个个torchtext.data.Example实例
-
创建torchtext.data.Example的时候,会调用field.preprocess方法
-
-
创建词汇表,用来将string token(“the cat eat apple”)转换成index({“the”:0,"cat":1,})
-
将处理后的数据进行batch操作。用torchtext.data.Iterator
- 将Datasets中的数据batch化
- 其中会包含一些
pad(padding)
操作,保证一个batch
中的example
长度一致。 - 在这里将
string token
转化成index
。
import torchtext.data
tokenize = lanbda x: x.split()
#先定义怎么处理文本和标签
TEXT = data.Field(sequential=True, tokenize=tokenize, lower=True)
LABEL = data.Field(sequential=False, use_vocab=False)
#这里是指明哪个列是数据,哪个列是标签
tv_datafields = [("id", None), ("comment_text", TEXT),("toxic", LABEL),("severe_toxic", LABEL)]
#读取训练集和验证集
train,vaild = data.TabularDataset.splits(path="data", train="train.csv", validation="valid.csv", format="csv", skip_header=True, fields=tv_datafields)
#读取测试集
test_datafields = [("id", None),("comment_text", TEXT)]
test = data.TabularDataset(path="data/test.csv", format="csv", skip_header=True, fields=test_datafields)
#在train中构建词汇表
TEXT.build_vocab(train)
train_iter,val_iter = data.BucketIterator.splits((train, vaild)#希望抽取的数据
,batch_sizes=(25, 25)#每个batch的大小,每个都是25
,device=-1#设置为CPU,GPU要指定编号
,sort_key=lambda x:len(x.comment_text)#依据什么分组
,sort_within_batch=False
,repeat=False)
test_iter = data.Iterator(test, batch_size=64, device=-1, sort=False, sort_within_batch=False, repeat=False)
熵衡量了一个概率分布的随机程度,或者说包含的信息量的大小。假设随机变量取值为x,对应的概率为p(x)。直观来看,取这个值的可能性很小,而它又发生了,则包含的信息量就越大。因此如果定义一个函数h(x)来描述随机变量取值为的信息量的大小的话,则h(x)应该是p(x)的单调减函数。假设有两个相互独立的随机变量x和y,取该值的概率为p(x)和p(y)。联合概率为
由于这两个随机变量是相互独立的,因此它们各自取某一值时包含的信息量应该是两个随机变量分别取这些值的时候包含的信息量之和
这要求*h(x)能把p(x)*的乘法转化为加法,在数学上,满足此要求的是对数函数。因此,可以把信息量定义为
对数函数前面加上了负号,这是因为对数函数是增函数,而我们要求*h(x)是p(x)*的减函数。
随机变量取值有各种情况,而且取每个值有一个概率,那我们计算它取各个值时的信息量的均值即数学期望即可,这个信息量的均值,就是熵。
$ p_i=p(x_i) $
当且仅当随机变量取某一值的概率为1,取其他值的概率为0时熵有极小值0。此时随机变量退化成普通的变量,取值固定。而当随机变量取所有值的概率相等时即均匀分布时熵有极大值。故熵的范围为
交叉熵的定义与熵类似,不同的是定义在两个概率分布而不是一个概率分布之上。
$ H(p,q)=-\sum p(x)log q(x) $
x是离散随机变量,p(x)和q(x)是它的两个概率分布。交叉熵衡量了两个概率分布的差异。其值越大,两个概率分布相差越大;其值越小,则两个概率分布的差异越小。
交叉熵在机器学习中用得更多,通常用于充当目标函数,以最小化两个概率分布的差异。