diff --git a/.gitignore b/.gitignore index 33d8e7e..85cd2df 100644 --- a/.gitignore +++ b/.gitignore @@ -18,5 +18,19 @@ sns_violin* NewData* motor05102023.csv run.sh - -Finetuning/embeddings/all-mpnet-base-v2/* +Modelo_embedding_Mexico_Puebla/all-mpnet-base-v2/model/* +3pasos/paraphrase-multilingual-mpnet-base-v2/Sta/EvalClass.csv +3pasos/paraphrase-multilingual-mpnet-base-v2/model/* +9pasos/paraphrase-multilingual-mpnet-base-v2/Sta/EvalClass.csv +9pasos/paraphrase-multilingual-mpnet-base-v2/model/* +50pasos/paraphrase-multilingual-mpnet-base-v2/Sta/EvalClass.csv +50pasos/paraphrase-multilingual-mpnet-base-v2/model/* +100pasos/paraphrase-multilingual-mpnet-base-v2/Sta/EvalClass.csv +100pasos/paraphrase-multilingual-mpnet-base-v2/model/* +Argument/* +__pycache__/models.cpython-311.pyc +data/raw/__pycache__/models.cpython-311.pyc +Modelo_embedding_Mexico_Puebla/* +Intentionality3/index.faiss +Intentionality3/index.pkl +conf/experiment_config.json diff --git a/DownloadModels.py b/DownloadModels.py index fea9b3d..612b29c 100644 --- a/DownloadModels.py +++ b/DownloadModels.py @@ -4,12 +4,27 @@ from sentence_transformers import SentenceTransformer # el mas rapido "paraphrase-MiniLM-L3-v2" y "all-MiniLM-L6-v2" # muy rappudo y muy acertado "all-MiniLM-L12-v2" #models=["all-MiniLM-L12-v2","paraphrase-MiniLM-L3-v2" , "all-MiniLM-L6-v2", -models=["all-mpnet-base-v2","multi-qa-mpnet-base-dot-v1"] +from pathlib import Path +import json +#"paraphrase-multilingual-mpnet-base-v2",'hackathon-pln-es/paraphrase-spanish-distilroberta' +nameModel="Modelo_embedding_Mexico_Puebla_hiiamasid" +def extractConfig(nameModel="Modelo_embedding_Mexico_Puebla",relPath="./conf/experiment_config.json",dataOut="train_dataset_pos"): + configPath=Path(relPath) + with open(configPath, 'r', encoding='utf-8') as file: + config = json.load(file)[nameModel] + if dataOut is list and len(dataOut)==2: + Output= config[dataOut[0]][dataOut[1]] + else: + Output= config[dataOut] + return Output +baseModel=extractConfig(nameModel=nameModel,dataOut="base_model") +models=[baseModel] for model in models: modelST = SentenceTransformer(model) # Define the path where you want to save the model - save_path = './embeddings/%s/'%(model) + save_path = './embeddings/%s/model'%(model) + print(save_path) # Save the model modelST.save(save_path) diff --git a/data/raw/validClass.json b/data/raw/validClass.json new file mode 100644 index 0000000..f9b10fa --- /dev/null +++ b/data/raw/validClass.json @@ -0,0 +1,60 @@ +{ + "32": [ + "Necesito informar sobre un deterioro en la carretera cerca de donde vivo.", + "Quiero expresar mi preocupación acerca de un bache en la calle que está cerca de mi domicilio.", + "Estoy solicitando la atención de las autoridades para solucionar un problema vial en las inmediaciones de mi vivienda.", + "Necesito poner en conocimiento de las autoridades competentes un bache en la vía cercana a mi residencia.", + "reportar bache" + + ], + "171": [ + "¿Me podrías decir cuáles son las opciones culturales en estos días?", + "Quiero informarme sobre los eventos culturales que no me puedo perder.", + "¿Puedes recomendarme eventos culturales?", + "Estoy buscando información sobre la agenda cultural y artística de Puebla." + ], + "273": [ + "Necesito información sobre programas de educación musical para la infancia.", + "¿Puede proporcionarme detalles sobre cursos de producción de música electrónica?", + "Me gustaría saber más sobre clases de música para adultos mayores.", + "Estoy interesado en talleres de música étnica y world music." + ], + "239": [ + "Quiero indicar que un semáforo no muestra la señal de alto constante.", + "Necesito reportar un semáforo que no muestra la señal de alto intermitente.", + "Estoy interesado en notificar sobre un semáforo que presenta un mal funcionamiento general.", + "Quiero comunicar que un semáforo no muestra ninguna señal de luz." + ], + "452": [ + "Estoy aquí para alertar sobre un coche en estado de abandono.", + "Quiero comunicar que un vehículo ha sido descuidado y está estacionado.", + "Necesito reportar un vehículo sin supervisión.", + "Estoy dispuesto a dar aviso sobre un automóvil abandonado en la vía pública." + ], + "23": [ + "¿Que actividades de cine hay esta semana?", + "¿Que actividades de club de lectrura hay en puebla?", + "¿Donde puedo participar en talleres de escritura?" + ], + "1194": + ["¿Cómo llegar a la zona arqueológica de Yohualichan desde el centro de Cuetzalan?", +"¿Cuál es la mejor ruta para visitar la cascada de Apulco desde Cuetzalan?", +"¿Qué transporte recomiendan para llegar a La Gloria desde el centro de Cuetzalan?"], + "1315":[ + "quien es el alcalde de la ciudad de puebla", + "quien es el presidente municipal de puebla", + "qué estudios tiene eduardo rivera pérez", + "qué cargos ha ocupado eduardo rivera pérez", + "como se llama el presidente municipal ", + "cual es el nombre del alcalde del municipio", + "como se llama el alcalde" + +], + "0":[ + "dfjhnr9o", + "fgrrd dfgres", + "Estoy molesto", + "No funciona" + ] + + } diff --git a/dbExtractTrainModelRamdonForest.py b/dbExtractTrainModelRamdonForest.py new file mode 100644 index 0000000..6903e74 --- /dev/null +++ b/dbExtractTrainModelRamdonForest.py @@ -0,0 +1,145 @@ +from models import dbvotes,dbcopies +from sentence_transformers import SentenceTransformer +from sklearn.ensemble import RandomForestClassifier +from sklearn.model_selection import train_test_split +from sklearn.metrics import accuracy_score +import pandas as pd +from typing import List +from langchain.pydantic_v1 import BaseModel +from langchain.schema.embeddings import Embeddings +from unidecode import unidecode +from nltk.corpus import stopwords +import re +from pathlib import Path +import json +import matplotlib.pyplot as plt +import seaborn as sns +def extractConfig(nameModel="Modelo_embedding_Mexico_Puebla",relPath="./conf/experiment_config.json",dataOut="train_dataset_pos"): + configPath=Path(relPath) + with open(configPath, 'r', encoding='utf-8') as file: + config = json.load(file)[nameModel] + if type(dataOut) is list and len(dataOut)==2: + Output= config[dataOut[0]][dataOut[1]] + else: + Output= config[dataOut] + return Output + +def remove_emoji(string): + emoji_pattern = re.compile("[" + u"\U0001F600-\U0001F64F" # emoticons + u"\U0001F300-\U0001F5FF" # symbols & pictographs + u"\U0001F680-\U0001F6FF" # transport & map symbols + u"\U0001F1E0-\U0001F1FF" # flags (iOS) + u"\U00002702-\U000027B0" + u"\U000024C2-\U0001F251" + "]+", flags=re.UNICODE) + return emoji_pattern.sub(r' ', string) + +def remove_unwanted(document,stopOK=False,punctuationOK=False,xtrasOK=False, emojiOk=False, unidecodeOK=False): + if punctuationOK: + # remove punctuation + for sig in [".",",","!","¿","?","=","(",")"]: + document=document.replace(sig," ") + + if xtrasOK: + # remove user mentions + document = re.sub("@[A-Za-z0-9_]+"," ", document) + # remove URLS + document = re.sub(r'http\S+', ' ', document) + # remove hashtags + document = re.sub("#[A-Za-z0-9_]+","", document) + if emojiOk: + # remove emoji's + document = remove_emoji(document) + + #document = re.sub("[^0-9A-Za-z ]", "" , document) + # remove double spaces + #print(document) + if unidecodeOK: + document=unidecode(document) + + + if stopOK: + words=document.split(" ") + stop_words = set(stopwords.words('spanish')) + words = [w for w in words if not w in stop_words] + document=" ".join(words) + + + + document = document.replace(' ',"") + #print(document) + return document.strip().lower() + +output=[] +for row in dbvotes(dbvotes.votes.id).select(): + if int(row.vote)==1: + Sal={} + #print(row.message, row.copy_id,row.vote) + query = (dbvotes.messages.id==row.message) + messagequery = dbvotes(query).select(dbvotes.messages.ALL) + Sal["texto"]=messagequery[0].message + Sal["etiqueta"]=row.copy_id + query = (dbcopies.copies.id==row.copy_id) + copiesquery =dbcopies(query).select(dbcopies.copies.ALL) + #Sal["copy_message"]=copiesquery[0].copy_message + Sal["intentionality"]=copiesquery[0].intentionality + #print(copiesquery) + output.append(Sal) + + +df=pd.DataFrame(output) + +train_data, test_data = train_test_split(df, test_size=0.2, random_state=42) + +def loadmodelEmb(model_name = "embeddings/all-MiniLM-L6-v2",model_kwargs = {'device': 'cpu'}): + st = SentenceTransformer(model_name) + return st + +class CustomEmbedding(Embeddings, BaseModel,): + """embedding model with preprocessing""" + def _get_embedding(self,text) -> List[float]: + #print(text,"text") + text=remove_unwanted(text,punctuationOK=True,stopOK=True) + Sal=emb.encode(text) + return Sal + def embed_documents(self, texts: List[str]) -> List[List[float]]: + Sal=[] + for text in texts: + Sal.append(self._get_embedding(text)) + + return Sal + def embed_query(self, text: str) -> List[float]: + return self._get_embedding(text) + +nameModel="Modelo_embedding_Mexico_Puebla" +valid_path = extractConfig(dataOut="valid_dataset") +baseModel= extractConfig(dataOut="base_model") +with open(valid_path, 'r', encoding='utf-8') as file: + queries_Categoricos = json.load(file) +model="./%s/%s/model"%(nameModel,baseModel) + +emb=loadmodelEmb(model_name = model) +emb2=CustomEmbedding() +train_embeddings = pd.DataFrame(emb2.embed_documents(train_data['texto'].tolist())) +test_embeddings = pd.DataFrame(emb2.embed_documents(test_data['texto'].tolist())) +print(pd.DataFrame(test_embeddings)) + +rf_model = RandomForestClassifier(n_estimators=100, random_state=42) +rf_model.fit(train_embeddings, train_data['etiqueta']) + +# Hacer predicciones en el conjunto de prueba +predictions = rf_model.predict(test_embeddings) + +# Calcular la precisión +accuracy = accuracy_score(test_data['etiqueta'], predictions) +print(f'Precisión del modelo: {accuracy:.2f}') + + +# verificar características importantes +feature_importances_df = pd.DataFrame( + {"feature": list(test_embeddings.columns), "importance": rf_model.feature_importances_} +).sort_values("importance", ascending=False) + +# Mostrar +print(feature_importances_df) diff --git a/downloaddb.sh b/downloaddb.sh new file mode 100755 index 0000000..ba64fd6 --- /dev/null +++ b/downloaddb.sh @@ -0,0 +1,2 @@ +scp mgil@apollo.latinux.net:/home/jbenitez/www/py4web/apps/AngelaSmartBot/databases/storage.db ./data/raw/databases +scp mgil@apollo.latinux.net:/opt/web2py/applications/MotorAngela/databases/storage.sqlite ./data/raw/databases diff --git a/finetrainmodel.py b/finetrainmodel.py index c41eb83..353ae4b 100644 --- a/finetrainmodel.py +++ b/finetrainmodel.py @@ -53,81 +53,70 @@ model.fit(train_objectives=[(train_dataloader, train_loss)],epochs=num_epochs,wa """ from sentence_transformers import SentenceTransformer, losses, InputExample from torch.utils.data import DataLoader +from unidecode import unidecode +from pathlib import Path +import json +import os +from datetime import datetime +nameModel="Modelo_embedding_Mexico_Puebla_hiiamasid" +def extractConfig(nameModel="Modelo_embedding_Mexico_Puebla",relPath="./conf/experiment_config.json",dataOut="train_dataset_pos"): + configPath=Path(relPath) + with open(configPath, 'r', encoding='utf-8') as file: + config = json.load(file)[nameModel] + if type(dataOut) is list and len(dataOut)==2: + Output= config[dataOut[0]][dataOut[1]] + else: + Output= config[dataOut] + return Output +def saveConfig(dictionary): + pathOutfile='./%s/%s/params/'%(nameModel,baseModel) + if not os.path.exists(pathOutfile): + os.makedirs(pathOutfile) + with open(pathOutfile+"params.json", "w",encoding='utf-8') as outfile: + json.dump(dictionary, outfile) +def saveData(dictionary): + Sal={} + pathOutfile='./%s/%s/data/'%(nameModel,baseModel) + if not os.path.exists(pathOutfile): + os.makedirs(pathOutfile) + + with open(pathOutfile+"train.json", "w",encoding='utf-8') as outfile: + json.dump(dictionary, outfile) +now = datetime.now() -model="embeddings/all-mpnet-base-v2" -modelST = SentenceTransformer(model) - +entrenamiento="V_%s_%s_%s"%(now.year,now.month,now.day) +baseModel=extractConfig(nameModel=nameModel,dataOut="base_model") +trainDatasetPos=extractConfig(nameModel=nameModel,dataOut="train_dataset_pos") +model=extractConfig(nameModel=nameModel,dataOut="path_model") +modelST = SentenceTransformer(model+"/model") train_loss = losses.MultipleNegativesRankingLoss(model=modelST) +train_path = Path(trainDatasetPos) +with open(train_path, 'r', encoding='utf-8') as file: + queries_Categoricos = json.load(file) -queries=["reportar un bache en mi comunidad", - "¿Como reporto un bacheo en mi comunidad?", - "Quiero informar sobre un hoyo en la calle cerca de mi hogar.", - "Necesito reportar un bache en la vía cercana a mi residencia.", - "Estoy preocupado por un hueco en la carretera que está cerca de donde vivo.", - "Me gustaría notificar sobre un desnivel en la carretera en las inmediaciones de mi domicilio.", - "Quiero presentar una queja sobre un socavón en la vía que conduce a mi casa.", - "Estoy interesado en denunciar una irregularidad en la calle cercana a mi vivienda.", - "Necesito dar aviso sobre un problema en la carretera próxima a mi residencia.", - "Estoy observando un inconveniente en la carretera cerca de donde vivo y quisiera reportarlo.", - "Me gustaría informar sobre un obstáculo en la vía que está cerca de mi casa.", - "Quiero señalar un desperfecto en la carretera cercana a mi hogar.", - "Necesito poner en conocimiento de las autoridades un bache en la calle adyacente a mi domicilio.", - "Estoy solicitando la atención de las autoridades viales para solucionar un problema en la vía cerca de mi vivienda.", - "Me gustaría expresar mi preocupación acerca de un bache en la carretera que está cerca de donde resido.", - "Quiero dejar constancia de un deterioro en la calle cercana a mi casa.", - "Estoy interesado en informar sobre un desperfecto vial en la carretera cercana a mi hogar.", - "Necesito notificar sobre un agujero en la carretera que conduce a mi residencia.", - "Me gustaría alertar sobre un bache en la vía cerca de mi hogar.", - "Quiero dar aviso sobre un desnivel en la calle próxima a mi vivienda.", - "Estoy buscando reportar un problema vial en la carretera cercana a mi casa.", - "Necesito informar sobre un obstáculo en la vía que está cerca de mi domicilio.", - "Me gustaría señalar una irregularidad en la carretera adyacente a mi residencia.", - "Quiero presentar una queja sobre un desperfecto en la calle cercana a mi hogar.", - "Estoy interesado en denunciar un socavón en la vía que conduce a mi casa.", - "Necesito notificar sobre un inconveniente en la carretera próxima a mi residencia.", - "Me gustaría informar sobre un deterioro en la carretera cerca de donde vivo.", - "Quiero expresar mi preocupación acerca de un bache en la calle que está cerca de mi domicilio.", - "Estoy solicitando la atención de las autoridades para solucionar un problema vial en las inmediaciones de mi casa.", - "Necesito poner en conocimiento de las autoridades competentes un bache en la vía cercana a mi residencia.", - "Me gustaría alertar sobre un agujero en la carretera cerca de mi hogar.", - "Quiero notificar sobre un desnivel en la calle adyacente a mi domicilio.", - "Estoy buscando reportar un desperfecto en la carretera que está cerca de mi casa.", - "Necesito dar aviso sobre un obstáculo en la vía próxima a mi hogar.", - "Me gustaría señalar una irregularidad en la carretera cercana a mi residencia.", - "Quiero presentar una queja sobre un socavón en la vía que conduce a mi residencia.", - "Estoy interesado en denunciar un inconveniente en la carretera próxima a mi casa.", - "Necesito informar sobre un deterioro en la carretera cerca de donde vivo.", - "Quiero expresar mi preocupación acerca de un bache en la calle que está cerca de mi domicilio.", - "Estoy solicitando la atención de las autoridades para solucionar un problema vial en las inmediaciones de mi vivienda.", - "Necesito poner en conocimiento de las autoridades competentes un bache en la vía cercana a mi residencia.", - "Me gustaría alertar sobre un agujero en la carretera cerca de mi hogar.", - "Quiero notificar sobre un desnivel en la calle adyacente a mi domicilio.", - "Estoy buscando reportar un desperfecto en la carretera que está cerca de mi casa.", - "Necesito dar aviso sobre un obstáculo en la vía próxima a mi hogar.", - "Me gustaría señalar una irregularidad en la carretera cercana a mi residencia.", - "Quiero presentar una queja sobre un socavón en la vía que conduce a mi residencia.", - "Estoy interesado en denunciar un inconveniente en la carretera próxima a mi casa.", - "Necesito informar sobre un deterioro en la carretera cerca de donde vivo.", - "Quiero expresar mi preocupación acerca de un bache en la calle que está cerca de mi domicilio.", - "Estoy solicitando la atención de las autoridades para solucionar un problema vial en las inmediaciones de mi vivienda.", - "Necesito poner en conocimiento de las autoridades competentes un bache en la vía cercana a mi residencia." - ] train_examples = [] -for q in queries: - train_examples.append(InputExample(texts=[ 'Reportar un bacheo',q])) +for i in queries_Categoricos.keys(): -print(train_examples) -train_dataloader = DataLoader(train_examples, shuffle=True, batch_size=2) -print(train_dataloader) -num_epochs = 2 -warmup_steps = int(len(train_dataloader) * num_epochs * 0.1) #10% of train data + for j in queries_Categoricos[i]: + i=unidecode(i).strip().lower() + j=unidecode(j).strip().lower() + + train_examples.append(InputExample(texts=[ i,j])) -modelST.fit(train_objectives=[(train_dataloader, train_loss)],epochs=num_epochs,warmup_steps=2) -save_path = './Finetuning/%s/'%(model) -# Save the model -modelST.save(save_path) \ No newline at end of file + +train_dataloader = DataLoader(train_examples, shuffle=True, batch_size=5)#16 +print(len(train_dataloader)) +modelST.fit(train_objectives=[(train_dataloader, train_loss)],epochs=extractConfig(dataOut=["params","num_epochs"]),warmup_steps=extractConfig(dataOut=["params","warmup_steps"])) +save_path = './%s/%s/model/'%(nameModel,baseModel) +modelST.save(save_path) + +params={"entrenamiento":entrenamiento,"baseModel":baseModel} +params.update(extractConfig(dataOut="params")) +saveConfig(params) +saveData(queries_Categoricos) + diff --git a/metrics.py b/metrics.py index ffcace9..904a1cb 100644 --- a/metrics.py +++ b/metrics.py @@ -5,7 +5,7 @@ from langchain.vectorstores import FAISS from langchain.pydantic_v1 import BaseModel from langchain.schema.embeddings import Embeddings from sentence_transformers import SentenceTransformer -from scipy.spatial import distance + from typing import List import sqlite3 import pandas as pd @@ -18,13 +18,27 @@ from unidecode import unidecode from nltk.corpus import stopwords import seaborn as sns import argparse - +from scipy.spatial import distance +from pathlib import Path +import json +import os +from nltk.corpus import stopwords +import nltk parser = argparse.ArgumentParser() parser.add_argument("-f", "--file", help="Nombre de archivo a procesar") parser.add_argument("-d", "--distance", default="distance") parser.add_argument("-m", "--models", default="All") args = parser.parse_args() +def extractConfig(nameModel="Modelo_embedding_Mexico_Puebla",relPath="./conf/experiment_config.json",dataOut="train_dataset_pos"): + configPath=Path(relPath) + with open(configPath, 'r', encoding='utf-8') as file: + config = json.load(file)[nameModel] + if type(dataOut) is list and len(dataOut)==2: + Output= config[dataOut[0]][dataOut[1]] + else: + Output= config[dataOut] + return Output # if args.file: # print ("El nombre de archivo a procesar es: ", ) @@ -95,15 +109,17 @@ def loadmodelEmb(model_name = "embeddings/all-MiniLM-L6-v2",model_kwargs = {'dev st = SentenceTransformer(model_name) return st - -def loadCopysAndData(pathsqlite="motor.sqlite"): +pathsqlite=extractConfig(dataOut="pathsqlite") +def loadCopysAndData(pathsqlite=pathsqlite): con = sqlite3.connect(pathsqlite) - copies_df = pd.read_sql_query("SELECT * from copies", con) - copiesT = copies_df[copies_df.copy_start =="T"] - copiesT=copiesT[["copy_message","id","name"]] + copies_df = pd.read_sql_query("SELECT * from copies WHERE intentionality IS NOT NULL", con) + copiesT = copies_df + copiesT=copiesT[["copy_message","id","name","intentionality"]] + #print(copiesT) data = copiesT + #print(data) B=DataFrameLoader(data,page_content_column="copy_message") - B2=DataFrameLoader(data,page_content_column="name") + B2=DataFrameLoader(data,page_content_column="intentionality") documents=B.load() documents2=B2.load() return documents,documents2 @@ -114,13 +130,13 @@ def makeFaissdb(documents,folder_path,embedding): pass db = FAISS.from_documents(documents, embedding) FAISS.save_local(db,folder_path=folder_path) - return [db,folder_path] - -def FinderDbs(query,dbs,filtred=False,th=1.2): + return db +def FinderDbs(query,dbs,filtred=False,th=5000): AllData={} for dbt in dbs: Sal = dbt.similarity_search_with_score(query,4) for output in Sal: + #print(output) if output[0].metadata["id"] in AllData.keys(): AllData[output[0].metadata["id"]]["d"]=min([AllData[output[0].metadata["id"]]["d"]-0.1,output[1]-0.1]) else: @@ -131,7 +147,7 @@ def FinderDbs(query,dbs,filtred=False,th=1.2): if filtred: filtredData={} for row in AllData.keys(): - if AllData[row]["d"]<1.2: + if AllData[row]["d"]