cv-tda 0.0.1__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 (54) hide show
  1. cv_tda-0.0.1/PKG-INFO +41 -0
  2. cv_tda-0.0.1/README.md +3 -0
  3. cv_tda-0.0.1/pyproject.toml +62 -0
  4. cv_tda-0.0.1/setup.cfg +4 -0
  5. cv_tda-0.0.1/src/cv_tda.egg-info/PKG-INFO +41 -0
  6. cv_tda-0.0.1/src/cv_tda.egg-info/SOURCES.txt +52 -0
  7. cv_tda-0.0.1/src/cv_tda.egg-info/dependency_links.txt +1 -0
  8. cv_tda-0.0.1/src/cv_tda.egg-info/requires.txt +22 -0
  9. cv_tda-0.0.1/src/cv_tda.egg-info/top_level.txt +1 -0
  10. cv_tda-0.0.1/src/cvtda/classification/NNClassifier.py +173 -0
  11. cv_tda-0.0.1/src/cvtda/classification/__init__.py +6 -0
  12. cv_tda-0.0.1/src/cvtda/classification/classify.py +209 -0
  13. cv_tda-0.0.1/src/cvtda/classification/estimate_quality.py +47 -0
  14. cv_tda-0.0.1/src/cvtda/classification/information_value.py +98 -0
  15. cv_tda-0.0.1/src/cvtda/dumping/__init__.py +9 -0
  16. cv_tda-0.0.1/src/cvtda/dumping/base.py +34 -0
  17. cv_tda-0.0.1/src/cvtda/dumping/devnull.py +18 -0
  18. cv_tda-0.0.1/src/cvtda/dumping/dump_name_concat.py +4 -0
  19. cv_tda-0.0.1/src/cvtda/dumping/numpy.py +36 -0
  20. cv_tda-0.0.1/src/cvtda/face_recognition/BaseLearner.py +67 -0
  21. cv_tda-0.0.1/src/cvtda/face_recognition/DiagramsLearner.py +33 -0
  22. cv_tda-0.0.1/src/cvtda/face_recognition/NNLearner.py +193 -0
  23. cv_tda-0.0.1/src/cvtda/face_recognition/SimpleTopologicalLearner.py +14 -0
  24. cv_tda-0.0.1/src/cvtda/face_recognition/__init__.py +4 -0
  25. cv_tda-0.0.1/src/cvtda/face_recognition/learn.py +99 -0
  26. cv_tda-0.0.1/src/cvtda/logging/__init__.py +8 -0
  27. cv_tda-0.0.1/src/cvtda/logging/base.py +39 -0
  28. cv_tda-0.0.1/src/cvtda/logging/cli.py +33 -0
  29. cv_tda-0.0.1/src/cvtda/logging/devnull.py +27 -0
  30. cv_tda-0.0.1/src/cvtda/neural_network/Dataset.py +101 -0
  31. cv_tda-0.0.1/src/cvtda/neural_network/NNBase.py +54 -0
  32. cv_tda-0.0.1/src/cvtda/neural_network/__init__.py +2 -0
  33. cv_tda-0.0.1/src/cvtda/topology/DiagramVectorizer.py +180 -0
  34. cv_tda-0.0.1/src/cvtda/topology/FeatureExtractor.py +89 -0
  35. cv_tda-0.0.1/src/cvtda/topology/FiltrationsExtractor.py +182 -0
  36. cv_tda-0.0.1/src/cvtda/topology/GeometryExtractor.py +163 -0
  37. cv_tda-0.0.1/src/cvtda/topology/GreyscaleExtractor.py +37 -0
  38. cv_tda-0.0.1/src/cvtda/topology/PointCloudsExtractor.py +37 -0
  39. cv_tda-0.0.1/src/cvtda/topology/__init__.py +7 -0
  40. cv_tda-0.0.1/src/cvtda/topology/interface/Extractor.py +123 -0
  41. cv_tda-0.0.1/src/cvtda/topology/interface/TopologicalExtractor.py +80 -0
  42. cv_tda-0.0.1/src/cvtda/topology/interface/__init__.py +2 -0
  43. cv_tda-0.0.1/src/cvtda/topology/utils/__init__.py +3 -0
  44. cv_tda-0.0.1/src/cvtda/topology/utils/hstack.py +30 -0
  45. cv_tda-0.0.1/src/cvtda/topology/utils/process_iter.py +7 -0
  46. cv_tda-0.0.1/src/cvtda/topology/utils/process_iter_dump.py +22 -0
  47. cv_tda-0.0.1/src/cvtda/utils/__init__.py +7 -0
  48. cv_tda-0.0.1/src/cvtda/utils/duplicates.py +105 -0
  49. cv_tda-0.0.1/src/cvtda/utils/image2pointcloud.py +20 -0
  50. cv_tda-0.0.1/src/cvtda/utils/rgb2gray.py +15 -0
  51. cv_tda-0.0.1/src/cvtda/utils/rgb2hsv.py +15 -0
  52. cv_tda-0.0.1/src/cvtda/utils/sequence2features.py +47 -0
  53. cv_tda-0.0.1/src/cvtda/utils/set_random_seed.py +13 -0
  54. cv_tda-0.0.1/src/cvtda/utils/spread_points.py +12 -0
