libz 0.6__tar.gz → 0.8__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.
- {libz-0.6 → libz-0.8}/PKG-INFO +1 -1
- libz-0.8/libz/DL/__init__.py +15 -0
- libz-0.8/libz/DL/prac8.py +73 -0
- libz-0.8/libz/DL/prac9.py +73 -0
- libz-0.8/libz/DLG/__init__.py +16 -0
- {libz-0.6 → libz-0.8}/libz/DLG/prac1.py +10 -2
- {libz-0.6 → libz-0.8}/libz/DLG/prac2.py +10 -2
- {libz-0.6 → libz-0.8}/libz/DLG/prac3.py +15 -2
- {libz-0.6 → libz-0.8}/libz/DLG/prac4.py +15 -2
- {libz-0.6 → libz-0.8}/libz/__init__.py +4 -1
- {libz-0.6 → libz-0.8}/libz/_core.py +10 -3
- libz-0.8/libz/_update.py +47 -0
- {libz-0.6 → libz-0.8}/libz.egg-info/PKG-INFO +1 -1
- {libz-0.6 → libz-0.8}/libz.egg-info/SOURCES.txt +2 -3
- {libz-0.6 → libz-0.8}/pyproject.toml +1 -1
- libz-0.6/libz/DL/__init__.py +0 -15
- libz-0.6/libz/DL/prac8.py +0 -114
- libz-0.6/libz/DL/prac9.py +0 -158
- libz-0.6/libz/DLG/__init__.py +0 -15
- libz-0.6/libz/DLG/prac8.py +0 -231
- libz-0.6/libz/DLG/prac9.py +0 -132
- {libz-0.6 → libz-0.8}/README.md +0 -0
- {libz-0.6 → libz-0.8}/libz/AWT/__init__.py +0 -0
- {libz-0.6 → libz-0.8}/libz/AWT/prac1.py +0 -0
- {libz-0.6 → libz-0.8}/libz/AWT/prac10.py +0 -0
- {libz-0.6 → libz-0.8}/libz/AWT/prac2.py +0 -0
- {libz-0.6 → libz-0.8}/libz/AWT/prac3.py +0 -0
- {libz-0.6 → libz-0.8}/libz/AWT/prac4.py +0 -0
- {libz-0.6 → libz-0.8}/libz/AWT/prac5.py +0 -0
- {libz-0.6 → libz-0.8}/libz/AWT/prac6.py +0 -0
- {libz-0.6 → libz-0.8}/libz/AWT/prac7.py +0 -0
- {libz-0.6 → libz-0.8}/libz/AWT/prac8.py +0 -0
- {libz-0.6 → libz-0.8}/libz/AWT/prac9.py +0 -0
- {libz-0.6 → libz-0.8}/libz/BDA/__init__.py +0 -0
- {libz-0.6 → libz-0.8}/libz/BDA/prac1.py +0 -0
- {libz-0.6 → libz-0.8}/libz/BDA/prac10.py +0 -0
- {libz-0.6 → libz-0.8}/libz/BDA/prac2.py +0 -0
- {libz-0.6 → libz-0.8}/libz/BDA/prac3.py +0 -0
- {libz-0.6 → libz-0.8}/libz/BDA/prac4.py +0 -0
- {libz-0.6 → libz-0.8}/libz/BDA/prac5.py +0 -0
- {libz-0.6 → libz-0.8}/libz/BDA/prac6.py +0 -0
- {libz-0.6 → libz-0.8}/libz/BDA/prac7.py +0 -0
- {libz-0.6 → libz-0.8}/libz/BDA/prac8.py +0 -0
- {libz-0.6 → libz-0.8}/libz/BDA/prac9.py +0 -0
- {libz-0.6 → libz-0.8}/libz/BIO/__init__.py +0 -0
- {libz-0.6 → libz-0.8}/libz/BIO/prac1.py +0 -0
- {libz-0.6 → libz-0.8}/libz/BIO/prac10.py +0 -0
- {libz-0.6 → libz-0.8}/libz/BIO/prac2.py +0 -0
- {libz-0.6 → libz-0.8}/libz/BIO/prac3.py +0 -0
- {libz-0.6 → libz-0.8}/libz/BIO/prac4.py +0 -0
- {libz-0.6 → libz-0.8}/libz/BIO/prac5.py +0 -0
- {libz-0.6 → libz-0.8}/libz/BIO/prac6.py +0 -0
- {libz-0.6 → libz-0.8}/libz/BIO/prac7.py +0 -0
- {libz-0.6 → libz-0.8}/libz/BIO/prac8.py +0 -0
- {libz-0.6 → libz-0.8}/libz/BIO/prac9.py +0 -0
- {libz-0.6 → libz-0.8}/libz/DL/prac1.py +0 -0
- {libz-0.6 → libz-0.8}/libz/DL/prac2.py +0 -0
- {libz-0.6 → libz-0.8}/libz/DL/prac3.py +0 -0
- {libz-0.6 → libz-0.8}/libz/DL/prac4.py +0 -0
- {libz-0.6 → libz-0.8}/libz/DL/prac5.py +0 -0
- {libz-0.6 → libz-0.8}/libz/DL/prac6.py +0 -0
- {libz-0.6 → libz-0.8}/libz/DL/prac7.py +0 -0
- {libz-0.6 → libz-0.8}/libz/DLG/prac5.py +0 -0
- {libz-0.6 → libz-0.8}/libz/DLG/prac6.py +0 -0
- {libz-0.6 → libz-0.8}/libz/DLG/prac7.py +0 -0
- {libz-0.6 → libz-0.8}/libz.egg-info/dependency_links.txt +0 -0
- {libz-0.6 → libz-0.8}/libz.egg-info/top_level.txt +0 -0
- {libz-0.6 → libz-0.8}/setup.cfg +0 -0
{libz-0.6 → libz-0.8}/PKG-INFO
RENAMED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from libz._core import register
|
|
2
|
+
|
|
3
|
+
TITLES = {
|
|
4
|
+
1: "pr1-Deep feed forward",
|
|
5
|
+
2: "pr2-REGULARIZATION AND OPTIMIZATION",
|
|
6
|
+
3: "pr3-SEMI-SUPERVISED LEARNING",
|
|
7
|
+
4: "pr4- Multitasking",
|
|
8
|
+
5: "pr5-CNN-BASED HANDWRITING RECOGNITION",
|
|
9
|
+
6: "pr6-CNN - UNSUPERVISED FEATURE LEARNING",
|
|
10
|
+
7: "pr7-RECURRENT NEURAL NETWORK",
|
|
11
|
+
8: "pr8-RECURSIVE NEURAL NETWORK(tree)",
|
|
12
|
+
9: "pr9-PCA VS LINEAR AUTOENCODER",
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
register(__name__, globals(), TITLES)
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Recursive Neural Networks
|
|
2
|
+
|
|
3
|
+
import torch
|
|
4
|
+
import torch.nn as nn
|
|
5
|
+
import torch.nn.functional as F
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class RecursiveNN(nn.Module):
|
|
9
|
+
|
|
10
|
+
def __init__(self, vocab_size, embed_dim, hidden_dim, num_classes):
|
|
11
|
+
super().__init__()
|
|
12
|
+
|
|
13
|
+
self.embedding = nn.Embedding(vocab_size, embed_dim)
|
|
14
|
+
self.combine = nn.Linear(embed_dim * 2, hidden_dim)
|
|
15
|
+
self.classifier = nn.Linear(hidden_dim, num_classes)
|
|
16
|
+
|
|
17
|
+
def forward(self, tree):
|
|
18
|
+
|
|
19
|
+
# Leaf node
|
|
20
|
+
if isinstance(tree, int):
|
|
21
|
+
return self.embedding(torch.tensor(tree))
|
|
22
|
+
|
|
23
|
+
# Recursive case
|
|
24
|
+
left, right = tree
|
|
25
|
+
|
|
26
|
+
left_vec = self.forward(left)
|
|
27
|
+
right_vec = self.forward(right)
|
|
28
|
+
|
|
29
|
+
combined = torch.cat([left_vec, right_vec])
|
|
30
|
+
|
|
31
|
+
return torch.tanh(self.combine(combined))
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
# Parameters
|
|
35
|
+
VOCAB_SIZE = 100
|
|
36
|
+
EMBED_DIM = 16
|
|
37
|
+
HIDDEN_DIM = 16
|
|
38
|
+
NUM_CLASSES = 2
|
|
39
|
+
|
|
40
|
+
# Create model
|
|
41
|
+
model = RecursiveNN(
|
|
42
|
+
VOCAB_SIZE,
|
|
43
|
+
EMBED_DIM,
|
|
44
|
+
HIDDEN_DIM,
|
|
45
|
+
NUM_CLASSES
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
# Word IDs
|
|
49
|
+
vocab = {
|
|
50
|
+
"the": 10,
|
|
51
|
+
"movie": 25,
|
|
52
|
+
"was": 4,
|
|
53
|
+
"great": 82
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
# Tree: ((the, movie), (was, great))
|
|
57
|
+
tree = (
|
|
58
|
+
(vocab["the"], vocab["movie"]),
|
|
59
|
+
(vocab["was"], vocab["great"])
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
# Get root vector
|
|
63
|
+
root = model(tree)
|
|
64
|
+
|
|
65
|
+
# Classify root
|
|
66
|
+
logits = model.classifier(root)
|
|
67
|
+
|
|
68
|
+
# Convert scores to probabilities
|
|
69
|
+
probabilities = F.softmax(logits, dim=0)
|
|
70
|
+
|
|
71
|
+
print("Root:", root)
|
|
72
|
+
print("Logits:", logits)
|
|
73
|
+
print("Probabilities:", probabilities)
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Linear Factor Models
|
|
2
|
+
|
|
3
|
+
import torch
|
|
4
|
+
import torch.nn as nn
|
|
5
|
+
import torch.optim as optim
|
|
6
|
+
from sklearn.datasets import make_blobs
|
|
7
|
+
from sklearn.decomposition import PCA
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
# 1. Create data
|
|
11
|
+
X, _ = make_blobs(
|
|
12
|
+
n_samples=1000,
|
|
13
|
+
n_features=10,
|
|
14
|
+
centers=3,
|
|
15
|
+
random_state=42
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
X = torch.tensor(X, dtype=torch.float32)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# 2. Linear Factor Model using PCA
|
|
22
|
+
pca = PCA(n_components=3)
|
|
23
|
+
factors = pca.fit_transform(X.numpy())
|
|
24
|
+
|
|
25
|
+
print("PCA Variance:", pca.explained_variance_ratio_)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
# 3. Linear Autoencoder
|
|
29
|
+
class LinearAutoencoder(nn.Module):
|
|
30
|
+
|
|
31
|
+
def __init__(self, input_dim, factor_dim):
|
|
32
|
+
super().__init__()
|
|
33
|
+
|
|
34
|
+
self.encoder = nn.Linear(input_dim, factor_dim)
|
|
35
|
+
self.decoder = nn.Linear(factor_dim, input_dim)
|
|
36
|
+
|
|
37
|
+
def forward(self, x):
|
|
38
|
+
factors = self.encoder(x)
|
|
39
|
+
output = self.decoder(factors)
|
|
40
|
+
|
|
41
|
+
return output, factors
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
# 4. Create model
|
|
45
|
+
model = LinearAutoencoder(10, 3)
|
|
46
|
+
|
|
47
|
+
loss_fn = nn.MSELoss()
|
|
48
|
+
optimizer = optim.Adam(model.parameters(), lr=0.01)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
# 5. Train model
|
|
52
|
+
for epoch in range(200):
|
|
53
|
+
|
|
54
|
+
optimizer.zero_grad()
|
|
55
|
+
|
|
56
|
+
output, factors = model(X)
|
|
57
|
+
|
|
58
|
+
loss = loss_fn(output, X)
|
|
59
|
+
|
|
60
|
+
loss.backward()
|
|
61
|
+
optimizer.step()
|
|
62
|
+
|
|
63
|
+
if (epoch + 1) % 50 == 0:
|
|
64
|
+
print(
|
|
65
|
+
"Epoch:", epoch + 1,
|
|
66
|
+
"Loss:", loss.item()
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
# 6. Get factor loading matrix
|
|
71
|
+
W = model.decoder.weight.detach()
|
|
72
|
+
|
|
73
|
+
print("Factor Loading Matrix Shape:", W.shape)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from libz._core import register
|
|
2
|
+
|
|
3
|
+
TITLES = {
|
|
4
|
+
1: "pr1-Deep feed forward",
|
|
5
|
+
2: "pr2-REGULARIZATION AND OPTIMIZATION",
|
|
6
|
+
3: "pr3-SEMI-SUPERVISED LEARNING",
|
|
7
|
+
4: "pr4- Multitasking",
|
|
8
|
+
5: "pr5-CNN-BASED HANDWRITING RECOGNITION",
|
|
9
|
+
6: "pr6-CNN - UNSUPERVISED FEATURE LEARNING",
|
|
10
|
+
7: "pr7-RECURRENT NEURAL NETWORK",
|
|
11
|
+
8: "pr8-RECURSIVE NEURAL NETWORK(tree)",
|
|
12
|
+
9: "pr9-PCA VS LINEAR AUTOENCODER",
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
# prac8 and prac9 show the DL code (no dynamic version needed)
|
|
16
|
+
register(__name__, globals(), TITLES, links={8: "DL", 9: "DL"})
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
# Deep Feed Forward Neural Network - works with any CSV classification dataset
|
|
2
2
|
# The target column and the feature columns are picked automatically.
|
|
3
3
|
# If accuracy is low, you are asked which columns to use and the model is retrained.
|
|
4
|
+
# Press Enter to use the built-in Breast Cancer dataset (from scikit-learn, no download).
|
|
4
5
|
import numpy as np
|
|
5
6
|
import pandas as pd
|
|
7
|
+
from sklearn.datasets import load_breast_cancer
|
|
6
8
|
from sklearn.model_selection import train_test_split
|
|
7
9
|
from sklearn.preprocessing import StandardScaler, LabelEncoder
|
|
8
10
|
from sklearn.metrics import classification_report, confusion_matrix
|
|
@@ -77,8 +79,14 @@ def ask_columns(df, target, dropped):
|
|
|
77
79
|
|
|
78
80
|
|
|
79
81
|
# ---------- 1. Load dataset ----------
|
|
80
|
-
path = input("Enter CSV file path: ").strip().strip('"')
|
|
81
|
-
|
|
82
|
+
path = input("Enter CSV file path or press Enter for built-in Breast Cancer data: ").strip().strip('"')
|
|
83
|
+
if path:
|
|
84
|
+
df = read_csv(path)
|
|
85
|
+
else:
|
|
86
|
+
data = load_breast_cancer(as_frame=True)
|
|
87
|
+
df = data.frame.copy()
|
|
88
|
+
df["target"] = data.target_names[data.target]
|
|
89
|
+
print("Using built-in Breast Cancer dataset")
|
|
82
90
|
print(df.head())
|
|
83
91
|
print("Shape:", df.shape)
|
|
84
92
|
|
|
@@ -3,9 +3,11 @@
|
|
|
3
3
|
# and the optimizers Adam, SGD and RMSprop.
|
|
4
4
|
# The target column and the feature columns are picked automatically.
|
|
5
5
|
# If accuracy is low, you are asked which columns to use and the models are retrained.
|
|
6
|
+
# Press Enter to use the built-in Wine dataset (from scikit-learn, no download).
|
|
6
7
|
import numpy as np
|
|
7
8
|
import pandas as pd
|
|
8
9
|
import matplotlib.pyplot as plt
|
|
10
|
+
from sklearn.datasets import load_wine
|
|
9
11
|
from sklearn.model_selection import train_test_split
|
|
10
12
|
from sklearn.preprocessing import StandardScaler, LabelEncoder
|
|
11
13
|
from sklearn.metrics import classification_report, confusion_matrix
|
|
@@ -103,8 +105,14 @@ EXPERIMENTS = [
|
|
|
103
105
|
]
|
|
104
106
|
|
|
105
107
|
# ---------- 1. Load dataset ----------
|
|
106
|
-
path = input("Enter CSV file path: ").strip().strip('"')
|
|
107
|
-
|
|
108
|
+
path = input("Enter CSV file path or press Enter for built-in Wine data: ").strip().strip('"')
|
|
109
|
+
if path:
|
|
110
|
+
df = read_csv(path)
|
|
111
|
+
else:
|
|
112
|
+
data = load_wine(as_frame=True)
|
|
113
|
+
df = data.frame.copy()
|
|
114
|
+
df["target"] = data.target_names[data.target]
|
|
115
|
+
print("Using built-in Wine dataset")
|
|
108
116
|
print(df.head())
|
|
109
117
|
print("Shape:", df.shape)
|
|
110
118
|
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
# (only predictions it is confident about) and retrains on the bigger dataset.
|
|
4
4
|
# The text column (longest average text) and the label column are picked automatically.
|
|
5
5
|
# If the semi-supervised accuracy is low, you are asked which columns to use and it retrains.
|
|
6
|
+
# Press Enter instead of a path to use the built-in 20 Newsgroups data (downloaded once, cached).
|
|
6
7
|
import numpy as np
|
|
7
8
|
import pandas as pd
|
|
8
9
|
from sklearn.model_selection import train_test_split
|
|
@@ -96,8 +97,20 @@ def train_model(X, y, n_classes):
|
|
|
96
97
|
|
|
97
98
|
|
|
98
99
|
# ---------- 1. Load dataset ----------
|
|
99
|
-
|
|
100
|
-
|
|
100
|
+
# Press Enter for the built-in 20 Newsgroups data (rec.autos vs sci.space).
|
|
101
|
+
# It is downloaded once (~14 MB) and then cached by scikit-learn.
|
|
102
|
+
path = input("Enter CSV file path or press Enter for built-in 20 Newsgroups data "
|
|
103
|
+
"(downloads once, ~14 MB): ").strip().strip('"')
|
|
104
|
+
if path:
|
|
105
|
+
df = read_csv(path)
|
|
106
|
+
else:
|
|
107
|
+
from sklearn.datasets import fetch_20newsgroups
|
|
108
|
+
news = fetch_20newsgroups(subset="all", categories=["rec.autos", "sci.space"],
|
|
109
|
+
remove=("headers", "footers", "quotes"))
|
|
110
|
+
df = pd.DataFrame({"text": news.data,
|
|
111
|
+
"label": [news.target_names[t] for t in news.target]})
|
|
112
|
+
df = df[df["text"].str.strip() != ""].reset_index(drop=True) # drop empty posts
|
|
113
|
+
print("Using built-in 20 Newsgroups dataset (rec.autos vs sci.space)")
|
|
101
114
|
print(df.head())
|
|
102
115
|
print("Shape:", df.shape)
|
|
103
116
|
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
# One shared network predicts several target columns at the same time.
|
|
3
3
|
# The target columns and the feature columns are picked automatically.
|
|
4
4
|
# If average accuracy is low, you are asked which columns to use and the model is retrained.
|
|
5
|
+
# Press Enter instead of a path to use the built-in scikit-learn Breast Cancer data (offline).
|
|
5
6
|
import numpy as np
|
|
6
7
|
import pandas as pd
|
|
7
8
|
import matplotlib.pyplot as plt
|
|
@@ -78,8 +79,20 @@ def ask_columns(df, targets, dropped):
|
|
|
78
79
|
|
|
79
80
|
|
|
80
81
|
# ---------- 1. Load dataset ----------
|
|
81
|
-
path = input("Enter CSV file path: ").strip().strip('"')
|
|
82
|
-
|
|
82
|
+
path = input("Enter CSV file path or press Enter for built-in Breast Cancer data: ").strip().strip('"')
|
|
83
|
+
if path:
|
|
84
|
+
df = read_csv(path)
|
|
85
|
+
else:
|
|
86
|
+
# Built-in scikit-learn data (offline). Three tasks are derived from its columns;
|
|
87
|
+
# the source columns are then dropped so the targets are not leaked as features.
|
|
88
|
+
from sklearn.datasets import load_breast_cancer
|
|
89
|
+
cancer = load_breast_cancer(as_frame=True)
|
|
90
|
+
df = cancer.frame.copy()
|
|
91
|
+
df["diagnosis"] = [cancer.target_names[t] for t in df["target"]] # malignant / benign
|
|
92
|
+
df["large_tumour"] = np.where(df["mean area"] >= df["mean area"].median(), "yes", "no")
|
|
93
|
+
df["smooth_surface"] = np.where(df["mean smoothness"] <= df["mean smoothness"].median(), "yes", "no")
|
|
94
|
+
df = df.drop(columns=["target", "mean area", "mean smoothness"])
|
|
95
|
+
print("Using built-in Breast Cancer dataset (tasks: diagnosis, large_tumour, smooth_surface)")
|
|
83
96
|
print(df.head())
|
|
84
97
|
print("Shape:", df.shape)
|
|
85
98
|
|
|
@@ -2,9 +2,14 @@ import os
|
|
|
2
2
|
import re
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
def register(module_name, namespace, titles=None):
|
|
6
|
-
"""Register the functions of a module.
|
|
5
|
+
def register(module_name, namespace, titles=None, links=None):
|
|
6
|
+
"""Register the functions of a module.
|
|
7
|
+
|
|
8
|
+
links maps a number to another subject's file, e.g. {8: "DL"} makes prac8
|
|
9
|
+
show DL/prac8.py, so both always print the same code.
|
|
10
|
+
"""
|
|
7
11
|
titles = titles or {}
|
|
12
|
+
links = links or {}
|
|
8
13
|
folder = os.path.dirname(namespace["__file__"])
|
|
9
14
|
subject = module_name.split(".")[-1]
|
|
10
15
|
numbers = sorted(
|
|
@@ -12,9 +17,11 @@ def register(module_name, namespace, titles=None):
|
|
|
12
17
|
for m in (re.fullmatch(r"prac(\d+)\.py", f) for f in os.listdir(folder))
|
|
13
18
|
if m
|
|
14
19
|
)
|
|
20
|
+
numbers = sorted(set(numbers) | set(links))
|
|
15
21
|
|
|
16
22
|
def make(n):
|
|
17
|
-
|
|
23
|
+
source = os.path.join(os.path.dirname(folder), links[n]) if n in links else folder
|
|
24
|
+
path = os.path.join(source, "prac{}.py".format(n))
|
|
18
25
|
|
|
19
26
|
def prac():
|
|
20
27
|
with open(path, encoding="utf-8") as f:
|
libz-0.8/libz/_update.py
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"""Tell the user when a newer libz is on PyPI (checked at most once a day)."""
|
|
2
|
+
import json
|
|
3
|
+
import os
|
|
4
|
+
import sys
|
|
5
|
+
import time
|
|
6
|
+
from urllib.request import urlopen
|
|
7
|
+
|
|
8
|
+
PYPI_URL = "https://pypi.org/pypi/libz/json"
|
|
9
|
+
CACHE_FILE = os.path.join(os.path.expanduser("~"), ".libz_update_check.json")
|
|
10
|
+
CHECK_EVERY = 24 * 60 * 60 # seconds
|
|
11
|
+
TIMEOUT = 1.5 # seconds to wait for PyPI
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _as_tuple(version):
|
|
15
|
+
return tuple(int(part) for part in version.split(".") if part.isdigit())
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _latest_version():
|
|
19
|
+
"""Latest version on PyPI, using the saved answer if it is less than a day old."""
|
|
20
|
+
try:
|
|
21
|
+
with open(CACHE_FILE) as f:
|
|
22
|
+
cache = json.load(f)
|
|
23
|
+
if time.time() - cache["checked"] < CHECK_EVERY:
|
|
24
|
+
return cache["latest"]
|
|
25
|
+
except (OSError, ValueError, KeyError):
|
|
26
|
+
pass
|
|
27
|
+
|
|
28
|
+
with urlopen(PYPI_URL, timeout=TIMEOUT) as response:
|
|
29
|
+
latest = json.load(response)["info"]["version"]
|
|
30
|
+
try:
|
|
31
|
+
with open(CACHE_FILE, "w") as f:
|
|
32
|
+
json.dump({"checked": time.time(), "latest": latest}, f)
|
|
33
|
+
except OSError:
|
|
34
|
+
pass
|
|
35
|
+
return latest
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def check_for_update(current):
|
|
39
|
+
if os.environ.get("LIBZ_NO_UPDATE_CHECK"):
|
|
40
|
+
return
|
|
41
|
+
try:
|
|
42
|
+
latest = _latest_version()
|
|
43
|
+
if _as_tuple(latest) > _as_tuple(current):
|
|
44
|
+
print("libz {} is available (you have {}). Update with: pip install -U libz".format(latest, current),
|
|
45
|
+
file=sys.stderr)
|
|
46
|
+
except Exception:
|
|
47
|
+
pass # offline or PyPI unreachable: never get in the way
|
|
@@ -2,6 +2,7 @@ README.md
|
|
|
2
2
|
pyproject.toml
|
|
3
3
|
libz/__init__.py
|
|
4
4
|
libz/_core.py
|
|
5
|
+
libz/_update.py
|
|
5
6
|
libz.egg-info/PKG-INFO
|
|
6
7
|
libz.egg-info/SOURCES.txt
|
|
7
8
|
libz.egg-info/dependency_links.txt
|
|
@@ -56,6 +57,4 @@ libz/DLG/prac3.py
|
|
|
56
57
|
libz/DLG/prac4.py
|
|
57
58
|
libz/DLG/prac5.py
|
|
58
59
|
libz/DLG/prac6.py
|
|
59
|
-
libz/DLG/prac7.py
|
|
60
|
-
libz/DLG/prac8.py
|
|
61
|
-
libz/DLG/prac9.py
|
|
60
|
+
libz/DLG/prac7.py
|
libz-0.6/libz/DL/__init__.py
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
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)
|
libz-0.6/libz/DL/prac8.py
DELETED
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
import torch
|
|
2
|
-
import torch.nn as nn
|
|
3
|
-
import torch.optim as optim
|
|
4
|
-
|
|
5
|
-
# 1. DEFINE RECURSIVE NEURAL NETWORK
|
|
6
|
-
class RecursiveNN(nn.Module):
|
|
7
|
-
|
|
8
|
-
def __init__(self, vocab_size, embed_dim, hidden_dim, num_classes):
|
|
9
|
-
super().__init__()
|
|
10
|
-
|
|
11
|
-
# Convert word IDs into vectors
|
|
12
|
-
self.embedding = nn.Embedding(vocab_size, hidden_dim)
|
|
13
|
-
|
|
14
|
-
# Combine left and right child representations
|
|
15
|
-
self.composition = nn.Linear(hidden_dim * 2, hidden_dim)
|
|
16
|
-
|
|
17
|
-
# Classify the final tree representation
|
|
18
|
-
self.classifier = nn.Linear(hidden_dim, num_classes)
|
|
19
|
-
|
|
20
|
-
def forward(self, tree):
|
|
21
|
-
|
|
22
|
-
# If the node is a leaf (word ID)
|
|
23
|
-
if isinstance(tree, int):
|
|
24
|
-
word = torch.tensor(tree, dtype=torch.long)
|
|
25
|
-
return self.embedding(word)
|
|
26
|
-
|
|
27
|
-
# Recursively process left and right children
|
|
28
|
-
left_vector = self.forward(tree[0])
|
|
29
|
-
right_vector = self.forward(tree[1])
|
|
30
|
-
|
|
31
|
-
# Combine both child vectors
|
|
32
|
-
combined = torch.cat((left_vector, right_vector))
|
|
33
|
-
|
|
34
|
-
# Generate parent representation
|
|
35
|
-
parent_vector = torch.tanh(
|
|
36
|
-
self.composition(combined)
|
|
37
|
-
)
|
|
38
|
-
return parent_vector
|
|
39
|
-
|
|
40
|
-
# 2. CREATE SAMPLE TREE DATA
|
|
41
|
-
# Label 1 = Positive sentiment
|
|
42
|
-
# Label 0 = Negative sentiment
|
|
43
|
-
training_data = [
|
|
44
|
-
(((10, 25), (4, 82)), 1), # Positive: "the movie was great"
|
|
45
|
-
(((10, 25), (4, 50)), 0), # Negative: "the movie was terrible"
|
|
46
|
-
((82, 25), 1), # Positive: "great movie"
|
|
47
|
-
((50, 25), 0) # Negative: "terrible movie"
|
|
48
|
-
]
|
|
49
|
-
|
|
50
|
-
# 3. INITIALIZE MODEL
|
|
51
|
-
model = RecursiveNN(
|
|
52
|
-
vocab_size=100,
|
|
53
|
-
embed_dim=16,
|
|
54
|
-
hidden_dim=16,
|
|
55
|
-
num_classes=2
|
|
56
|
-
)
|
|
57
|
-
|
|
58
|
-
# 4. DEFINE LOSS AND OPTIMIZER
|
|
59
|
-
optimizer = optim.Adam(
|
|
60
|
-
model.parameters(),
|
|
61
|
-
lr=0.05
|
|
62
|
-
)
|
|
63
|
-
criterion = nn.CrossEntropyLoss()
|
|
64
|
-
|
|
65
|
-
# 5. TRAIN THE MODEL
|
|
66
|
-
print("Starting training...")
|
|
67
|
-
for epoch in range(20):
|
|
68
|
-
total_loss = 0
|
|
69
|
-
|
|
70
|
-
for tree, label in training_data:
|
|
71
|
-
optimizer.zero_grad()
|
|
72
|
-
|
|
73
|
-
# Generate representation of the complete tree
|
|
74
|
-
root_vector = model(tree)
|
|
75
|
-
|
|
76
|
-
# Predict sentiment from the root vector
|
|
77
|
-
logits = model.classifier(root_vector).unsqueeze(0)
|
|
78
|
-
|
|
79
|
-
# Actual label
|
|
80
|
-
target = torch.tensor([label], dtype=torch.long)
|
|
81
|
-
|
|
82
|
-
# Calculate loss and update parameters
|
|
83
|
-
loss = criterion(logits, target)
|
|
84
|
-
|
|
85
|
-
loss.backward()
|
|
86
|
-
optimizer.step()
|
|
87
|
-
|
|
88
|
-
total_loss += loss.item()
|
|
89
|
-
|
|
90
|
-
if (epoch + 1) % 5 == 0:
|
|
91
|
-
print(
|
|
92
|
-
f"Epoch {epoch + 1:02d}/20 | "
|
|
93
|
-
f"Loss: {total_loss:.4f}"
|
|
94
|
-
)
|
|
95
|
-
|
|
96
|
-
# 6. TEST THE TRAINED MODEL
|
|
97
|
-
print("\nTesting trained model:")
|
|
98
|
-
model.eval()
|
|
99
|
-
|
|
100
|
-
with torch.no_grad():
|
|
101
|
-
for tree, label in training_data:
|
|
102
|
-
|
|
103
|
-
root_vector = model(tree)
|
|
104
|
-
logits = model.classifier(root_vector)
|
|
105
|
-
|
|
106
|
-
prediction = torch.argmax(logits, dim=-1).item()
|
|
107
|
-
|
|
108
|
-
actual = "Positive" if label == 1 else "Negative"
|
|
109
|
-
predicted = "Positive" if prediction == 1 else "Negative"
|
|
110
|
-
|
|
111
|
-
print("Tree:", tree)
|
|
112
|
-
print("Actual sentiment:", actual)
|
|
113
|
-
print("Predicted sentiment:", predicted)
|
|
114
|
-
print("-" * 40)
|
libz-0.6/libz/DL/prac9.py
DELETED
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
import torch
|
|
2
|
-
import torch.nn as nn
|
|
3
|
-
import torch.optim as optim
|
|
4
|
-
import numpy as np
|
|
5
|
-
import matplotlib.pyplot as plt
|
|
6
|
-
|
|
7
|
-
from sklearn.decomposition import PCA
|
|
8
|
-
from sklearn.datasets import make_blobs
|
|
9
|
-
|
|
10
|
-
# 1. GENERATE SYNTHETIC DATA
|
|
11
|
-
X_np, _ = make_blobs(
|
|
12
|
-
n_samples=1000,
|
|
13
|
-
n_features=10,
|
|
14
|
-
centers=3,
|
|
15
|
-
random_state=42
|
|
16
|
-
)
|
|
17
|
-
|
|
18
|
-
X_tensor = torch.tensor(X_np, dtype=torch.float32)
|
|
19
|
-
print("Original data shape:", X_np.shape)
|
|
20
|
-
|
|
21
|
-
# 2. APPROACH A: PCA
|
|
22
|
-
pca = PCA(n_components=3)
|
|
23
|
-
X_pca = pca.fit_transform(X_np)
|
|
24
|
-
|
|
25
|
-
print("\nPCA Output Shape:", X_pca.shape)
|
|
26
|
-
print(
|
|
27
|
-
"PCA Explained Variance Ratio:",
|
|
28
|
-
pca.explained_variance_ratio_
|
|
29
|
-
)
|
|
30
|
-
|
|
31
|
-
print(
|
|
32
|
-
"Total Explained Variance:",
|
|
33
|
-
round(pca.explained_variance_ratio_.sum(), 4)
|
|
34
|
-
)
|
|
35
|
-
|
|
36
|
-
# 3. DEFINE LINEAR AUTOENCODER
|
|
37
|
-
class LinearAutoencoder(nn.Module):
|
|
38
|
-
def __init__(self, input_dim, latent_dim):
|
|
39
|
-
super().__init__()
|
|
40
|
-
|
|
41
|
-
# Encoder reduces dimensions
|
|
42
|
-
self.encoder = nn.Linear(
|
|
43
|
-
input_dim,
|
|
44
|
-
latent_dim,
|
|
45
|
-
bias=False
|
|
46
|
-
)
|
|
47
|
-
|
|
48
|
-
# Decoder reconstructs original dimensions
|
|
49
|
-
self.decoder = nn.Linear(
|
|
50
|
-
latent_dim,
|
|
51
|
-
input_dim,
|
|
52
|
-
bias=True
|
|
53
|
-
)
|
|
54
|
-
|
|
55
|
-
def forward(self, x):
|
|
56
|
-
h = self.encoder(x)
|
|
57
|
-
x_recon = self.decoder(h)
|
|
58
|
-
return x_recon, h
|
|
59
|
-
|
|
60
|
-
# 4. SET HYPERPARAMETERS
|
|
61
|
-
input_dim = 10
|
|
62
|
-
latent_dim = 3
|
|
63
|
-
|
|
64
|
-
model = LinearAutoencoder(
|
|
65
|
-
input_dim,
|
|
66
|
-
latent_dim
|
|
67
|
-
)
|
|
68
|
-
|
|
69
|
-
criterion = nn.MSELoss()
|
|
70
|
-
|
|
71
|
-
optimizer = optim.Adam(
|
|
72
|
-
model.parameters(),
|
|
73
|
-
lr=0.01
|
|
74
|
-
)
|
|
75
|
-
|
|
76
|
-
# 5. TRAIN THE AUTOENCODER
|
|
77
|
-
model.train()
|
|
78
|
-
for epoch in range(200):
|
|
79
|
-
optimizer.zero_grad()
|
|
80
|
-
|
|
81
|
-
reconstructions, latent_factors = model(X_tensor)
|
|
82
|
-
loss = criterion(
|
|
83
|
-
reconstructions,
|
|
84
|
-
X_tensor
|
|
85
|
-
)
|
|
86
|
-
|
|
87
|
-
loss.backward()
|
|
88
|
-
optimizer.step()
|
|
89
|
-
|
|
90
|
-
if (epoch + 1) % 50 == 0:
|
|
91
|
-
print(
|
|
92
|
-
f"Epoch [{epoch + 1}/200], "
|
|
93
|
-
f"Reconstruction MSE Loss: {loss.item():.4f}"
|
|
94
|
-
)
|
|
95
|
-
|
|
96
|
-
# 6. EXTRACT LEARNED FACTORS
|
|
97
|
-
model.eval()
|
|
98
|
-
with torch.no_grad():
|
|
99
|
-
reconstructions, latent_factors = model(X_tensor)
|
|
100
|
-
latent_factors = latent_factors.numpy()
|
|
101
|
-
reconstructions = reconstructions.numpy()
|
|
102
|
-
W = model.decoder.weight.detach().numpy()
|
|
103
|
-
|
|
104
|
-
print(
|
|
105
|
-
"\nAutoencoder Latent Shape:",
|
|
106
|
-
latent_factors.shape
|
|
107
|
-
)
|
|
108
|
-
|
|
109
|
-
print(
|
|
110
|
-
"Factor Loading Matrix Shape:",
|
|
111
|
-
W.shape
|
|
112
|
-
)
|
|
113
|
-
|
|
114
|
-
# 7. COMPARE RECONSTRUCTION ERROR
|
|
115
|
-
pca_reconstructed = pca.inverse_transform(X_pca)
|
|
116
|
-
pca_mse = np.mean(
|
|
117
|
-
(X_np - pca_reconstructed) ** 2
|
|
118
|
-
)
|
|
119
|
-
|
|
120
|
-
ae_mse = np.mean(
|
|
121
|
-
(X_np - reconstructions) ** 2
|
|
122
|
-
)
|
|
123
|
-
|
|
124
|
-
print(
|
|
125
|
-
"\nPCA Reconstruction MSE:",
|
|
126
|
-
round(pca_mse, 4)
|
|
127
|
-
)
|
|
128
|
-
|
|
129
|
-
print(
|
|
130
|
-
"Autoencoder Reconstruction MSE:",
|
|
131
|
-
round(ae_mse, 4)
|
|
132
|
-
)
|
|
133
|
-
|
|
134
|
-
# 8. PLOT PCA EXPLAINED VARIANCE
|
|
135
|
-
plt.figure(figsize=(7, 4))
|
|
136
|
-
plt.bar(
|
|
137
|
-
range(1, 4),
|
|
138
|
-
pca.explained_variance_ratio_
|
|
139
|
-
)
|
|
140
|
-
|
|
141
|
-
plt.title("PCA Explained Variance Ratio")
|
|
142
|
-
plt.xlabel("Principal Component")
|
|
143
|
-
plt.ylabel("Explained Variance Ratio")
|
|
144
|
-
plt.xticks([1, 2, 3])
|
|
145
|
-
plt.grid(axis="y")
|
|
146
|
-
plt.show()
|
|
147
|
-
|
|
148
|
-
# 9. PLOT RECONSTRUCTION ERROR COMPARISON
|
|
149
|
-
plt.figure(figsize=(7, 4))
|
|
150
|
-
plt.bar(
|
|
151
|
-
["PCA", "Linear Autoencoder"],
|
|
152
|
-
[pca_mse, ae_mse]
|
|
153
|
-
)
|
|
154
|
-
|
|
155
|
-
plt.title("Reconstruction Error Comparison")
|
|
156
|
-
plt.ylabel("Mean Squared Error")
|
|
157
|
-
plt.grid(axis="y")
|
|
158
|
-
plt.show()
|
libz-0.6/libz/DLG/__init__.py
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
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 / CSV / MNIST)",
|
|
9
|
-
6: "CNN - unsupervised feature learning (any image folder / CSV / 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)
|
libz-0.6/libz/DLG/prac8.py
DELETED
|
@@ -1,231 +0,0 @@
|
|
|
1
|
-
# Recursive Neural Network (tree structured) for sentence classification - any text CSV
|
|
2
|
-
# Every sentence is turned into a binary tree automatically (split in halves),
|
|
3
|
-
# and the network combines child vectors bottom-up until it reaches the root.
|
|
4
|
-
# The text column (longest text) and the label column are picked automatically,
|
|
5
|
-
# and the words kept per sentence adapt to the data (95th percentile, max 30).
|
|
6
|
-
# If accuracy is low, you are asked which columns to use and the model is retrained.
|
|
7
|
-
# Press Enter to use a small built-in sentiment dataset.
|
|
8
|
-
import re
|
|
9
|
-
import math
|
|
10
|
-
import random
|
|
11
|
-
|
|
12
|
-
import pandas as pd
|
|
13
|
-
import torch
|
|
14
|
-
import torch.nn as nn
|
|
15
|
-
import torch.optim as optim
|
|
16
|
-
|
|
17
|
-
random.seed(42)
|
|
18
|
-
torch.manual_seed(42)
|
|
19
|
-
|
|
20
|
-
SAMPLE = [
|
|
21
|
-
("the movie was great", "Positive"),
|
|
22
|
-
("the movie was terrible", "Negative"),
|
|
23
|
-
("great movie", "Positive"),
|
|
24
|
-
("terrible movie", "Negative"),
|
|
25
|
-
("i loved the acting", "Positive"),
|
|
26
|
-
("i hated the acting", "Negative"),
|
|
27
|
-
("the story was wonderful and fun", "Positive"),
|
|
28
|
-
("the story was boring and slow", "Negative"),
|
|
29
|
-
("what a fantastic film", "Positive"),
|
|
30
|
-
("what an awful film", "Negative"),
|
|
31
|
-
("really enjoyed it", "Positive"),
|
|
32
|
-
("really disliked it", "Negative"),
|
|
33
|
-
]
|
|
34
|
-
MAX_SAMPLES = 2000 # recursive training is slow, so large files are sampled
|
|
35
|
-
MAX_WORDS = 30 # upper limit of words kept per sentence
|
|
36
|
-
MIN_ACCURACY = 0.70 # below this you get to choose the columns yourself
|
|
37
|
-
TARGET_NAMES = {"target", "label", "labels", "class", "output", "outcome", "result", "y",
|
|
38
|
-
"sentiment", "category"}
|
|
39
|
-
EPOCHS = 20
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
# ---------- helpers ----------
|
|
43
|
-
def read_csv(path):
|
|
44
|
-
"""Read a CSV with any separator (, ; tab |) and encoding."""
|
|
45
|
-
with open(path, encoding="latin-1") as f:
|
|
46
|
-
first_line = f.readline()
|
|
47
|
-
sep = max([",", ";", "\t", "|"], key=first_line.count)
|
|
48
|
-
try:
|
|
49
|
-
df = pd.read_csv(path, sep=sep)
|
|
50
|
-
except UnicodeDecodeError:
|
|
51
|
-
df = pd.read_csv(path, sep=sep, encoding="latin-1")
|
|
52
|
-
df = df.loc[:, ~df.columns.astype(str).str.startswith("Unnamed")]
|
|
53
|
-
return df.dropna(axis=1, how="all")
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
def guess_text_label(df):
|
|
57
|
-
"""Text = non-numeric column with the longest average text.
|
|
58
|
-
Label = a column named like a target, else one with 2..20 unique values, else the first other column."""
|
|
59
|
-
text_cols = [c for c in df.columns if not pd.api.types.is_numeric_dtype(df[c])]
|
|
60
|
-
if not text_cols:
|
|
61
|
-
return None, None
|
|
62
|
-
text = max(text_cols, key=lambda c: df[c].dropna().astype(str).str.len().mean())
|
|
63
|
-
others = [c for c in df.columns if c != text]
|
|
64
|
-
for c in others:
|
|
65
|
-
if str(c).lower() in TARGET_NAMES:
|
|
66
|
-
return text, c
|
|
67
|
-
for c in others:
|
|
68
|
-
if 2 <= df[c].nunique() <= 20:
|
|
69
|
-
return text, c
|
|
70
|
-
return text, others[0]
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
def ask_columns(df, text, label):
|
|
74
|
-
print(f"\nAccuracy is below {MIN_ACCURACY:.0%}. You can choose the columns yourself.")
|
|
75
|
-
print("Columns:", list(df.columns))
|
|
76
|
-
new_text = input(f"Text column (Enter to keep '{text}'): ").strip() or text
|
|
77
|
-
if new_text not in df.columns:
|
|
78
|
-
print(f"'{new_text}' not found, keeping '{text}'.")
|
|
79
|
-
new_text = text
|
|
80
|
-
new_label = input(f"Label column (Enter to keep '{label}'): ").strip() or label
|
|
81
|
-
if new_label not in df.columns or new_label == new_text:
|
|
82
|
-
print(f"'{new_label}' cannot be used, keeping '{label}'.")
|
|
83
|
-
new_label = label
|
|
84
|
-
changed = new_text != text or new_label != label
|
|
85
|
-
return new_text, new_label, changed
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
def tokenize(text, max_words=MAX_WORDS):
|
|
89
|
-
return re.findall(r"[a-z0-9']+", str(text).lower())[:max_words]
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
def words_limit(texts):
|
|
93
|
-
"""95th percentile of sentence lengths, but never more than MAX_WORDS."""
|
|
94
|
-
lengths = [len(tokenize(t, None)) for t in texts]
|
|
95
|
-
lengths = [n for n in lengths if n > 0] or [1]
|
|
96
|
-
p95 = math.ceil(pd.Series(lengths).quantile(0.95))
|
|
97
|
-
return max(1, min(MAX_WORDS, p95))
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
def build_tree(ids):
|
|
101
|
-
"""[w1, w2, w3, w4] -> ((w1, w2), (w3, w4))"""
|
|
102
|
-
if len(ids) == 1:
|
|
103
|
-
return ids[0]
|
|
104
|
-
mid = len(ids) // 2
|
|
105
|
-
return (build_tree(ids[:mid]), build_tree(ids[mid:]))
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
# ---------- Recursive Neural Network ----------
|
|
109
|
-
class RecursiveNN(nn.Module):
|
|
110
|
-
def __init__(self, vocab_size, hidden_dim, num_classes):
|
|
111
|
-
super().__init__()
|
|
112
|
-
self.embedding = nn.Embedding(vocab_size, hidden_dim)
|
|
113
|
-
self.composition = nn.Linear(hidden_dim * 2, hidden_dim)
|
|
114
|
-
self.classifier = nn.Linear(hidden_dim, num_classes)
|
|
115
|
-
|
|
116
|
-
def encode(self, tree):
|
|
117
|
-
if isinstance(tree, int): # leaf = word
|
|
118
|
-
return self.embedding(torch.tensor(tree))
|
|
119
|
-
left = self.encode(tree[0])
|
|
120
|
-
right = self.encode(tree[1])
|
|
121
|
-
return torch.tanh(self.composition(torch.cat((left, right))))
|
|
122
|
-
|
|
123
|
-
def forward(self, tree):
|
|
124
|
-
return self.classifier(self.encode(tree))
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
def predict(model, tree):
|
|
128
|
-
with torch.no_grad():
|
|
129
|
-
return model(tree).argmax().item()
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
# ---------- 1. Load data ----------
|
|
133
|
-
path = input("Enter CSV file path or press Enter for sample data: ").strip().strip('"')
|
|
134
|
-
if path:
|
|
135
|
-
df = read_csv(path)
|
|
136
|
-
print(df.head())
|
|
137
|
-
print("Shape:", df.shape)
|
|
138
|
-
if df.shape[1] < 2:
|
|
139
|
-
raise SystemExit("The CSV needs at least a text column and a label column.")
|
|
140
|
-
text_col, label_col = guess_text_label(df)
|
|
141
|
-
if text_col is None:
|
|
142
|
-
print("\nNo text (non-numeric) column was found. Please choose the columns yourself.")
|
|
143
|
-
print("Columns:", list(df.columns))
|
|
144
|
-
text_col = input("Text column: ").strip()
|
|
145
|
-
if text_col not in df.columns:
|
|
146
|
-
print(f"'{text_col}' not found, using '{df.columns[0]}'.")
|
|
147
|
-
text_col = df.columns[0]
|
|
148
|
-
label_col = input("Label column: ").strip()
|
|
149
|
-
if label_col not in df.columns or label_col == text_col:
|
|
150
|
-
label_col = [c for c in df.columns if c != text_col][0]
|
|
151
|
-
print(f"Using '{label_col}' as label column.")
|
|
152
|
-
|
|
153
|
-
# ---------- 2. Train (repeats if accuracy is low and you choose other columns) ----------
|
|
154
|
-
while True:
|
|
155
|
-
if path:
|
|
156
|
-
sub = df[[text_col, label_col]].dropna()
|
|
157
|
-
pairs = list(zip(sub[text_col].astype(str), sub[label_col].astype(str)))
|
|
158
|
-
random.shuffle(pairs)
|
|
159
|
-
pairs = pairs[:MAX_SAMPLES]
|
|
160
|
-
print(f"\nText column: {text_col} | Label column: {label_col}")
|
|
161
|
-
else:
|
|
162
|
-
pairs = SAMPLE
|
|
163
|
-
|
|
164
|
-
max_words = words_limit([t for t, _ in pairs])
|
|
165
|
-
class_names = sorted(set(label for _, label in pairs))
|
|
166
|
-
data = [(tokenize(t, max_words), class_names.index(l)) for t, l in pairs]
|
|
167
|
-
data = [(words, l) for words, l in data if words]
|
|
168
|
-
print("Classes:", class_names)
|
|
169
|
-
print("Words kept per sentence:", max_words)
|
|
170
|
-
|
|
171
|
-
if not data:
|
|
172
|
-
print("No usable sentences in this column.")
|
|
173
|
-
text_col, label_col, changed = ask_columns(df, text_col, label_col)
|
|
174
|
-
if not changed:
|
|
175
|
-
raise SystemExit("Nothing to train on.")
|
|
176
|
-
continue
|
|
177
|
-
|
|
178
|
-
# Vocabulary and trees
|
|
179
|
-
vocab = {"<unk>": 0}
|
|
180
|
-
for words, _ in data:
|
|
181
|
-
for w in words:
|
|
182
|
-
vocab.setdefault(w, len(vocab))
|
|
183
|
-
|
|
184
|
-
trees = [(build_tree([vocab[w] for w in words]), label) for words, label in data]
|
|
185
|
-
split = int(len(trees) * 0.8)
|
|
186
|
-
train_data, test_data = (trees, trees) if len(trees) < 50 else (trees[:split], trees[split:])
|
|
187
|
-
print("Vocabulary size:", len(vocab), "| Train:", len(train_data), "| Test:", len(test_data))
|
|
188
|
-
print("Example tree:", train_data[0][0])
|
|
189
|
-
|
|
190
|
-
model = RecursiveNN(len(vocab), hidden_dim=32, num_classes=len(class_names))
|
|
191
|
-
optimizer = optim.Adam(model.parameters(), lr=0.01)
|
|
192
|
-
criterion = nn.CrossEntropyLoss()
|
|
193
|
-
|
|
194
|
-
for epoch in range(EPOCHS):
|
|
195
|
-
model.train()
|
|
196
|
-
random.shuffle(train_data)
|
|
197
|
-
total_loss = 0
|
|
198
|
-
for tree, label in train_data:
|
|
199
|
-
optimizer.zero_grad()
|
|
200
|
-
loss = criterion(model(tree).unsqueeze(0), torch.tensor([label]))
|
|
201
|
-
loss.backward()
|
|
202
|
-
optimizer.step()
|
|
203
|
-
total_loss += loss.item()
|
|
204
|
-
if (epoch + 1) % 5 == 0:
|
|
205
|
-
print(f"Epoch {epoch + 1:02d}/{EPOCHS} | Loss: {total_loss / len(train_data):.4f}")
|
|
206
|
-
|
|
207
|
-
model.eval()
|
|
208
|
-
test_acc = sum(predict(model, tree) == label for tree, label in test_data) / len(test_data)
|
|
209
|
-
print(f"Test Accuracy: {test_acc * 100:.2f}%")
|
|
210
|
-
if not path or test_acc >= MIN_ACCURACY:
|
|
211
|
-
break
|
|
212
|
-
text_col, label_col, changed = ask_columns(df, text_col, label_col)
|
|
213
|
-
if not changed:
|
|
214
|
-
break
|
|
215
|
-
|
|
216
|
-
# ---------- 3. Final results ----------
|
|
217
|
-
print(f"\nTest Accuracy: {test_acc * 100:.2f}%")
|
|
218
|
-
|
|
219
|
-
print("\nSample predictions:")
|
|
220
|
-
for tree, label in test_data[:5]:
|
|
221
|
-
print("Tree:", tree)
|
|
222
|
-
print("Actual:", class_names[label], "| Predicted:", class_names[predict(model, tree)])
|
|
223
|
-
print("-" * 40)
|
|
224
|
-
|
|
225
|
-
# ---------- 4. Classify your own sentence ----------
|
|
226
|
-
sentence = input("Type a sentence to classify (Enter to skip): ").strip()
|
|
227
|
-
if sentence:
|
|
228
|
-
ids = [vocab.get(w, 0) for w in tokenize(sentence, max_words)] or [0]
|
|
229
|
-
tree = build_tree(ids)
|
|
230
|
-
print("Tree:", tree)
|
|
231
|
-
print("Predicted:", class_names[predict(model, tree)])
|
libz-0.6/libz/DLG/prac9.py
DELETED
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
# PCA vs Linear Autoencoder - works with any numeric CSV
|
|
2
|
-
# Both reduce the data to k dimensions; a linear autoencoder learns the same
|
|
3
|
-
# subspace as PCA, so their reconstruction errors should be almost equal.
|
|
4
|
-
# The numeric columns are picked automatically (ID-like, constant and text columns
|
|
5
|
-
# are dropped, missing values filled with the median), and k is chosen automatically
|
|
6
|
-
# as the smallest number of components that explains at least 90% of the variance.
|
|
7
|
-
# Press Enter to use synthetic data.
|
|
8
|
-
import numpy as np
|
|
9
|
-
import pandas as pd
|
|
10
|
-
import matplotlib.pyplot as plt
|
|
11
|
-
from sklearn.decomposition import PCA
|
|
12
|
-
from sklearn.datasets import make_blobs
|
|
13
|
-
from sklearn.preprocessing import StandardScaler
|
|
14
|
-
from tensorflow.keras.models import Sequential
|
|
15
|
-
from tensorflow.keras.layers import Input, Dense
|
|
16
|
-
from tensorflow.keras.optimizers import Adam
|
|
17
|
-
|
|
18
|
-
VARIANCE_TO_KEEP = 0.90 # k = fewest components explaining at least this much variance
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
# ---------- helpers ----------
|
|
22
|
-
def read_csv(path):
|
|
23
|
-
"""Read a CSV with any separator (, ; tab |) and encoding."""
|
|
24
|
-
with open(path, encoding="latin-1") as f:
|
|
25
|
-
first_line = f.readline()
|
|
26
|
-
sep = max([",", ";", "\t", "|"], key=first_line.count)
|
|
27
|
-
try:
|
|
28
|
-
df = pd.read_csv(path, sep=sep)
|
|
29
|
-
except UnicodeDecodeError:
|
|
30
|
-
df = pd.read_csv(path, sep=sep, encoding="latin-1")
|
|
31
|
-
df = df.loc[:, ~df.columns.astype(str).str.startswith("Unnamed")]
|
|
32
|
-
return df.dropna(axis=1, how="all")
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
def is_id(col):
|
|
36
|
-
name = str(col.name).lower()
|
|
37
|
-
return (name in ("id", "index") or name.endswith("_id")
|
|
38
|
-
or (pd.api.types.is_integer_dtype(col) and col.nunique() == len(col)))
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
def numeric_features(df):
|
|
42
|
-
"""Keep numeric, non-ID, non-constant columns and fill missing values with the median."""
|
|
43
|
-
keep = [c for c in df.columns
|
|
44
|
-
if pd.api.types.is_numeric_dtype(df[c]) and not is_id(df[c]) and df[c].nunique() > 1]
|
|
45
|
-
X = df[keep].copy()
|
|
46
|
-
return X.fillna(X.median()), keep
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
# 1. Load data
|
|
50
|
-
path = input("Enter CSV file path or press Enter for synthetic data: ").strip().strip('"')
|
|
51
|
-
if path:
|
|
52
|
-
df = read_csv(path)
|
|
53
|
-
print(df.head())
|
|
54
|
-
print("Shape:", df.shape)
|
|
55
|
-
df, used = numeric_features(df)
|
|
56
|
-
print("Numeric columns used:", used)
|
|
57
|
-
if len(used) < 2:
|
|
58
|
-
raise SystemExit("PCA needs at least 2 usable numeric columns - this CSV does not have them.")
|
|
59
|
-
X = df.values
|
|
60
|
-
else:
|
|
61
|
-
X, _ = make_blobs(n_samples=1000, n_features=10, centers=3, random_state=42)
|
|
62
|
-
|
|
63
|
-
X = StandardScaler().fit_transform(X).astype("float32")
|
|
64
|
-
n_features = X.shape[1]
|
|
65
|
-
|
|
66
|
-
# Choose k automatically from a full PCA
|
|
67
|
-
cumulative = np.cumsum(PCA().fit(X).explained_variance_ratio_)
|
|
68
|
-
k = int(np.searchsorted(cumulative, VARIANCE_TO_KEEP - 1e-9) + 1)
|
|
69
|
-
k = max(1, min(k, n_features))
|
|
70
|
-
print(f"Using {k} components (explains {cumulative[k - 1] * 100:.2f}% of variance)")
|
|
71
|
-
print("Data shape:", X.shape, "| Components:", k)
|
|
72
|
-
|
|
73
|
-
# 2. PCA
|
|
74
|
-
pca = PCA(n_components=k)
|
|
75
|
-
X_pca = pca.fit_transform(X)
|
|
76
|
-
pca_mse = np.mean((X - pca.inverse_transform(X_pca)) ** 2)
|
|
77
|
-
print("\nPCA Explained Variance Ratio:", pca.explained_variance_ratio_.round(4))
|
|
78
|
-
print("Total Explained Variance:", round(pca.explained_variance_ratio_.sum(), 4))
|
|
79
|
-
|
|
80
|
-
# 3. Linear autoencoder: n_features -> k -> n_features, no activation functions
|
|
81
|
-
autoencoder = Sequential([
|
|
82
|
-
Input(shape=(n_features,)),
|
|
83
|
-
Dense(k, use_bias=False, name="encoder"),
|
|
84
|
-
Dense(n_features, name="decoder"),
|
|
85
|
-
])
|
|
86
|
-
autoencoder.compile(optimizer=Adam(learning_rate=0.01), loss="mse")
|
|
87
|
-
history = autoencoder.fit(X, X, epochs=200, batch_size=64, verbose=0)
|
|
88
|
-
|
|
89
|
-
encoder = Sequential([Input(shape=(n_features,)), autoencoder.get_layer("encoder")])
|
|
90
|
-
latent = encoder.predict(X, verbose=0)
|
|
91
|
-
ae_mse = np.mean((X - autoencoder.predict(X, verbose=0)) ** 2)
|
|
92
|
-
print("\nAutoencoder latent shape:", latent.shape)
|
|
93
|
-
print("Decoder weight (factor loading) shape:", autoencoder.get_layer("decoder").get_weights()[0].shape)
|
|
94
|
-
|
|
95
|
-
# 4. Compare
|
|
96
|
-
print(f"\nPCA Reconstruction MSE: {pca_mse:.4f}")
|
|
97
|
-
print(f"Autoencoder Reconstruction MSE: {ae_mse:.4f}")
|
|
98
|
-
|
|
99
|
-
# 5. Plots
|
|
100
|
-
plt.figure(figsize=(7, 4))
|
|
101
|
-
plt.plot(history.history["loss"])
|
|
102
|
-
plt.axhline(pca_mse, color="red", linestyle="--", label="PCA MSE")
|
|
103
|
-
plt.title("Autoencoder Training Loss")
|
|
104
|
-
plt.xlabel("Epoch")
|
|
105
|
-
plt.ylabel("MSE")
|
|
106
|
-
plt.legend()
|
|
107
|
-
plt.grid(True)
|
|
108
|
-
plt.show()
|
|
109
|
-
|
|
110
|
-
plt.figure(figsize=(7, 4))
|
|
111
|
-
plt.bar(range(1, k + 1), pca.explained_variance_ratio_)
|
|
112
|
-
plt.title("PCA Explained Variance Ratio")
|
|
113
|
-
plt.xlabel("Principal Component")
|
|
114
|
-
plt.ylabel("Explained Variance Ratio")
|
|
115
|
-
plt.grid(axis="y")
|
|
116
|
-
plt.show()
|
|
117
|
-
|
|
118
|
-
plt.figure(figsize=(7, 4))
|
|
119
|
-
plt.bar(["PCA", "Linear Autoencoder"], [pca_mse, ae_mse])
|
|
120
|
-
plt.title("Reconstruction Error Comparison")
|
|
121
|
-
plt.ylabel("Mean Squared Error")
|
|
122
|
-
plt.grid(axis="y")
|
|
123
|
-
plt.show()
|
|
124
|
-
|
|
125
|
-
if k >= 2:
|
|
126
|
-
fig, axes = plt.subplots(1, 2, figsize=(11, 4))
|
|
127
|
-
axes[0].scatter(X_pca[:, 0], X_pca[:, 1], s=8)
|
|
128
|
-
axes[0].set_title("PCA: first 2 components")
|
|
129
|
-
axes[1].scatter(latent[:, 0], latent[:, 1], s=8, color="orange")
|
|
130
|
-
axes[1].set_title("Autoencoder: first 2 latent factors")
|
|
131
|
-
plt.tight_layout()
|
|
132
|
-
plt.show()
|
{libz-0.6 → libz-0.8}/README.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{libz-0.6 → libz-0.8}/setup.cfg
RENAMED
|
File without changes
|