В этом посте мы рассмотрим еще один способ создания гиперболических вложений. Этот подход хорош, когда у вас есть набор точек данных, и для каждой точки данных у вас есть соответствующие «положительные» точки данных и «отрицательные» точки данных. Положительные точки данных — это точки данных, которые вы хотите расположить близко друг к другу в пространстве встраивания, а отрицательные точки данных — это точки данных, которые вы хотите отдалить. Этот алгоритм отлично подходит для иерархических данных и описан в книге «Вложения Пуанкаре для изучения иерархических представлений» Никеля и Кейлы [1]. Он особенно хорошо работает для встраивания в небольшие измерения, поэтому может значительно увеличить время обучения и подходит для данных со скрытой иерархией.
Этот набор данных точек данных, которые имеют «положительную» связь, также можно рассматривать как график, независимо от того, являются ли узлы точками данных, а ребра соединяют узлы, которые положительно связаны.
Это означает, что с помощью этого подхода можно встроить широкий спектр данных, включая, помимо прочего, слова, предложения, геномы, сети социальных сетей и многое другое.
Теперь вопрос в том, как мне встроить свои данные с помощью этого алгоритма? Мы покажем вам, как это сделать, на примере wordnet. Сначала мы помещаем наши данные в разделение X и Y. X — это множество положительных примеров формы 6000x2, так как у нас есть 6000 положительных примеров и два слова на положительный пример. Y имеет форму 6000x15, так как у нас есть 6000 записей и 10 пар отрицательных примеров. Давайте задействуем это, сначала давайте получим набор положительных примеров:
noun_closure = pd.read_csv("data/mammal_closure.csv") noun_closure.head()
Теперь давайте создадим функцию, которая создает и добавляет отрицательные примеры в набор данных:
def load_wordnet_data(file, negatives=10): # Load dataset of positive examples noun_closure = pd.read_csv(file) noun_closure_np = noun_closure[["id1","id2"]].values edges = set() for i, j in noun_closure_np: edges.add((i,j)) # Get all unique nouns in the dataset unique_nouns = list(set( noun_closure["id1"].tolist()+noun_closure["id2"].tolist() )) # For each positive example lets get 10 negative examples neg_examples = {} for noun in unique_nouns: neg_list = [] while len(neg_list) < negatives: neg_noun = choice(unique_nouns) if neg_noun != noun \ and neg_noun not in neg_list \ and (noun, neg_noun) not in edges: neg_list.append(neg_noun) neg_examples[noun] = neg_list # Lets add the negative examples to our dataset noun_closure["neg_pairs"] = noun_closure["id1"].apply(lambda x: neg_examples[x]) return noun_closure, unique_nouns
А теперь вызовите функцию и поместите вывод в набор данных Tensorflow.
# Make training dataset noun_closure, unique_nouns = load_wordnet_data("data/mammal_closure.csv", negatives=15) noun_closure_dataset = noun_closure[["id1","id2"]].values batch_size = 16 train_dataset = tf.data.Dataset.from_tensor_slices((noun_closure_dataset, noun_closure["neg_pairs"].tolist())) train_dataset = train_dataset.shuffle(buffer_size=1024).batch(batch_size)
Пришло время создать экземпляр нашей модели Hierarchical Embeddings и обучить ее на нашем наборе данных:
from hyperlib.model.pehr import HierarchicalEmbeddings # Create model model = HierarchicalEmbeddings(embedding_length=len(unique_nouns), embedding_dim=5, c=1.0, clip_value=0.95) sgd = keras.optimizers.SGD(learning_rate=5e-3) # Run custom training loop model.fit( train_dataset, epochs=20, optimizer=sgd )
Мы обучали его всего 10 эпох, но давайте посмотрим сейчас, давайте посмотрим на наши встраивания и посмотрим, насколько они хороши. Давайте посмотрим на эмбеддинги, близкие к dog:
vocab = model.get_vocabulary() embs = model.get_embeddings() mammal = M.expmap0(model(tf.constant('dog.n.01')), c=1) dists = M.dist(mammal, embs, c=1.0) top = tf.math.top_k(-dists[:,0], k=20) for i in top.indices: print(vocab[i])
Хорошо, как насчет летучей мыши:
mammal = M.expmap0(model(tf.constant('bat.n.01')), c=1) dists = M.dist(mammal, embs, c=1.0) top = tf.math.top_k(-dists[:,0], k=20) for i in top.indices: print(vocab[i])
Выглядит неплохо, я в восторге! Только в 5 измерениях и 10 эпохах мы могли сгенерировать эти вложения. Если у вас есть набор данных со скрытой иерархией, это может дать вам прирост производительности!
Рекомендации
[1] Вложения Пуанкаре для изучения иерархических представлений. Никель и Кейла