Введение
Используйте TensorFlow для обучения векторов китайских слов и выполнения простых семантических задач.
обзор
Введен в полный курс стека, как использоватьgensim
Обучение векторов китайских слов, то есть встраивание слов (Word Embedding)
Установите gensim, если у вас его нет
pip install gensim
Подготовьте корпус, например, данные сегментации слов китайской Википедии.
загрузить библиотеку
# -*- coding: utf-8 -*-
from gensim.models import Word2Vec
from gensim.models.word2vec import LineSentence
import time
Обучите модель и сохраните ее, обучение на моем ноутбуке заняло 1403 секунды.
t0 = int(time.time())
sentences = LineSentence('wiki.zh.word.text')
model = Word2Vec(sentences, size=128, window=5, min_count=5, workers=4)
print('训练耗时 %d s' % (int(time.time()) - t0))
model.save('gensim_128')
Загрузите модель и используйте
model = Word2Vec.load('gensim_128')
# 相关词
items = model.wv.most_similar('数学')
for i, item in enumerate(items):
print(i, item[0], item[1])
# 语义类比
print('=' * 20)
items = model.wv.most_similar(positive=['纽约', '中国'], negative=['北京'])
for i, item in enumerate(items):
print(i, item[0], item[1])
# 不相关词
print('=' * 20)
print(model.wv.doesnt_match(['早餐', '午餐', '晚餐', '手机']))
# 计算相关度
print('=' * 20)
print(model.wv.similarity('男人', '女人'))
принцип
Вектор слова представляет собой представление слова
- После того, как у вас есть вектор слова, вы можете представить предложение в виде векторной последовательности, то есть двумерного тензора.
- Если это несколько предложений одинаковой длины, их можно представить в виде трехмерного тензора.
Грубо говоря, вектор слов представляет собой двумерную матрицу размерамиV*d
,V
это общее количество слов,d
размерность вектора слов
One-Hot
представлять каждое слово какV
Вектор измерения, только размер, соответствующий текущему слову, равен 1, остальные измерения равны 0
вложения слов будутOne-Hot
Многомерный разреженный вектор, представленный словом, отображается в низкоразмерный плотный вектор слова с действительным знаком, соответствующий слову
Есть два основных способа обучения векторов слов.
- CBOW (непрерывный набор слов): прогнозирование текущего слова на основе слов контекста.
- Skip-Gram: предсказание контекстных слов на основе текущего слова
Здесь мы в основном говорим о принципе Skip-Gram.
Ввод представляет собой целочисленный идентификатор, соответствующий слову илиOne-Hot
Указывает, что соответствующий вектор слов получается после слоя внедрения, а выходная вероятность, соответствующая каждому слову, получается после слоя отображения и обработки softmax.
Поскольку словари, как правило, очень большие, десятки тысяч, сотни тысяч или даже миллионы, множественная классификация непосредственно всего словаря приведет к очень большому объему вычислений.
Эффективным решением является Negative Sampling, который каждый раз случайным образом отбирает несколько отрицательных образцов.
Предполагая, что размер словаря равен 5W, для определенного входного слова известны соответствующие правильные выходные слова, а затем из словаря случайным образом выбираются слова N. Вероятность того, что эти N слов являются правильными выходными словами, очень мала, поэтому это можно рассматривать как отрицательный образец
- Дайте вам изображение собаки и определите соответствующее видовое название
- Дайте вам пять фотографий собак и определите, является ли каждая из них хаски.
Таким образом, проблема с несколькими классификациями 5W-классификации превращается в N задач с двумя классификациями, что также обеспечивает обучаемые градиенты и значительно сокращает объем вычислений.
В конкретной реализации вы можете использоватьNoise-Contrastive Estimation
(NCE) как функция потерь, используемая в TensorFlowtf.nn.nce_loss()
Просто
выполнить
Загрузите библиотеку и корпус, всего 254419 строк
# -*- coding: utf-8 -*-
import pickle
import numpy as np
import tensorflow as tf
import collections
from tqdm import tqdm
with open('wiki.zh.word.text', 'rb') as fr:
lines = fr.readlines()
print('共%d行' % len(lines))
print(lines[0].decode('utf-8'))
Всего 148134974 слова
lines = [line.decode('utf-8') for line in lines]
words = ' '.join(lines)
words = words.replace('\n', '').split(' ')
print('共%d个词' % len(words))
Словарь определений
vocab_size = 50000
vocab = collections.Counter(words).most_common(vocab_size - 1)
Статистика частотности слов
count = [['UNK', 0]]
count.extend(vocab)
print(count[:10])
Взаимное сопоставление между словами и идентификаторами
word2id = {}
id2word = {}
for i, w in enumerate(count):
word2id[w[0]] = i
id2word[i] = w[0]
print(id2word[100], word2id['数学'])
Преобразование корпуса в последовательность идентификаторов, всего 22385926 UNK.
data = []
for i in tqdm(range(len(lines))):
line = lines[i].strip('\n').split(' ')
d = []
for word in line:
if word in word2id:
d.append(word2id[word])
else:
d.append(0)
count[0][1] += 1
data.append(d)
print('UNK数量%d' % count[0][1])
Подготовьте обучающие данные
X_train = []
Y_train = []
window = 3
for i in tqdm(range(len(data))):
d = data[i]
for j in range(len(d)):
start = j - window
end = j + window
if start < 0:
start = 0
if end >= len(d):
end = len(d) - 1
while start <= end:
if start == j:
start += 1
continue
else:
X_train.append(d[j])
Y_train.append(d[start])
start += 1
X_train = np.squeeze(np.array(X_train))
Y_train = np.squeeze(np.array(Y_train))
Y_train = np.expand_dims(Y_train, -1)
print(X_train.shape, Y_train.shape)
Задайте параметры модели
batch_size = 128
embedding_size = 128
valid_size = 16
valid_range = 100
valid_examples = np.random.choice(valid_range, valid_size, replace=False)
num_negative_samples = 64
Определить модель
X = tf.placeholder(tf.int32, shape=[batch_size], name='X')
Y = tf.placeholder(tf.int32, shape=[batch_size, 1], name='Y')
valid = tf.placeholder(tf.int32, shape=[None], name='valid')
embeddings = tf.Variable(tf.random_uniform([vocab_size, embedding_size], -1.0, 1.0))
embed = tf.nn.embedding_lookup(embeddings, X)
nce_weights = tf.Variable(tf.truncated_normal([vocab_size, embedding_size], stddev=1.0 / np.sqrt(embedding_size)))
nce_biases = tf.Variable(tf.zeros([vocab_size]))
loss = tf.reduce_mean(tf.nn.nce_loss(weights=nce_weights, biases=nce_biases, labels=Y, inputs=embed, num_sampled=num_negative_samples, num_classes=vocab_size))
optimizer = tf.train.AdamOptimizer().minimize(loss)
Нормировать вектор слов и вычислить сходство с заданным словом
norm = tf.sqrt(tf.reduce_sum(tf.square(embeddings), axis=1, keep_dims=True))
normalized_embeddings = embeddings / norm
valid_embeddings = tf.nn.embedding_lookup(normalized_embeddings, valid)
similarity = tf.matmul(valid_embeddings, normalized_embeddings, transpose_b=True)
Обучите модель
sess = tf.Session()
sess.run(tf.global_variables_initializer())
offset = 0
losses = []
for i in tqdm(range(1000000)):
if offset + batch_size >= X_train.shape[0]:
offset = (offset + batch_size) % X_train.shape[0]
X_batch = X_train[offset: offset + batch_size]
Y_batch = Y_train[offset: offset + batch_size]
_, loss_ = sess.run([optimizer, loss], feed_dict={X: X_batch, Y: Y_batch})
losses.append(loss_)
if i % 2000 == 0 and i > 0:
print('Iteration %d Average Loss %f' % (i, np.mean(losses)))
losses = []
if i % 10000 == 0:
sim = sess.run(similarity, feed_dict={valid: valid_examples})
for j in range(valid_size):
valid_word = id2word[valid_examples[j]]
top_k = 5
nearests = (-sim[j, :]).argsort()[1: top_k + 1]
s = 'Nearest to %s:' % valid_word
for k in range(top_k):
s += ' ' + id2word[nearests[k]]
print(s)
offset += batch_size
Сохранить модель, конечный вектор слова, картографический словарь
saver = tf.train.Saver()
saver.save(sess, './tf_128')
final_embeddings = sess.run(normalized_embeddings)
with open('tf_128.pkl', 'wb') as fw:
pickle.dump({'embeddings': final_embeddings, 'word2id': word2id, 'id2word': id2word}, fw, protocol=4)
Используйте обученную модель и векторы слов на одном компьютере
Загрузите библиотеку и результирующий вектор слов, сопоставление словаря
# -*- coding: utf-8 -*-
import tensorflow as tf
import numpy as np
from sklearn.manifold import TSNE
import matplotlib.pyplot as plt
import pickle
with open('tf_128.pkl', 'rb') as fr:
data = pickle.load(fr)
final_embeddings = data['embeddings']
word2id = data['word2id']
id2word = data['id2word']
Получите 200 лучших слов, не состоящих из одного слова, с наибольшей частотой и выполните визуализацию уменьшения размерности tSNE на их векторах слов.
word_indexs = []
count = 0
plot_only = 200
for i in range(1, len(id2word)):
if len(id2word[i]) > 1:
word_indexs.append(i)
count += 1
if count == plot_only:
break
tsne = TSNE(perplexity=30, n_components=2, init='pca', n_iter=5000)
two_d_embeddings = tsne.fit_transform(final_embeddings[word_indexs, :])
labels = [id2word[i] for i in word_indexs]
plt.figure(figsize=(15, 12))
for i, label in enumerate(labels):
x, y = two_d_embeddings[i, :]
plt.scatter(x, y)
plt.annotate(label, (x, y), ha='center', va='top', fontproperties='Microsoft YaHei')
plt.savefig('词向量降维可视化.png')
Видно, что семантически родственные слова действительно находятся в сходных позициях.
Модели TensorFlow могут быть загружены, что даетvalid
Укажите идентификатор, соответствующий некоторым словам, чтобы получить похожие слова
sess = tf.Session()
sess.run(tf.global_variables_initializer())
saver = tf.train.import_meta_graph('tf_128.meta')
saver.restore(sess, tf.train.latest_checkpoint('.'))
graph = tf.get_default_graph()
valid = graph.get_tensor_by_name('valid:0')
similarity = graph.get_tensor_by_name('MatMul_1:0')
word = '数学'
sim = sess.run(similarity, feed_dict={valid: [word2id[word]]})
top_k = 10
nearests = (-sim[0, :]).argsort()[1: top_k + 1]
s = 'Nearest to %s:' % word
for k in range(top_k):
s += ' ' + id2word[nearests[k]]
print(s)
10 самых подходящих слов для математики
Nearest to 数学: 理论 物理学 应用 物理 科学 化学 定义 哲学 生物学 天文学
Используйте векторы слов для других семантических задач
# 计算相关度
def cal_sim(w1, w2):
return np.dot(final_embeddings[word2id[w1]], final_embeddings[word2id[w2]])
print(cal_sim('男人', '女人'))
# 相关词
word = '数学'
sim = [[id2word[i], cal_sim(word, id2word[i])] for i in range(len(id2word))]
sim.sort(key=lambda x:x[1], reverse=True)
top_k = 10
for i in range(top_k):
print(sim[i + 1])
# 不相关词
def find_mismatch(words):
vectors = [final_embeddings[word2id[word]] for word in words]
scores = {word: np.mean([cal_sim(word, w) for w in words]) for word in words}
scores = sorted(scores.items(), key=lambda x:x[1])
return scores[0][0]
print(find_mismatch(['早餐', '午餐', '晚餐', '手机']))
Ссылаться на
- Эффективная оценка представлений слов в векторном пространстве:АР Вест V.org/ABS/1301.37…
- Распределенные представления слов и фраз и их композиционность:Бумаги.Грязевой Бодхисаттва.Цао Цао/бумага/5021-…
- Векторные представления слов:woohoo.tensorflow.org/tutorials/i…