cv_tda-0.0.1/PKG-INFO ADDED
@@ -0,0 +1,41 @@
1
+ Metadata-Version: 2.4
2
+ Name: cv-tda
3
+ Version: 0.0.1
4
+ Summary: A Library to Solve Various Computer Vision Problems Using Topological Data Analysis
5
+ Author-email: Aleksandr Abramov <ggttpo100ajiex@yandex.ru>
6
+ License-Expression: MIT
7
+ Project-URL: Repository, https://github.com/TTPO100AJIEX/CVTDA
8
+ Keywords: topological data analysis,computer vision,algebraic topology,image analysis,classification,face recognition,topological features
9
+ Classifier: Development Status :: 4 - Beta
10
+ Classifier: Intended Audience :: Science/Research
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Operating System :: OS Independent
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Topic :: Scientific/Engineering
15
+ Classifier: Topic :: Scientific/Engineering :: Image Processing
16
+ Requires-Python: ==3.10
17
+ Description-Content-Type: text/markdown
18
+ Requires-Dist: giotto-tda==0.6.2
19
+ Requires-Dist: gudhi>=3.10.1
20
+ Requires-Dist: joblib>=1.4.2
21
+ Requires-Dist: scikit-learn==1.6.1
22
+ Requires-Dist: scikit-image>=0.25.0
23
+ Requires-Dist: tqdm>=4.67.1
24
+ Provides-Extra: classification
25
+ Requires-Dist: catboost>=1.2.7; extra == "classification"
26
+ Requires-Dist: xgboost>=3.0.0; extra == "classification"
27
+ Requires-Dist: matplotlib>=3.10.1; extra == "classification"
28
+ Requires-Dist: pandas>=2.2.3; extra == "classification"
29
+ Requires-Dist: torch>=2.5.1; extra == "classification"
30
+ Requires-Dist: torchvision>=0.20.1; extra == "classification"
31
+ Requires-Dist: torchph==0.0.0; extra == "classification"
32
+ Provides-Extra: face-recognition
33
+ Requires-Dist: pytorch-metric-learning==2.8.1; extra == "face-recognition"
34
+ Requires-Dist: matplotlib>=3.10.1; extra == "face-recognition"
35
+ Requires-Dist: torch>=2.5.1; extra == "face-recognition"
36
+ Requires-Dist: torchvision>=0.20.1; extra == "face-recognition"
37
+ Requires-Dist: torchph==0.0.0; extra == "face-recognition"
38
+
39
+ # Computer Vision With Topological Data Analysis
40
+
41
+ TO BE DONE
cv_tda-0.0.1/README.md ADDED
@@ -0,0 +1,3 @@
1
+ # Computer Vision With Topological Data Analysis
2
+
3
+ TO BE DONE
@@ -0,0 +1,62 @@
1
+ [build-system]
2
+ requires = ["setuptools >= 77.0.3"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "cv-tda"
7
+ version = "0.0.1"
8
+ authors = [
9
+ { name = "Aleksandr Abramov", email = "ggttpo100ajiex@yandex.ru" },
10
+ ]
11
+ description = "A Library to Solve Various Computer Vision Problems Using Topological Data Analysis"
12
+ readme = "README.md"
13
+ requires-python = "==3.10"
14
+ dependencies = [
15
+ "giotto-tda==0.6.2",
16
+ "gudhi>=3.10.1",
17
+ "joblib>=1.4.2",
18
+ "scikit-learn==1.6.1",
19
+ "scikit-image>=0.25.0",
20
+ "tqdm>=4.67.1",
21
+ ]
22
+ keywords = [
23
+ "topological data analysis",
24
+ "computer vision",
25
+ "algebraic topology",
26
+ "image analysis",
27
+ "classification",
28
+ "face recognition",
29
+ "topological features",
30
+ ]
31
+ classifiers = [
32
+ "Development Status :: 4 - Beta",
33
+ "Intended Audience :: Science/Research",
34
+ "Intended Audience :: Developers",
35
+ "Operating System :: OS Independent",
36
+ "Programming Language :: Python :: 3.10",
37
+ "Topic :: Scientific/Engineering",
38
+ "Topic :: Scientific/Engineering :: Image Processing",
39
+ ]
40
+ license = "MIT"
41
+ license-files = ["LICENCE*"]
42
+
43
+ [project.optional-dependencies]
44
+ classification = [
45
+ "catboost>=1.2.7",
46
+ "xgboost>=3.0.0",
47
+ "matplotlib>=3.10.1",
48
+ "pandas>=2.2.3",
49
+ "torch>=2.5.1",
50
+ "torchvision>=0.20.1",
51
+ "torchph==0.0.0"
52
+ ]
53
+ face_recognition = [
54
+ "pytorch-metric-learning==2.8.1",
55
+ "matplotlib>=3.10.1",
56
+ "torch>=2.5.1",
57
+ "torchvision>=0.20.1",
58
+ "torchph==0.0.0"
59
+ ]
60
+
61
+ [project.urls]
62
+ Repository = "https://github.com/TTPO100AJIEX/CVTDA"
cv_tda-0.0.1/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,41 @@
1
+ Metadata-Version: 2.4
2
+ Name: cv-tda
3
+ Version: 0.0.1
4
+ Summary: A Library to Solve Various Computer Vision Problems Using Topological Data Analysis
5
+ Author-email: Aleksandr Abramov <ggttpo100ajiex@yandex.ru>
6
+ License-Expression: MIT
7
+ Project-URL: Repository, https://github.com/TTPO100AJIEX/CVTDA
8
+ Keywords: topological data analysis,computer vision,algebraic topology,image analysis,classification,face recognition,topological features
9
+ Classifier: Development Status :: 4 - Beta
10
+ Classifier: Intended Audience :: Science/Research
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Operating System :: OS Independent
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Topic :: Scientific/Engineering
15
+ Classifier: Topic :: Scientific/Engineering :: Image Processing
16
+ Requires-Python: ==3.10
17
+ Description-Content-Type: text/markdown
18
+ Requires-Dist: giotto-tda==0.6.2
19
+ Requires-Dist: gudhi>=3.10.1
20
+ Requires-Dist: joblib>=1.4.2
21
+ Requires-Dist: scikit-learn==1.6.1
22
+ Requires-Dist: scikit-image>=0.25.0
23
+ Requires-Dist: tqdm>=4.67.1
24
+ Provides-Extra: classification
25
+ Requires-Dist: catboost>=1.2.7; extra == "classification"
26
+ Requires-Dist: xgboost>=3.0.0; extra == "classification"
27
+ Requires-Dist: matplotlib>=3.10.1; extra == "classification"
28
+ Requires-Dist: pandas>=2.2.3; extra == "classification"
29
+ Requires-Dist: torch>=2.5.1; extra == "classification"
30
+ Requires-Dist: torchvision>=0.20.1; extra == "classification"
31
+ Requires-Dist: torchph==0.0.0; extra == "classification"
32
+ Provides-Extra: face-recognition
33
+ Requires-Dist: pytorch-metric-learning==2.8.1; extra == "face-recognition"
34
+ Requires-Dist: matplotlib>=3.10.1; extra == "face-recognition"
35
+ Requires-Dist: torch>=2.5.1; extra == "face-recognition"
36
+ Requires-Dist: torchvision>=0.20.1; extra == "face-recognition"
37
+ Requires-Dist: torchph==0.0.0; extra == "face-recognition"
38
+
39
+ # Computer Vision With Topological Data Analysis
40
+
41
+ TO BE DONE
@@ -0,0 +1,52 @@
1
+ README.md
2
+ pyproject.toml
3
+ src/cv_tda.egg-info/PKG-INFO
4
+ src/cv_tda.egg-info/SOURCES.txt
5
+ src/cv_tda.egg-info/dependency_links.txt
6
+ src/cv_tda.egg-info/requires.txt
7
+ src/cv_tda.egg-info/top_level.txt
8
+ src/cvtda/classification/NNClassifier.py
9
+ src/cvtda/classification/__init__.py
10
+ src/cvtda/classification/classify.py
11
+ src/cvtda/classification/estimate_quality.py
12
+ src/cvtda/classification/information_value.py
13
+ src/cvtda/dumping/__init__.py
14
+ src/cvtda/dumping/base.py
15
+ src/cvtda/dumping/devnull.py
16
+ src/cvtda/dumping/dump_name_concat.py
17
+ src/cvtda/dumping/numpy.py
18
+ src/cvtda/face_recognition/BaseLearner.py
19
+ src/cvtda/face_recognition/DiagramsLearner.py
20
+ src/cvtda/face_recognition/NNLearner.py
21
+ src/cvtda/face_recognition/SimpleTopologicalLearner.py
22
+ src/cvtda/face_recognition/__init__.py
23
+ src/cvtda/face_recognition/learn.py
24
+ src/cvtda/logging/__init__.py
25
+ src/cvtda/logging/base.py
26
+ src/cvtda/logging/cli.py
27
+ src/cvtda/logging/devnull.py
28
+ src/cvtda/neural_network/Dataset.py
29
+ src/cvtda/neural_network/NNBase.py
30
+ src/cvtda/neural_network/__init__.py
31
+ src/cvtda/topology/DiagramVectorizer.py
32
+ src/cvtda/topology/FeatureExtractor.py
33
+ src/cvtda/topology/FiltrationsExtractor.py
34
+ src/cvtda/topology/GeometryExtractor.py
35
+ src/cvtda/topology/GreyscaleExtractor.py
36
+ src/cvtda/topology/PointCloudsExtractor.py
37
+ src/cvtda/topology/__init__.py
38
+ src/cvtda/topology/interface/Extractor.py
39
+ src/cvtda/topology/interface/TopologicalExtractor.py
40
+ src/cvtda/topology/interface/__init__.py
41
+ src/cvtda/topology/utils/__init__.py
42
+ src/cvtda/topology/utils/hstack.py
43
+ src/cvtda/topology/utils/process_iter.py
44
+ src/cvtda/topology/utils/process_iter_dump.py
45
+ src/cvtda/utils/__init__.py
46
+ src/cvtda/utils/duplicates.py
47
+ src/cvtda/utils/image2pointcloud.py
48
+ src/cvtda/utils/rgb2gray.py
49
+ src/cvtda/utils/rgb2hsv.py
50
+ src/cvtda/utils/sequence2features.py
51
+ src/cvtda/utils/set_random_seed.py
52
+ src/cvtda/utils/spread_points.py
@@ -0,0 +1,22 @@
1
+ giotto-tda==0.6.2
2
+ gudhi>=3.10.1
3
+ joblib>=1.4.2
4
+ scikit-learn==1.6.1
5
+ scikit-image>=0.25.0
6
+ tqdm>=4.67.1
7
+
8
+ [classification]
9
+ catboost>=1.2.7
10
+ xgboost>=3.0.0
11
+ matplotlib>=3.10.1
12
+ pandas>=2.2.3
13
+ torch>=2.5.1
14
+ torchvision>=0.20.1
15
+ torchph==0.0.0
16
+
17
+ [face_recognition]
18
+ pytorch-metric-learning==2.8.1
19
+ matplotlib>=3.10.1
20
+ torch>=2.5.1
21
+ torchvision>=0.20.1
22
+ torchph==0.0.0
@@ -0,0 +1 @@
1
+ cvtda
@@ -0,0 +1,173 @@
1
+ import typing
2
+
3
+ import numpy
4
+ import torch
5
+ import sklearn.base
6
+ import sklearn.metrics
7
+ import torch.utils.data
8
+
9
+ import cvtda.utils
10
+ import cvtda.logging
11
+ import cvtda.neural_network
12
+
13
+
14
+ class NNClassifier(sklearn.base.ClassifierMixin):
15
+ def __init__(
16
+ self,
17
+
18
+ n_jobs: int = -1,
19
+ random_state: int = 42,
20
+
21
+ device: torch.device = torch.device("cuda"),
22
+ batch_size: int = 256,
23
+ learning_rate: float = 1e-3,
24
+ n_epochs: int = 100,
25
+
26
+ skip_diagrams: bool = False,
27
+ skip_images: bool = False,
28
+ skip_features: bool = False
29
+ ):
30
+ self.n_jobs_ = n_jobs
31
+ self.random_state_ = random_state
32
+
33
+ self.device_ = device
34
+ self.batch_size_ = batch_size
35
+ self.learning_rate_ = learning_rate
36
+ self.n_epochs_ = n_epochs
37
+
38
+ self.skip_diagrams_ = skip_diagrams
39
+ self.skip_images_ = skip_images
40
+ self.skip_features_ = skip_features
41
+
42
+
43
+ def fit(self, train: cvtda.neural_network.Dataset, val: typing.Optional[cvtda.neural_network.Dataset]):
44
+ cvtda.utils.set_random_seed(self.random_state_)
45
+ train_dl = torch.utils.data.DataLoader(
46
+ torch.utils.data.TensorDataset(train.images, train.features, train.labels, torch.arange(len(train))),
47
+ batch_size = self.batch_size_,
48
+ shuffle = True
49
+ )
50
+ self.init_(len(torch.unique(train.labels)), *next(iter(train_dl)), train)
51
+
52
+ for epoch in range(self.n_epochs_):
53
+ sum_loss = 0
54
+
55
+ self.model_list_.train()
56
+ for images, features, labels, diagram_idxs in cvtda.logging.logger().pbar(train_dl, desc = f"Epoch {epoch}"):
57
+ self.optimizer_.zero_grad()
58
+ pred = self.forward_(images, features, diagram_idxs, train)
59
+ loss = torch.nn.functional.cross_entropy(pred, labels.to(self.device_), reduction = 'mean')
60
+ loss.backward()
61
+ self.optimizer_.step()
62
+ sum_loss += loss.item()
63
+ postfix = { 'loss': sum_loss, 'lr': self.optimizer_.param_groups[0]['lr'] }
64
+ self.scheduler_.step()
65
+
66
+ if val is not None:
67
+ val_proba = self.predict_proba_(val)
68
+ val_pred = numpy.argmax(val_proba, axis = 1)
69
+ postfix['val_acc'] = sklearn.metrics.accuracy_score(val.labels, val_pred)
70
+
71
+ print(f"Epoch {epoch}:", postfix)
72
+
73
+ self.fitted_ = True
74
+ return self
75
+
76
+ def predict_proba(self, dataset: cvtda.neural_network.Dataset) -> numpy.ndarray:
77
+ assert self.fitted_ is True, 'fit() must be called before predict_proba()'
78
+ cvtda.utils.set_random_seed(self.random_state_)
79
+ return self.predict_proba_(dataset)
80
+
81
+
82
+ def init_(
83
+ self,
84
+ num_classes: int,
85
+ images: torch.Tensor,
86
+ features: torch.Tensor,
87
+ labels: torch.Tensor,
88
+ diagram_idxs: torch.Tensor,
89
+ dataset: cvtda.neural_network.Dataset
90
+ ):
91
+ diagrams = [] if self.skip_diagrams_ else dataset.get_diagrams(diagram_idxs)
92
+
93
+ is_no_topology = (self.skip_diagrams_ and self.skip_features_ and not self.skip_images_)
94
+ print('Topology: ', not is_no_topology)
95
+ print('Images: ', images.shape)
96
+ print('Features: ', features.shape)
97
+
98
+ if is_no_topology:
99
+ images_output = num_classes
100
+ else:
101
+ images_output = 1024
102
+
103
+ self.nn_base_ = cvtda.neural_network.NNBase(
104
+ num_diagrams = len(diagrams) // 2,
105
+ skip_diagrams = self.skip_diagrams_,
106
+ skip_images = self.skip_images_,
107
+ skip_features = self.skip_features_,
108
+ images_n_channels = images.shape[1],
109
+ images_output = images_output
110
+ ).to(self.device_).train()
111
+
112
+ self.model_ = torch.nn.Sequential(
113
+ torch.nn.Dropout(0.4), torch.nn.LazyLinear(256), torch.nn.BatchNorm1d(256), torch.nn.GELU(),
114
+ torch.nn.Dropout(0.3), torch.nn.Linear(256, 128), torch.nn.BatchNorm1d(128), torch.nn.GELU(),
115
+ torch.nn.Dropout(0.2), torch.nn.Linear(128, 64), torch.nn.BatchNorm1d(64), torch.nn.GELU(),
116
+ torch.nn.Dropout(0.1), torch.nn.Linear(64, 32), torch.nn.BatchNorm1d(32), torch.nn.GELU(),
117
+ torch.nn.Linear(32, num_classes)
118
+ ).to(self.device_).train()
119
+
120
+ if is_no_topology:
121
+ self.model_ = torch.nn.Identity()
122
+
123
+ self.model_list_ = torch.nn.ModuleList([ self.nn_base_, self.model_ ])
124
+
125
+ self.optimizer_ = torch.optim.AdamW(
126
+ params = self.model_list_.parameters(),
127
+ lr = self.learning_rate_ * 100
128
+ )
129
+
130
+ def lr_scheduler_lambda(epoch):
131
+ if epoch < self.n_epochs_ // 10:
132
+ return 1
133
+ if epoch < self.n_epochs_ // 4:
134
+ return 0.1
135
+ if epoch < self.n_epochs_ // 2:
136
+ return 0.01
137
+ if epoch < 3 * self.n_epochs_ // 4:
138
+ return 0.001
139
+ return 0.0001
140
+ self.scheduler_ = torch.optim.lr_scheduler.LambdaLR(self.optimizer_, lr_scheduler_lambda)
141
+
142
+ self.forward_(images, features, diagram_idxs, dataset)
143
+ if not is_no_topology:
144
+ cvtda.logging.logger().print(f'Input to LazyLinear: {self.model_[1].in_features}')
145
+ cvtda.logging.logger().print(f'Parameters: {sum(p.numel() for p in self.model_list_.parameters())}')
146
+
147
+ def forward_(
148
+ self,
149
+ images: torch.Tensor,
150
+ features: torch.Tensor,
151
+ diagram_idxs: torch.Tensor,
152
+ dataset: cvtda.neural_network.Dataset
153
+ ) -> torch.Tensor:
154
+ images = images.to(self.device_)
155
+ features = features.to(self.device_)
156
+ if self.skip_diagrams_:
157
+ return self.model_(self.nn_base_(images, features))
158
+ return self.model_(self.nn_base_(images, features, *dataset.get_diagrams(diagram_idxs)))
159
+
160
+ def predict_proba_(self, dataset: cvtda.neural_network.Dataset) -> numpy.ndarray:
161
+ dl = torch.utils.data.DataLoader(
162
+ torch.utils.data.TensorDataset(dataset.images, dataset.features, torch.arange(len(dataset))),
163
+ batch_size = self.batch_size_,
164
+ shuffle = False
165
+ )
166
+
167
+ y_pred_proba = [ ]
168
+ self.model_list_.eval()
169
+ with torch.no_grad():
170
+ for images, features, diagram_idxs in dl:
171
+ y_pred_proba.append(self.forward_(images, features, diagram_idxs, dataset))
172
+ y_pred_proba = torch.vstack(y_pred_proba)
173
+ return torch.nn.functional.softmax(y_pred_proba, dim = 1).cpu().numpy()
@@ -0,0 +1,6 @@
1
+ from .classify import classify
2
+ from .estimate_quality import estimate_quality
3
+ from .information_value import calculate_binary_information_value
4
+ from .information_value import calculate_information_value
5
+ from .information_value import InformationValueFeatureSelector
6
+ from .NNClassifier import NNClassifier
@@ -0,0 +1,209 @@
1
+ import os
2
+ import typing
3
+
4
+ import numpy
5
+ import torch
6
+ import pandas
7
+ import xgboost
8
+ import catboost
9
+ import sklearn.base
10
+ import sklearn.ensemble
11
+ import sklearn.neighbors
12
+ import matplotlib.pyplot as plt
13
+
14
+ import cvtda.dumping
15
+ import cvtda.neural_network
16
+ from .NNClassifier import NNClassifier
17
+ from .estimate_quality import estimate_quality
18
+
19
+ def classify(
20
+ train_images: numpy.ndarray,
21
+ train_features: numpy.ndarray,
22
+ train_labels: numpy.ndarray,
23
+ train_diagrams: typing.Optional[typing.List[numpy.ndarray]],
24
+
25
+ test_images: numpy.ndarray,
26
+ test_features: numpy.ndarray,
27
+ test_labels: numpy.ndarray,
28
+ test_diagrams: typing.Optional[typing.List[numpy.ndarray]],
29
+
30
+ label_names: typing.Optional[typing.List[str]] = None,
31
+ confusion_matrix_include_values: bool = True,
32
+
33
+ n_jobs: int = -1,
34
+ random_state: int = 42,
35
+ dump_name: typing.Optional[str] = None,
36
+ only_get_from_dump: bool = False,
37
+
38
+ knn_neighbours: int = 50,
39
+
40
+ random_forest_estimators: int = 100,
41
+
42
+ nn_device: torch.device = torch.device('cuda'),
43
+ nn_batch_size: int = 256,
44
+ nn_learning_rate: float = 1e-3,
45
+ nn_epochs: int = 100,
46
+
47
+ grad_boost_max_iter: int = 20,
48
+ grad_boost_max_depth: int = 4,
49
+ grad_boost_max_features: float = 0.1,
50
+
51
+ xgboost_n_classifiers: int = 25,
52
+ xgboost_max_depth: int = 4,
53
+ xgboost_device: str = 'gpu',
54
+
55
+ catboost_iterations: int = 600,
56
+ catboost_depth: int = 4,
57
+ catboost_device: str = 'GPU',
58
+
59
+ without_diagrams: bool = False
60
+ ):
61
+ if (train_images is not None) and (not only_get_from_dump):
62
+ nn_train = cvtda.neural_network.Dataset(
63
+ train_images, train_diagrams, train_features, train_labels, n_jobs = n_jobs, device = nn_device
64
+ )
65
+ nn_test = cvtda.neural_network.Dataset(
66
+ test_images, test_diagrams, test_features, test_labels, n_jobs = n_jobs, device = nn_device
67
+ )
68
+
69
+ def classify_one(classifier: sklearn.base.ClassifierMixin, name: str, display_name: str, ax: plt.Axes):
70
+ if without_diagrams and name == 'NNClassifier_diagrams':
71
+ print(f'Skipping {name} - {classifier}')
72
+ return {}
73
+
74
+ print(f'Trying {name} - {classifier}')
75
+
76
+ dumper = cvtda.dumping.dumper()
77
+ model_dump_name = cvtda.dumping.dump_name_concat(dump_name, name)
78
+ if only_get_from_dump or dumper.has_dump(model_dump_name):
79
+ y_pred_proba = dumper.get_dump(model_dump_name)
80
+ else:
81
+ if type(classifier) == NNClassifier:
82
+ classifier.fit(nn_train, nn_test)
83
+ y_pred_proba = classifier.predict_proba(nn_test)
84
+ else:
85
+ classifier.fit(train_features, train_labels)
86
+ y_pred_proba = classifier.predict_proba(test_features)
87
+
88
+ if model_dump_name is not None:
89
+ dumper.save_dump(y_pred_proba, model_dump_name)
90
+
91
+ ax.set_title(display_name)
92
+ result = {
93
+ 'classifier': display_name,
94
+ **estimate_quality(
95
+ y_pred_proba, test_labels, ax,
96
+ label_names = label_names, confusion_matrix_include_values = confusion_matrix_include_values
97
+ )
98
+ }
99
+ print(result)
100
+ return result
101
+
102
+ classifiers = [
103
+ sklearn.neighbors.KNeighborsClassifier(
104
+ n_jobs = n_jobs,
105
+ n_neighbors = knn_neighbours
106
+ ),
107
+ sklearn.ensemble.RandomForestClassifier(
108
+ n_estimators = random_forest_estimators,
109
+ random_state = random_state,
110
+ n_jobs = n_jobs
111
+ ),
112
+ sklearn.ensemble.HistGradientBoostingClassifier(
113
+ random_state = random_state,
114
+ max_iter = grad_boost_max_iter,
115
+ max_depth = grad_boost_max_depth,
116
+ max_features = grad_boost_max_features,
117
+ verbose = 2
118
+ ),
119
+ catboost.CatBoostClassifier(
120
+ iterations = catboost_iterations,
121
+ depth = catboost_depth,
122
+ random_seed = random_state,
123
+ loss_function = 'MultiClass',
124
+ devices = '0-3',
125
+ task_type = catboost_device,
126
+ verbose = True
127
+ ),
128
+ xgboost.XGBClassifier(
129
+ n_jobs = n_jobs,
130
+ n_estimators = xgboost_n_classifiers,
131
+ max_depth = xgboost_max_depth,
132
+ device = xgboost_device
133
+ ),
134
+ NNClassifier(
135
+ random_state = random_state,
136
+ device = nn_device,
137
+ batch_size = nn_batch_size,
138
+ learning_rate = nn_learning_rate,
139
+ n_epochs = nn_epochs * 2,
140
+ skip_diagrams = True,
141
+ skip_images = True,
142
+ skip_features = False,
143
+ ),
144
+ NNClassifier(
145
+ random_state = random_state,
146
+ device = nn_device,
147
+ batch_size = nn_batch_size,
148
+ learning_rate = nn_learning_rate,
149
+ n_epochs = nn_epochs // 5,
150
+ skip_diagrams = False,
151
+ skip_images = True,
152
+ skip_features = True,
153
+ ),
154
+ NNClassifier(
155
+ random_state = random_state,
156
+ device = nn_device,
157
+ batch_size = nn_batch_size,
158
+ learning_rate = nn_learning_rate,
159
+ n_epochs = nn_epochs,
160
+ skip_diagrams = True,
161
+ skip_images = False,
162
+ skip_features = True,
163
+ ),
164
+ NNClassifier(
165
+ random_state = random_state,
166
+ device = nn_device,
167
+ batch_size = nn_batch_size,
168
+ learning_rate = nn_learning_rate,
169
+ n_epochs = nn_epochs,
170
+ skip_diagrams = True,
171
+ skip_images = False,
172
+ skip_features = False,
173
+ )
174
+ ]
175
+ names = [
176
+ 'KNeighborsClassifier',
177
+ 'RandomForestClassifier',
178
+ 'HistGradientBoostingClassifier',
179
+ 'CatBoostClassifier',
180
+ 'XGBClassifier',
181
+ 'NNClassifier_features',
182
+ 'NNClassifier_diagrams',
183
+ 'NNClassifier_images',
184
+ 'NNClassifier_features_images'
185
+ ]
186
+ display_names = [
187
+ 'Метод k ближайших соседей',
188
+ 'Случайный лес',
189
+ 'Град. бустинг на основе гистограмм',
190
+ 'CatBoost',
191
+ 'XGBoost',
192
+ 'Нейронная сеть для тополог. признаков',
193
+ 'Обучаемая векторизация диаграмм',
194
+ 'ResNet50 – базовая модель',
195
+ 'Комбинированная нейронная сеть'
196
+ ]
197
+
198
+ figure, axes = plt.subplots(3, 3, figsize = (15, 15))
199
+ df = pandas.DataFrame([ classify_one(*args) for args in zip(classifiers, names, display_names, axes.flat) ])
200
+ figure.tight_layout()
201
+
202
+ dumper = cvtda.dumping.dumper()
203
+ if (dump_name is not None) and isinstance(dumper, cvtda.dumping.NumpyDumper):
204
+ file = dumper.get_file_name_(cvtda.dumping.dump_name_concat(dump_name, "confusion_matrixes"))
205
+ os.makedirs(os.path.dirname(file), exist_ok = True)
206
+ figure.savefig(file[:-4] + ".svg")
207
+ figure.savefig(file[:-4] + ".png")
208
+ df.to_csv(dumper.get_file_name_(cvtda.dumping.dump_name_concat(dump_name, "quality_metrics.csv"))[:-4])
209
+ return df
@@ -0,0 +1,47 @@
1
+ import typing
2
+
3
+ import numpy
4
+ import sklearn.metrics
5
+ import matplotlib.pyplot as plt
6
+
7
+ def estimate_quality(
8
+ y_pred_proba: numpy.ndarray,
9
+ y_true: numpy.ndarray,
10
+ ax: typing.Optional[plt.Axes] = None,
11
+ label_names: typing.Optional[typing.List[str]] = None,
12
+ confusion_matrix_include_values: bool = True
13
+ ) -> dict:
14
+ if label_names is None:
15
+ label_names = list(range(y_pred_proba.shape[1]))
16
+
17
+ y_pred = numpy.argmax(y_pred_proba, axis = 1)
18
+ if ax:
19
+ sklearn.metrics.ConfusionMatrixDisplay.from_predictions(
20
+ y_true, y_pred, ax = ax, colorbar = False,
21
+ display_labels = label_names, include_values = confusion_matrix_include_values
22
+ )
23
+ ax.set_xticks(ax.get_xticks(), labels = ax.get_xticklabels(), rotation = 45, ha = "right", rotation_mode = "anchor")
24
+ ax.set_xlabel(None)
25
+ ax.set_ylabel(None)
26
+
27
+ numeric_labels = list(range(y_pred_proba.shape[1]))
28
+ auc_roc_input = y_pred_proba
29
+ multi_class = 'ovo'
30
+ average = 'macro'
31
+
32
+ if y_pred_proba.shape[1] == 2:
33
+ auc_roc_input = y_pred_proba[:, 1]
34
+ multi_class = 'raise'
35
+ average = 'binary'
36
+
37
+ metrics = {
38
+ 'Accuracy': sklearn.metrics.accuracy_score (y_true, y_pred),
39
+ 'AUC-ROC': sklearn.metrics.roc_auc_score (y_true, auc_roc_input, multi_class = multi_class, labels = numeric_labels),
40
+ 'Precision': sklearn.metrics.precision_score (y_true, y_pred, average = average, zero_division = 0),
41
+ 'Recall': sklearn.metrics.recall_score (y_true, y_pred, average = average),
42
+ 'F1-score': sklearn.metrics.f1_score (y_true, y_pred, average = average)
43
+ }
44
+ for k in [ 2, 3, 5, 7, 9, 15, 30 ]:
45
+ if y_pred_proba.shape[1] > k:
46
+ metrics[f'TOP-{k} Accuracy'] = sklearn.metrics.top_k_accuracy_score(y_true, y_pred_proba, k = k, labels = numeric_labels)
47
+ return metrics