Commit ·
6202f17
0
Parent(s):
model trained on few data
Browse files- .gitignore +2 -0
- audit_model_finetuning.ipynb +679 -0
.gitignore
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
data/*
|
| 2 |
+
docs/*
|
audit_model_finetuning.ipynb
ADDED
|
@@ -0,0 +1,679 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"cells": [
|
| 3 |
+
{
|
| 4 |
+
"cell_type": "markdown",
|
| 5 |
+
"metadata": {},
|
| 6 |
+
"source": [
|
| 7 |
+
"# Self-Supervised Fine-Tuning of Mistral-7B on Audit Reports\n",
|
| 8 |
+
"\n",
|
| 9 |
+
"This notebook demonstrates how to adapt a Large Language Model (Mistral-7B) to the domain of professional audit reports using self-supervised fine-tuning (continued pretraining). \n",
|
| 10 |
+
"\n",
|
| 11 |
+
"**Objective**: Enhance the model's domain fluency, vocabulary, and stylistic consistency for audit documentation.\n",
|
| 12 |
+
"**Method**: Causal Language Modeling (Next-Token Prediction) on raw text extracted from PDF reports.\n",
|
| 13 |
+
"**Hardware**: Optimized for a T4 GPU (Google Colab free tier compatible) using QLoRA (4-bit quantization + LoRA).\n",
|
| 14 |
+
"\n",
|
| 15 |
+
"## 1. Setup and Installation\n",
|
| 16 |
+
"We need to install the necessary libraries for PDF extraction, efficient model loading, and training.\n",
|
| 17 |
+
"\n",
|
| 18 |
+
"**IMPORTANT**: After running the installation cell below, you MUST restart the runtime/session (Runtime > Restart session) for the updates to take effect, then run the cells starting from the imports."
|
| 19 |
+
]
|
| 20 |
+
},
|
| 21 |
+
{
|
| 22 |
+
"cell_type": "code",
|
| 23 |
+
"execution_count": 1,
|
| 24 |
+
"metadata": {},
|
| 25 |
+
"outputs": [
|
| 26 |
+
{
|
| 27 |
+
"name": "stdout",
|
| 28 |
+
"output_type": "stream",
|
| 29 |
+
"text": [
|
| 30 |
+
"Installation complete. Please RESTART the runtime (Runtime > Restart session) to apply changes, then run the next cells.\n"
|
| 31 |
+
]
|
| 32 |
+
}
|
| 33 |
+
],
|
| 34 |
+
"source": [
|
| 35 |
+
"# Install all key dependencies including PyTorch components to ensure version compatibility\n",
|
| 36 |
+
"!pip install -q -U torch torchvision torchaudio transformers peft datasets bitsandbytes trl pdfplumber accelerate\n",
|
| 37 |
+
"\n",
|
| 38 |
+
"print(\"Installation complete. Please RESTART the runtime (Runtime > Restart session) to apply changes, then run the next cells.\")"
|
| 39 |
+
]
|
| 40 |
+
},
|
| 41 |
+
{
|
| 42 |
+
"cell_type": "code",
|
| 43 |
+
"execution_count": 2,
|
| 44 |
+
"metadata": {},
|
| 45 |
+
"outputs": [
|
| 46 |
+
{
|
| 47 |
+
"data": {
|
| 48 |
+
"text/plain": [
|
| 49 |
+
"<torch._C.Generator at 0x7b00d3b86a30>"
|
| 50 |
+
]
|
| 51 |
+
},
|
| 52 |
+
"execution_count": 2,
|
| 53 |
+
"metadata": {},
|
| 54 |
+
"output_type": "execute_result"
|
| 55 |
+
}
|
| 56 |
+
],
|
| 57 |
+
"source": [
|
| 58 |
+
"import os\n",
|
| 59 |
+
"import glob\n",
|
| 60 |
+
"import pdfplumber\n",
|
| 61 |
+
"import torch\n",
|
| 62 |
+
"from datasets import Dataset, DatasetDict\n",
|
| 63 |
+
"from transformers import (\n",
|
| 64 |
+
" AutoModelForCausalLM,\n",
|
| 65 |
+
" AutoTokenizer,\n",
|
| 66 |
+
" BitsAndBytesConfig,\n",
|
| 67 |
+
" TrainingArguments,\n",
|
| 68 |
+
" Trainer,\n",
|
| 69 |
+
" DataCollatorForLanguageModeling\n",
|
| 70 |
+
")\n",
|
| 71 |
+
"from peft import LoraConfig, get_peft_model, prepare_model_for_kbit_training, TaskType\n",
|
| 72 |
+
"import re\n",
|
| 73 |
+
"\n",
|
| 74 |
+
"# Set seed for reproducibility\n",
|
| 75 |
+
"torch.manual_seed(42)"
|
| 76 |
+
]
|
| 77 |
+
},
|
| 78 |
+
{
|
| 79 |
+
"cell_type": "code",
|
| 80 |
+
"execution_count": 3,
|
| 81 |
+
"metadata": {},
|
| 82 |
+
"outputs": [
|
| 83 |
+
{
|
| 84 |
+
"name": "stdout",
|
| 85 |
+
"output_type": "stream",
|
| 86 |
+
"text": [
|
| 87 |
+
"Drive already mounted at /content/drive; to attempt to forcibly remount, call drive.mount(\"/content/drive\", force_remount=True).\n",
|
| 88 |
+
"Mounted Google Drive. DATA_DIR set to: /content/drive/MyDrive/Data\n"
|
| 89 |
+
]
|
| 90 |
+
}
|
| 91 |
+
],
|
| 92 |
+
"source": [
|
| 93 |
+
"import sys\n",
|
| 94 |
+
"from pathlib import Path\n",
|
| 95 |
+
"\n",
|
| 96 |
+
"# Check if running in Colab\n",
|
| 97 |
+
"if 'google.colab' in sys.modules:\n",
|
| 98 |
+
" from google.colab import drive\n",
|
| 99 |
+
" try:\n",
|
| 100 |
+
" drive.mount('/content/drive')\n",
|
| 101 |
+
" except:\n",
|
| 102 |
+
" pass\n",
|
| 103 |
+
" # Update DATA_DIR to point to mounted Drive\n",
|
| 104 |
+
" # Make sure you have uploaded the Data folder to your Google Drive root\n",
|
| 105 |
+
" DATA_DIR = Path('/content/drive/MyDrive/Data')\n",
|
| 106 |
+
" print(f\"Mounted Google Drive. DATA_DIR set to: {DATA_DIR}\")\n",
|
| 107 |
+
"else:\n",
|
| 108 |
+
" DATA_DIR = Path(\"./Data\")\n",
|
| 109 |
+
" print(f\"Not running in Colab. Using local Data directory: {DATA_DIR}\")"
|
| 110 |
+
]
|
| 111 |
+
},
|
| 112 |
+
{
|
| 113 |
+
"cell_type": "markdown",
|
| 114 |
+
"metadata": {},
|
| 115 |
+
"source": [
|
| 116 |
+
"## 2. Data Preparation\n",
|
| 117 |
+
"\n",
|
| 118 |
+
"We will extract text from the PDF audit reports located in the `Data` directory. \n",
|
| 119 |
+
"\n",
|
| 120 |
+
"**Cleaning Steps**:\n",
|
| 121 |
+
"- Extract text using `pdfplumber`.\n",
|
| 122 |
+
"- Remove potential headers and footers (heuristic: very short lines at top/bottom of pages).\n",
|
| 123 |
+
"- Normalize whitespace.\n",
|
| 124 |
+
"- Anonymize sensitive patterns (placeholder implementation)."
|
| 125 |
+
]
|
| 126 |
+
},
|
| 127 |
+
{
|
| 128 |
+
"cell_type": "code",
|
| 129 |
+
"execution_count": 4,
|
| 130 |
+
"metadata": {},
|
| 131 |
+
"outputs": [
|
| 132 |
+
{
|
| 133 |
+
"name": "stdout",
|
| 134 |
+
"output_type": "stream",
|
| 135 |
+
"text": [
|
| 136 |
+
"Searching for PDFs in: /content/drive/MyDrive/Data\n",
|
| 137 |
+
"Processing /content/drive/MyDrive/Data/Annual_Review_of_Audit_Quality_2025.pdf...\n",
|
| 138 |
+
"Processing /content/drive/MyDrive/Data/BDO_LLP_Audit_Quality_Inspection_and_Supervision_2025.pdf...\n",
|
| 139 |
+
"Processing /content/drive/MyDrive/Data/Deloitte_LLP_Audit_Quality_Inspection_and_Supervision_2025.pdf...\n",
|
| 140 |
+
"Processing /content/drive/MyDrive/Data/Ernst__Young_LLP_Audit_Quality_Inspection_and_Supervision_2025.pdf...\n",
|
| 141 |
+
"Processing /content/drive/MyDrive/Data/Forvis_Mazars_LLP_Audit_Quality_Inspection_and_Supervision_2025.pdf...\n",
|
| 142 |
+
"Processing /content/drive/MyDrive/Data/KPMG_LLP_Audit_Quality_Inspection_and_Supervision_2025.pdf...\n",
|
| 143 |
+
"Processing /content/drive/MyDrive/Data/PricewaterhouseCoopers_LLP_Audit_Quality_Inspection_and_Supervision_2025.pdf...\n",
|
| 144 |
+
"Processing /content/drive/MyDrive/Data/Annual_Review_of_Audit_Quality_2024_7yhxTsi.pdf...\n",
|
| 145 |
+
"Processing /content/drive/MyDrive/Data/Tier_1_Firms__Overview_2023.pdf...\n",
|
| 146 |
+
"Processing /content/drive/MyDrive/Data/FRC_Audit_Quality_Inspection_and_Supervision_Public_Report_2022_-_Tier_1_Firms_Overview.pdf...\n",
|
| 147 |
+
"Processing /content/drive/MyDrive/Data/Individual_Rights_Data_Privacy_Policy.pdf...\n",
|
| 148 |
+
"\n",
|
| 149 |
+
"Successfully loaded 11 documents.\n"
|
| 150 |
+
]
|
| 151 |
+
}
|
| 152 |
+
],
|
| 153 |
+
"source": [
|
| 154 |
+
"def extract_text_from_pdf(pdf_path):\n",
|
| 155 |
+
" text_content = []\n",
|
| 156 |
+
" with pdfplumber.open(pdf_path) as pdf:\n",
|
| 157 |
+
" for page in pdf.pages:\n",
|
| 158 |
+
" # Extract text\n",
|
| 159 |
+
" text = page.extract_text()\n",
|
| 160 |
+
" if not text:\n",
|
| 161 |
+
" continue\n",
|
| 162 |
+
" \n",
|
| 163 |
+
" lines = text.split('\\n')\n",
|
| 164 |
+
" \n",
|
| 165 |
+
" # Basic Heuristic: Remove first and last lines if they likely resemble headers/footers (e.g., page numbers or short titles)\n",
|
| 166 |
+
" # Adjust this logic based on your specific PDF layout\n",
|
| 167 |
+
" if len(lines) > 2:\n",
|
| 168 |
+
" # Remove header if short (arbitrary length < 50 chars as a heuristic)\n",
|
| 169 |
+
" if len(lines[0]) < 50:\n",
|
| 170 |
+
" lines = lines[1:]\n",
|
| 171 |
+
" # Remove footer if short and looks like page number\n",
|
| 172 |
+
" if len(lines) > 0 and len(lines[-1]) < 20:\n",
|
| 173 |
+
" lines = lines[:-1]\n",
|
| 174 |
+
" \n",
|
| 175 |
+
" page_text = \"\\n\".join(lines)\n",
|
| 176 |
+
" text_content.append(page_text)\n",
|
| 177 |
+
" \n",
|
| 178 |
+
" full_text = \"\\n\\n\".join(text_content)\n",
|
| 179 |
+
" return full_text\n",
|
| 180 |
+
"\n",
|
| 181 |
+
"def clean_data(text):\n",
|
| 182 |
+
" # Normalize whitespace\n",
|
| 183 |
+
" text = re.sub(r'\\s+', ' ', text).strip()\n",
|
| 184 |
+
" \n",
|
| 185 |
+
" # Placeholder for anonymization (e.g., replace emails, phone numbers)\n",
|
| 186 |
+
" # This regex is a simple example and should be expanded for real production use\n",
|
| 187 |
+
" text = re.sub(r'[\\w\\.-]+@[\\w\\.-]+', '[EMAIL]', text)\n",
|
| 188 |
+
" \n",
|
| 189 |
+
" return text\n",
|
| 190 |
+
"\n",
|
| 191 |
+
"# Main Data Loading Loop\n",
|
| 192 |
+
"try:\n",
|
| 193 |
+
" data_dir = DATA_DIR\n",
|
| 194 |
+
"except NameError:\n",
|
| 195 |
+
" data_dir = \"./Data\"\n",
|
| 196 |
+
" \n",
|
| 197 |
+
"print(f\"Searching for PDFs in: {data_dir}\")\n",
|
| 198 |
+
"pdf_files = glob.glob(str(data_dir / \"*.pdf\"))\n",
|
| 199 |
+
"\n",
|
| 200 |
+
"raw_texts = []\n",
|
| 201 |
+
"for pdf_file in pdf_files:\n",
|
| 202 |
+
" print(f\"Processing {pdf_file}...\")\n",
|
| 203 |
+
" try:\n",
|
| 204 |
+
" raw_text = extract_text_from_pdf(pdf_file)\n",
|
| 205 |
+
" cleaned_text = clean_data(raw_text)\n",
|
| 206 |
+
" if len(cleaned_text) > 500: # Only keep documents with substantial content\n",
|
| 207 |
+
" raw_texts.append(cleaned_text)\n",
|
| 208 |
+
" except Exception as e:\n",
|
| 209 |
+
" print(f\"Error processing {pdf_file}: {e}\")\n",
|
| 210 |
+
"\n",
|
| 211 |
+
"print(f\"\\nSuccessfully loaded {len(raw_texts)} documents.\")"
|
| 212 |
+
]
|
| 213 |
+
},
|
| 214 |
+
{
|
| 215 |
+
"cell_type": "markdown",
|
| 216 |
+
"metadata": {},
|
| 217 |
+
"source": [
|
| 218 |
+
"## 3. Dataset Tokenization and Chunking\n",
|
| 219 |
+
"\n",
|
| 220 |
+
"We need to process the text into chunks suitable for the model's context window. \n",
|
| 221 |
+
"- **Context Window**: 1024 tokens (Reduced from 2048 to save VRAM).\n",
|
| 222 |
+
"- **Overlap**: No overlap in packing strategy.\n",
|
| 223 |
+
"- **Format**: Prepare as a Hugging Face Dataset."
|
| 224 |
+
]
|
| 225 |
+
},
|
| 226 |
+
{
|
| 227 |
+
"cell_type": "code",
|
| 228 |
+
"execution_count": 5,
|
| 229 |
+
"metadata": {},
|
| 230 |
+
"outputs": [
|
| 231 |
+
{
|
| 232 |
+
"name": "stdout",
|
| 233 |
+
"output_type": "stream",
|
| 234 |
+
"text": [
|
| 235 |
+
"DatasetDict({\n",
|
| 236 |
+
" train: Dataset({\n",
|
| 237 |
+
" features: ['text'],\n",
|
| 238 |
+
" num_rows: 9\n",
|
| 239 |
+
" })\n",
|
| 240 |
+
" test: Dataset({\n",
|
| 241 |
+
" features: ['text'],\n",
|
| 242 |
+
" num_rows: 2\n",
|
| 243 |
+
" })\n",
|
| 244 |
+
"})\n"
|
| 245 |
+
]
|
| 246 |
+
},
|
| 247 |
+
{
|
| 248 |
+
"name": "stderr",
|
| 249 |
+
"output_type": "stream",
|
| 250 |
+
"text": [
|
| 251 |
+
"/usr/local/lib/python3.12/dist-packages/huggingface_hub/utils/_auth.py:104: UserWarning: \n",
|
| 252 |
+
"Error while fetching `HF_TOKEN` secret value from your vault: 'Requesting secret HF_TOKEN timed out. Secrets can only be fetched when running from the Colab UI.'.\n",
|
| 253 |
+
"You are not authenticated with the Hugging Face Hub in this notebook.\n",
|
| 254 |
+
"If the error persists, please let us know by opening an issue on GitHub (https://github.com/huggingface/huggingface_hub/issues/new).\n",
|
| 255 |
+
" warnings.warn(\n"
|
| 256 |
+
]
|
| 257 |
+
},
|
| 258 |
+
{
|
| 259 |
+
"data": {
|
| 260 |
+
"application/vnd.jupyter.widget-view+json": {
|
| 261 |
+
"model_id": "d7d2664df18f403cbc36eab98e88f893",
|
| 262 |
+
"version_major": 2,
|
| 263 |
+
"version_minor": 0
|
| 264 |
+
},
|
| 265 |
+
"text/plain": [
|
| 266 |
+
"Chunking and Tokenizing: 0%| | 0/9 [00:00<?, ? examples/s]"
|
| 267 |
+
]
|
| 268 |
+
},
|
| 269 |
+
"metadata": {},
|
| 270 |
+
"output_type": "display_data"
|
| 271 |
+
},
|
| 272 |
+
{
|
| 273 |
+
"data": {
|
| 274 |
+
"application/vnd.jupyter.widget-view+json": {
|
| 275 |
+
"model_id": "164effd8479149a2b96f05a0d4af7ac1",
|
| 276 |
+
"version_major": 2,
|
| 277 |
+
"version_minor": 0
|
| 278 |
+
},
|
| 279 |
+
"text/plain": [
|
| 280 |
+
"Chunking and Tokenizing: 0%| | 0/2 [00:00<?, ? examples/s]"
|
| 281 |
+
]
|
| 282 |
+
},
|
| 283 |
+
"metadata": {},
|
| 284 |
+
"output_type": "display_data"
|
| 285 |
+
},
|
| 286 |
+
{
|
| 287 |
+
"name": "stdout",
|
| 288 |
+
"output_type": "stream",
|
| 289 |
+
"text": [
|
| 290 |
+
"Train chunks: 107\n",
|
| 291 |
+
"Test chunks: 23\n"
|
| 292 |
+
]
|
| 293 |
+
}
|
| 294 |
+
],
|
| 295 |
+
"source": [
|
| 296 |
+
"# Create HF Dataset\n",
|
| 297 |
+
"dataset = Dataset.from_dict({\"text\": raw_texts})\n",
|
| 298 |
+
"\n",
|
| 299 |
+
"# Split into train and validation\n",
|
| 300 |
+
"dataset = dataset.train_test_split(test_size=0.1, seed=42)\n",
|
| 301 |
+
"print(dataset)\n",
|
| 302 |
+
"\n",
|
| 303 |
+
"# Load Tokenizer\n",
|
| 304 |
+
"model_id = \"mistralai/Mistral-7B-v0.1\"\n",
|
| 305 |
+
"tokenizer = AutoTokenizer.from_pretrained(model_id, trust_remote_code=True)\n",
|
| 306 |
+
"tokenizer.pad_token = tokenizer.eos_token # Mistral has no pad token by default\n",
|
| 307 |
+
"\n",
|
| 308 |
+
"def chunk_and_tokenize(examples):\n",
|
| 309 |
+
" # Flatten texts into a single long string of tokens\n",
|
| 310 |
+
" chunk_size = 1024 # Reduced from 2048 to save VRAM\n",
|
| 311 |
+
" \n",
|
| 312 |
+
" # Basic tokenization without padding/truncated\n",
|
| 313 |
+
" tokens = tokenizer(examples[\"text\"], truncation=False, return_attention_mask=False)[\"input_ids\"]\n",
|
| 314 |
+
" \n",
|
| 315 |
+
" # Flatten list of lists into one big list of tokens\n",
|
| 316 |
+
" concatenated_tokens = [tok for doc in tokens for tok in doc]\n",
|
| 317 |
+
" \n",
|
| 318 |
+
" # Calculate total length divisible by chunk_size\n",
|
| 319 |
+
" # We drop the small remainder at the very end of the entire dataset\n",
|
| 320 |
+
" total_length = len(concatenated_tokens)\n",
|
| 321 |
+
" if total_length >= chunk_size:\n",
|
| 322 |
+
" total_length = (total_length // chunk_size) * chunk_size\n",
|
| 323 |
+
" else:\n",
|
| 324 |
+
" # Handle highly unlikely case where entire dataset < chunk_size tokens\n",
|
| 325 |
+
" # Pad to chunk_size\n",
|
| 326 |
+
" concatenated_tokens += [tokenizer.eos_token_id] * (chunk_size - total_length)\n",
|
| 327 |
+
" total_length = chunk_size\n",
|
| 328 |
+
"\n",
|
| 329 |
+
" # Split by chunks of max_len\n",
|
| 330 |
+
" result = {\n",
|
| 331 |
+
" \"input_ids\": [concatenated_tokens[i : i + chunk_size] for i in range(0, total_length, chunk_size)],\n",
|
| 332 |
+
" \"labels\": [concatenated_tokens[i : i + chunk_size] for i in range(0, total_length, chunk_size)]\n",
|
| 333 |
+
" }\n",
|
| 334 |
+
" \n",
|
| 335 |
+
" return result\n",
|
| 336 |
+
"\n",
|
| 337 |
+
"# Apply processing\n",
|
| 338 |
+
"tokenized_dataset = dataset.map(\n",
|
| 339 |
+
" chunk_and_tokenize,\n",
|
| 340 |
+
" batched=True,\n",
|
| 341 |
+
" remove_columns=dataset[\"train\"].column_names,\n",
|
| 342 |
+
" desc=\"Chunking and Tokenizing\"\n",
|
| 343 |
+
")\n",
|
| 344 |
+
"\n",
|
| 345 |
+
"print(f\"Train chunks: {len(tokenized_dataset['train'])}\")\n",
|
| 346 |
+
"print(f\"Test chunks: {len(tokenized_dataset['test'])}\")"
|
| 347 |
+
]
|
| 348 |
+
},
|
| 349 |
+
{
|
| 350 |
+
"cell_type": "markdown",
|
| 351 |
+
"metadata": {},
|
| 352 |
+
"source": [
|
| 353 |
+
"## 4. Model Loading with QLoRA\n",
|
| 354 |
+
"\n",
|
| 355 |
+
"We load Mistral-7B in 4-bit quantization to fit on a T4 GPU.\n",
|
| 356 |
+
"Then we attach LoRA adapters for parameter-efficient fine-tuning."
|
| 357 |
+
]
|
| 358 |
+
},
|
| 359 |
+
{
|
| 360 |
+
"cell_type": "code",
|
| 361 |
+
"execution_count": 6,
|
| 362 |
+
"metadata": {},
|
| 363 |
+
"outputs": [
|
| 364 |
+
{
|
| 365 |
+
"data": {
|
| 366 |
+
"application/vnd.jupyter.widget-view+json": {
|
| 367 |
+
"model_id": "0ae545926d92459b8ab84e155ad3685e",
|
| 368 |
+
"version_major": 2,
|
| 369 |
+
"version_minor": 0
|
| 370 |
+
},
|
| 371 |
+
"text/plain": [
|
| 372 |
+
"Loading weights: 0%| | 0/291 [00:00<?, ?it/s]"
|
| 373 |
+
]
|
| 374 |
+
},
|
| 375 |
+
"metadata": {},
|
| 376 |
+
"output_type": "display_data"
|
| 377 |
+
},
|
| 378 |
+
{
|
| 379 |
+
"name": "stdout",
|
| 380 |
+
"output_type": "stream",
|
| 381 |
+
"text": [
|
| 382 |
+
"trainable params: 41,943,040 || all params: 7,283,675,136 || trainable%: 0.5758\n"
|
| 383 |
+
]
|
| 384 |
+
}
|
| 385 |
+
],
|
| 386 |
+
"source": [
|
| 387 |
+
"# 4-bit Quantization Config\n",
|
| 388 |
+
"bnb_config = BitsAndBytesConfig(\n",
|
| 389 |
+
" load_in_4bit=True,\n",
|
| 390 |
+
" bnb_4bit_quant_type=\"nf4\",\n",
|
| 391 |
+
" bnb_4bit_compute_dtype=torch.float16, # or bfloat16 if supported by hardware\n",
|
| 392 |
+
" bnb_4bit_use_double_quant=False,\n",
|
| 393 |
+
")\n",
|
| 394 |
+
"\n",
|
| 395 |
+
"# Load Base Model\n",
|
| 396 |
+
"model = AutoModelForCausalLM.from_pretrained(\n",
|
| 397 |
+
" model_id,\n",
|
| 398 |
+
" quantization_config=bnb_config,\n",
|
| 399 |
+
" device_map=\"auto\",\n",
|
| 400 |
+
" trust_remote_code=True\n",
|
| 401 |
+
")\n",
|
| 402 |
+
"\n",
|
| 403 |
+
"# Enable gradient checkpointing to save memory\n",
|
| 404 |
+
"model.gradient_checkpointing_enable()\n",
|
| 405 |
+
"model = prepare_model_for_kbit_training(model)\n",
|
| 406 |
+
"\n",
|
| 407 |
+
"# LoRA Configuration\n",
|
| 408 |
+
"peft_config = LoraConfig(\n",
|
| 409 |
+
" r=16, # Rank\n",
|
| 410 |
+
" lora_alpha=32,\n",
|
| 411 |
+
" lora_dropout=0.05,\n",
|
| 412 |
+
" bias=\"none\",\n",
|
| 413 |
+
" task_type=\"CAUSAL_LM\",\n",
|
| 414 |
+
" # Target all linear layers for better adaptation\n",
|
| 415 |
+
" target_modules=[\"q_proj\", \"k_proj\", \"v_proj\", \"o_proj\", \"gate_proj\", \"up_proj\", \"down_proj\"]\n",
|
| 416 |
+
")\n",
|
| 417 |
+
"\n",
|
| 418 |
+
"model = get_peft_model(model, peft_config)\n",
|
| 419 |
+
"model.print_trainable_parameters()"
|
| 420 |
+
]
|
| 421 |
+
},
|
| 422 |
+
{
|
| 423 |
+
"cell_type": "markdown",
|
| 424 |
+
"metadata": {},
|
| 425 |
+
"source": [
|
| 426 |
+
"## 5. Training\n",
|
| 427 |
+
"\n",
|
| 428 |
+
"We use the basic `Trainer` with `DataCollatorForLanguageModeling`. \n",
|
| 429 |
+
"The objective is purely self-supervised next-token prediction."
|
| 430 |
+
]
|
| 431 |
+
},
|
| 432 |
+
{
|
| 433 |
+
"cell_type": "code",
|
| 434 |
+
"execution_count": 7,
|
| 435 |
+
"metadata": {},
|
| 436 |
+
"outputs": [
|
| 437 |
+
{
|
| 438 |
+
"name": "stderr",
|
| 439 |
+
"output_type": "stream",
|
| 440 |
+
"text": [
|
| 441 |
+
"/usr/local/lib/python3.12/dist-packages/torch/_dynamo/eval_frame.py:1181: UserWarning: torch.utils.checkpoint: the use_reentrant parameter should be passed explicitly. Starting in PyTorch 2.9, calling checkpoint without use_reentrant will raise an exception. use_reentrant=False is recommended, but if you need to preserve the current default behavior, you can pass use_reentrant=True. Refer to docs for more details on the differences between the two variants.\n",
|
| 442 |
+
" return fn(*args, **kwargs)\n"
|
| 443 |
+
]
|
| 444 |
+
},
|
| 445 |
+
{
|
| 446 |
+
"data": {
|
| 447 |
+
"text/html": [
|
| 448 |
+
"\n",
|
| 449 |
+
" <div>\n",
|
| 450 |
+
" \n",
|
| 451 |
+
" <progress value='42' max='42' style='width:300px; height:20px; vertical-align: middle;'></progress>\n",
|
| 452 |
+
" [42/42 30:01, Epoch 3/3]\n",
|
| 453 |
+
" </div>\n",
|
| 454 |
+
" <table border=\"1\" class=\"dataframe\">\n",
|
| 455 |
+
" <thead>\n",
|
| 456 |
+
" <tr style=\"text-align: left;\">\n",
|
| 457 |
+
" <th>Step</th>\n",
|
| 458 |
+
" <th>Training Loss</th>\n",
|
| 459 |
+
" <th>Validation Loss</th>\n",
|
| 460 |
+
" </tr>\n",
|
| 461 |
+
" </thead>\n",
|
| 462 |
+
" <tbody>\n",
|
| 463 |
+
" <tr>\n",
|
| 464 |
+
" <td>10</td>\n",
|
| 465 |
+
" <td>2.144592</td>\n",
|
| 466 |
+
" <td>2.107712</td>\n",
|
| 467 |
+
" </tr>\n",
|
| 468 |
+
" <tr>\n",
|
| 469 |
+
" <td>20</td>\n",
|
| 470 |
+
" <td>1.789090</td>\n",
|
| 471 |
+
" <td>1.951720</td>\n",
|
| 472 |
+
" </tr>\n",
|
| 473 |
+
" <tr>\n",
|
| 474 |
+
" <td>30</td>\n",
|
| 475 |
+
" <td>1.445677</td>\n",
|
| 476 |
+
" <td>1.882343</td>\n",
|
| 477 |
+
" </tr>\n",
|
| 478 |
+
" <tr>\n",
|
| 479 |
+
" <td>40</td>\n",
|
| 480 |
+
" <td>1.282020</td>\n",
|
| 481 |
+
" <td>1.864601</td>\n",
|
| 482 |
+
" </tr>\n",
|
| 483 |
+
" </tbody>\n",
|
| 484 |
+
"</table><p>"
|
| 485 |
+
],
|
| 486 |
+
"text/plain": [
|
| 487 |
+
"<IPython.core.display.HTML object>"
|
| 488 |
+
]
|
| 489 |
+
},
|
| 490 |
+
"metadata": {},
|
| 491 |
+
"output_type": "display_data"
|
| 492 |
+
},
|
| 493 |
+
{
|
| 494 |
+
"name": "stderr",
|
| 495 |
+
"output_type": "stream",
|
| 496 |
+
"text": [
|
| 497 |
+
"/usr/local/lib/python3.12/dist-packages/torch/_dynamo/eval_frame.py:1181: UserWarning: torch.utils.checkpoint: the use_reentrant parameter should be passed explicitly. Starting in PyTorch 2.9, calling checkpoint without use_reentrant will raise an exception. use_reentrant=False is recommended, but if you need to preserve the current default behavior, you can pass use_reentrant=True. Refer to docs for more details on the differences between the two variants.\n",
|
| 498 |
+
" return fn(*args, **kwargs)\n",
|
| 499 |
+
"/usr/local/lib/python3.12/dist-packages/torch/_dynamo/eval_frame.py:1181: UserWarning: torch.utils.checkpoint: the use_reentrant parameter should be passed explicitly. Starting in PyTorch 2.9, calling checkpoint without use_reentrant will raise an exception. use_reentrant=False is recommended, but if you need to preserve the current default behavior, you can pass use_reentrant=True. Refer to docs for more details on the differences between the two variants.\n",
|
| 500 |
+
" return fn(*args, **kwargs)\n"
|
| 501 |
+
]
|
| 502 |
+
},
|
| 503 |
+
{
|
| 504 |
+
"data": {
|
| 505 |
+
"text/plain": [
|
| 506 |
+
"TrainOutput(global_step=42, training_loss=1.6343639180773781, metrics={'train_runtime': 1842.9007, 'train_samples_per_second': 0.174, 'train_steps_per_second': 0.023, 'total_flos': 1.4106535567294464e+16, 'train_loss': 1.6343639180773781, 'epoch': 3.0})"
|
| 507 |
+
]
|
| 508 |
+
},
|
| 509 |
+
"execution_count": 7,
|
| 510 |
+
"metadata": {},
|
| 511 |
+
"output_type": "execute_result"
|
| 512 |
+
}
|
| 513 |
+
],
|
| 514 |
+
"source": [
|
| 515 |
+
"# Clear cache before training\n",
|
| 516 |
+
"torch.cuda.empty_cache()\n",
|
| 517 |
+
"\n",
|
| 518 |
+
"# Data Collator\n",
|
| 519 |
+
"data_collator = DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm=False)\n",
|
| 520 |
+
"\n",
|
| 521 |
+
"# Training Arguments\n",
|
| 522 |
+
"training_args = TrainingArguments(\n",
|
| 523 |
+
" output_dir=\"./audit-mistral-finetuned\",\n",
|
| 524 |
+
" per_device_train_batch_size=1, # Reduced to 1 to fit T4 VRAM\n",
|
| 525 |
+
" gradient_accumulation_steps=8, # Increased to 8 to maintain effective batch size\n",
|
| 526 |
+
" learning_rate=2e-4,\n",
|
| 527 |
+
" logging_steps=10,\n",
|
| 528 |
+
" num_train_epochs=3, # Increased to 3 epochs\n",
|
| 529 |
+
" save_strategy=\"epoch\",\n",
|
| 530 |
+
" eval_strategy=\"steps\", # Evaluate more frequently\n",
|
| 531 |
+
" eval_steps=10,\n",
|
| 532 |
+
" fp16=True,\n",
|
| 533 |
+
" optim=\"paged_adamw_8bit\", # Memory efficient optimizer\n",
|
| 534 |
+
" report_to=\"none\"\n",
|
| 535 |
+
")\n",
|
| 536 |
+
"\n",
|
| 537 |
+
"# Initialize Trainer\n",
|
| 538 |
+
"trainer = Trainer(\n",
|
| 539 |
+
" model=model,\n",
|
| 540 |
+
" args=training_args,\n",
|
| 541 |
+
" train_dataset=tokenized_dataset[\"train\"],\n",
|
| 542 |
+
" eval_dataset=tokenized_dataset[\"test\"],\n",
|
| 543 |
+
" data_collator=data_collator,\n",
|
| 544 |
+
")\n",
|
| 545 |
+
"\n",
|
| 546 |
+
"# Start Training\n",
|
| 547 |
+
"trainer.train()"
|
| 548 |
+
]
|
| 549 |
+
},
|
| 550 |
+
{
|
| 551 |
+
"cell_type": "markdown",
|
| 552 |
+
"metadata": {},
|
| 553 |
+
"source": [
|
| 554 |
+
"## 6. Evaluation\n",
|
| 555 |
+
"\n",
|
| 556 |
+
"We calculate Perplexity as a quantitative metric of how well the model predicts the domain text."
|
| 557 |
+
]
|
| 558 |
+
},
|
| 559 |
+
{
|
| 560 |
+
"cell_type": "code",
|
| 561 |
+
"execution_count": 8,
|
| 562 |
+
"metadata": {},
|
| 563 |
+
"outputs": [
|
| 564 |
+
{
|
| 565 |
+
"data": {
|
| 566 |
+
"text/html": [
|
| 567 |
+
"\n",
|
| 568 |
+
" <div>\n",
|
| 569 |
+
" \n",
|
| 570 |
+
" <progress value='3' max='3' style='width:300px; height:20px; vertical-align: middle;'></progress>\n",
|
| 571 |
+
" [3/3 00:21]\n",
|
| 572 |
+
" </div>\n",
|
| 573 |
+
" "
|
| 574 |
+
],
|
| 575 |
+
"text/plain": [
|
| 576 |
+
"<IPython.core.display.HTML object>"
|
| 577 |
+
]
|
| 578 |
+
},
|
| 579 |
+
"metadata": {},
|
| 580 |
+
"output_type": "display_data"
|
| 581 |
+
},
|
| 582 |
+
{
|
| 583 |
+
"name": "stdout",
|
| 584 |
+
"output_type": "stream",
|
| 585 |
+
"text": [
|
| 586 |
+
"Perplexity: 6.47\n"
|
| 587 |
+
]
|
| 588 |
+
}
|
| 589 |
+
],
|
| 590 |
+
"source": [
|
| 591 |
+
"import math\n",
|
| 592 |
+
"\n",
|
| 593 |
+
"eval_results = trainer.evaluate()\n",
|
| 594 |
+
"perplexity = math.exp(eval_results['eval_loss'])\n",
|
| 595 |
+
"print(f\"Perplexity: {perplexity:.2f}\")"
|
| 596 |
+
]
|
| 597 |
+
},
|
| 598 |
+
{
|
| 599 |
+
"cell_type": "markdown",
|
| 600 |
+
"metadata": {},
|
| 601 |
+
"source": [
|
| 602 |
+
"## 7. Inference\n",
|
| 603 |
+
"\n",
|
| 604 |
+
"Test the model's generation capabilities on an audit-related prompt."
|
| 605 |
+
]
|
| 606 |
+
},
|
| 607 |
+
{
|
| 608 |
+
"cell_type": "code",
|
| 609 |
+
"execution_count": null,
|
| 610 |
+
"metadata": {},
|
| 611 |
+
"outputs": [
|
| 612 |
+
{
|
| 613 |
+
"name": "stderr",
|
| 614 |
+
"output_type": "stream",
|
| 615 |
+
"text": [
|
| 616 |
+
"Setting `pad_token_id` to `eos_token_id`:2 for open-end generation.\n"
|
| 617 |
+
]
|
| 618 |
+
},
|
| 619 |
+
{
|
| 620 |
+
"name": "stdout",
|
| 621 |
+
"output_type": "stream",
|
| 622 |
+
"text": [
|
| 623 |
+
"The audit of the financial statements reveals that the audited entity is likely to be impacted by a significant risk related to climate change. The entity must include a statement in its annual report, as required under the Companies Act 2006, to that effect. In this example, the entity’s statement is included on the inside front cover of its annual report and sets out the following: “Climate change is one of the greatest threats to our future prosperity. We are taking action to reduce our impact on the environment and to prepare for the opportunities and risks of climate change. We are setting science-based targets to reduce our emissions and to increase our use of renewable energy. We are developing our climate risk disclosures to provide greater transparency to our stakeholders\n"
|
| 624 |
+
]
|
| 625 |
+
}
|
| 626 |
+
],
|
| 627 |
+
"source": [
|
| 628 |
+
"# Save the model (adapters only)\n",
|
| 629 |
+
"trainer.save_model(\"/content/drive/MyDrive/Self_Supervised_finetuning_Model/audit-mistral-7b-qlora\")\n",
|
| 630 |
+
"\n",
|
| 631 |
+
"# Inference Prompt\n",
|
| 632 |
+
"prompt = \"The audit of the financial statements reveals that\"\n",
|
| 633 |
+
"inputs = tokenizer(prompt, return_tensors=\"pt\").to(\"cuda\")\n",
|
| 634 |
+
"\n",
|
| 635 |
+
"# Generate\n",
|
| 636 |
+
"with torch.no_grad():\n",
|
| 637 |
+
" outputs = model.generate(\n",
|
| 638 |
+
" **inputs,\n",
|
| 639 |
+
" max_new_tokens=150,\n",
|
| 640 |
+
" temperature=0.7,\n",
|
| 641 |
+
" top_p=0.9,\n",
|
| 642 |
+
" do_sample=True\n",
|
| 643 |
+
" )\n",
|
| 644 |
+
"\n",
|
| 645 |
+
"print(tokenizer.decode(outputs[0], skip_special_tokens=True))"
|
| 646 |
+
]
|
| 647 |
+
},
|
| 648 |
+
{
|
| 649 |
+
"cell_type": "code",
|
| 650 |
+
"execution_count": 10,
|
| 651 |
+
"metadata": {},
|
| 652 |
+
"outputs": [],
|
| 653 |
+
"source": [
|
| 654 |
+
"trainer.save_model(\"/content/drive/MyDrive/Self_Supervised_finetuning_Model/audit-mistral-7b-qlora\")\n"
|
| 655 |
+
]
|
| 656 |
+
}
|
| 657 |
+
],
|
| 658 |
+
"metadata": {
|
| 659 |
+
"kernelspec": {
|
| 660 |
+
"display_name": "Python 3",
|
| 661 |
+
"language": "python",
|
| 662 |
+
"name": "python3"
|
| 663 |
+
},
|
| 664 |
+
"language_info": {
|
| 665 |
+
"codemirror_mode": {
|
| 666 |
+
"name": "ipython",
|
| 667 |
+
"version": 3
|
| 668 |
+
},
|
| 669 |
+
"file_extension": ".py",
|
| 670 |
+
"mimetype": "text/x-python",
|
| 671 |
+
"name": "python",
|
| 672 |
+
"nbconvert_exporter": "python",
|
| 673 |
+
"pygments_lexer": "ipython3",
|
| 674 |
+
"version": "3.10.12"
|
| 675 |
+
}
|
| 676 |
+
},
|
| 677 |
+
"nbformat": 4,
|
| 678 |
+
"nbformat_minor": 2
|
| 679 |
+
}
|