From 318c183d4879cb0ec75a0ef1b5e814959c0c20d1 Mon Sep 17 00:00:00 2001 From: saeedfirouzi Date: Sun, 9 Nov 2025 13:44:28 +0000 Subject: [PATCH] fix preprocess and add train jina --- .gitignore | 5 +- .../generate_random_negative_sample.py | 45 +++-- data_preprocess/preprocess_v1.py | 81 ++++---- data_preprocess/text_embedder.py | 2 +- requirements.txt | 3 +- .../data_loader_gholam_pquad.ipynb | 0 .../data_loader_longrag-fa.ipynb | 0 .../data_loader_miracle.ipynb | 0 .../data_preprocess}/data_loader_mldr.ipynb | 0 .../data_loader_parsinlu.ipynb | 0 .../data_loader_persianqa.ipynb | 0 .../data_loader_synthetic.ipynb | 18 ++ research_notebook/data_preprocess/test.ipynb | 168 +++++++++++++++++ research_notebook/train/train_jina.ipynb | 178 ++++++++++++++++++ train/jina/jina_train.py | 128 +++++++++++++ 15 files changed, 575 insertions(+), 53 deletions(-) rename {data_preprocess_notebook => research_notebook/data_preprocess}/data_loader_gholam_pquad.ipynb (100%) rename {data_preprocess_notebook => research_notebook/data_preprocess}/data_loader_longrag-fa.ipynb (100%) rename {data_preprocess_notebook => research_notebook/data_preprocess}/data_loader_miracle.ipynb (100%) rename {data_preprocess_notebook => research_notebook/data_preprocess}/data_loader_mldr.ipynb (100%) rename {data_preprocess_notebook => research_notebook/data_preprocess}/data_loader_parsinlu.ipynb (100%) rename {data_preprocess_notebook => research_notebook/data_preprocess}/data_loader_persianqa.ipynb (100%) rename {data_preprocess_notebook => research_notebook/data_preprocess}/data_loader_synthetic.ipynb (97%) create mode 100644 research_notebook/data_preprocess/test.ipynb create mode 100644 research_notebook/train/train_jina.ipynb create mode 100644 train/jina/jina_train.py diff --git a/.gitignore b/.gitignore index 3deb043..b5e0f9d 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,7 @@ data */__pycache__/* .env .venv -*.json \ No newline at end of file +*.json +models +*.log +research_notebook/data \ No newline at end of file diff --git a/data_preprocess/generate_random_negative_sample.py b/data_preprocess/generate_random_negative_sample.py index 722a899..570e2e9 100644 --- a/data_preprocess/generate_random_negative_sample.py +++ b/data_preprocess/generate_random_negative_sample.py @@ -1,12 +1,13 @@ import random from tqdm import tqdm import numpy as np +import faiss from data_preprocess.text_embedder import TextEmbedder -THRESHOLD_MULTIPLY = 0.9 -RANDOM_NEGATIVE_COUNT = 25 +THRESHOLD_MULTIPLY = 0.95 +RANDOM_NEGATIVE_COUNT = 6 batch_size = 100 text_embedder = TextEmbedder() @@ -21,7 +22,10 @@ def generate_random_negative_sample(all_dataset): dataset: list of dicts """ len_dataset = len(all_dataset) - all_dataset_embeddings = [{'question_embedding': "", 'passage_positive_embedding': [], 'passage_negative_embeddings': []} for _ in range(len_dataset)] + all_dataset_embeddings = [{'question_embedding': "", 'passage_positive_embedding': []} for _ in range(len_dataset)] + + all_embeddings = [] + all_texts = [] print("calculate question embeddings") # calculate question embeddings @@ -54,6 +58,8 @@ def generate_random_negative_sample(all_dataset): for id in range(i, min(i + batch_size, len_dataset)): for passage_id in range(len(all_dataset[id]['passage_positive'])): all_dataset_embeddings[id]['passage_positive_embedding'].append(passage_positive_embeddings[count]) + all_embeddings.append(passage_positive_embeddings[count]) + all_texts.append(all_dataset[id]['passage_positive'][passage_id]) count += 1 print("calculate passage negative embeddings") @@ -70,26 +76,35 @@ def generate_random_negative_sample(all_dataset): count = 0 for id in range(i, min(i + batch_size, len_dataset)): for passage_id in range(len(all_dataset[id]['passage_negative'])): - all_dataset_embeddings[id]['passage_negative_embeddings'].append(passage_negative_embeddings[count]) + all_embeddings.append(passage_negative_embeddings[count]) + all_texts.append(all_dataset[id]['passage_negative'][passage_id]) count += 1 + ############ Create FAISS index ############ + all_embeddings = np.array(all_embeddings, dtype=np.float32) + dim = all_embeddings.shape[1] + index = faiss.IndexFlatIP(dim) + faiss.normalize_L2(all_embeddings) + index.add(all_embeddings) + + ############ Get random hard negative passages ############ print("getting random negative passages") for id in tqdm(range(len_dataset)): + not_valid_passages = all_dataset[id]['passage_negative'] + all_dataset[id]['passage_positive'] question_embeddings = all_dataset_embeddings[id]['question_embedding'] + question_embeddings_normalized = np.array([question_embeddings], dtype=np.float32) + faiss.normalize_L2(question_embeddings_normalized) passage_positive_embeddings = all_dataset_embeddings[id]['passage_positive_embedding'][0] score_question_passage_positive = np.dot(question_embeddings, passage_positive_embeddings) - while len(all_dataset[id]['passage_negative_random']) < RANDOM_NEGATIVE_COUNT: - random_id = random.randint(0, len_dataset - 1) - if random_id != id: - all_passages_embedding = all_dataset_embeddings[random_id]['passage_negative_embeddings'] + all_dataset_embeddings[random_id]['passage_positive_embedding'] - all_passages = all_dataset[random_id]['passage_negative'] + all_dataset[random_id]['passage_positive'] - random_passage_id = random.randint(0, len(all_passages) - 1) - random_passage_embeddings = all_passages_embedding[random_passage_id] - score_question_random_passage = np.dot(question_embeddings, random_passage_embeddings) - - if score_question_random_passage < THRESHOLD_MULTIPLY * score_question_passage_positive: - all_dataset[id]['passage_negative_random'].append(all_passages[random_passage_id]) + num_retrieved = 30 + vector_scores, vector_ids = index.search(question_embeddings_normalized, num_retrieved) + for vector_score, vector_id in zip(vector_scores[0], vector_ids[0]): + if (all_texts[vector_id] not in not_valid_passages) and (vector_score < THRESHOLD_MULTIPLY * score_question_passage_positive): + all_dataset[id]['passage_negative_random'].append(all_texts[vector_id]) + + if len(all_dataset[id]['passage_negative_random']) >= RANDOM_NEGATIVE_COUNT: + break return all_dataset \ No newline at end of file diff --git a/data_preprocess/preprocess_v1.py b/data_preprocess/preprocess_v1.py index 1c9723a..67a0f29 100644 --- a/data_preprocess/preprocess_v1.py +++ b/data_preprocess/preprocess_v1.py @@ -90,7 +90,7 @@ def load_pquad_dataset(): return all_dataset -def remove_false_negative(dataset): +def remove_false_negative(dataset, random_negative_sample=False): """ remove false negative samples from synthetic dataset Args: @@ -98,17 +98,22 @@ def remove_false_negative(dataset): Returns: dataset: list of dicts """ + if random_negative_sample: + negative_name = "passage_negative_random" + else: + negative_name = "passage_negative" + # calculate passage negative embeddings negative_count_all = 0 negative_count_removed = 0 len_dataset = len(dataset) - batch_size = 100 + batch_size = 50 for i in tqdm(range(0, len_dataset, batch_size)): question_list = [] passage_negative_list = [] for id in range(i, min(i + batch_size, len_dataset)): - for passage in dataset[id]['passage_negative']: + for passage in dataset[id][negative_name]: question_list.append(dataset[id]['question']) passage_negative_list.append(passage) @@ -120,11 +125,11 @@ def remove_false_negative(dataset): count = 0 for id in range(i, min(i + batch_size, len_dataset)): new_negative_list = [] - for passage_id in range(len(dataset[id]['passage_negative'])): + for passage_id in range(len(dataset[id][negative_name])): if results[count] == "0": - new_negative_list.append(dataset[id]['passage_negative'][passage_id]) + new_negative_list.append(dataset[id][negative_name][passage_id]) count += 1 - dataset[id]['passage_negative'] = new_negative_list + dataset[id][negative_name] = new_negative_list print(f"removed {negative_count_removed} false negative samples from {negative_count_all} samples") print("--------------------------------") @@ -145,40 +150,40 @@ def save_dataset(dataset, output_path): def main(output_path): - #load synthetic dataset - print("--------------------------------") - print("loading synthetic dataset") - synthetic_train_path = "/home/firouzi/embedding_model/data_preprocess_notebook/data/synthetic-persian-qa-retrieval/train.jsonl" - synthetic_corpus_path = "/home/firouzi/embedding_model/data_preprocess_notebook/data/synthetic-persian-qa-retrieval/corpus.jsonl" - synthetic_queries_path = "/home/firouzi/embedding_model/data_preprocess_notebook/data/synthetic-persian-qa-retrieval/queries.jsonl" + # #load synthetic dataset + # print("--------------------------------") + # print("loading synthetic dataset") + # synthetic_train_path = "/home/firouzi/embedding_model/data_preprocess_notebook/data/synthetic-persian-qa-retrieval/train.jsonl" + # synthetic_corpus_path = "/home/firouzi/embedding_model/data_preprocess_notebook/data/synthetic-persian-qa-retrieval/corpus.jsonl" + # synthetic_queries_path = "/home/firouzi/embedding_model/data_preprocess_notebook/data/synthetic-persian-qa-retrieval/queries.jsonl" - synthetic_dataset = load_synthetic_dataset(synthetic_train_path, synthetic_queries_path, synthetic_corpus_path) - print(f"synthetic dataset loaded : {len(synthetic_dataset)} samples") - print("--------------------------------") + # synthetic_dataset = load_synthetic_dataset(synthetic_train_path, synthetic_queries_path, synthetic_corpus_path) + # print(f"synthetic dataset loaded : {len(synthetic_dataset)} samples") + # print("--------------------------------") - #load pquad dataset - print("loading pquad dataset") - pquad_dataset = load_pquad_dataset() - print(f"pquad dataset loaded : {len(pquad_dataset)} samples") - print("--------------------------------") + # #load pquad dataset + # print("loading pquad dataset") + # pquad_dataset = load_pquad_dataset() + # print(f"pquad dataset loaded : {len(pquad_dataset)} samples") + # print("--------------------------------") - # removing false negative samples from synthetic dataset - print("start to remove false negative samples from synthetic dataset") - synthetic_dataset = remove_false_negative(synthetic_dataset) - print(f"successfully removed false negative samples from synthetic dataset") - print("--------------------------------") + # # merge synthetic and pquad dataset + # print("start to merge synthetic and pquad dataset") + # all_dataset = synthetic_dataset + pquad_dataset + # print(f"successfully merged synthetic and pquad dataset") + # print("--------------------------------") - # removing false negative samples from pquad dataset - print("start to remove false negative samples from pquad dataset") - pquad_dataset = remove_false_negative(pquad_dataset) - print(f"successfully removed false negative samples from pquad dataset") - print("--------------------------------") + # # removing false negative samples from all dataset + # print("start to remove false negative samples from all dataset") + # all_dataset = remove_false_negative(all_dataset, random_negative_sample=False) + # print(f"successfully removed false negative samples from all dataset") + # print("--------------------------------") - # merge synthetic and pquad dataset - print("start to merge synthetic and pquad dataset") - all_dataset = synthetic_dataset + pquad_dataset - print(f"successfully merged synthetic and pquad dataset") - print("--------------------------------") + with open("/home/firouzi/embedding_model/data/train.json", "r", encoding="utf-8") as f: + all_dataset = json.load(f) + + for i in range(len(all_dataset)): + all_dataset[i]['passage_negative_random'] = [] #generate random negative samples print("start to generate random negative samples") @@ -186,6 +191,12 @@ def main(output_path): print(f"successfully generated random negative samples") print("--------------------------------") + # removing random false negative samples from all dataset + print("start to remove random false negative samples from all dataset") + all_dataset = remove_false_negative(all_dataset, random_negative_sample=True) + print(f"successfully removed random false negative samples from all dataset") + print("--------------------------------") + # save dataset print("start to save dataset") save_dataset(all_dataset, output_path) diff --git a/data_preprocess/text_embedder.py b/data_preprocess/text_embedder.py index cab6f41..a6df636 100644 --- a/data_preprocess/text_embedder.py +++ b/data_preprocess/text_embedder.py @@ -34,7 +34,7 @@ class TextEmbedder: "input": texts } responses = requests.post("http://78.38.161.78:3094/v1/embeddings", headers=self.headers, json=payload) - embeddings = [np.array(response["embedding"]) for response in responses.json()["data"]] + embeddings = [np.array(response["embedding"], dtype=np.float32) for response in responses.json()["data"]] return embeddings \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index cb65d71..12f88f9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,3 @@ python-dotenv==1.1.1 -hazm \ No newline at end of file +hazm +faiss-cpu \ No newline at end of file diff --git a/data_preprocess_notebook/data_loader_gholam_pquad.ipynb b/research_notebook/data_preprocess/data_loader_gholam_pquad.ipynb similarity index 100% rename from data_preprocess_notebook/data_loader_gholam_pquad.ipynb rename to research_notebook/data_preprocess/data_loader_gholam_pquad.ipynb diff --git a/data_preprocess_notebook/data_loader_longrag-fa.ipynb b/research_notebook/data_preprocess/data_loader_longrag-fa.ipynb similarity index 100% rename from data_preprocess_notebook/data_loader_longrag-fa.ipynb rename to research_notebook/data_preprocess/data_loader_longrag-fa.ipynb diff --git a/data_preprocess_notebook/data_loader_miracle.ipynb b/research_notebook/data_preprocess/data_loader_miracle.ipynb similarity index 100% rename from data_preprocess_notebook/data_loader_miracle.ipynb rename to research_notebook/data_preprocess/data_loader_miracle.ipynb diff --git a/data_preprocess_notebook/data_loader_mldr.ipynb b/research_notebook/data_preprocess/data_loader_mldr.ipynb similarity index 100% rename from data_preprocess_notebook/data_loader_mldr.ipynb rename to research_notebook/data_preprocess/data_loader_mldr.ipynb diff --git a/data_preprocess_notebook/data_loader_parsinlu.ipynb b/research_notebook/data_preprocess/data_loader_parsinlu.ipynb similarity index 100% rename from data_preprocess_notebook/data_loader_parsinlu.ipynb rename to research_notebook/data_preprocess/data_loader_parsinlu.ipynb diff --git a/data_preprocess_notebook/data_loader_persianqa.ipynb b/research_notebook/data_preprocess/data_loader_persianqa.ipynb similarity index 100% rename from data_preprocess_notebook/data_loader_persianqa.ipynb rename to research_notebook/data_preprocess/data_loader_persianqa.ipynb diff --git a/data_preprocess_notebook/data_loader_synthetic.ipynb b/research_notebook/data_preprocess/data_loader_synthetic.ipynb similarity index 97% rename from data_preprocess_notebook/data_loader_synthetic.ipynb rename to research_notebook/data_preprocess/data_loader_synthetic.ipynb index 84448be..48d6889 100644 --- a/data_preprocess_notebook/data_loader_synthetic.ipynb +++ b/research_notebook/data_preprocess/data_loader_synthetic.ipynb @@ -271,6 +271,24 @@ "id": "4917b3a0", "metadata": {}, "outputs": [], + "source": [ + "import faiss\n", + "import numpy as np\n", + "\n", + "\n", + "x = np.array([1, 2, 3, 4, 5])\n", + "\n", + "faiss.normalize_L2(x)\n", + "\n", + "print(x)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ea9dcd98", + "metadata": {}, + "outputs": [], "source": [] } ], diff --git a/research_notebook/data_preprocess/test.ipynb b/research_notebook/data_preprocess/test.ipynb new file mode 100644 index 0000000..17e0371 --- /dev/null +++ b/research_notebook/data_preprocess/test.ipynb @@ -0,0 +1,168 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 2, + "id": "96240870", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "سیاراتی که در مدار نزدیک به ستاره های کوتوله سرخ قرار دارند، به دلیل نزدیکی به ستاره مادر، تحت تابش تشعشعات شدید قرار می گیرند. این تابش می تواند شرایط زیست محیطی را به شدت تحت تأثیر قرار دهد و ممکن است تنها مکان هایی که حیات در آنجا امکان وجود دارد، زیر لایه های ضخیم یخ باشد. این شرایط می تواند مانع از شکل گیری و تکامل حیات در سطح سیاره شود.\n", + "{\"result\": \"0\"}\n", + "--------------------------------\n", + "کتاب تابستان به دلیل داستان جذاب و توصیف‌های زیبا از طبیعت و زندگی، توجه تمام علاقه‌مندان به ادبیات داستانی را به خود جلب می‌کند. این کتاب نه تنها احساسات عمیق انسانی را به تصویر می‌کشد بلکه خواننده را به دنیای خاطرات شیرین تابستان‌های کودکی می‌برد.\n", + "{{\"result\": \"0\"}}\n", + "\n", + "--------------------------------\n", + "حضرت ادریس علیه السلام به عنوان منشاء و معلم بسیاری از علوم شناخته می‌شود. او به عنوان یکی از قدیمی‌ترین پیشوایان علم، افکار بشر را به سمت استدلال و دقت در بحث سوق داده است. همچنین، او اولین کسی است که علم نجوم را به الهام الهی استخراج کرده و زمین را به چهار ربع تقسیم نموده است. در دعای روز اول ماه رجب نیز به علم ادریس اشاره شده است.\n", + "{\"result\": \"0\"}\n", + "--------------------------------\n", + "ستاره‌های کوتوله سرخ معمولاً به صورت دوره‌ای شعله‌هایی از پرتوهای ماورا بنفش و اشعه X ساطع می‌کنند که می‌تواند اتمسفر سیارات اطراف را از بین ببرد و احتمال تشکیل حیات را کاهش دهد. اما ستاره Ross 128 به عنوان یک ستاره آرام شناخته می‌شود و این ویژگی باعث می‌شود که شرایط بهتری برای تشکیل حیات در سیاره Ross 128b فراهم شود.\n", + "{\"result\": \"0\"}\n", + "--------------------------------\n", + "پوست کودکان به دلیل عدم تکامل کامل ملانوسیت‌ها، سیستم عروقی پوستی و توانایی تولید عرق حساس است. ملانوسیت‌ها که مسئول تولید ملانین هستند، از پوست در برابر اشعه ماورای بنفش محافظت می‌کنند. همچنین، سیستم عروقی پوستی در کودکان هنوز به طور کامل توسعه نیافته و این امر می‌تواند منجر به آسیب‌پذیری بیشتر پوست شود. علاوه بر این، پوست کودکان نمی‌تواند به اندازه کافی عرق تولید کند، که باعث می‌شود رطوبت پوست کاهش یابد. به همین دلیل، پوست کودکان به ویژه نوزادان به نسبت وزن بدن در معرض آسیب بیشتری قرار دارد.\n", + "{\"result\": \"0\"}\n", + "--------------------------------\n", + "نزول این آیه به واکنش‌های معاصرین پیامبر اسلام، به ویژه ابوجهل و دیگر مخالفان، اشاره دارد که به دلیل عدم درک صحیح از معانی عمیق آیات و قدرت خداوند، به تمسخر و انکار آن می‌پرداختند. این آیه به نوعی به آنها پاسخ می‌دهد و نشان می‌دهد که حتی در آتش، درختی وجود دارد که فراتر از تصور آنهاست. این واکنش‌ها نشان‌دهنده چالش‌های اعتقادی و فکری در آن زمان بود.\n", + "{\"result\": \"0\"}\n", + "--------------------------------\n", + "شرایط محیطی می‌تواند به عنوان فیلتر عمل کند زیرا عوامل متعددی مانند مقدار و نوع کالری، دما، اتمسفر، آب، خشکی، آفتاب، و بلایای طبیعی مانند آتشفشان و زلزله بر روی موجودات زنده تأثیر می‌گذارد. این عوامل می‌توانند موجودات را به چالش بکشند و تنها آن‌هایی که توانایی سازگاری با این شرایط را دارند، زنده می‌مانند و به نسل‌های بعدی منتقل می‌شوند.\n", + "{\"result\": \"0\"}\n", + "\n", + "--------------------------------\n", + "خشکی پوست ممکن است موقتی یا فصلی باشد. به عنوان مثال، در فصل زمستان به دلیل هوای سرد و خشک، بسیاری از افراد دچار خشکی پوست می‌شوند. در مقابل، در فصل‌های گرم و مرطوب، ممکن است این مشکل کاهش یابد. با این حال، برخی افراد ممکن است به طور دائمی با خشکی پوست مواجه باشند که نیاز به مراقبت و درمان مداوم دارد.\n", + "{\"result\": \"0\"}\n", + "--------------------------------\n", + "سحابی خرچنگ دریایی، که با نام NGC 6357 شناخته می‌شود، به دلیل وجود ستاره‌های غیرمعمول روشن و عظیم در آن، به عنوان یک مکان مهم در کهکشان معرفی می‌شود. این سحابی همچنین خوشۀ ستاره‌ای باز Pismis 24 را در نزدیکی مرکز خود دارد که نشان‌دهنده فعالیت‌های شدید ستاره‌زایی در این ناحیه است. درخشش آبی در نزدیکی منطقه تشکیل ستاره داخلی ناشی از انتشار گاز هیدروژن یونیزه است که به جذابیت این سحابی افزوده است.\n", + "{\"result\": \"0\"}\n", + "--------------------------------\n", + "سحابی خرچنگ ده سال نوری وسعت دارد و در مرکز آن یک تپ اختر قرار دارد. این تپ اختر به سنگینی خورشید اما به اندازه یک شهر کوچک است و ثانیه‌ای سی بار به دور خود می‌چرخد. همچنین، سحابی خرچنگ با سرعتی حدود 10000 کیلومتر بر ثانیه منبسط می‌شود و انتظار می‌رود که در چند هزار سال آینده به تدریج کم‌فروغ‌تر شده و سرانجام ناپدید گردد.\n", + "{\"result\": \"0\"}\n", + "--------------------------------\n", + "وجود یک اقیانوس زیر سطحی در قمر اروپا می تواند شرایط لازم برای زندگی موجودات میکروسکوپی را فراهم کند. این اقیانوس می تواند شامل مواد مغذی و حرارت لازم برای حیات باشد. با توجه به اینکه بخار آب فوران شده از سطح اروپا ممکن است به این اقیانوس مرتبط باشد، بررسی های آینده می تواند به دانشمندان کمک کند تا پتانسیل اروپا برای تبدیل شدن به یک محل قابل سکونت را بدون نیاز به حفاری لایه یخ بررسی کنند.\n", + "{{\"result\": \"0\"}}\n", + "--------------------------------\n", + "چگالش بوز-اینشتین حالتی از ماده است که در دماهای بسیار پایین ایجاد می‌شود و در آن اتم‌ها رفتار موجی خود را نشان می‌دهند. در این حالت، قوانین فیزیک کلاسیک به کنار می‌روند و فیزیک کوانتومی حاکم می‌شود. اتم‌ها در این حالت به گونه‌ای حرکت می‌کنند که انگار بر روی یکدیگر سوار هستند و این رفتار تنها در دماهای بسیار پایین قابل مشاهده است.\n", + "{\"result\": \"0\"}\n", + "--------------------------------\n", + "در سال 2012، انجمن سلطنتی شیمی مسابقه‌ای را برای یافتن بهترین توضیح برای اثر امپمبا برگزار کرد. برنده این مسابقه نظریه‌ای را ارائه داد که علت این پدیده را 'ابرسرد شدن' می‌دانست. این نشان می‌دهد که این موضوع همچنان مورد توجه محققان و دانشمندان است و تلاش‌ها برای درک بهتر آن ادامه دارد.\n", + "{\"result\": \"0\"}\n", + "--------------------------------\n", + "داستان کتاب عاشق آتشفشان در قرن هجدهم و در میان آشفتگی‌های دربار ناپلی اتفاق می‌افتد. این رمان به بررسی موضوعاتی چون عشق، تاریخ و روابط اجتماعی می‌پردازد و داستان زندگی سر ویلیام همیلتون و همسرش اِما را روایت می‌کند. همچنین، این داستان به تحولات سیاسی و اجتماعی آن زمان نیز اشاره دارد.\n", + "{\"result\": \"0\"}\n", + "--------------------------------\n", + "انفجارهای هوایی به دلیل قدرت تخریب بالای خود و نادر بودن برخورد سیارک‌ها، خطرناک‌تر محسوب می‌شوند. در حالی که برخورد سیارک‌های بزرگ به ندرت اتفاق می‌افتد، انفجارهای هوایی می‌توانند به طور ناگهانی و بدون هشدار پیشین رخ دهند. به عنوان مثال، انفجار سیارکی به اندازه یک خانه در سال ۱۳۹۲ در چلیابینسک روسیه منجر به آسیب دیدن بیش از ۱۶۰۰ نفر شد. این نشان می‌دهد که انفجارهای هوایی می‌توانند تأثیرات جدی بر روی جمعیت‌های انسانی داشته باشند.\n", + "{\"result\": \"0\"}\n", + "--------------------------------\n", + "پرتقال به دلیل خواص ضدعفونی‌کننده و ضد میکروبی که دارد، می‌تواند به درمان مشکلات پوستی کمک کند. به عنوان مثال، شما می‌توانید از پوست پرتقال له شده به عنوان مرهم برای اگزما و ناراحتی‌های پوستی استفاده کنید. این خاصیت به دلیل وجود ترکیبات طبیعی در پوست پرتقال است که به تسکین و بهبود وضعیت پوست کمک می‌کند.\n", + "{{\"result\": \"0\"}}\n", + "--------------------------------\n", + "نوسانات درخشندگی ستاره KIC 8462852 به‌طور نامنظم و شدید اتفاق می‌افتند و این الگو با آنچه معمولاً در ستاره‌های دارای سیارات فراخورشیدی مشاهده می‌شود، متفاوت است. در حالی که وجود یک سیاره می‌تواند باعث نوسانات درخشندگی شود، در این مورد، نوسانات به‌قدری پیچیده و غیرقابل پیش‌بینی هستند که فرضیه‌های دیگر مانند وجود ابرهای میان ستاره‌ای، دنباله‌دارها یا حتی اَبَرسازه‌های بیگانگان فضایی نیز مطرح شده‌اند.\n", + "{\"result\": \"0\"}\n", + "--------------------------------\n", + "پاریس به عنوان یک مقصد گردشگری محبوب به دلیل جاذبه‌های تاریخی، فرهنگی و هنری خود شناخته می‌شود. این شهر با برج ایفل، موزه لوور، کاتدرال نوتردام و خیابان‌های زیبا و پر از زندگی، هر ساله میلیون‌ها گردشگر را به خود جذب می‌کند. همچنین، فرهنگ غنی، غذاهای لذیذ و فضاهای رمانتیک پاریس، تجربه‌ای منحصر به فرد را برای بازدیدکنندگان فراهم می‌آورد. به همین دلیل، پاریس به عنوان 'شهر نور' و 'شهر عشق' در قلب بسیاری از مردم جهان جای دارد.\n", + "{\"result\": \"0\"}\n", + "--------------------------------\n" + ] + } + ], + "source": [ + "import requests\n", + "from dotenv import load_dotenv\n", + "import os\n", + "import re\n", + "\n", + "load_dotenv()\n", + "\n", + "qwen = False\n", + "if qwen:\n", + " url = \"https://qwen3.chatllm.aiengines.ir/v1/chat/completions\"\n", + " model = \"Qwen/Qwen3-4B-Instruct-2507\"\n", + " headers = {\"Content-Type\": \"application/json\", \"Authorization\": f\"Bearer {os.getenv('LLM_AS_RERANKER_PASS')}\"}\n", + "else:\n", + " url = \"http://192.168.130.206:4001/v1/chat/completions\"\n", + " model = \"google/gemma-3-27b-it\"\n", + " headers = {\"Content-Type\": \"application/json\"}\n", + "\n", + "instruction = \"\"\"\n", + "You are a helpful assistant that help me to find that the text is relevant to the question or not.\n", + "You are given a question and a text.\n", + "You must evaluate the text based on the question and return \"1\" if the text is relevant to the question and \"0\" if the text is not relevant to the question.\n", + " \n", + "be carefull, I have chosen the text randomly from my dataset so the text must answer the question independently.\n", + "You must return the result in the following format:\n", + "{{\"result\": \"1\" or \"0\"}}\n", + "\"\"\"\n", + "\n", + "question = \"چرا خورشید اینقدر داغ است؟\"\n", + "texts = [\n", + " \"سیاراتی که در مدار نزدیک به ستاره های کوتوله سرخ قرار دارند، به دلیل نزدیکی به ستاره مادر، تحت تابش تشعشعات شدید قرار می گیرند. این تابش می تواند شرایط زیست محیطی را به شدت تحت تأثیر قرار دهد و ممکن است تنها مکان هایی که حیات در آنجا امکان وجود دارد، زیر لایه های ضخیم یخ باشد. این شرایط می تواند مانع از شکل گیری و تکامل حیات در سطح سیاره شود.\",\n", + " \"کتاب تابستان به دلیل داستان جذاب و توصیف‌های زیبا از طبیعت و زندگی، توجه تمام علاقه‌مندان به ادبیات داستانی را به خود جلب می‌کند. این کتاب نه تنها احساسات عمیق انسانی را به تصویر می‌کشد بلکه خواننده را به دنیای خاطرات شیرین تابستان‌های کودکی می‌برد.\",\n", + " \"حضرت ادریس علیه السلام به عنوان منشاء و معلم بسیاری از علوم شناخته می‌شود. او به عنوان یکی از قدیمی‌ترین پیشوایان علم، افکار بشر را به سمت استدلال و دقت در بحث سوق داده است. همچنین، او اولین کسی است که علم نجوم را به الهام الهی استخراج کرده و زمین را به چهار ربع تقسیم نموده است. در دعای روز اول ماه رجب نیز به علم ادریس اشاره شده است.\",\n", + " \"ستاره‌های کوتوله سرخ معمولاً به صورت دوره‌ای شعله‌هایی از پرتوهای ماورا بنفش و اشعه X ساطع می‌کنند که می‌تواند اتمسفر سیارات اطراف را از بین ببرد و احتمال تشکیل حیات را کاهش دهد. اما ستاره Ross 128 به عنوان یک ستاره آرام شناخته می‌شود و این ویژگی باعث می‌شود که شرایط بهتری برای تشکیل حیات در سیاره Ross 128b فراهم شود.\",\n", + " \"پوست کودکان به دلیل عدم تکامل کامل ملانوسیت‌ها، سیستم عروقی پوستی و توانایی تولید عرق حساس است. ملانوسیت‌ها که مسئول تولید ملانین هستند، از پوست در برابر اشعه ماورای بنفش محافظت می‌کنند. همچنین، سیستم عروقی پوستی در کودکان هنوز به طور کامل توسعه نیافته و این امر می‌تواند منجر به آسیب‌پذیری بیشتر پوست شود. علاوه بر این، پوست کودکان نمی‌تواند به اندازه کافی عرق تولید کند، که باعث می‌شود رطوبت پوست کاهش یابد. به همین دلیل، پوست کودکان به ویژه نوزادان به نسبت وزن بدن در معرض آسیب بیشتری قرار دارد.\",\n", + " \"نزول این آیه به واکنش‌های معاصرین پیامبر اسلام، به ویژه ابوجهل و دیگر مخالفان، اشاره دارد که به دلیل عدم درک صحیح از معانی عمیق آیات و قدرت خداوند، به تمسخر و انکار آن می‌پرداختند. این آیه به نوعی به آنها پاسخ می‌دهد و نشان می‌دهد که حتی در آتش، درختی وجود دارد که فراتر از تصور آنهاست. این واکنش‌ها نشان‌دهنده چالش‌های اعتقادی و فکری در آن زمان بود.\",\n", + " \"شرایط محیطی می‌تواند به عنوان فیلتر عمل کند زیرا عوامل متعددی مانند مقدار و نوع کالری، دما، اتمسفر، آب، خشکی، آفتاب، و بلایای طبیعی مانند آتشفشان و زلزله بر روی موجودات زنده تأثیر می‌گذارد. این عوامل می‌توانند موجودات را به چالش بکشند و تنها آن‌هایی که توانایی سازگاری با این شرایط را دارند، زنده می‌مانند و به نسل‌های بعدی منتقل می‌شوند.\",\n", + " \"خشکی پوست ممکن است موقتی یا فصلی باشد. به عنوان مثال، در فصل زمستان به دلیل هوای سرد و خشک، بسیاری از افراد دچار خشکی پوست می‌شوند. در مقابل، در فصل‌های گرم و مرطوب، ممکن است این مشکل کاهش یابد. با این حال، برخی افراد ممکن است به طور دائمی با خشکی پوست مواجه باشند که نیاز به مراقبت و درمان مداوم دارد.\",\n", + " \"سحابی خرچنگ دریایی، که با نام NGC 6357 شناخته می‌شود، به دلیل وجود ستاره‌های غیرمعمول روشن و عظیم در آن، به عنوان یک مکان مهم در کهکشان معرفی می‌شود. این سحابی همچنین خوشۀ ستاره‌ای باز Pismis 24 را در نزدیکی مرکز خود دارد که نشان‌دهنده فعالیت‌های شدید ستاره‌زایی در این ناحیه است. درخشش آبی در نزدیکی منطقه تشکیل ستاره داخلی ناشی از انتشار گاز هیدروژن یونیزه است که به جذابیت این سحابی افزوده است.\",\n", + " \"سحابی خرچنگ ده سال نوری وسعت دارد و در مرکز آن یک تپ اختر قرار دارد. این تپ اختر به سنگینی خورشید اما به اندازه یک شهر کوچک است و ثانیه‌ای سی بار به دور خود می‌چرخد. همچنین، سحابی خرچنگ با سرعتی حدود 10000 کیلومتر بر ثانیه منبسط می‌شود و انتظار می‌رود که در چند هزار سال آینده به تدریج کم‌فروغ‌تر شده و سرانجام ناپدید گردد.\",\n", + " \"وجود یک اقیانوس زیر سطحی در قمر اروپا می تواند شرایط لازم برای زندگی موجودات میکروسکوپی را فراهم کند. این اقیانوس می تواند شامل مواد مغذی و حرارت لازم برای حیات باشد. با توجه به اینکه بخار آب فوران شده از سطح اروپا ممکن است به این اقیانوس مرتبط باشد، بررسی های آینده می تواند به دانشمندان کمک کند تا پتانسیل اروپا برای تبدیل شدن به یک محل قابل سکونت را بدون نیاز به حفاری لایه یخ بررسی کنند.\",\n", + " \"چگالش بوز-اینشتین حالتی از ماده است که در دماهای بسیار پایین ایجاد می‌شود و در آن اتم‌ها رفتار موجی خود را نشان می‌دهند. در این حالت، قوانین فیزیک کلاسیک به کنار می‌روند و فیزیک کوانتومی حاکم می‌شود. اتم‌ها در این حالت به گونه‌ای حرکت می‌کنند که انگار بر روی یکدیگر سوار هستند و این رفتار تنها در دماهای بسیار پایین قابل مشاهده است.\",\n", + " \"در سال 2012، انجمن سلطنتی شیمی مسابقه‌ای را برای یافتن بهترین توضیح برای اثر امپمبا برگزار کرد. برنده این مسابقه نظریه‌ای را ارائه داد که علت این پدیده را 'ابرسرد شدن' می‌دانست. این نشان می‌دهد که این موضوع همچنان مورد توجه محققان و دانشمندان است و تلاش‌ها برای درک بهتر آن ادامه دارد.\",\n", + " \"داستان کتاب عاشق آتشفشان در قرن هجدهم و در میان آشفتگی‌های دربار ناپلی اتفاق می‌افتد. این رمان به بررسی موضوعاتی چون عشق، تاریخ و روابط اجتماعی می‌پردازد و داستان زندگی سر ویلیام همیلتون و همسرش اِما را روایت می‌کند. همچنین، این داستان به تحولات سیاسی و اجتماعی آن زمان نیز اشاره دارد.\",\n", + " \"انفجارهای هوایی به دلیل قدرت تخریب بالای خود و نادر بودن برخورد سیارک‌ها، خطرناک‌تر محسوب می‌شوند. در حالی که برخورد سیارک‌های بزرگ به ندرت اتفاق می‌افتد، انفجارهای هوایی می‌توانند به طور ناگهانی و بدون هشدار پیشین رخ دهند. به عنوان مثال، انفجار سیارکی به اندازه یک خانه در سال ۱۳۹۲ در چلیابینسک روسیه منجر به آسیب دیدن بیش از ۱۶۰۰ نفر شد. این نشان می‌دهد که انفجارهای هوایی می‌توانند تأثیرات جدی بر روی جمعیت‌های انسانی داشته باشند.\",\n", + " \"پرتقال به دلیل خواص ضدعفونی‌کننده و ضد میکروبی که دارد، می‌تواند به درمان مشکلات پوستی کمک کند. به عنوان مثال، شما می‌توانید از پوست پرتقال له شده به عنوان مرهم برای اگزما و ناراحتی‌های پوستی استفاده کنید. این خاصیت به دلیل وجود ترکیبات طبیعی در پوست پرتقال است که به تسکین و بهبود وضعیت پوست کمک می‌کند.\",\n", + " \"نوسانات درخشندگی ستاره KIC 8462852 به‌طور نامنظم و شدید اتفاق می‌افتند و این الگو با آنچه معمولاً در ستاره‌های دارای سیارات فراخورشیدی مشاهده می‌شود، متفاوت است. در حالی که وجود یک سیاره می‌تواند باعث نوسانات درخشندگی شود، در این مورد، نوسانات به‌قدری پیچیده و غیرقابل پیش‌بینی هستند که فرضیه‌های دیگر مانند وجود ابرهای میان ستاره‌ای، دنباله‌دارها یا حتی اَبَرسازه‌های بیگانگان فضایی نیز مطرح شده‌اند.\",\n", + " \"پاریس به عنوان یک مقصد گردشگری محبوب به دلیل جاذبه‌های تاریخی، فرهنگی و هنری خود شناخته می‌شود. این شهر با برج ایفل، موزه لوور، کاتدرال نوتردام و خیابان‌های زیبا و پر از زندگی، هر ساله میلیون‌ها گردشگر را به خود جذب می‌کند. همچنین، فرهنگ غنی، غذاهای لذیذ و فضاهای رمانتیک پاریس، تجربه‌ای منحصر به فرد را برای بازدیدکنندگان فراهم می‌آورد. به همین دلیل، پاریس به عنوان 'شهر نور' و 'شهر عشق' در قلب بسیاری از مردم جهان جای دارد.\"\n", + " ]\n", + " \n", + "for text in texts:\n", + " input_message = f\"\"\"{{\"question\": \"{question}\", \"text\": \"{text}\"}}\"\"\"\n", + " messages = [{\"role\": \"system\", \"content\": instruction}, {\"role\": \"user\", \"content\": input_message}]\n", + "\n", + " payload = {\n", + " \"model\": model,\n", + " \"messages\": messages,\n", + " \"max_tokens\": 100\n", + " }\n", + "\n", + " req = requests.post(url, headers=headers, json=payload)\n", + " print(text)\n", + " print(req.json()['choices'][0]['message']['content'])\n", + " print(\"--------------------------------\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "53e5e322", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/research_notebook/train/train_jina.ipynb b/research_notebook/train/train_jina.ipynb new file mode 100644 index 0000000..d49be08 --- /dev/null +++ b/research_notebook/train/train_jina.ipynb @@ -0,0 +1,178 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "16798408", + "metadata": {}, + "outputs": [], + "source": [ + "import json\n", + "\n", + "with open(\"/home/firouzi/embedding_model/data/train_100.json\", \"r\", encoding=\"utf-8\") as f:\n", + " all_dataset = json.load(f)\n", + "\n", + "data_count = []\n", + "for data in all_dataset:\n", + " data_count.append(len(data[\"passage_negative\"]) + len(data[\"passage_negative_random\"]))\n", + "\n", + "\n", + "counts = {}\n", + "\n", + "for num in data_count:\n", + " if num in counts:\n", + " counts[num] += 1\n", + " else:\n", + " counts[num] = 1" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "a0eb428f", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{8: 22, 6: 11, 7: 20, 9: 46, 5: 1}" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "counts" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "ca0412d2", + "metadata": {}, + "outputs": [], + "source": [ + "from datasets import Dataset\n", + "\n", + "with open(\"/home/firouzi/embedding_model/data/train_100.json\", \"r\", encoding=\"utf-8\") as f:\n", + " all_dataset = json.load(f)\n", + "\n", + "anchors = []\n", + "positives = []\n", + "negatives_1 = []\n", + "negatives_2 = []\n", + "negatives_3 = []\n", + "negatives_4 = []\n", + "negatives_5 = []\n", + "for data in all_dataset:\n", + " anchors.append(data[\"question\"])\n", + " positives.append(data[\"passage_positive\"])\n", + " all_negatives = data[\"passage_negative\"] + data[\"passage_negative_random\"]\n", + " if len(all_negatives) < 5:\n", + " for i in range(5 - len(all_negatives)):\n", + " all_negatives.append(all_negatives[0])\n", + " negatives_1.append(all_negatives[0])\n", + " negatives_2.append(all_negatives[1])\n", + " negatives_3.append(all_negatives[2])\n", + " negatives_4.append(all_negatives[3])\n", + " negatives_5.append(all_negatives[4])\n", + "\n", + "dataset = Dataset.from_dict({\n", + " \"anchor\": anchors,\n", + " \"positive\": positives,\n", + " \"negative_1\": negatives_1,\n", + " \"negative_2\": negatives_2,\n", + " \"negative_3\": negatives_3,\n", + " \"negative_4\": negatives_4,\n", + " \"negative_5\": negatives_5,\n", + "})\n" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "cc963d18", + "metadata": {}, + "outputs": [], + "source": [ + "dataset_split = dataset.train_test_split(test_size=0.05, seed=42)\n", + "\n", + "train_dataset = dataset_split[\"train\"]\n", + "test_dataset = dataset_split[\"test\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "593f7ce4", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "95" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(train_dataset)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "f0443056", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "5" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(test_dataset)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "377f53ba", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/train/jina/jina_train.py b/train/jina/jina_train.py new file mode 100644 index 0000000..4ab2179 --- /dev/null +++ b/train/jina/jina_train.py @@ -0,0 +1,128 @@ +from datasets import Dataset +import json +from sentence_transformers import ( + SentenceTransformer, + SentenceTransformerTrainer, + SentenceTransformerTrainingArguments, +) +from sentence_transformers.losses import MultipleNegativesRankingLoss +from sentence_transformers.training_args import BatchSamplers +from sentence_transformers.evaluation import RerankingEvaluator + + +########### Load model ########### +# 1. Load a model to finetune with 2. (Optional) model card data +model = SentenceTransformer("jinaai/jina-embeddings-v3", + trust_remote_code=True, + local_files_only=False, + model_kwargs={'default_task': 'retrieval'}) + + +########### Load dataset ########### +# 3. Load a dataset to finetune on +with open("/home/firouzi/embedding_model/data/train_100.json", "r", encoding="utf-8") as f: + all_dataset = json.load(f) + +anchors = [] +positives = [] +negatives_1 = [] +negatives_2 = [] +negatives_3 = [] +negatives_4 = [] +negatives_5 = [] +for data in all_dataset: + anchors.append(data["question"]) + positives.append(data["passage_positive"]) + all_negatives = data["passage_negative"] + data["passage_negative_random"] + if len(all_negatives) < 5: + for i in range(5 - len(all_negatives)): + all_negatives.append(all_negatives[0]) + negatives_1.append(all_negatives[0]) + negatives_2.append(all_negatives[1]) + negatives_3.append(all_negatives[2]) + negatives_4.append(all_negatives[3]) + negatives_5.append(all_negatives[4]) + +dataset = Dataset.from_dict({ + "anchor": anchors, + "positive": positives, + "negative_1": negatives_1, + "negative_2": negatives_2, + "negative_3": negatives_3, + "negative_4": negatives_4, + "negative_5": negatives_5, +}) + +dataset_split = dataset.train_test_split(test_size=0.05, seed=42) + +train_dataset = dataset_split["train"] +eval_dataset = dataset_split["test"] +########### Load loss function ########### +# 4. Define a loss function +loss = MultipleNegativesRankingLoss(model) + +########### Load training arguments ########### +# 5. (Optional) Specify training arguments +args = SentenceTransformerTrainingArguments( + # Required parameter: + output_dir="models/jina_v3", + # Optional training parameters: + num_train_epochs=1, + per_device_train_batch_size=16, + per_device_eval_batch_size=16, + learning_rate=2e-5, + warmup_ratio=0.1, + fp16=True, # Set to False if you get an error that your GPU can't run on FP16 + bf16=False, # Set to True if you have a GPU that supports BF16 + batch_sampler=BatchSamplers.NO_DUPLICATES, # MultipleNegativesRankingLoss benefits from no duplicate samples in a batch + # Optional tracking/debugging parameters: + eval_strategy="steps", + eval_steps=100, + save_strategy="steps", + save_steps=100, + save_total_limit=2, + logging_steps=100, + run_name="jina_v3", # Will be used in W&B if `wandb` is installed +) + +########### Load evaluator ########### +# 6. (Optional) Create an evaluator & evaluate the base model +eval_dataset_evaluator = [ + { + "query": sample["anchor"], + "positive": [sample["positive"]], + "negative": [sample["negative_1"], sample["negative_2"], sample["negative_3"], sample["negative_4"], sample["negative_5"]], + } + for sample in eval_dataset +] +dev_evaluator = RerankingEvaluator( + name="jina_v3", + samples=eval_dataset_evaluator, +) +dev_evaluator(model) + +########### Load trainer ########### +# 7. Create a trainer & train +trainer = SentenceTransformerTrainer( + model=model, + args=args, + train_dataset=train_dataset, + eval_dataset=eval_dataset, + loss=loss, + evaluator=dev_evaluator, +) +trainer.train() + +########### Load test evaluator ########### +# (Optional) Evaluate the trained model on the test set +# test_evaluator = TripletEvaluator( +# anchors=test_dataset["anchor"], +# positives=test_dataset["positive"], +# negatives=test_dataset["negative"], +# name="all-nli-test", +# ) +# test_evaluator(model) + +########### Save the trained model ########### +# 8. Save the trained model +model.save_pretrained("models/jina_v3")