Заявление об авторских правах: Данная статья является оригинальной статьей блогера, просьба указывать источник для перепечатки
В предыдущей статье было рассказано, как установить и использовать BERT для задач подобия текста, в том числе как изменить код для обучения и тестирования. Исходя из этого, в этой статье рассказывается, как выполнять задачи классификации текста.
Подробнее см. в задаче на сходство текста:Введение в BERT и практика задачи на сходство китайского текста
Разница между задачей сходства текста и задачей классификации текста заключается в подготовке набора данных иrun_classifier.py
Строительная часть класса данных в .
0. Подготовка
Если вы хотите сделать это в соответствии с набором данных, который мы подготовилиfine-tuning
, сначала необходимо загрузить предварительно обученную модель. Поскольку речь идет о китайском тексте, загрузите соответствующую китайскую модель предварительной подготовки.
BERTgit
адрес:google-research/bert
- BERT-Base, Chinese: Chinese Simplified and Traditional, 12-layer, 768-hidden, 12-heads, 110M parameters
имя файлаchinese_L-12_H-768_A-12.zip
. распаковать его вbert
папку, содержащую следующие три файла:
- Файл конфигурации (bert_config.json): используется для указания гиперпараметров модели.
- Файл словаря (vocab.txt): для сопоставления идентификаторов WordPiece и Word.
- Контрольная точка Tensorflow (bert_model.ckpt): содержит веса предварительно обученной модели (фактически содержит три файла)
1. Подготовка набора данных
Для задач классификации текста формат набора данных, который необходимо подготовить, выглядит следующим образом:label, 文本
, где метка может быть строкой китайских символов или числом.
как:天气, 一会好像要下雨了
или0, 一会好像要下雨了
Сохраните подготовленные данные в текстовом файле, например,.txt
,.csv
Ждать. Что касается того, какое имя и суффикс использовать, если они соответствуют имени в классе данных.
Например, вrun_classifier.py
класс данных вget_train_examples
метод, файл тренировочного набора по умолчаниюtrain.csv
, вы можете изменить имя файла на свое собственное имя.
def get_train_examples(self, data_dir):
"""See base class."""
file_path = os.path.join(data_dir, 'train.csv')
2. Добавьте пользовательский класс данных
Назовите новый класс данных для классификации текста какTextClassifierProcessor
,следующее
class TextClassifierProcessor(DataProcessor):
Перепишите четыре метода родительского класса, чтобы реализовать процесс сбора данных.
-
get_train_examples
: получить тренировочный наборInputExample
коллекция -
get_dev_examples
: Для проверочного набора... -
get_test_examples
: Для тестового набора... -
get_labels
: получить список меток классификации набора данных.
InputExample
Класс действует как обучающий/тестовый пример для одной последовательности классификации. построилInputExample
,Включаютid, text_a, text_b, label
.
Он определяется следующим образом:
class InputExample(object):
"""A single training/test example for simple sequence classification."""
def __init__(self, guid, text_a, text_b=None, label=None):
"""Constructs a InputExample.
Args:
guid: Unique id for the example.
text_a: string. The untokenized text of the first sequence. For single
sequence tasks, only this sequence must be specified.
text_b: (Optional) string. The untokenized text of the second sequence.
Only must be specified for sequence pair tasks.
label: (Optional) string. The label of the example. This should be
specified for train and dev examples, but not for test examples.
"""
self.guid = guid
self.text_a = text_a
self.text_b = text_b
self.label = label
переписатьget_train_examples
метод, только для задач классификации текстаlabel
и текст, так что просто назначьтеtext_a
.
Поскольку подготовленный набор данныхЭтикеткаитекстдаразделенных запятыми, поэтому сначала разделите каждую строку данных запятыми, затемsplit_line[0]
присвоить меткуlabel
,split_line[1]
назначить текст наtext_a
.
Здесь подготовленные метки набора данных и тексты разделены запятыми.Неизбежно, что тексты не имеют одинаковых английских запятых.Во избежание получения неполных текстовых данных рекомендуется использовать
str.find(',')
найди где стоит первая запятаяlabel = line[:line.find(',')].strip()
То же самое делается для тестового набора и набора проверки.
def get_train_examples(self, data_dir):
"""See base class."""
file_path = os.path.join(data_dir, 'train.csv')
examples = []
with open(file_path, encoding='utf-8') as f:
reader = f.readlines()
for (i, line) in enumerate(reader):
guid = "train-%d" % (i)
split_line = line.strip().split(",")
text_a = tokenization.convert_to_unicode(split_line[1])
text_b = None
label = str(split_line[0])
examples.append(
InputExample(guid=guid, text_a=text_a, text_b=text_b, label=label))
return examples
get_labels
Метод используется для получения всех меток категорий набора данных, которые представлены числами 1, 2, 3.... Если категорий 66 (1-66), метод реализации следующий:
def get_labels(self):
"""See base class."""
labels = [str(i) for i in range(1,67)]
return labels
Для удобства можно создать переменную словарного типа для хранения соответствия между числовыми категориями и текстовыми метками. Конечно, вы также можете использовать текстовые метки напрямую, в зависимости от того, что вы хотите использовать.
определенныйTextClassifierProcessor
После класса, вам также нужно добавить его вmain
в функцииprocessors
в переменную.
Найдите функцию main() и добавьте вновь определенный класс данных, как показано ниже:
def main(_):
tf.logging.set_verbosity(tf.logging.INFO)
processors = {
"cola": ColaProcessor,
"mnli": MnliProcessor,
"mrpc": MrpcProcessor,
"xnli": XnliProcessor,
"sim": SimProcessor,
"classifier":TextClassifierProcessor, # 增加此行
}
3. Измените вывод прогноза
существуетrun_classifier.py
В файле часть предсказания выведет два файла, которыеpredict.tf_record
иtest_results.tsv
. вtest_results.tsv
Сохраняются значения вероятности, принадлежащие всем категориям, полученным каждым тестовым данным, и размерность [n * num_labels].
Однако этот результат не отражает напрямую полученный результат предсказания, поэтому код обработки добавляется для непосредственного получения полученной категории предсказания.
Исходный код выглядит следующим образом:
if FLAGS.do_predict:
print('*'*30,'do_predict', '*'*30)
predict_examples = processor.get_test_examples(FLAGS.data_dir)
num_actual_predict_examples = len(predict_examples)
if FLAGS.use_tpu:
# TPU requires a fixed batch size for all batches, therefore the number
# of examples must be a multiple of the batch size, or else examples
# will get dropped. So we pad with fake examples which are ignored
# later on.
while len(predict_examples) % FLAGS.predict_batch_size != 0:
predict_examples.append(PaddingInputExample())
predict_file = os.path.join(FLAGS.output_dir, "predict.tf_record")
file_based_convert_examples_to_features(predict_examples, label_list,
FLAGS.max_seq_length, tokenizer,
predict_file)
tf.logging.info("***** Running prediction*****")
tf.logging.info(" Num examples = %d (%d actual, %d padding)",
len(predict_examples), num_actual_predict_examples,
len(predict_examples) - num_actual_predict_examples)
tf.logging.info(" Batch size = %d", FLAGS.predict_batch_size)
predict_drop_remainder = True if FLAGS.use_tpu else False
predict_input_fn = file_based_input_fn_builder(
input_file=predict_file,
seq_length=FLAGS.max_seq_length,
is_training=False,
drop_remainder=predict_drop_remainder)
result = estimator.predict(input_fn=predict_input_fn)
output_predict_file = os.path.join(
FLAGS.output_dir, "test_results.tsv")
with tf.gfile.GFile(output_predict_file, "w") as writer:
num_written_lines = 0
tf.logging.info("***** Predict results *****")
for (i, prediction) in enumerate(result):
probabilities = prediction["probabilities"]
if i >= num_actual_predict_examples:
break
output_line = "\t".join(
str(class_probability)
for class_probability in probabilities) + "\n"
writer.write(output_line)
num_written_lines += 1
assert num_written_lines == num_actual_predict_examples
Модифицированный код выглядит следующим образом:
result_predict_file = os.path.join(
FLAGS.output_dir, "test_labels_out.txt")
right = 0 # 预测正确的个数
f_res = open(result_predict_file, 'w') #将结果保存到此文件中
with tf.gfile.GFile(output_predict_file, "w") as writer:
num_written_lines = 0
tf.logging.info("***** Predict results *****")
for (i, prediction) in enumerate(result):
probabilities = prediction["probabilities"] #预测结果
if i >= num_actual_predict_examples:
break
output_line = "\t".join(
str(class_probability)
for class_probability in probabilities) + "\n"
# 获取概率值最大的类别的下标Index
index = np.argmax(probabilities, axis = 0)
# 将真实标签和预测标签及对应的概率值写入到结果文件中
res_line = 'real: %s, \tpred:%s, \tscore = %.2f\n' \
%(lable_to_cate[real_label[i]], lable_to_cate[index+1], probabilities[index])
f_res.write(res_line)
writer.write(output_line)
num_written_lines += 1
if real_label[i] == (index+1):
right += 1
print('precision = %.2f' %(right / len(real_label)))
4.тонкая настройка модели
После подготовки набора данных и изменения класса данных следующим шагом будет то, какfine-tuning
Модель.
Проверятьrun_classifier.py
Входная часть файла содержит необходимые параметры, требуемые моделью тонкой настройки, а именно:
if __name__ == "__main__":
flags.mark_flag_as_required("data_dir")
flags.mark_flag_as_required("task_name")
flags.mark_flag_as_required("vocab_file")
flags.mark_flag_as_required("bert_config_file")
flags.mark_flag_as_required("output_dir")
tf.app.run()
Некоторые описания параметров
data_dir
: путь хранения данныхtask_mask
: Имя процессора, для задач классификации текста этоclassifier
vocab_file
: адрес файла словаряbert_config_file
: файл конфигурацииoutput_dir
: Выходной адрес модели
Так как необходимо установить много параметров, они единообразно размещены вш сценарийв, имяfine-tuning_classifier.sh
,Следующее:
#!/usr/bin/env bash
export BERT_BASE_DIR=/**/NLP/bert/chinese_L-12_H-768_A-12 #全局变量 下载的预训练bert地址
export MY_DATASET=/**/NLP/bert/data/text_classifition #全局变量 数据集所在地址
python run_classifier.py \
--task_name=classifier \
--do_train=true \
--do_eval=true \
--do_predict=true \
--data_dir=$MY_DATASET \
--vocab_file=$BERT_BASE_DIR/vocab.txt \
--bert_config_file=$BERT_BASE_DIR/bert_config.json \
--init_checkpoint=$BERT_BASE_DIR/bert_model.ckpt \
--max_seq_length=32 \
--train_batch_size=64 \
--learning_rate=5e-5 \
--num_train_epochs=10.0 \
--output_dir=./fine_tuning_out/text_classifier_64_epoch10_5e5
Выполнение заказа
sh ./fine-tuning_classifier.sh
Сгенерированный файл модели, вoutput_dir
каталог следующим образом:
test_labels_out.txt
Содержание следующее:
реальная: погода, пред: погода, оценка = 1.00
использоватьtensorboard
Проверятьloss
тенденции, следующим образом:
Подробнее см. в задаче на сходство текста:Введение в BERT и практика задачи на сходство китайского текста