libz 0.3__tar.gz → 0.5__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. {libz-0.3 → libz-0.5}/PKG-INFO +1 -1
  2. libz-0.5/libz/DL/__init__.py +15 -0
  3. libz-0.5/libz/DLG/__init__.py +15 -0
  4. libz-0.5/libz/DLG/prac1.py +71 -0
  5. libz-0.5/libz/DLG/prac2.py +108 -0
  6. libz-0.5/libz/DLG/prac3.py +108 -0
  7. libz-0.5/libz/DLG/prac4.py +105 -0
  8. libz-0.5/libz/DLG/prac5.py +99 -0
  9. libz-0.5/libz/DLG/prac6.py +119 -0
  10. libz-0.5/libz/DLG/prac7.py +110 -0
  11. libz-0.5/libz/DLG/prac8.py +141 -0
  12. libz-0.5/libz/DLG/prac9.py +93 -0
  13. {libz-0.3 → libz-0.5}/libz/__init__.py +1 -1
  14. {libz-0.3 → libz-0.5}/libz/_core.py +43 -34
  15. {libz-0.3 → libz-0.5}/libz.egg-info/PKG-INFO +1 -1
  16. {libz-0.3 → libz-0.5}/pyproject.toml +1 -1
  17. libz-0.3/libz/DL/__init__.py +0 -3
  18. libz-0.3/libz/DLG/__init__.py +0 -3
  19. libz-0.3/libz/DLG/prac1.py +0 -36
  20. libz-0.3/libz/DLG/prac2.py +0 -3
  21. libz-0.3/libz/DLG/prac3.py +0 -3
  22. libz-0.3/libz/DLG/prac4.py +0 -3
  23. libz-0.3/libz/DLG/prac5.py +0 -3
  24. libz-0.3/libz/DLG/prac6.py +0 -3
  25. libz-0.3/libz/DLG/prac7.py +0 -3
  26. libz-0.3/libz/DLG/prac8.py +0 -3
  27. libz-0.3/libz/DLG/prac9.py +0 -3
  28. {libz-0.3 → libz-0.5}/README.md +0 -0
  29. {libz-0.3 → libz-0.5}/libz/AWT/__init__.py +0 -0
  30. {libz-0.3 → libz-0.5}/libz/AWT/prac1.py +0 -0
  31. {libz-0.3 → libz-0.5}/libz/AWT/prac10.py +0 -0
  32. {libz-0.3 → libz-0.5}/libz/AWT/prac2.py +0 -0
  33. {libz-0.3 → libz-0.5}/libz/AWT/prac3.py +0 -0
  34. {libz-0.3 → libz-0.5}/libz/AWT/prac4.py +0 -0
  35. {libz-0.3 → libz-0.5}/libz/AWT/prac5.py +0 -0
  36. {libz-0.3 → libz-0.5}/libz/AWT/prac6.py +0 -0
  37. {libz-0.3 → libz-0.5}/libz/AWT/prac7.py +0 -0
  38. {libz-0.3 → libz-0.5}/libz/AWT/prac8.py +0 -0
  39. {libz-0.3 → libz-0.5}/libz/AWT/prac9.py +0 -0
  40. {libz-0.3 → libz-0.5}/libz/BDA/__init__.py +0 -0
  41. {libz-0.3 → libz-0.5}/libz/BDA/prac1.py +0 -0
  42. {libz-0.3 → libz-0.5}/libz/BDA/prac10.py +0 -0
  43. {libz-0.3 → libz-0.5}/libz/BDA/prac2.py +0 -0
  44. {libz-0.3 → libz-0.5}/libz/BDA/prac3.py +0 -0
  45. {libz-0.3 → libz-0.5}/libz/BDA/prac4.py +0 -0
  46. {libz-0.3 → libz-0.5}/libz/BDA/prac5.py +0 -0
  47. {libz-0.3 → libz-0.5}/libz/BDA/prac6.py +0 -0
  48. {libz-0.3 → libz-0.5}/libz/BDA/prac7.py +0 -0
  49. {libz-0.3 → libz-0.5}/libz/BDA/prac8.py +0 -0
  50. {libz-0.3 → libz-0.5}/libz/BDA/prac9.py +0 -0
  51. {libz-0.3 → libz-0.5}/libz/BIO/__init__.py +0 -0
  52. {libz-0.3 → libz-0.5}/libz/BIO/prac1.py +0 -0
  53. {libz-0.3 → libz-0.5}/libz/BIO/prac10.py +0 -0
  54. {libz-0.3 → libz-0.5}/libz/BIO/prac2.py +0 -0
  55. {libz-0.3 → libz-0.5}/libz/BIO/prac3.py +0 -0
  56. {libz-0.3 → libz-0.5}/libz/BIO/prac4.py +0 -0
  57. {libz-0.3 → libz-0.5}/libz/BIO/prac5.py +0 -0
  58. {libz-0.3 → libz-0.5}/libz/BIO/prac6.py +0 -0
  59. {libz-0.3 → libz-0.5}/libz/BIO/prac7.py +0 -0
  60. {libz-0.3 → libz-0.5}/libz/BIO/prac8.py +0 -0
  61. {libz-0.3 → libz-0.5}/libz/BIO/prac9.py +0 -0
  62. {libz-0.3 → libz-0.5}/libz/DL/prac1.py +0 -0
  63. {libz-0.3 → libz-0.5}/libz/DL/prac2.py +0 -0
  64. {libz-0.3 → libz-0.5}/libz/DL/prac3.py +0 -0
  65. {libz-0.3 → libz-0.5}/libz/DL/prac4.py +0 -0
  66. {libz-0.3 → libz-0.5}/libz/DL/prac5.py +0 -0
  67. {libz-0.3 → libz-0.5}/libz/DL/prac6.py +0 -0
  68. {libz-0.3 → libz-0.5}/libz/DL/prac7.py +0 -0
  69. {libz-0.3 → libz-0.5}/libz/DL/prac8.py +0 -0
  70. {libz-0.3 → libz-0.5}/libz/DL/prac9.py +0 -0
  71. {libz-0.3 → libz-0.5}/libz.egg-info/SOURCES.txt +0 -0
  72. {libz-0.3 → libz-0.5}/libz.egg-info/dependency_links.txt +0 -0
  73. {libz-0.3 → libz-0.5}/libz.egg-info/top_level.txt +0 -0
  74. {libz-0.3 → libz-0.5}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: libz
