Разные вложения для одних и тех же предложений с факельным трансформатором

Привет всем и заранее извиняюсь за, вероятно, довольно простой вопрос - у меня есть теория о том, что вызывает проблему, но было бы здорово подтвердить это людьми, которые знают об этом больше, чем я.

Я пытался реализовать этот фрагмент кода Python в Google Colab. Фрагмент предназначен для определения сходства предложений. Код работает нормально, но я обнаружил, что вложения и расстояния меняются каждый раз, когда я его запускаю, что не идеально для моего предполагаемого варианта использования.

import torch
from scipy.spatial.distance import cosine
from transformers import AutoModel, AutoTokenizer

# Import our models. The package will take care of downloading the models automatically
tokenizer = AutoTokenizer.from_pretrained("qiyuw/pcl-bert-base-uncased")
model = AutoModel.from_pretrained("qiyuw/pcl-bert-base-uncased")

# Tokenize input texts
texts = [
    "There's a kid on a skateboard.",
    "A kid is skateboarding.",
    "A kid is inside the house."
]
inputs = tokenizer(texts, padding=True, truncation=True, return_tensors = "pt")

# Get the embeddings
with torch.no_grad():
    embeddings = model(**inputs, output_hidden_states=True, return_dict=True).pooler_output

# Calculate cosine similarities
# Cosine similarities are in [-1, 1]. Higher means more similar
cosine_sim_0_1 = 1 - cosine(embeddings[0], embeddings[1])
cosine_sim_0_2 = 1 - cosine(embeddings[0], embeddings[2])

print("Cosine similarity between \"%s\" and \"%s\" is: %.3f" % (texts[0], texts[1], cosine_sim_0_1))
print("Cosine similarity between \"%s\" and \"%s\" is: %.3f" % (texts[0], texts[2], cosine_sim_0_2))

Я думаю, что проблема должна быть специфичной для модели, поскольку я получаю предупреждение о вновь инициализированных весах пулера, а Pooler_output в конечном итоге — это то, что код читает, чтобы сообщить о сходстве:

Some weights of RobertaModel were not initialized from the model checkpoint at qiyuw/pcl-roberta-large and are newly initialized: ['roberta.pooler.dense.bias', 'roberta.pooler.dense.weight']
You should probably TRAIN this model on a down-stream task to be able to use it for predictions and inference.

Переключение на альтернативную модель, которая не выдает этого предупреждения (например, приговор-трансформеры/all-mpnet-base-v2), делает выходные данные воспроизводимыми, поэтому я думаю, что это из-за приведенного выше предупреждения об инициализации весов. Итак, вот мои вопросы:

  1. Могу ли я сделать выходные данные воспроизводимыми, инициализируя/засевая модель по-другому?
  2. Если я не могу обеспечить воспроизводимость результатов, есть ли способ повысить точность и уменьшить различия между запусками?
  3. Есть ли способ найти модели Huggingface, которые будут инициализировать веса пулера, чтобы я мог найти модель, которая соответствует моим целям?

заранее спасибо

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
3
0
75
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Сомневаюсь, что это особенность конкретной модели. Известно, что предварительно обученные модели внедрения создают несколько разные внедрения для одного и того же ввода (в вашем случае — текстов).

Об этом ведется несколько открытых разговоров, однако я экспериментировал с этим как на пустой, так и на предварительно обученной модели RoBerta и обнаружил, что установка начальных значений модели для задач внедрения контролирует такое поведение. Однако настройки начального числа для параметров модели (например, смещения) может быть недостаточно, действительно, некоторые модели внедрения могут выполнять выборку из распределения токенов в конце процесса вывода.

Предупреждающее сообщение:

Some weights of RobertaModel were not initialized from the model checkpoint at qiyuw/pcl-roberta-large and are newly initialized: ['roberta.pooler.dense.bias', 'roberta.pooler.dense.weight']
You should probably TRAIN this model on a down-stream task to be able to use it for predictions and inference.

подразумевает, что веса предварительно обученной модели не были загружены и использованы при инициализации. В зависимости от процесса инициализации этой конкретной модели Берта, весьма вероятно, что вы создаете новые внедрения при инициализации.

