Upload 8 files
Browse files- data2text_gl_v1/config.json +32 -0
- data2text_gl_v1/pytorch_model.bin +3 -0
- data2text_gl_v1/special_tokens_map.json +5 -0
- data2text_gl_v1/spiece.model +3 -0
- data2text_gl_v1/tokenizer_config.json +12 -0
- generate_text.py +59 -0
- test-dataset.csv +0 -0
- train.py +169 -0
data2text_gl_v1/config.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"_name_or_path": "google/mt5-base",
|
| 3 |
+
"architectures": [
|
| 4 |
+
"T5ForConditionalGeneration"
|
| 5 |
+
],
|
| 6 |
+
"d_ff": 2048,
|
| 7 |
+
"d_kv": 64,
|
| 8 |
+
"d_model": 768,
|
| 9 |
+
"decoder_start_token_id": 0,
|
| 10 |
+
"dense_act_fn": "gelu_new",
|
| 11 |
+
"dropout_rate": 0.1,
|
| 12 |
+
"eos_token_id": 1,
|
| 13 |
+
"feed_forward_proj": "gated-gelu",
|
| 14 |
+
"initializer_factor": 1.0,
|
| 15 |
+
"is_encoder_decoder": true,
|
| 16 |
+
"is_gated_act": true,
|
| 17 |
+
"layer_norm_epsilon": 1e-06,
|
| 18 |
+
"model_type": "t5",
|
| 19 |
+
"num_decoder_layers": 12,
|
| 20 |
+
"num_heads": 12,
|
| 21 |
+
"num_layers": 12,
|
| 22 |
+
"output_past": true,
|
| 23 |
+
"pad_token_id": 0,
|
| 24 |
+
"relative_attention_max_distance": 128,
|
| 25 |
+
"relative_attention_num_buckets": 32,
|
| 26 |
+
"tie_word_embeddings": false,
|
| 27 |
+
"tokenizer_class": "T5Tokenizer",
|
| 28 |
+
"torch_dtype": "float32",
|
| 29 |
+
"transformers_version": "4.24.0",
|
| 30 |
+
"use_cache": true,
|
| 31 |
+
"vocab_size": 250112
|
| 32 |
+
}
|
data2text_gl_v1/pytorch_model.bin
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:1d4df627a25b9dddc62330eb29318e77e4f9d480ce49fd0933548f023ff3bf41
|
| 3 |
+
size 2329702581
|
data2text_gl_v1/special_tokens_map.json
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"eos_token": "</s>",
|
| 3 |
+
"pad_token": "<pad>",
|
| 4 |
+
"unk_token": "<unk>"
|
| 5 |
+
}
|
data2text_gl_v1/spiece.model
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:ef78f86560d809067d12bac6c09f19a462cb3af3f54d2b8acbba26e1433125d6
|
| 3 |
+
size 4309802
|
data2text_gl_v1/tokenizer_config.json
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"additional_special_tokens": null,
|
| 3 |
+
"eos_token": "</s>",
|
| 4 |
+
"extra_ids": 0,
|
| 5 |
+
"name_or_path": "google/mt5-base",
|
| 6 |
+
"pad_token": "<pad>",
|
| 7 |
+
"sp_model_kwargs": {},
|
| 8 |
+
"special_tokens_map_file": "/home/patrick/.cache/torch/transformers/685ac0ca8568ec593a48b61b0a3c272beee9bc194a3c7241d15dcadb5f875e53.f76030f3ec1b96a8199b2593390c610e76ca8028ef3d24680000619ffb646276",
|
| 9 |
+
"tokenizer_class": "T5Tokenizer",
|
| 10 |
+
"tokenizer_file": null,
|
| 11 |
+
"unk_token": "<unk>"
|
| 12 |
+
}
|
generate_text.py
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from transformers import T5ForConditionalGeneration, T5Tokenizer, AutoTokenizer
|
| 2 |
+
import pandas as pd
|
| 3 |
+
import os
|
| 4 |
+
import nltk
|
| 5 |
+
import string
|
| 6 |
+
import math
|
| 7 |
+
import sys
|
| 8 |
+
import argparse
|
| 9 |
+
import random
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
"""# Modelo T5
|
| 13 |
+
Importamos o modelo preadestrado
|
| 14 |
+
"""
|
| 15 |
+
|
| 16 |
+
"""# Corpus
|
| 17 |
+
#J# Leemos nuestro dataset.
|
| 18 |
+
"""
|
| 19 |
+
|
| 20 |
+
test_split = pd.read_csv('./test-dataset.csv', encoding="latin-1")
|
| 21 |
+
test_split= test_split.reset_index()
|
| 22 |
+
|
| 23 |
+
def generate(text):
|
| 24 |
+
print("Tokenizing sequence...")
|
| 25 |
+
x = tokenizer(text, return_tensors='pt', padding=True).to(model.device)
|
| 26 |
+
print("Generating description...")
|
| 27 |
+
out = model.generate(**x, do_sample=False, num_beams=10, max_new_tokens = 50)
|
| 28 |
+
return tokenizer.decode(out[0], skip_special_tokens=True)
|
| 29 |
+
|
| 30 |
+
parser = argparse.ArgumentParser()
|
| 31 |
+
parser.add_argument("-i", "--input_table", type=int, default=280, required=False, help="Specify data ID")
|
| 32 |
+
parser.add_argument("-o", "--output", type=str, default="./", required=False, help="Specify output path")
|
| 33 |
+
args = parser.parse_args()
|
| 34 |
+
|
| 35 |
+
data_id = args.input_table
|
| 36 |
+
output_path = args.output
|
| 37 |
+
|
| 38 |
+
if data_id not in range(0, 569):
|
| 39 |
+
sys.exit("ERROR: ID must be in the range [0,568] (testing IDs)")
|
| 40 |
+
|
| 41 |
+
#J# cargamos el modelo pre-entrenado que queramos, junto con su tokenizador
|
| 42 |
+
print("Loading model...")
|
| 43 |
+
model = T5ForConditionalGeneration.from_pretrained('data2text_gl_v1')
|
| 44 |
+
tokenizer = T5Tokenizer.from_pretrained("data2text_gl_v1")
|
| 45 |
+
|
| 46 |
+
print("Loading data... (dataset-id: " + str(test_split.id[int(data_id)]) + ")")
|
| 47 |
+
|
| 48 |
+
data = test_split.table[int(data_id)]
|
| 49 |
+
gold = test_split.caption[int(data_id)]
|
| 50 |
+
generation = generate(data)
|
| 51 |
+
img_id = str(test_split.id[int(data_id)])
|
| 52 |
+
|
| 53 |
+
pattern = "- Test ID: {} (DB id: {})\n- Data table: {}\n- Generated text: {}\n- Gold text: {}"
|
| 54 |
+
|
| 55 |
+
print(pattern.format(data_id, img_id, data[0:100] + "... </table>", generation, gold))
|
| 56 |
+
|
| 57 |
+
with open(output_path + "generated_"+ str(data_id) + ".txt", "w") as output_file:
|
| 58 |
+
output_file.write(pattern.format(data_id, img_id, data, generation, gold))
|
| 59 |
+
output_file.close()
|
test-dataset.csv
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
train.py
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# -*- coding: utf-8 -*
|
| 2 |
+
#!pip install transformers
|
| 3 |
+
#!pip install pandas
|
| 4 |
+
#!pip install numpy
|
| 5 |
+
#!pip install SentencePiece
|
| 6 |
+
|
| 7 |
+
import sys, argparse
|
| 8 |
+
import torch
|
| 9 |
+
from transformers import T5ForConditionalGeneration, T5Tokenizer
|
| 10 |
+
import pandas as pd
|
| 11 |
+
import os
|
| 12 |
+
import numpy as np
|
| 13 |
+
from tqdm.auto import tqdm, trange
|
| 14 |
+
import gc
|
| 15 |
+
from datetime import datetime
|
| 16 |
+
import time
|
| 17 |
+
|
| 18 |
+
st = time.time() #start time
|
| 19 |
+
|
| 20 |
+
parser = argparse.ArgumentParser()
|
| 21 |
+
parser.add_argument("-n","--model_name", type=str, default="d2t_model", required=False, help="Specify model name")
|
| 22 |
+
parser.add_argument("-e","--epochs", type=int, default=100, required=False, help="Specify training epochs")
|
| 23 |
+
args = parser.parse_args()
|
| 24 |
+
|
| 25 |
+
model_name = args.model_name
|
| 26 |
+
epochs = args.epochs
|
| 27 |
+
|
| 28 |
+
print("Model name: " + model_name + " Epochs: " + str(epochs))
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
"""# Modelo T5
|
| 32 |
+
Importamos o modelo preadestrado
|
| 33 |
+
"""
|
| 34 |
+
|
| 35 |
+
model = T5ForConditionalGeneration.from_pretrained('google/mt5-base')
|
| 36 |
+
tokenizer = T5Tokenizer.from_pretrained('google/mt5-base')
|
| 37 |
+
model.cuda();
|
| 38 |
+
optimizer = torch.optim.Adam(params=[p for p in model.parameters() if p.requires_grad], lr=1e-5)
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
#Load dataset (dataset-gl.csv or dataset-es.csv)
|
| 42 |
+
all_data = pd.read_csv('./datasets/dataset-gl.csv', encoding="latin-1")
|
| 43 |
+
|
| 44 |
+
#seleccionamos 2733 registros para training (seria la particion 70-30 en dataset-es.csv)
|
| 45 |
+
#en dataset-gl.csv contamos con mas registros, por lo que en test habria 500 en lugar de 300 casos
|
| 46 |
+
|
| 47 |
+
train_split = all_data.iloc[:2733, :]
|
| 48 |
+
test_split = all_data.iloc[2733:, :]
|
| 49 |
+
|
| 50 |
+
#Clean dataset rows
|
| 51 |
+
train_split=train_split.dropna()
|
| 52 |
+
train_split=train_split.dropna(axis=0)
|
| 53 |
+
train_split=train_split.reset_index()
|
| 54 |
+
print(torch.cuda.list_gpu_processes())
|
| 55 |
+
|
| 56 |
+
def split_batches(df, batch_size):
|
| 57 |
+
batches = []
|
| 58 |
+
for i in range(0, len(df), batch_size):
|
| 59 |
+
if (i+batch_size) > len(df):
|
| 60 |
+
batches.append(df[i:])
|
| 61 |
+
else:
|
| 62 |
+
batches.append(df[i: i+batch_size])
|
| 63 |
+
return batches
|
| 64 |
+
|
| 65 |
+
|
| 66 |
+
def cleanup():
|
| 67 |
+
gc.collect()
|
| 68 |
+
torch.cuda.empty_cache()
|
| 69 |
+
|
| 70 |
+
cleanup()
|
| 71 |
+
|
| 72 |
+
optimizer.param_groups[0]['lr'] = 1e-5
|
| 73 |
+
|
| 74 |
+
"""# Adestramento"""
|
| 75 |
+
|
| 76 |
+
model.train();
|
| 77 |
+
batch_size = 8
|
| 78 |
+
max_len = 384
|
| 79 |
+
accumulation_steps = 1
|
| 80 |
+
save_steps = 1
|
| 81 |
+
epochs_tq = trange(epochs) #epochs
|
| 82 |
+
|
| 83 |
+
window = 4000
|
| 84 |
+
ewm = 0
|
| 85 |
+
errors = 0
|
| 86 |
+
|
| 87 |
+
cleanup()
|
| 88 |
+
|
| 89 |
+
batches = split_batches(train_split, batch_size)
|
| 90 |
+
|
| 91 |
+
for i in epochs_tq:
|
| 92 |
+
print("Epoch:", i)
|
| 93 |
+
batch_count = 0
|
| 94 |
+
for batch in batches:
|
| 95 |
+
batch_count += 1
|
| 96 |
+
print("Batch:", batch_count)
|
| 97 |
+
xx = batch.table.values.tolist()
|
| 98 |
+
yy = batch.table.values.tolist()
|
| 99 |
+
try:
|
| 100 |
+
x = tokenizer(xx, return_tensors='pt', padding=True, truncation=True, max_length=max_len).to(model.device)
|
| 101 |
+
y = tokenizer(yy, return_tensors='pt', padding=True, truncation=True, max_length=max_len).to(model.device)
|
| 102 |
+
# do not force the model to predict pad tokens
|
| 103 |
+
y.input_ids[y.input_ids==0] = -100
|
| 104 |
+
|
| 105 |
+
loss = model(
|
| 106 |
+
input_ids=x.input_ids,
|
| 107 |
+
attention_mask=x.attention_mask,
|
| 108 |
+
labels=y.input_ids,
|
| 109 |
+
decoder_attention_mask=y.attention_mask,
|
| 110 |
+
return_dict=True
|
| 111 |
+
).loss
|
| 112 |
+
loss.backward()
|
| 113 |
+
|
| 114 |
+
except RuntimeError as e:
|
| 115 |
+
errors += 1
|
| 116 |
+
print("ERROR")
|
| 117 |
+
print(i, x.input_ids.shape[1], y.input_ids.shape[1], e)
|
| 118 |
+
loss = None
|
| 119 |
+
cleanup()
|
| 120 |
+
continue
|
| 121 |
+
|
| 122 |
+
w = 1 / min(i+1, window)
|
| 123 |
+
ewm = ewm * (1-w) + loss.item() * w
|
| 124 |
+
epochs_tq.set_description(f'loss: {ewm}')
|
| 125 |
+
|
| 126 |
+
if i % accumulation_steps == 0:
|
| 127 |
+
optimizer.step()
|
| 128 |
+
optimizer.zero_grad()
|
| 129 |
+
cleanup()
|
| 130 |
+
|
| 131 |
+
if i % window == 0 and i > 0:
|
| 132 |
+
print(ewm, errors)
|
| 133 |
+
errors = 0
|
| 134 |
+
cleanup()
|
| 135 |
+
# optimizer.param_groups[0]['lr'] *= 0.999
|
| 136 |
+
if i % save_steps == 0 and i > 0:
|
| 137 |
+
model.save_pretrained(model_name + "_" + str(epochs))
|
| 138 |
+
tokenizer.save_pretrained(model_name + "_" + str(epochs))
|
| 139 |
+
print('saving...', i, optimizer.param_groups[0]['lr'])
|
| 140 |
+
|
| 141 |
+
model.save_pretrained(model_name + "_" + str(epochs))
|
| 142 |
+
tokenizer.save_pretrained(model_name + "_" + str(epochs))
|
| 143 |
+
|
| 144 |
+
total_time = time.time() - st
|
| 145 |
+
print("Training time:", time.strftime("%H:%M:%S", time.gmtime(total_time)))
|
| 146 |
+
|
| 147 |
+
"""# Test"""
|
| 148 |
+
model.eval();
|
| 149 |
+
|
| 150 |
+
def generate(text):
|
| 151 |
+
x = tokenizer(text, return_tensors='pt', padding=True).to(model.device)
|
| 152 |
+
out = model.generate(**x, do_sample=False, num_beams=10, max_length=100)
|
| 153 |
+
return tokenizer.decode(out[0], skip_special_tokens=True)
|
| 154 |
+
|
| 155 |
+
with open(f"{model_name}_{epochs}_predictions_{datetime.now()}.txt", "w") as f:
|
| 156 |
+
f.write("Training time:" + str(time.strftime("%H:%M:%S", time.gmtime(total_time))))
|
| 157 |
+
for index, row in test_split.iterrows():
|
| 158 |
+
text_id = str(row["id"])
|
| 159 |
+
text1 = str(row["table"])
|
| 160 |
+
text2 = str(row["caption"])
|
| 161 |
+
|
| 162 |
+
f.write(text_id + "\n" + text1 + "\n")
|
| 163 |
+
print(text_id + "\n" + text1)
|
| 164 |
+
f.write("Prediction:\n")
|
| 165 |
+
f.write(generate(text1) + "\n")
|
| 166 |
+
print(generate(text1))
|
| 167 |
+
f.write("Truth:\n")
|
| 168 |
+
f.write(text2 + "\n\n")
|
| 169 |
+
print(text2)
|