mhamza-007 commited on
Commit
2a98daa
·
verified ·
1 Parent(s): dcc4a1f

Upload 10 files

Browse files
training/__init__.py ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Shared training, evaluation and model-persistence logic."""
2
+
3
+ from training.data_split import split_data
4
+ from training.evaluation import evaluate_predictions, select_best_model
5
+ from training.model_io import load_model, save_model
6
+ from training.trainer import build_text_pipeline, train_and_evaluate_models
7
+
8
+ __all__ = [
9
+ "build_text_pipeline",
10
+ "evaluate_predictions",
11
+ "load_model",
12
+ "save_model",
13
+ "select_best_model",
14
+ "split_data",
15
+ "train_and_evaluate_models",
16
+ ]
training/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (615 Bytes). View file
 
training/__pycache__/data_split.cpython-312.pyc ADDED
Binary file (756 Bytes). View file
 
training/__pycache__/evaluation.cpython-312.pyc ADDED
Binary file (1.37 kB). View file
 
training/__pycache__/model_io.cpython-312.pyc ADDED
Binary file (2.75 kB). View file
 
training/__pycache__/trainer.cpython-312.pyc ADDED
Binary file (1.62 kB). View file
 
training/data_split.py ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Train/test split."""
2
+
3
+ from sklearn.model_selection import train_test_split
4
+
5
+ from config.constants import LABEL_COLUMN, RANDOM_STATE, TEST_SIZE, TEXT_COLUMN
6
+
7
+
8
+ def split_data(df, text_column=TEXT_COLUMN, label_column=LABEL_COLUMN,
9
+ test_size=TEST_SIZE, random_state=RANDOM_STATE):
10
+ """Split the cleaned DataFrame into train/test text and labels."""
11
+ X = df[text_column]
12
+ y = df[label_column]
13
+ return train_test_split(X, y, test_size=test_size, shuffle=True,
14
+ random_state=random_state)
training/evaluation.py ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Metrics computed for every trained model."""
2
+
3
+ from sklearn.metrics import accuracy_score, classification_report
4
+
5
+
6
+ def evaluate_predictions(y_test, y_pred):
7
+ """Return the weighted F1/precision/recall plus accuracy for one model."""
8
+ report = classification_report(y_test, y_pred, output_dict=True)
9
+ f1 = report['weighted avg']['f1-score']
10
+ precision = report['weighted avg']['precision']
11
+ recall = report['weighted avg']['recall']
12
+ accuracy = accuracy_score(y_test, y_pred)
13
+
14
+ return {
15
+ 'F1 Score': f1,
16
+ 'Precision': precision,
17
+ 'Recall': recall,
18
+ 'Accuracy': accuracy,
19
+ }
20
+
21
+
22
+ def select_best_model(results_df):
23
+ """Return ``(best_model_name, best_model)`` - the row with the highest F1."""
24
+ best_model_name = results_df.loc[results_df['F1 Score'].idxmax(), 'Model']
25
+ best_model = results_df.loc[
26
+ results_df['Model'] == best_model_name, 'Trained Model'].values[0]
27
+ return best_model_name, best_model
training/model_io.py ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Saving and loading the trained pipeline."""
2
+
3
+ import json
4
+ from datetime import datetime, timezone
5
+ from pathlib import Path
6
+
7
+ import joblib
8
+
9
+ from config.paths import ARTIFACTS_DIR, DEFAULT_MODEL_PATH
10
+
11
+ #: Machine-readable summary of a training run, read by the web API.
12
+ DEFAULT_METRICS_PATH = ARTIFACTS_DIR / "metrics.json"
13
+
14
+
15
+ def save_model(model, path=DEFAULT_MODEL_PATH):
16
+ """Persist ``model`` with joblib"""
17
+ path = Path(path)
18
+ path.parent.mkdir(parents=True, exist_ok=True)
19
+ joblib.dump(model, path)
20
+ return path
21
+
22
+
23
+ def load_model(path=DEFAULT_MODEL_PATH):
24
+ """Load a pipeline previously saved by :func:`save_model`."""
25
+ return joblib.load(path)
26
+
27
+
28
+ def save_metrics(results_df, best_model_name, path=DEFAULT_METRICS_PATH,
29
+ dataset=None, plots=None):
30
+ """Write the run's scores to JSON so the web app can display them.
31
+
32
+ ``run_pipeline`` prints this table and then throws it away; the API needs it
33
+ to show which models were compared and which one won, without hardcoding
34
+ numbers in the front end.
35
+ """
36
+ path = Path(path)
37
+ path.parent.mkdir(parents=True, exist_ok=True)
38
+
39
+ scores = results_df.drop(columns=['Trained Model'])
40
+ models = [
41
+ {
42
+ 'model': row['Model'],
43
+ 'f1': float(row['F1 Score']),
44
+ 'precision': float(row['Precision']),
45
+ 'recall': float(row['Recall']),
46
+ 'accuracy': float(row['Accuracy']),
47
+ 'is_best': row['Model'] == best_model_name,
48
+ }
49
+ for _, row in scores.iterrows()
50
+ ]
51
+
52
+ payload = {
53
+ 'best_model': best_model_name,
54
+ 'selected_by': 'highest weighted F1 on the test set',
55
+ 'generated_at': datetime.now(timezone.utc).isoformat(timespec='seconds'),
56
+ 'dataset': dataset or {},
57
+ 'models': models,
58
+ 'plots': plots or {},
59
+ }
60
+
61
+ path.write_text(json.dumps(payload, indent=2), encoding='utf-8')
62
+ return path
training/trainer.py ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Training loop shared by all four classifiers."""
2
+
3
+ import pandas as pd
4
+ from sklearn.feature_extraction.text import TfidfVectorizer
5
+ from sklearn.pipeline import Pipeline
6
+
7
+ from training.evaluation import evaluate_predictions, select_best_model
8
+
9
+
10
+ def build_text_pipeline(model):
11
+ """Wrap ``model`` behind a ``TfidfVectorizer``."""
12
+ return Pipeline([('vect', TfidfVectorizer()),
13
+ ('clf', model)])
14
+
15
+
16
+ def train_and_evaluate_models(models, X_train, X_test, y_train, y_test):
17
+ """Train every model in ``models`` and compare them on the test set."""
18
+ results = []
19
+
20
+ for model_name, model in models.items():
21
+ # Create a text classification pipeline with TF-IDF vectorizer and the specified model
22
+ text_clf = build_text_pipeline(model)
23
+
24
+ # Train the model
25
+ text_clf.fit(X_train, y_train)
26
+
27
+ # Make predictions on the test set
28
+ y_pred = text_clf.predict(X_test)
29
+
30
+ # Evaluate the model
31
+ metrics = evaluate_predictions(y_test, y_pred)
32
+
33
+ # Store the results in a dictionary
34
+ result_dict = {
35
+ 'Model': model_name,
36
+ 'Trained Model': text_clf, # Store the trained model
37
+ **metrics,
38
+ }
39
+
40
+ # Append the results to the list
41
+ results.append(result_dict)
42
+
43
+ # Convert the list of dictionaries to a DataFrame
44
+ results_df = pd.DataFrame(results)
45
+
46
+ # Find the best model based on the highest F1 Score
47
+ best_model_name, best_model = select_best_model(results_df)
48
+
49
+ return best_model_name, best_model, results_df