Safetensors
bert
Generated from Trainer
apapagi commited on
Commit
ab85805
·
1 Parent(s): 5d742b6

update 2026

Browse files
.DS_Store ADDED
Binary file (6.15 kB). View file
 
.gitignore ADDED
@@ -0,0 +1 @@
 
 
1
+ .DS_Store
adapter_config.json DELETED
@@ -1,43 +0,0 @@
1
- {
2
- "alora_invocation_tokens": null,
3
- "alpha_pattern": {},
4
- "arrow_config": null,
5
- "auto_mapping": null,
6
- "base_model_name_or_path": "nlpaueb/legal-bert-base-uncased",
7
- "bias": "none",
8
- "corda_config": null,
9
- "ensure_weight_tying": false,
10
- "eva_config": null,
11
- "exclude_modules": null,
12
- "fan_in_fan_out": false,
13
- "inference_mode": true,
14
- "init_lora_weights": true,
15
- "layer_replication": null,
16
- "layers_pattern": null,
17
- "layers_to_transform": null,
18
- "loftq_config": {},
19
- "lora_alpha": 16,
20
- "lora_bias": false,
21
- "lora_dropout": 0.1,
22
- "lora_ga_config": null,
23
- "megatron_config": null,
24
- "megatron_core": "megatron.core",
25
- "modules_to_save": null,
26
- "peft_type": "LORA",
27
- "peft_version": "0.19.1",
28
- "qalora_group_size": 16,
29
- "r": 8,
30
- "rank_pattern": {},
31
- "revision": null,
32
- "target_modules": [
33
- "query",
34
- "value"
35
- ],
36
- "target_parameters": null,
37
- "task_type": "FEATURE_EXTRACTION",
38
- "trainable_token_indices": null,
39
- "use_bdlora": null,
40
- "use_dora": false,
41
- "use_qalora": false,
42
- "use_rslora": false
43
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
adapter_model.safetensors DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:b5bc8eb3b718153088f03cc5fd984198f8f0c143b9936ea6bee3efadf5e5d65b
3
- size 1186328
 
 
 
 
config.json CHANGED
@@ -1,47 +1,34 @@
1
  {
 
2
  "architectures": [
3
- "BertForPreTraining"
4
  ],
5
  "attention_probs_dropout_prob": 0.1,
6
  "bos_token_id": 0,
7
- "do_sample": false,
 
 
8
  "eos_token_ids": 0,
9
  "finetuning_task": null,
10
  "hidden_act": "gelu",
11
  "hidden_dropout_prob": 0.1,
12
  "hidden_size": 768,
13
- "id2label": {
14
- "0": "LABEL_0",
15
- "1": "LABEL_1"
16
- },
17
  "initializer_range": 0.02,
18
  "intermediate_size": 3072,
19
  "is_decoder": false,
20
- "label2id": {
21
- "LABEL_0": 0,
22
- "LABEL_1": 1
23
- },
24
  "layer_norm_eps": 1e-12,
25
- "length_penalty": 1.0,
26
- "max_length": 20,
27
  "max_position_embeddings": 512,
28
  "model_type": "bert",
29
  "num_attention_heads": 12,
30
- "num_beams": 1,
31
  "num_hidden_layers": 12,
32
- "num_labels": 2,
33
- "num_return_sequences": 1,
34
- "output_attentions": false,
35
- "output_hidden_states": false,
36
  "output_past": true,
37
  "pad_token_id": 0,
38
  "pruned_heads": {},
39
- "repetition_penalty": 1.0,
40
- "temperature": 1.0,
41
- "top_k": 50,
42
- "top_p": 1.0,
43
  "torchscript": false,
 
44
  "type_vocab_size": 2,
45
  "use_bfloat16": false,
 
46
  "vocab_size": 30522
47
  }
 
1
  {
2
+ "add_cross_attention": false,
3
  "architectures": [
4
+ "BertForMaskedLM"
5
  ],
6
  "attention_probs_dropout_prob": 0.1,
7
  "bos_token_id": 0,
8
+ "classifier_dropout": null,
9
+ "dtype": "float32",
10
+ "eos_token_id": null,
11
  "eos_token_ids": 0,
12
  "finetuning_task": null,
13
  "hidden_act": "gelu",
14
  "hidden_dropout_prob": 0.1,
15
  "hidden_size": 768,
 
 
 
 
16
  "initializer_range": 0.02,
17
  "intermediate_size": 3072,
18
  "is_decoder": false,
 
 
 
 
19
  "layer_norm_eps": 1e-12,
 
 
20
  "max_position_embeddings": 512,
21
  "model_type": "bert",
22
  "num_attention_heads": 12,
 
23
  "num_hidden_layers": 12,
 
 
 
 
24
  "output_past": true,
25
  "pad_token_id": 0,
26
  "pruned_heads": {},
27
+ "tie_word_embeddings": true,
 
 
 
28
  "torchscript": false,
29
+ "transformers_version": "5.9.0",
30
  "type_vocab_size": 2,
31
  "use_bfloat16": false,
32
+ "use_cache": true,
33
  "vocab_size": 30522
34
  }
inference.ipynb ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "code",
5
+ "execution_count": 1,
6
+ "id": "73e2d6cb-82b5-42cc-919d-dceaaf1f09f7",
7
+ "metadata": {},
8
+ "outputs": [
9
+ {
10
+ "name": "stderr",
11
+ "output_type": "stream",
12
+ "text": [
13
+ "/home/apapagiannis/update_2025/eurovoc_training/.venv/lib/python3.10/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
14
+ " from .autonotebook import tqdm as notebook_tqdm\n",
15
+ "Loading weights: 100%|██████████| 197/197 [00:00<00:00, 8783.65it/s]\n",
16
+ "[transformers] \u001b[1mBertModel LOAD REPORT\u001b[0m from: ./merged_model\n",
17
+ "Key | Status | \n",
18
+ "-------------------------------------------+------------+-\n",
19
+ "cls.predictions.transform.dense.bias | UNEXPECTED | \n",
20
+ "cls.predictions.transform.LayerNorm.bias | UNEXPECTED | \n",
21
+ "cls.predictions.transform.LayerNorm.weight | UNEXPECTED | \n",
22
+ "cls.predictions.transform.dense.weight | UNEXPECTED | \n",
23
+ "cls.predictions.bias | UNEXPECTED | \n",
24
+ "pooler.dense.bias | MISSING | \n",
25
+ "pooler.dense.weight | MISSING | \n",
26
+ "\n",
27
+ "Notes:\n",
28
+ "- UNEXPECTED:\tcan be ignored when loading from different task/architecture; not ok if you expect identical arch.\n",
29
+ "- MISSING:\tthose params were newly initialized because missing from the checkpoint. Consider training on your downstream task.\n"
30
+ ]
31
+ },
32
+ {
33
+ "name": "stdout",
34
+ "output_type": "stream",
35
+ "text": [
36
+ "energy vs energy: 0.7808\n",
37
+ "energy vs criminal: 0.5920\n"
38
+ ]
39
+ }
40
+ ],
41
+ "source": [
42
+ "import torch\n",
43
+ "from transformers import AutoModel, AutoTokenizer\n",
44
+ "\n",
45
+ "model_dir = \"./merged_model\"\n",
46
+ "\n",
47
+ "# What you actually want — embedding quality\n",
48
+ "model = AutoModel.from_pretrained(model_dir) # NOT AutoModelForMaskedLM\n",
49
+ "tokenizer = AutoTokenizer.from_pretrained(model_dir)\n",
50
+ "\n",
51
+ "def embed(text):\n",
52
+ " inputs = tokenizer(text, return_tensors=\"pt\", truncation=True, max_length=512)\n",
53
+ " with torch.no_grad():\n",
54
+ " out = model(**inputs)\n",
55
+ " return out.last_hidden_state[:, 0, :] # CLS token\n",
56
+ "\n",
57
+ "# Test: similar legal concepts should be closer than unrelated ones\n",
58
+ "from torch.nn.functional import cosine_similarity\n",
59
+ "\n",
60
+ "e1 = embed(\"renewable energy regulation\")\n",
61
+ "e2 = embed(\"solar power and wind policy\") # should be close\n",
62
+ "e3 = embed(\"criminal sentencing guidelines\") # should be far\n",
63
+ "\n",
64
+ "print(f\"energy vs energy: {cosine_similarity(e1, e2).item():.4f}\") # expect ~high\n",
65
+ "print(f\"energy vs criminal: {cosine_similarity(e1, e3).item():.4f}\") # expect ~lower"
66
+ ]
67
+ },
68
+ {
69
+ "cell_type": "code",
70
+ "execution_count": null,
71
+ "id": "94556c9a-bd65-489f-b2ab-d44b9b0812c7",
72
+ "metadata": {},
73
+ "outputs": [],
74
+ "source": []
75
+ }
76
+ ],
77
+ "metadata": {
78
+ "kernelspec": {
79
+ "display_name": "eurovoc_training",
80
+ "language": "python",
81
+ "name": "my-venv"
82
+ },
83
+ "language_info": {
84
+ "codemirror_mode": {
85
+ "name": "ipython",
86
+ "version": 3
87
+ },
88
+ "file_extension": ".py",
89
+ "mimetype": "text/x-python",
90
+ "name": "python",
91
+ "nbconvert_exporter": "python",
92
+ "pygments_lexer": "ipython3",
93
+ "version": "3.10.12"
94
+ }
95
+ },
96
+ "nbformat": 4,
97
+ "nbformat_minor": 5
98
+ }
inference.py DELETED
@@ -1,47 +0,0 @@
1
- #!/usr/bin/env python3
2
- """EuroBERT Inference - Predict Masked Tokens"""
3
-
4
- import torch
5
- import argparse
6
- from transformers import AutoTokenizer, AutoModelForMaskedLM, pipeline
7
- from peft import PeftModel
8
-
9
- BASE_MODEL = "nlpaueb/legal-bert-base-uncased"
10
- ADAPTER_PATH = "./model"
11
-
12
-
13
- def main():
14
- parser = argparse.ArgumentParser(description="EuroBERT - Predict Masked Tokens")
15
- parser.add_argument("--text", type=str, default="The European [MASK] regulates digital platforms.",
16
- help="Text with [MASK] tokens to predict")
17
- parser.add_argument("--top-k", type=int, default=5, help="Number of top predictions")
18
- parser.add_argument("--adapter-path", type=str, default=ADAPTER_PATH, help="Path to LoRA adapter")
19
- parser.add_argument("--device", type=str, default="cuda" if torch.cuda.is_available() else "cpu")
20
-
21
- args = parser.parse_args()
22
-
23
- # Load model
24
- print(f"📦 Loading {BASE_MODEL}")
25
- model = AutoModelForMaskedLM.from_pretrained(BASE_MODEL)
26
- tokenizer = AutoTokenizer.from_pretrained(BASE_MODEL)
27
-
28
- print(f"⚡ Loading LoRA adapter from {args.adapter_path}")
29
- model = PeftModel.from_pretrained(model, args.adapter_path)
30
- model.to(args.device)
31
- model.eval()
32
-
33
- print(f"🎮 Device: {args.device}\n")
34
-
35
- # Predict masked tokens
36
- pipe = pipeline("fill-mask", model=model, tokenizer=tokenizer)
37
- results = pipe(args.text, top_k=args.top_k)
38
-
39
- print(f"📝 Input: {args.text}")
40
- print(f"🎯 Top {args.top_k} predictions:")
41
- for i, result in enumerate(results, 1):
42
- print(f" {i}. '{result['token_str']}' (score: {result['score']:.4f})")
43
- print(f" → {result['sequence']}")
44
-
45
-
46
- if __name__ == "__main__":
47
- main()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
merge_with_base.ipynb ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "code",
5
+ "execution_count": null,
6
+ "id": "36a93a8b-1c82-4b47-b34d-cf6ce5dafc2e",
7
+ "metadata": {
8
+ "tags": []
9
+ },
10
+ "outputs": [],
11
+ "source": [
12
+ "from transformers import AutoModelForMaskedLM, AutoTokenizer\n",
13
+ "from peft import PeftModel\n",
14
+ "\n",
15
+ "base_model_name = \"nlpaueb/legal-bert-base-uncased\"\n",
16
+ "adapter_model_dir = \"results/checkpoint-xxxx\" # update with your actual checkpoint path\n",
17
+ "outdir = \"./merged_model\"\n",
18
+ "\n",
19
+ "# Load base + adapter\n",
20
+ "base_model = AutoModelForMaskedLM.from_pretrained(base_model_name)\n",
21
+ "peft_model = PeftModel.from_pretrained(base_model, adapter_model_dir)\n",
22
+ "\n",
23
+ "# Verify LoRA weights exist before merging\n",
24
+ "lora_keys = [k for k in peft_model.state_dict() if \"lora_\" in k]\n",
25
+ "print(f\"Found {len(lora_keys)} LoRA keys — should be 48 (2 per layer × 2 matrices × 12 layers)\")\n",
26
+ "assert len(lora_keys) > 0, \"No LoRA keys found — wrong checkpoint?\"\n",
27
+ "\n",
28
+ "# Merge and unload\n",
29
+ "merged = peft_model.merge_and_unload()\n",
30
+ "\n",
31
+ "# Verify no LoRA keys remain\n",
32
+ "merged_keys = [k for k in merged.state_dict() if \"lora_\" in k]\n",
33
+ "print(f\"LoRA keys after merge: {len(merged_keys)} — should be 0\")\n",
34
+ "\n",
35
+ "# Save\n",
36
+ "merged.save_pretrained(outdir, safe_serialization=True)\n",
37
+ "tokenizer = AutoTokenizer.from_pretrained(base_model_name)\n",
38
+ "tokenizer.save_pretrained(outdir)\n",
39
+ "print(\"Saved cleanly.\")"
40
+ ]
41
+ },
42
+ {
43
+ "cell_type": "code",
44
+ "execution_count": null,
45
+ "id": "43cddd93-7c0b-4bd7-b010-4657d7f09951",
46
+ "metadata": {},
47
+ "outputs": [],
48
+ "source": []
49
+ }
50
+ ],
51
+ "metadata": {
52
+ "kernelspec": {
53
+ "display_name": "eubert",
54
+ "language": "python",
55
+ "name": "eurovoc-venv"
56
+ },
57
+ "language_info": {
58
+ "codemirror_mode": {
59
+ "name": "ipython",
60
+ "version": 3
61
+ },
62
+ "file_extension": ".py",
63
+ "mimetype": "text/x-python",
64
+ "name": "python",
65
+ "nbconvert_exporter": "python",
66
+ "pygments_lexer": "ipython3",
67
+ "version": "3.10.12"
68
+ }
69
+ },
70
+ "nbformat": 4,
71
+ "nbformat_minor": 5
72
+ }
rng_state.pth → model.safetensors RENAMED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:16b08ab4ae85fee7596463136852d5f70af6c20c7d3271c15beaff64a55bfa82
3
- size 14645
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:be53e87dd08b424e9b1a4ba3cb24005f702e69f1b9a04ac26cbaee79e035f69e
3
+ size 438080896
optimizer.pt DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:a3d02bfa992da6e69864499fd31dcb3d704675d16e55a0c5ad7c329ad3798f24
3
- size 2401099
 
 
 
 
scaler.pt DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:d0ed87b5f1b332e484564368c4a705e3c051fee55e9e66e1633af48d12d24104
3
- size 1383
 
 
 
 
scheduler.pt DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:dd3190e85b69bf1e75bdbf9b2e683ac33113ee45837950be410af0b40d2c7f0b
3
- size 1465
 
 
 
 
tokenizer.json CHANGED
@@ -1,11 +1,6 @@
1
  {
2
  "version": "1.0",
3
- "truncation": {
4
- "direction": "Right",
5
- "max_length": 512,
6
- "strategy": "LongestFirst",
7
- "stride": 0
8
- },
9
  "padding": null,
10
  "added_tokens": [
11
  {
 
1
  {
2
  "version": "1.0",
3
+ "truncation": null,
 
 
 
 
 
4
  "padding": null,
5
  "added_tokens": [
6
  {
train.ipynb ADDED
@@ -0,0 +1,289 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "id": "cd96b784",
6
+ "metadata": {},
7
+ "source": [
8
+ "# EuroBERT training"
9
+ ]
10
+ },
11
+ {
12
+ "cell_type": "code",
13
+ "execution_count": null,
14
+ "id": "95edf3f9-59b6-4af3-8c14-2463256d4ec1",
15
+ "metadata": {
16
+ "tags": []
17
+ },
18
+ "outputs": [],
19
+ "source": [
20
+ "import os\n",
21
+ "os.environ[\"CUDA_VISIBLE_DEVICES\"] = \"0\""
22
+ ]
23
+ },
24
+ {
25
+ "cell_type": "markdown",
26
+ "id": "d0f5cc51",
27
+ "metadata": {},
28
+ "source": [
29
+ "## Load dataset from huggingface"
30
+ ]
31
+ },
32
+ {
33
+ "cell_type": "code",
34
+ "execution_count": null,
35
+ "id": "4b536d72",
36
+ "metadata": {
37
+ "tags": []
38
+ },
39
+ "outputs": [],
40
+ "source": [
41
+ "from datasets import load_dataset\n",
42
+ "\n",
43
+ "dataset = load_dataset(\n",
44
+ " \"json\",\n",
45
+ " data_files=\"/home/apapagiannis/EuroVoc/files/*\",\n",
46
+ " split=\"train\"\n",
47
+ ")\n",
48
+ "\n",
49
+ "print(dataset)"
50
+ ]
51
+ },
52
+ {
53
+ "cell_type": "code",
54
+ "execution_count": null,
55
+ "id": "54d215a0",
56
+ "metadata": {
57
+ "tags": []
58
+ },
59
+ "outputs": [],
60
+ "source": [
61
+ "split_dataset = dataset.train_test_split(test_size=0.1, seed=42)\n",
62
+ "\n",
63
+ "train_dataset = split_dataset[\"train\"]\n",
64
+ "eval_dataset = split_dataset[\"test\"]"
65
+ ]
66
+ },
67
+ {
68
+ "cell_type": "markdown",
69
+ "id": "eefec7f8",
70
+ "metadata": {},
71
+ "source": [
72
+ "## Tokenize text"
73
+ ]
74
+ },
75
+ {
76
+ "cell_type": "code",
77
+ "execution_count": null,
78
+ "id": "f2236486",
79
+ "metadata": {
80
+ "tags": []
81
+ },
82
+ "outputs": [],
83
+ "source": [
84
+ "from transformers import AutoTokenizer, AutoModelForMaskedLM\n",
85
+ "\n",
86
+ "BERT_MODEL_NAME = \"nlpaueb/legal-bert-base-uncased\"\n",
87
+ "\n",
88
+ "tokenizer = AutoTokenizer.from_pretrained(BERT_MODEL_NAME)\n",
89
+ "model = AutoModelForMaskedLM.from_pretrained(BERT_MODEL_NAME)\n",
90
+ "\n",
91
+ "if tokenizer.pad_token is None:\n",
92
+ " tokenizer.pad_token = tokenizer.cls_token"
93
+ ]
94
+ },
95
+ {
96
+ "cell_type": "code",
97
+ "execution_count": null,
98
+ "id": "825d7a3d",
99
+ "metadata": {
100
+ "tags": []
101
+ },
102
+ "outputs": [],
103
+ "source": [
104
+ "def tokenize_function(batch):\n",
105
+ " texts = []\n",
106
+ "\n",
107
+ " for t in batch[\"text\"]:\n",
108
+ " if t is None:\n",
109
+ " texts.append(\"\")\n",
110
+ " else:\n",
111
+ " texts.append(str(t))\n",
112
+ "\n",
113
+ " return tokenizer(\n",
114
+ " texts,\n",
115
+ " truncation=True,\n",
116
+ " max_length=512\n",
117
+ " )\n",
118
+ "\n",
119
+ "tokenized_train = train_dataset.map(tokenize_function, batched=True, remove_columns=train_dataset.column_names)\n",
120
+ "tokenized_eval = eval_dataset.map(tokenize_function, batched=True, remove_columns=eval_dataset.column_names)"
121
+ ]
122
+ },
123
+ {
124
+ "cell_type": "markdown",
125
+ "id": "9fc6309a",
126
+ "metadata": {},
127
+ "source": [
128
+ "## Load model and set up training arguments"
129
+ ]
130
+ },
131
+ {
132
+ "cell_type": "code",
133
+ "execution_count": null,
134
+ "id": "ccd9ea70",
135
+ "metadata": {
136
+ "tags": []
137
+ },
138
+ "outputs": [],
139
+ "source": [
140
+ "from transformers import AutoModelForMaskedLM\n",
141
+ "\n",
142
+ "model = AutoModelForMaskedLM.from_pretrained(BERT_MODEL_NAME)"
143
+ ]
144
+ },
145
+ {
146
+ "cell_type": "code",
147
+ "execution_count": null,
148
+ "id": "5ce5b33a",
149
+ "metadata": {
150
+ "tags": []
151
+ },
152
+ "outputs": [],
153
+ "source": [
154
+ "from transformers import DataCollatorForLanguageModeling\n",
155
+ "\n",
156
+ "data_collator = DataCollatorForLanguageModeling(\n",
157
+ " tokenizer=tokenizer,\n",
158
+ " mlm=True,\n",
159
+ " mlm_probability=0.15\n",
160
+ ")"
161
+ ]
162
+ },
163
+ {
164
+ "cell_type": "code",
165
+ "execution_count": null,
166
+ "id": "645f2ac6",
167
+ "metadata": {
168
+ "tags": []
169
+ },
170
+ "outputs": [],
171
+ "source": [
172
+ "# Define LoRA configuration and apply it to the model\n",
173
+ "from peft import LoraConfig, get_peft_model, TaskType\n",
174
+ "\n",
175
+ "lora_config = LoraConfig(\n",
176
+ " task_type=TaskType.FEATURE_EXTRACTION,\n",
177
+ " r=8,\n",
178
+ " lora_alpha=16,\n",
179
+ " lora_dropout=0.1,\n",
180
+ " target_modules=[\"query\", \"value\"] # BERT attention layers\n",
181
+ ")\n",
182
+ "\n",
183
+ "model = get_peft_model(model, lora_config)\n",
184
+ "\n",
185
+ "model.print_trainable_parameters()"
186
+ ]
187
+ },
188
+ {
189
+ "cell_type": "code",
190
+ "execution_count": null,
191
+ "id": "9dd7dfbb",
192
+ "metadata": {
193
+ "tags": []
194
+ },
195
+ "outputs": [],
196
+ "source": [
197
+ "from transformers import TrainingArguments, EarlyStoppingCallback\n",
198
+ "\n",
199
+ "training_args = TrainingArguments(\n",
200
+ " output_dir=\"./results\",\n",
201
+ "\n",
202
+ " num_train_epochs=3,\n",
203
+ " per_device_train_batch_size=8, # INCREASE this with LoRA\n",
204
+ " per_device_eval_batch_size=8,\n",
205
+ "\n",
206
+ " eval_strategy=\"steps\",\n",
207
+ " eval_steps=500,\n",
208
+ "\n",
209
+ " save_steps=1000,\n",
210
+ " logging_steps=100,\n",
211
+ "\n",
212
+ " learning_rate=2e-4,\n",
213
+ " warmup_steps=200,\n",
214
+ "\n",
215
+ " fp16=True, # or bf16=True if supported\n",
216
+ " report_to=\"none\",\n",
217
+ " \n",
218
+ " save_total_limit=3, # Keep only last 3 checkpoints\n",
219
+ " load_best_model_at_end=True,\n",
220
+ " metric_for_best_model=\"eval_loss\",\n",
221
+ " greater_is_better=False,\n",
222
+ "\n",
223
+ ")\n",
224
+ "\n",
225
+ "# Early stopping callback\n",
226
+ "# Monitors eval loss - stops if no improvement for 3 evaluations (~1500 steps)\n",
227
+ "early_stopping = EarlyStoppingCallback(\n",
228
+ " early_stopping_patience=3, # Stop if no improvement for 3 evals\n",
229
+ " early_stopping_threshold=0.001, # Minimum improvement threshold\n",
230
+ ")"
231
+ ]
232
+ },
233
+ {
234
+ "cell_type": "code",
235
+ "execution_count": null,
236
+ "id": "531b1862",
237
+ "metadata": {
238
+ "tags": []
239
+ },
240
+ "outputs": [],
241
+ "source": [
242
+ "from transformers import Trainer\n",
243
+ "\n",
244
+ "trainer = Trainer(\n",
245
+ " model=model,\n",
246
+ " args=training_args,\n",
247
+ " train_dataset=tokenized_train,\n",
248
+ " eval_dataset=tokenized_eval,\n",
249
+ " data_collator=data_collator,\n",
250
+ " callbacks=[early_stopping],\n",
251
+ ")"
252
+ ]
253
+ },
254
+ {
255
+ "cell_type": "code",
256
+ "execution_count": null,
257
+ "id": "3d41560e-66d7-406f-8be4-3ccbe7950879",
258
+ "metadata": {},
259
+ "outputs": [],
260
+ "source": [
261
+ "trainer.train()\n",
262
+ "\n",
263
+ "model.save_pretrained(\"./fine_tuned_model\")\n",
264
+ "tokenizer.save_pretrained(\"./fine_tuned_model\")"
265
+ ]
266
+ }
267
+ ],
268
+ "metadata": {
269
+ "kernelspec": {
270
+ "display_name": "eubert",
271
+ "language": "python",
272
+ "name": "eurovoc-venv"
273
+ },
274
+ "language_info": {
275
+ "codemirror_mode": {
276
+ "name": "ipython",
277
+ "version": 3
278
+ },
279
+ "file_extension": ".py",
280
+ "mimetype": "text/x-python",
281
+ "name": "python",
282
+ "nbconvert_exporter": "python",
283
+ "pygments_lexer": "ipython3",
284
+ "version": "3.10.12"
285
+ }
286
+ },
287
+ "nbformat": 4,
288
+ "nbformat_minor": 5
289
+ }
train.py DELETED
@@ -1,227 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- EuroBERT Fine-tuning Script with Improvements
4
- - Multi-GPU support
5
- - Early stopping (loss stabilization detection)
6
- - Random data sampling (removed date sorting)
7
- - Reduced epochs for efficiency
8
- """
9
-
10
- import os
11
- import argparse
12
- from datetime import datetime
13
- import torch
14
- from datasets import load_dataset
15
- from transformers import (
16
- AutoTokenizer,
17
- AutoModelForMaskedLM,
18
- DataCollatorForLanguageModeling,
19
- TrainingArguments,
20
- Trainer,
21
- EarlyStoppingCallback,
22
- )
23
- from peft import LoraConfig, get_peft_model, TaskType
24
-
25
-
26
- def parse_arguments():
27
- parser = argparse.ArgumentParser(description="Train EuroBERT model with LoRA")
28
- parser.add_argument(
29
- "--gpu-ids",
30
- type=str,
31
- default="0,1,2",
32
- help="GPU IDs to use (comma-separated). Default: all 3 RTX 3080s",
33
- )
34
- parser.add_argument(
35
- "--batch-size",
36
- type=int,
37
- default=16,
38
- help="Per-device batch size. With 3 GPUs and LoRA: 16 per GPU = 48 total",
39
- )
40
- parser.add_argument(
41
- "--epochs",
42
- type=int,
43
- default=1,
44
- help="Number of epochs (default: 1, reduced from 3 due to large dataset)",
45
- )
46
- parser.add_argument(
47
- "--data-path",
48
- type=str,
49
- default="/home/apapagiannis/EuroVoc/files/*",
50
- help="Path to training data",
51
- )
52
- parser.add_argument(
53
- "--output-dir",
54
- type=str,
55
- default="./results",
56
- help="Output directory for results",
57
- )
58
- parser.add_argument(
59
- "--model-name",
60
- type=str,
61
- default="nlpaueb/legal-bert-base-uncased",
62
- help="Base model to fine-tune",
63
- )
64
- return parser.parse_args()
65
-
66
-
67
- def load_and_prepare_data(data_path, tokenizer, model_name):
68
- """Load dataset and prepare for training."""
69
- print("📦 Loading dataset...")
70
- dataset = load_dataset("json", data_files=data_path, split="train")
71
- print(f"Total samples: {len(dataset):,}")
72
-
73
- # Split into train/eval
74
- print("Splitting data (90% train, 10% eval)...")
75
- split_dataset = dataset.train_test_split(test_size=0.1, seed=42)
76
- train_dataset = split_dataset["train"]
77
- eval_dataset = split_dataset["test"]
78
-
79
- print(f" Train: {len(train_dataset):,} samples")
80
- print(f" Eval: {len(eval_dataset):,} samples")
81
-
82
- # Tokenization function
83
- def tokenize_function(batch):
84
- texts = []
85
- for t in batch.get("text", batch.get("content", [])):
86
- texts.append(str(t) if t is not None else "")
87
-
88
- return tokenizer(
89
- texts,
90
- truncation=True,
91
- max_length=512,
92
- padding="max_length",
93
- )
94
-
95
- print("Tokenizing datasets...")
96
- tokenized_train = train_dataset.map(
97
- tokenize_function,
98
- batched=True,
99
- remove_columns=train_dataset.column_names,
100
- desc="Tokenizing train",
101
- )
102
- tokenized_eval = eval_dataset.map(
103
- tokenize_function,
104
- batched=True,
105
- remove_columns=eval_dataset.column_names,
106
- desc="Tokenizing eval",
107
- )
108
-
109
- return tokenized_train, tokenized_eval
110
-
111
-
112
- def setup_model_with_lora(model_name):
113
- """Load model and apply LoRA configuration."""
114
- print(f"🤖 Loading model: {model_name}")
115
- model = AutoModelForMaskedLM.from_pretrained(model_name)
116
-
117
- print("⚡ Setting up LoRA configuration...")
118
- # IMPORTANT: For BERT MLM training, use FEATURE_EXTRACTION
119
- # NOTE: If you switch to causal LM (GPT-style), change to TaskType.CAUSAL_LM
120
- lora_config = LoraConfig(
121
- task_type=TaskType.FEATURE_EXTRACTION, # MLM pre-training task
122
- r=8,
123
- lora_alpha=16,
124
- lora_dropout=0.1,
125
- target_modules=["query", "value"], # BERT attention layers
126
- bias="none",
127
- )
128
-
129
- model = get_peft_model(model, lora_config)
130
- model.print_trainable_parameters()
131
- return model
132
-
133
-
134
- def main():
135
- args = parse_arguments()
136
-
137
- # Set GPU devices
138
- os.environ["CUDA_VISIBLE_DEVICES"] = args.gpu_ids
139
- num_gpus = len(args.gpu_ids.split(","))
140
- print(f"🎮 Using {num_gpus} GPU(s): {args.gpu_ids}")
141
- print(f"📊 GPU Info:")
142
- if torch.cuda.is_available():
143
- for i in range(torch.cuda.device_count()):
144
- print(f" GPU {i}: {torch.cuda.get_device_name(i)}")
145
-
146
- # Load tokenizer
147
- print(f"📝 Loading tokenizer from {args.model_name}")
148
- tokenizer = AutoTokenizer.from_pretrained(args.model_name)
149
- if tokenizer.pad_token is None:
150
- tokenizer.pad_token = tokenizer.cls_token
151
-
152
- # Load and prepare data
153
- tokenized_train, tokenized_eval = load_and_prepare_data(
154
- args.data_path, tokenizer, args.model_name
155
- )
156
-
157
- # Setup model with LoRA
158
- model = setup_model_with_lora(args.model_name)
159
-
160
- # Data collator
161
- data_collator = DataCollatorForLanguageModeling(
162
- tokenizer=tokenizer,
163
- mlm=True,
164
- mlm_probability=0.15,
165
- )
166
-
167
- # Calculate steps for context
168
- train_steps_per_epoch = len(tokenized_train) // (args.batch_size * num_gpus)
169
- print(f"\n📈 Training Configuration:")
170
- print(f" Batch size (per GPU): {args.batch_size}")
171
- print(f" Total batch size: {args.batch_size * num_gpus}")
172
- print(f" Steps per epoch: {train_steps_per_epoch:,}")
173
- print(f" Epochs: {args.epochs}")
174
- print(f" Total steps: {train_steps_per_epoch * args.epochs:,}")
175
- print(f" Early stopping: YES (monitor loss stability around 60k steps)")
176
-
177
- # Training arguments with early stopping
178
- training_args = TrainingArguments(
179
- output_dir=args.output_dir,
180
- num_train_epochs=args.epochs,
181
- per_device_train_batch_size=args.batch_size,
182
- per_device_eval_batch_size=args.batch_size,
183
- eval_strategy="steps",
184
- eval_steps=500,
185
- save_steps=1000,
186
- logging_steps=100,
187
- learning_rate=2e-4,
188
- warmup_steps=200,
189
- fp16=True, # RTX 3080 supports FP16
190
- report_to="none",
191
- save_total_limit=3, # Keep only last 3 checkpoints
192
- load_best_model_at_end=True,
193
- metric_for_best_model="eval_loss",
194
- greater_is_better=False,
195
- )
196
-
197
- # Early stopping callback
198
- # Monitors eval loss - stops if no improvement for 3 evaluations (~1500 steps)
199
- early_stopping = EarlyStoppingCallback(
200
- early_stopping_patience=3, # Stop if no improvement for 3 evals
201
- early_stopping_threshold=0.001, # Minimum improvement threshold
202
- )
203
-
204
- # Create trainer
205
- print("\n🚀 Initializing trainer...")
206
- trainer = Trainer(
207
- model=model,
208
- args=training_args,
209
- train_dataset=tokenized_train,
210
- eval_dataset=tokenized_eval,
211
- data_collator=data_collator,
212
- callbacks=[early_stopping],
213
- )
214
-
215
- # Train
216
- print("\n🔥 Starting training...\n")
217
- trainer.train()
218
-
219
- # Save model
220
- print("\n💾 Saving fine-tuned model...")
221
- model.save_pretrained(os.path.join(args.output_dir, "fine_tuned_model"))
222
- tokenizer.save_pretrained(os.path.join(args.output_dir, "fine_tuned_model"))
223
- print(f"✓ Model saved to {os.path.join(args.output_dir, 'fine_tuned_model')}")
224
-
225
-
226
- if __name__ == "__main__":
227
- main()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trainer_state.json DELETED
The diff for this file is too large to render. See raw diff
 
training_args.bin DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:40a4825312a77639f789ba54a89fc281e36a6ca718b6259b972c5a5db048463b
3
- size 5201