Кроме того, не инициализируйте модель каждый раз, когда вы запускаете скрипт. Я предлагаю вам использовать Jupyter Notebook для создания блока ячеек, инициализировать модель один раз и наблюдать, получаете ли вы одинаковые внедрения для одного и того же входного значения, прежде чем переходить к чему-то большему. разрабатывать, например, пытаться контролировать семена, независимо от того, какие слои их используют.

В качестве примера рассмотрим следующий код для слоя внедрения из документации pytorch:

from torch import nn
embedding = nn.Embedding(10, 3)
input = torch.LongTensor([[1, 2, 4, 5], [4, 3, 2, 9]])
embedding(input)

Если приведенный выше код будет запущен (независимо от того, инициализировали ли вы уже embedding), вы получите новые вложения, сгенерированные из нормального распределения N(0,1). Если вы не выполните повторную инициализацию embeddings, вы увидите, что сгенерированное значение input не изменилось, сколько бы раз вы его ни запускали.

Действительно, модель Берта, которую вы используете выше, использует аналогичное (немного более сложное) использование слоя внедрения.

Ответ принят как подходящий

Вы правы, веса слоев модели для bert.pooler.dense.bias и bert.pooler.dense.weight инициализируются случайным образом. Вы можете инициализировать эти слои всегда одинаково для воспроизводимого вывода, но я сомневаюсь, что код вывода, который вы скопировали оттуда readme , верен. Как вы уже упомянули, слои пула не инициализируются, и их класс модели также следит за тем, чтобы пул_слой не добавлялся:

...
self.bert = BertModel(config, add_pooling_layer=False)
...

Оценочный сценарий репозитория следует вызвать в соответствии с файлом readme с помощью следующей команды:

python evaluation.py --model_name_or_path qiyuw/pcl-bert-base-uncased --mode test --pooler cls_before_pooler

Если вы посмотрите на это, ваш код вывода для qiyuw/pcl-bert-base-uncased должен быть следующим:

import torch
from scipy.spatial.distance import cosine
from transformers import AutoModel, AutoTokenizer

# Import our models. The package will take care of downloading the models automatically
tokenizer = AutoTokenizer.from_pretrained("qiyuw/pcl-bert-base-uncased")
model = AutoModel.from_pretrained("qiyuw/pcl-bert-base-uncased")

# Tokenize input texts
texts = [
    "There's a kid on a skateboard.",
    "A kid is skateboarding.",
    "A kid is inside the house."
]
inputs = tokenizer(texts, padding=True, truncation=True, return_tensors = "pt")

# Get the embeddings
with torch.inference_mode():
    embeddings = model(**inputs)
    embeddings = embeddings.last_hidden_state[:, 0]

# Calculate cosine similarities
# Cosine similarities are in [-1, 1]. Higher means more similar
cosine_sim_0_1 = 1 - cosine(embeddings[0], embeddings[1])
cosine_sim_0_2 = 1 - cosine(embeddings[0], embeddings[2])

print("Cosine similarity between \"%s\" and \"%s\" is: %.3f" % (texts[0], texts[1], cosine_sim_0_1))
print("Cosine similarity between \"%s\" and \"%s\" is: %.3f" % (texts[0], texts[2], cosine_sim_0_2))

Выход:

Cosine similarity between "There's a kid on a skateboard." and "A kid is skateboarding." is: 0.941
Cosine similarity between "There's a kid on a skateboard." and "A kid is inside the house." is: 0.779

Могу ли я сделать выходные данные воспроизводимыми, инициализируя/засевая модель по-другому?

Да, ты можешь. Используйте torch.maunal_seed:

import torch
from transformers import AutoModel, AutoTokenizer

model_random = AutoModel.from_pretrained("qiyuw/pcl-bert-base-uncased")
torch.manual_seed(42)
model_repoducible1 = AutoModel.from_pretrained("qiyuw/pcl-bert-base-uncased")

torch.manual_seed(42)
model_repoducible2 = AutoModel.from_pretrained("qiyuw/pcl-bert-base-uncased")

print(torch.allclose(model_random.pooler.dense.weight, model_repoducible1.pooler.dense.weight))
print(torch.allclose(model_random.pooler.dense.weight, model_repoducible2.pooler.dense.weight))
print(torch.allclose(model_repoducible1.pooler.dense.weight, model_repoducible2.pooler.dense.weight))

Выход:

False
False
True

Другие вопросы по теме