3
- Version: 0.3
3
+ Version: 0.5
4
4
  Summary: A lightweight Python utility toolkit.
5
5
  Requires-Python: >=3.7
6
6
  Description-Content-Type: text/markdown
@@ -0,0 +1,15 @@
1
+ from libz._core import register
2
+
3
+ TITLES = {
4
+ 1: "Deep feed forward",
5
+ 2: "Regularization and optimization",
6
+ 3: "Semi-supervised learning",
7
+ 4: "Multitasking",
8
+ 5: "CNN-based handwriting recognition",
9
+ 6: "CNN - unsupervised feature learning",
10
+ 7: "Recurrent neural network",
11
+ 8: "Recursive neural network (tree)",
12
+ 9: "PCA vs linear autoencoder",
13
+ }
14
+
15
+ register(__name__, globals(), TITLES)
@@ -0,0 +1,15 @@
1
+ from libz._core import register
2
+
3
+ TITLES = {
4
+ 1: "Deep feed forward (any CSV)",
5
+ 2: "Regularization and optimization (any CSV)",
6
+ 3: "Semi-supervised learning (any text CSV)",
7
+ 4: "Multitasking (any CSV)",
8
+ 5: "CNN-based handwriting recognition (any image folder / MNIST)",
9
+ 6: "CNN - unsupervised feature learning (any image folder / digits)",
10
+ 7: "Recurrent neural network (any text CSV / IMDB)",
11
+ 8: "Recursive neural network (tree) (any text CSV / sample)",
12
+ 9: "PCA vs linear autoencoder (any numeric CSV / synthetic)",
13
+ }
14
+
15
+ register(__name__, globals(), TITLES)
@@ -0,0 +1,71 @@
1
+ # Deep Feed Forward Neural Network - works with any CSV classification dataset
2
+ import numpy as np
3
+ import pandas as pd
4
+ from sklearn.model_selection import train_test_split
5
+ from sklearn.preprocessing import StandardScaler, LabelEncoder
6
+ from sklearn.metrics import classification_report, confusion_matrix
7
+ from tensorflow.keras.models import Sequential
8
+ from tensorflow.keras.layers import Input, Dense, Dropout
9
+ from tensorflow.keras.callbacks import EarlyStopping
10
+
11
+ # 1. Load dataset
12
+ path = input("Enter CSV file path: ").strip().strip('"')
13
+ df = pd.read_csv(path)
14
+ df = df.loc[:, ~df.columns.str.contains("^Unnamed")]
15
+ print(df.head())
16
+ print("Columns:", list(df.columns))
17
+ target = input("Enter target column: ").strip()
18
+
19
+ # 2. Preprocess
20
+ df = df.dropna(subset=[target]).drop_duplicates()
21
+ X = df.drop(columns=[target])
22
+ X = X.drop(columns=[c for c in X.columns if c.lower() == "id"])
23
+ for c in X.columns:
24
+ if pd.api.types.is_numeric_dtype(X[c]):
25
+ X[c] = X[c].fillna(X[c].median())
26
+ else:
27
+ X[c] = X[c].fillna(X[c].mode()[0])
28
+ X = pd.get_dummies(X, drop_first=True, dtype=int)
29
+
30
+ encoder = LabelEncoder()
31
+ y = encoder.fit_transform(df[target].astype(str))
32
+ n_classes = len(encoder.classes_)
33
+ print("Classes:", list(encoder.classes_))
34
+
35
+ # 3. Split and scale
36
+ X_train, X_test, y_train, y_test = train_test_split(
37
+ X, y, test_size=0.2, random_state=42, stratify=y
38
+ )
39
+ scaler = StandardScaler()
40
+ X_train = scaler.fit_transform(X_train)
41
+ X_test = scaler.transform(X_test)
42
+
43
+ # 4. Build deep feed forward network
44
+ model = Sequential([
45
+ Input(shape=(X_train.shape[1],)),
46
+ Dense(128, activation="relu"),
47
+ Dropout(0.3),
48
+ Dense(64, activation="relu"),
49
+ Dropout(0.2),
50
+ Dense(32, activation="relu"),
51
+ Dense(n_classes, activation="softmax"),
52
+ ])
53
+ model.compile(optimizer="adam", loss="sparse_categorical_crossentropy", metrics=["accuracy"])
54
+ model.summary()
55
+
56
+ # 5. Train
57
+ early_stop = EarlyStopping(monitor="val_loss", patience=5, restore_best_weights=True)
58
+ model.fit(X_train, y_train, epochs=50, batch_size=32,
59
+ validation_split=0.2, callbacks=[early_stop], verbose=1)
60
+
61
+ # 6. Evaluate
62
+ train_acc = model.evaluate(X_train, y_train, verbose=0)[1]
63
+ test_acc = model.evaluate(X_test, y_test, verbose=0)[1]
64
+ y_pred = model.predict(X_test, verbose=0).argmax(axis=1)
65
+
66
+ print(f"\nTraining Accuracy: {train_acc * 100:.2f}%")
67
+ print(f"Testing Accuracy: {test_acc * 100:.2f}%")
68
+ print("\nClassification Report:")
69
+ print(classification_report(y_test, y_pred, target_names=encoder.classes_))
70
+ print("Confusion Matrix:")
71
+ print(confusion_matrix(y_test, y_pred))
@@ -0,0 +1,108 @@
1
+ # Regularization and Optimization - works with any CSV classification dataset
2
+ # Compares: no regularization vs L2 + Dropout + Early Stopping,
3
+ # and the optimizers Adam, SGD and RMSprop.
4
+ import numpy as np
5
+ import pandas as pd
6
+ import matplotlib.pyplot as plt
7
+ from sklearn.model_selection import train_test_split
8
+ from sklearn.preprocessing import StandardScaler, LabelEncoder
9
+ from sklearn.metrics import classification_report, confusion_matrix
10
+ from tensorflow.keras.models import Sequential
11
+ from tensorflow.keras.layers import Input, Dense, Dropout
12
+ from tensorflow.keras.regularizers import l2
13
+ from tensorflow.keras.callbacks import EarlyStopping
14
+
15
+ # 1. Load dataset
16
+ path = input("Enter CSV file path: ").strip().strip('"')
17
+ df = pd.read_csv(path)
18
+ df = df.loc[:, ~df.columns.str.contains("^Unnamed")]
19
+ print(df.head())
20
+ print("Columns:", list(df.columns))
21
+ target = input("Enter target column: ").strip()
22
+
23
+ # 2. Preprocess
24
+ df = df.dropna(subset=[target]).drop_duplicates()
25
+ X = df.drop(columns=[target])
26
+ X = X.drop(columns=[c for c in X.columns if c.lower() == "id"])
27
+ for c in X.columns:
28
+ if pd.api.types.is_numeric_dtype(X[c]):
29
+ X[c] = X[c].fillna(X[c].median())
30
+ else:
31
+ X[c] = X[c].fillna(X[c].mode()[0])
32
+ X = pd.get_dummies(X, drop_first=True, dtype=int)
33
+
34
+ encoder = LabelEncoder()
35
+ y = encoder.fit_transform(df[target].astype(str))
36
+ n_classes = len(encoder.classes_)
37
+ print("Classes:", list(encoder.classes_))
38
+
39
+ X_train, X_test, y_train, y_test = train_test_split(
40
+ X, y, test_size=0.2, random_state=42, stratify=y
41
+ )
42
+ scaler = StandardScaler()
43
+ X_train = scaler.fit_transform(X_train)
44
+ X_test = scaler.transform(X_test)
45
+
46
+
47
+ # 3. Model builder
48
+ def build_model(regularize, optimizer):
49
+ reg = l2(0.001) if regularize else None
50
+ drop = 0.3 if regularize else 0.0
51
+ model = Sequential([
52
+ Input(shape=(X_train.shape[1],)),
53
+ Dense(128, activation="relu", kernel_regularizer=reg),
54
+ Dropout(drop),
55
+ Dense(64, activation="relu", kernel_regularizer=reg),
56
+ Dropout(drop),
57
+ Dense(n_classes, activation="softmax"),
58
+ ])
59
+ model.compile(optimizer=optimizer, loss="sparse_categorical_crossentropy", metrics=["accuracy"])
60
+ return model
61
+
62
+
63
+ # 4. Train every experiment
64
+ experiments = [
65
+ ("No regularization (Adam)", False, "adam"),
66
+ ("L2 + Dropout + EarlyStop (Adam)", True, "adam"),
67
+ ("L2 + Dropout + EarlyStop (SGD)", True, "sgd"),
68
+ ("L2 + Dropout + EarlyStop (RMSprop)", True, "rmsprop"),
69
+ ]
70
+
71
+ results = []
72
+ histories = {}
73
+ models = {}
74
+ for name, regularize, optimizer in experiments:
75
+ print(f"\nTraining: {name}")
76
+ model = build_model(regularize, optimizer)
77
+ callbacks = [EarlyStopping(monitor="val_loss", patience=5, restore_best_weights=True)] if regularize else []
78
+ history = model.fit(X_train, y_train, epochs=50, batch_size=32,
79
+ validation_split=0.2, callbacks=callbacks, verbose=0)
80
+ train_acc = model.evaluate(X_train, y_train, verbose=0)[1]
81
+ test_acc = model.evaluate(X_test, y_test, verbose=0)[1]
82
+ results.append([name, train_acc * 100, test_acc * 100, len(history.history["loss"])])
83
+ histories[name] = history
84
+ models[name] = model
85
+
86
+ # 5. Compare results
87
+ results_df = pd.DataFrame(results, columns=["Model", "Train Acc", "Test Acc", "Epochs"])
88
+ print("\nComparison:")
89
+ print(results_df.round(2).to_string(index=False))
90
+
91
+ # 6. Plot validation loss of each experiment
92
+ plt.figure(figsize=(9, 5))
93
+ for name, history in histories.items():
94
+ plt.plot(history.history["val_loss"], label=name)
95
+ plt.title("Validation Loss: Regularization and Optimizers")
96
+ plt.xlabel("Epoch")
97
+ plt.ylabel("Validation Loss")
98
+ plt.legend()
99
+ plt.grid(True)
100
+ plt.show()
101
+
102
+ # 7. Detailed report of the best model
103
+ best = results_df.sort_values("Test Acc", ascending=False).iloc[0]["Model"]
104
+ y_pred = models[best].predict(X_test, verbose=0).argmax(axis=1)
105
+ print(f"\nBest model: {best}")
106
+ print(classification_report(y_test, y_pred, target_names=encoder.classes_))
107
+ print("Confusion Matrix:")
108
+ print(confusion_matrix(y_test, y_pred))
@@ -0,0 +1,108 @@
1
+ # Semi-Supervised Learning (self-training with pseudo-labels) - works with any text CSV
2
+ # Only part of the training data keeps its labels. The model labels the rest itself
3
+ # (only predictions it is confident about) and retrains on the bigger dataset.
4
+ import numpy as np
5
+ import pandas as pd
6
+ from sklearn.model_selection import train_test_split
7
+ from sklearn.feature_extraction.text import TfidfVectorizer
8
+ from sklearn.preprocessing import LabelEncoder
9
+ from sklearn.metrics import classification_report, confusion_matrix
10
+ from tensorflow.keras.models import Sequential
11
+ from tensorflow.keras.layers import Input, Dense, Dropout
12
+ from tensorflow.keras.callbacks import EarlyStopping
13
+
14
+ # 1. Load dataset (example: spam.csv -> text column v2, label column v1)
15
+ path = input("Enter CSV file path: ").strip().strip('"')
16
+ try:
17
+ df = pd.read_csv(path)
18
+ except UnicodeDecodeError:
19
+ df = pd.read_csv(path, encoding="latin-1")
20
+ print(df.head())
21
+ print("Columns:", list(df.columns))
22
+ text_col = input("Enter text column: ").strip()
23
+ label_col = input("Enter label column: ").strip()
24
+ labeled_ratio = float(input("Fraction of training data that keeps labels (Enter for 0.3): ") or 0.3)
25
+
26
+ # 2. Clean and encode
27
+ df = df[[text_col, label_col]].dropna().drop_duplicates()
28
+ encoder = LabelEncoder()
29
+ y = encoder.fit_transform(df[label_col].astype(str))
30
+ n_classes = len(encoder.classes_)
31
+ print("Classes:", list(encoder.classes_))
32
+ print(df[label_col].value_counts())
33
+
34
+ X_train_text, X_test_text, y_train, y_test = train_test_split(
35
+ df[text_col].astype(str), y, test_size=0.2, random_state=42, stratify=y
36
+ )
37
+
38
+ # 3. TF-IDF features
39
+ vectorizer = TfidfVectorizer(max_features=5000, stop_words="english")
40
+ X_train = vectorizer.fit_transform(X_train_text).toarray().astype("float32")
41
+ X_test = vectorizer.transform(X_test_text).toarray().astype("float32")
42
+
43
+ # 4. Split training data into labelled and unlabelled parts
44
+ X_lab, X_unlab, y_lab, _ = train_test_split(
45
+ X_train, y_train, train_size=labeled_ratio, random_state=42, stratify=y_train
46
+ )
47
+ print("Labelled samples:", len(X_lab))
48
+ print("Unlabelled samples:", len(X_unlab))
49
+
50
+
51
+ # 5. Model
52
+ def train_model(X, y):
53
+ model = Sequential([
54
+ Input(shape=(X.shape[1],)),
55
+ Dense(64, activation="relu"),
56
+ Dropout(0.3),
57
+ Dense(32, activation="relu"),
58
+ Dropout(0.3),
59
+ Dense(n_classes, activation="softmax"),
60
+ ])
61
+ model.compile(optimizer="adam", loss="sparse_categorical_crossentropy", metrics=["accuracy"])
62
+ model.fit(X, y, epochs=20, batch_size=32, validation_split=0.2, verbose=0,
63
+ callbacks=[EarlyStopping(monitor="val_loss", patience=3, restore_best_weights=True)])
64
+ return model
65
+
66
+
67
+ # 6. Baseline: supervised model trained on the labelled part only
68
+ baseline = train_model(X_lab, y_lab)
69
+ baseline_acc = baseline.evaluate(X_test, y_test, verbose=0)[1]
70
+ print(f"\nBaseline (labelled data only) Test Accuracy: {baseline_acc * 100:.2f}%")
71
+
72
+ # 7. Self-training: add confident pseudo-labels and retrain
73
+ threshold = 0.90
74
+ model = baseline
75
+ X_cur, y_cur, pool = X_lab, y_lab, X_unlab
76
+
77
+ for round_no in range(1, 4):
78
+ probs = model.predict(pool, verbose=0)
79
+ confident = probs.max(axis=1) >= threshold
80
+ if confident.sum() == 0:
81
+ print("No more confident predictions.")
82
+ break
83
+
84
+ X_cur = np.vstack([X_cur, pool[confident]])
85
+ y_cur = np.concatenate([y_cur, probs[confident].argmax(axis=1)])
86
+ pool = pool[~confident]
87
+ print(f"Round {round_no}: added {confident.sum()} pseudo-labels "
88
+ f"(training size {len(X_cur)}, {len(pool)} unlabelled left)")
89
+
90
+ model = train_model(X_cur, y_cur)
91
+
92
+ # 8. Compare
93
+ ssl_acc = model.evaluate(X_test, y_test, verbose=0)[1]
94
+ print(f"\nBaseline Test Accuracy: {baseline_acc * 100:.2f}%")
95
+ print(f"Semi-Supervised Test Accuracy: {ssl_acc * 100:.2f}%")
96
+
97
+ if ssl_acc > baseline_acc:
98
+ print("Semi-supervised learning improved the model.")
99
+ elif ssl_acc < baseline_acc:
100
+ print("Baseline model performed better.")
101
+ else:
102
+ print("Both models performed equally.")
103
+
104
+ y_pred = model.predict(X_test, verbose=0).argmax(axis=1)
105
+ print("\nClassification Report (semi-supervised model):")
106
+ print(classification_report(y_test, y_pred, target_names=encoder.classes_))
107
+ print("Confusion Matrix:")
108
+ print(confusion_matrix(y_test, y_pred))
@@ -0,0 +1,105 @@
1
+ # Multitask Learning - works with any CSV dataset
2
+ # One shared network predicts several target columns at the same time.
3
+ import numpy as np
4
+ import pandas as pd
5
+ import matplotlib.pyplot as plt
6
+ from sklearn.model_selection import train_test_split
7
+ from sklearn.preprocessing import StandardScaler, LabelEncoder
8
+ from sklearn.metrics import accuracy_score, f1_score, confusion_matrix
9
+ from tensorflow.keras.models import Model
10
+ from tensorflow.keras.layers import Input, Dense, Dropout
11
+
12
+ # 1. Load dataset (use sep=";" for files like student-mat.csv)
13
+ path = input("Enter CSV file path: ").strip().strip('"')
14
+ sep = input("Column separator (press Enter for comma): ") or ","
15
+ df = pd.read_csv(path, sep=sep)
16
+ df = df.loc[:, ~df.columns.str.contains("^Unnamed")]
17
+ print(df.head())
18
+ print("Columns:", list(df.columns))
19
+ targets = [t.strip() for t in input("Enter 2 or more target columns (comma separated): ").split(",")]
20
+
21
+ # 2. Create one label per task
22
+ df = df.dropna(subset=targets).drop_duplicates()
23
+ Y = []
24
+ encoders = []
25
+ for t in targets:
26
+ col = df[t]
27
+ # Numeric column with many values -> High / Low (split at median)
28
+ if pd.api.types.is_numeric_dtype(col) and col.nunique() > 10:
29
+ col = np.where(col >= col.median(), "High", "Low")
30
+ enc = LabelEncoder()
31
+ Y.append(enc.fit_transform(pd.Series(col).astype(str)))
32
+ encoders.append(enc)
33
+ print(f"{t} classes:", list(enc.classes_))
34
+
35
+ # 3. Prepare input features
36
+ X = df.drop(columns=targets)
37
+ X = X.drop(columns=[c for c in X.columns if c.lower() == "id"])
38
+ for c in X.columns:
39
+ if pd.api.types.is_numeric_dtype(X[c]):
40
+ X[c] = X[c].fillna(X[c].median())
41
+ else:
42
+ X[c] = X[c].fillna(X[c].mode()[0])
43
+ X = pd.get_dummies(X, drop_first=True, dtype=int).values
44
+
45
+ train_idx, test_idx = train_test_split(np.arange(len(X)), test_size=0.2, random_state=42)
46
+ scaler = StandardScaler()
47
+ X_train = scaler.fit_transform(X[train_idx])
48
+ X_test = scaler.transform(X[test_idx])
49
+ Y_train = [y[train_idx] for y in Y]
50
+ Y_test = [y[test_idx] for y in Y]
51
+
52
+ # 4. Build multitask network: shared layers + one output head per task
53
+ inputs = Input(shape=(X_train.shape[1],))
54
+ shared = Dense(64, activation="relu")(inputs)
55
+ shared = Dropout(0.2)(shared)
56
+ shared = Dense(32, activation="relu")(shared)
57
+ outputs = [
58
+ Dense(len(enc.classes_), activation="softmax", name=f"task{i + 1}")(shared)
59
+ for i, enc in enumerate(encoders)
60
+ ]
61
+
62
+ model = Model(inputs, outputs)
63
+ model.compile(
64
+ optimizer="adam",
65
+ loss=["sparse_categorical_crossentropy"] * len(targets),
66
+ metrics=[["accuracy"]] * len(targets),
67
+ )
68
+ model.summary()
69
+
70
+ # 5. Train
71
+ history = model.fit(X_train, Y_train, epochs=100, batch_size=32,
72
+ validation_split=0.2, verbose=0)
73
+
74
+ plt.figure(figsize=(8, 5))
75
+ plt.plot(history.history["loss"], label="Training Loss")
76
+ plt.plot(history.history["val_loss"], label="Validation Loss")
77
+ plt.title("Multitask Training Loss")
78
+ plt.xlabel("Epoch")
79
+ plt.ylabel("Total Loss")
80
+ plt.legend()
81
+ plt.grid(True)
82
+ plt.show()
83
+
84
+ # 6. Evaluate every task
85
+ preds = model.predict(X_test, verbose=0)
86
+ if len(targets) == 1:
87
+ preds = [preds]
88
+
89
+ results = []
90
+ for i, t in enumerate(targets):
91
+ y_pred = preds[i].argmax(axis=1)
92
+ acc = accuracy_score(Y_test[i], y_pred)
93
+ f1 = f1_score(Y_test[i], y_pred, average="weighted", zero_division=0)
94
+ results.append([t, acc * 100, f1 * 100])
95
+ print(f"\n{t} Confusion Matrix:")
96
+ print(confusion_matrix(Y_test[i], y_pred))
97
+
98
+ print("\nTask-wise Evaluation:")
99
+ print(pd.DataFrame(results, columns=["Task", "Accuracy", "F1 Score"]).round(2).to_string(index=False))
100
+
101
+ # 7. Predict all tasks for one sample
102
+ print("\nSample prediction (first test row):")
103
+ for i, t in enumerate(targets):
104
+ p = preds[i][0]
105
+ print(f"{t}: {encoders[i].classes_[p.argmax()]} (probability {p.max():.4f})")
@@ -0,0 +1,99 @@
1
+ # CNN-Based Handwriting Recognition - works with any folder of handwriting images
2
+ # Folder layout: one subfolder per class, e.g. data/A/*.png, data/B/*.png ...
3
+ # Press Enter to use the built-in MNIST handwritten digits.
4
+ import os
5
+ import numpy as np
6
+ import matplotlib.pyplot as plt
7
+ from PIL import Image
8
+ from sklearn.model_selection import train_test_split
9
+ from sklearn.metrics import classification_report, confusion_matrix
10
+ from tensorflow.keras.models import Sequential
11
+ from tensorflow.keras.layers import Input, Conv2D, MaxPooling2D, Flatten, Dense, Dropout
12
+ from tensorflow.keras.callbacks import EarlyStopping
13
+
14
+ IMG_SIZE = 28
15
+
16
+ # 1. Load dataset
17
+ folder = input("Enter image folder (one subfolder per class) or press Enter for MNIST: ").strip().strip('"')
18
+
19
+ if folder:
20
+ class_names = sorted(d for d in os.listdir(folder) if os.path.isdir(os.path.join(folder, d)))
21
+ X, y = [], []
22
+ for label, name in enumerate(class_names):
23
+ for file in os.listdir(os.path.join(folder, name)):
24
+ try:
25
+ img = Image.open(os.path.join(folder, name, file)).convert("L")
26
+ except OSError:
27
+ continue # skip files that are not images
28
+ X.append(np.array(img.resize((IMG_SIZE, IMG_SIZE))))
29
+ y.append(label)
30
+ X = np.array(X, dtype="float32") / 255.0
31
+ y = np.array(y)
32
+ # Scanned handwriting is dark ink on white paper: invert so ink is bright (like MNIST)
33
+ if X.mean() > 0.5:
34
+ X = 1.0 - X
35
+ X_train, X_test, y_train, y_test = train_test_split(
36
+ X, y, test_size=0.2, random_state=42, stratify=y
37
+ )
38
+ else:
39
+ from tensorflow.keras.datasets import mnist
40
+ (X_train, y_train), (X_test, y_test) = mnist.load_data()
41
+ X_train = X_train.astype("float32") / 255.0
42
+ X_test = X_test.astype("float32") / 255.0
43
+ class_names = [str(i) for i in range(10)]
44
+
45
+ # Add channel dimension: (samples, height, width, 1)
46
+ X_train = X_train[..., np.newaxis]
47
+ X_test = X_test[..., np.newaxis]
48
+ n_classes = len(class_names)
49
+ print("Classes:", class_names)
50
+ print("Training images:", X_train.shape, "Testing images:", X_test.shape)
51
+
52
+ # 2. Build CNN
53
+ model = Sequential([
54
+ Input(shape=(IMG_SIZE, IMG_SIZE, 1)),
55
+ Conv2D(32, 3, activation="relu", padding="same"),
56
+ MaxPooling2D(),
57
+ Conv2D(64, 3, activation="relu", padding="same"),
58
+ MaxPooling2D(),
59
+ Flatten(),
60
+ Dense(128, activation="relu"),
61
+ Dropout(0.3),
62
+ Dense(n_classes, activation="softmax"),
63
+ ])
64
+ model.compile(optimizer="adam", loss="sparse_categorical_crossentropy", metrics=["accuracy"])
65
+ model.summary()
66
+
67
+ # 3. Train
68
+ history = model.fit(
69
+ X_train, y_train, epochs=10, batch_size=64, validation_split=0.1,
70
+ callbacks=[EarlyStopping(monitor="val_loss", patience=3, restore_best_weights=True)],
71
+ )
72
+
73
+ plt.figure(figsize=(8, 5))
74
+ plt.plot(history.history["accuracy"], label="Training Accuracy")
75
+ plt.plot(history.history["val_accuracy"], label="Validation Accuracy")
76
+ plt.title("CNN Handwriting Recognition Accuracy")
77
+ plt.xlabel("Epoch")
78
+ plt.ylabel("Accuracy")
79
+ plt.legend()
80
+ plt.grid(True)
81
+ plt.show()
82
+
83
+ # 4. Evaluate
84
+ test_loss, test_acc = model.evaluate(X_test, y_test, verbose=0)
85
+ y_pred = model.predict(X_test, verbose=0).argmax(axis=1)
86
+ print(f"\nTest Accuracy: {test_acc * 100:.2f}%")
87
+ print(classification_report(y_test, y_pred, target_names=class_names))
88
+ print("Confusion Matrix:")
89
+ print(confusion_matrix(y_test, y_pred))
90
+
91
+ # 5. Show some test images with predictions
92
+ plt.figure(figsize=(12, 3))
93
+ for i in range(min(8, len(X_test))):
94
+ plt.subplot(1, 8, i + 1)
95
+ plt.imshow(X_test[i].squeeze(), cmap="gray")
96
+ plt.title(f"Pred: {class_names[y_pred[i]]}\nTrue: {class_names[y_test[i]]}")
97
+ plt.axis("off")
98
+ plt.tight_layout()
99
+ plt.show()
@@ -0,0 +1,119 @@
1
+ # CNN Unsupervised Feature Learning (Exemplar CNN + K-Means) - works with any image folder
2
+ # Folder layout: one subfolder per class (class names are used ONLY for evaluation).
3
+ # Press Enter to use sklearn's built-in handwritten digits.
4
+ import os
5
+ import numpy as np
6
+ import matplotlib.pyplot as plt
7
+ from PIL import Image
8
+ from sklearn.cluster import KMeans
9
+ from sklearn.metrics import adjusted_rand_score, normalized_mutual_info_score
10
+ from sklearn.preprocessing import StandardScaler, normalize
11
+ from tensorflow.keras.models import Model
12
+ from tensorflow.keras.layers import Input, Conv2D, MaxPooling2D, Flatten, Dense
13
+
14
+ np.random.seed(42)
15
+ IMG_SIZE = 28
16
+
17
+ # 1. Load dataset
18
+ folder = input("Enter image folder (one subfolder per class) or press Enter for digits: ").strip().strip('"')
19
+
20
+ if folder:
21
+ class_names = sorted(d for d in os.listdir(folder) if os.path.isdir(os.path.join(folder, d)))
22
+ X, y = [], []
23
+ for label, name in enumerate(class_names):
24
+ for file in os.listdir(os.path.join(folder, name)):
25
+ try:
26
+ img = Image.open(os.path.join(folder, name, file)).convert("L")
27
+ except OSError:
28
+ continue
29
+ X.append(np.array(img.resize((IMG_SIZE, IMG_SIZE))))
30
+ y.append(label)
31
+ X = np.array(X, dtype="float32") / 255.0
32
+ y = np.array(y)
33
+ else:
34
+ from sklearn.datasets import load_digits
35
+ digits = load_digits()
36
+ X = digits.images.astype("float32") / 16.0
37
+ y = digits.target
38
+ class_names = [str(i) for i in range(10)]
39
+
40
+ X = X[..., np.newaxis] # (samples, height, width, 1)
41
+ print("Dataset shape:", X.shape)
42
+
43
+ n_clusters = int(input(f"Number of clusters (Enter for {len(class_names)}): ") or len(class_names))
44
+
45
+ # 2. Pretext task: exemplar learning
46
+ # Each chosen image becomes its own "class"; the CNN learns to recognise
47
+ # noisy / shifted views of it, which teaches it useful features without labels.
48
+ NUM_EXEMPLARS = min(100, len(X))
49
+ VIEWS = 8
50
+
51
+ chosen = np.random.choice(len(X), NUM_EXEMPLARS, replace=False)
52
+ views, view_labels = [], []
53
+ for i, idx in enumerate(chosen):
54
+ for v in range(VIEWS):
55
+ img = X[idx].copy()
56
+ if v > 0:
57
+ img = np.roll(img, shift=np.random.randint(-1, 2), axis=np.random.randint(0, 2))
58
+ img = np.clip(img + np.random.normal(0, 0.05, img.shape), 0, 1)
59
+ views.append(img)
60
+ view_labels.append(i)
61
+ views = np.array(views, dtype="float32")
62
+ view_labels = np.array(view_labels)
63
+ print("Exemplar training samples:", len(views))
64
+
65
+ # 3. Exemplar CNN
66
+ inputs = Input(shape=X.shape[1:])
67
+ x = Conv2D(16, 3, activation="relu", padding="same")(inputs)
68
+ x = MaxPooling2D()(x)
69
+ x = Conv2D(32, 3, activation="relu", padding="same")(x)
70
+ x = MaxPooling2D()(x)
71
+ x = Flatten()(x)
72
+ features = Dense(64, activation="relu", name="features")(x)
73
+ outputs = Dense(NUM_EXEMPLARS, activation="softmax")(features)
74
+
75
+ exemplar_cnn = Model(inputs, outputs)
76
+ exemplar_cnn.compile(optimizer="adam", loss="sparse_categorical_crossentropy", metrics=["accuracy"])
77
+ history = exemplar_cnn.fit(views, view_labels, epochs=30, batch_size=32, shuffle=True, verbose=1)
78
+
79
+ # 4. Extract learned features and cluster them
80
+ feature_extractor = Model(inputs, features)
81
+ learned = feature_extractor.predict(X, verbose=0)
82
+ learned = normalize(StandardScaler().fit_transform(learned)) # scale features before clustering
83
+ print("Extracted feature shape:", learned.shape)
84
+
85
+ clusters = KMeans(n_clusters=n_clusters, n_init=10, random_state=42).fit_predict(learned)
86
+
87
+ # 5. Evaluate (true labels used only here)
88
+ print(f"\nAdjusted Rand Index (ARI): {adjusted_rand_score(y, clusters):.4f}")
89
+ print(f"Normalized Mutual Information (NMI): {normalized_mutual_info_score(y, clusters):.4f}")
90
+
91
+ print("\nMost common actual classes in each cluster:")
92
+ for c in range(n_clusters):
93
+ counts = np.bincount(y[clusters == c], minlength=len(class_names))
94
+ top = np.argsort(counts)[::-1][:3]
95
+ print(f"Cluster {c}:", [(class_names[t], int(counts[t])) for t in top if counts[t] > 0])
96
+
97
+ # 6. Plot pretext loss and sample images from each cluster
98
+ plt.figure(figsize=(7, 4))
99
+ plt.plot(history.history["loss"], marker="o")
100
+ plt.title("Exemplar CNN Training Loss")
101
+ plt.xlabel("Epoch")
102
+ plt.ylabel("Loss")
103
+ plt.grid(True)
104
+ plt.show()
105
+
106
+ per_row = 6
107
+ fig, axes = plt.subplots(n_clusters, per_row, figsize=(per_row, n_clusters))
108
+ axes = np.array(axes).reshape(n_clusters, per_row)
109
+ for c in range(n_clusters):
110
+ members = np.where(clusters == c)[0][:per_row]
111
+ for j in range(per_row):
112
+ ax = axes[c, j]
113
+ ax.axis("off")
114
+ if j < len(members):
115
+ ax.imshow(X[members[j]].squeeze(), cmap="gray")
116
+ axes[c, 0].set_title(f"C{c}", fontsize=8, loc="left")
117
+ plt.suptitle("Sample images in each cluster")
118
+ plt.tight_layout()
119
+ plt.show()