This repository has been archived by the owner on Oct 20, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 12023fb
Showing
28 changed files
with
1,649 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
presentation | ||
Demos | ||
.ipynb_checkpoints |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
anaconda3-2019.10 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
# -*- coding: utf-8 -*- | ||
from typing import Any, Dict, List, Tuple, Callable | ||
|
||
import numpy as np | ||
|
||
np.seterr(all='raise') | ||
|
||
|
||
class Loss: | ||
def loss(self, w: Any, x: Any, y: Any, **kwargs: Any) -> Any: | ||
raise RuntimeError("loss() was not defined in class!") | ||
|
||
|
||
class Linear(Loss): | ||
def loss(self, w: Any, x: Any, y: Any, **kwargs: Any) -> Any: | ||
raise RuntimeError("loss() was not defined in class!") | ||
|
||
|
||
class Gradient: | ||
def grad(self, w: Any, x: Any, y: Any, **kwargs: Any) -> Any: | ||
raise RuntimeError("grad() was not defined in class!") | ||
|
||
|
||
class LinearMSE(Linear, Gradient): | ||
"""Mean Squared Error.""" | ||
|
||
def loss(self, | ||
w: np.matrix, | ||
x: np.matrix, | ||
y: np.matrix, | ||
**kwargs: Any) -> float: | ||
""" | ||
Loss function. Returns float value: MSE. | ||
Positional arguments: | ||
w: np.matrix. Weights of Linear regression. | ||
x: np.matrix. Samples. | ||
y: np.matrix. Real answers. | ||
""" | ||
y_pred = x * w | ||
misses = np.array(y_pred - y) | ||
misses = misses**2 | ||
loss = np.sum(misses) / len(y) | ||
return loss | ||
|
||
def grad(self, | ||
w: np.matrix, | ||
x: np.matrix, | ||
y: np.matrix, | ||
**kwargs: Any) -> np.matrix: | ||
""" | ||
Gradient vector function for linear regression. Returns grad vector. | ||
Positional arguments: | ||
w: np.matrix. Weights of Linear regression. | ||
x: np.matrix. Samples. | ||
y: np.matrix. Real answers. | ||
""" | ||
gradvec = [] | ||
for j, _ in enumerate(w): | ||
gradcoord = np.sum([2 * x[i, j] * (x[i] * w - y[i]) | ||
for i in range(x.shape[0])]) / x.shape[0] | ||
gradvec.append(gradcoord) | ||
return np.matrix(gradvec) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
# -*- coding: utf-8 -*- | ||
from typing import Any, Tuple, Union | ||
|
||
import numpy as np | ||
|
||
from .Loss import Gradient as LG | ||
|
||
np.seterr(all='raise') | ||
|
||
|
||
class Optimization: | ||
def step(self, w: Any, x: Any, y: Any, **kwargs: Any) -> Any: | ||
raise RuntimeError("step() was not defined in class!") | ||
|
||
|
||
class Linear(Optimization): | ||
def step(self, w: Any, x: Any, y: Any, **kwargs: Any) -> Tuple[Any, Any]: | ||
raise RuntimeError("step() was not defined in class!") | ||
|
||
|
||
class Gradient(Linear): | ||
def __init__(self, lossObj: LG, **kwargs: Union[int, float]) -> None: | ||
self._random_weight = kwargs.get("random_weight", 0.001) | ||
self._random_grad = kwargs.get("random_grad", 0) | ||
self._lossObj = lossObj | ||
if not isinstance(lossObj, LG): | ||
raise TypeError("lossObj is not a Gradient loss function") | ||
|
||
def loss(self, w: np.matrix, x: np.matrix, y: np.matrix) -> float: | ||
return self._lossObj.loss(w, x, y) | ||
|
||
def step(self, | ||
w: np.matrix, | ||
x: np.matrix, | ||
y: np.matrix, | ||
**kwargs: Any) -> Tuple[np.matrix, float]: | ||
max_loss_try = kwargs.get("max_loss_try", 10) | ||
lr = kwargs.get("lr", 0.001) | ||
|
||
old_loss = self.loss(w, x, y) | ||
loss = old_loss + 1 | ||
|
||
while (max_loss_try > 0) and (old_loss < loss): | ||
try_w = self._prep_weights(w) | ||
try_g = self._gradient(try_w, x, y) | ||
try_w = self._upd_weights(try_g, try_w, lr=lr) | ||
loss = self.loss(try_w, x, y) | ||
max_loss_try -= 1 | ||
lr /= 2 | ||
|
||
return try_w, lr | ||
|
||
def _gradient(self, | ||
w: np.matrix, | ||
x: np.matrix, | ||
y: np.matrix) -> np.ndarray: | ||
g = self._lossObj.grad(w, x, y).reshape(*w.shape) | ||
return g + np.random.randn(*g.shape) * self._random_grad | ||
|
||
def _prep_weights(self, w: np.matrix) -> np.matrix: | ||
return w + np.random.randn(*w.shape) * self._random_weight | ||
|
||
def _upd_weights(self, | ||
g: np.ndarray, | ||
w: np.matrix, | ||
lr: float) -> np.matrix: | ||
return w - g * lr | ||
|
||
|
||
class SGD(Gradient): | ||
def __init__(self, lossObj: LG, **kwargs: Union[float, int]) -> None: | ||
super().__init__(lossObj, **kwargs) | ||
self._batch_size = int(kwargs.get("batch_size", 10)) | ||
|
||
def step(self, | ||
w: np.matrix, | ||
x: np.matrix, | ||
y: np.matrix, | ||
**kwargs: Any) -> np.matrix: | ||
lr = kwargs.get("lr", 0.001) | ||
w = self._prep_weights(w) | ||
x, y = self._shuffle_xy(x, y) | ||
|
||
for b in range(0, x.shape[0], self._batch_size): | ||
x_batch = x[b:b + self._batch_size] | ||
y_batch = y[b:b + self._batch_size] | ||
g = self._gradient(w, x_batch, y_batch) | ||
w = self._upd_weights(g, w, lr=lr) | ||
return w, lr | ||
|
||
def _shuffle_xy(self, | ||
x: np.matrix, | ||
y: np.matrix) -> Tuple[np.matrix, np.matrix]: | ||
shuffled_x = np.empty(x.shape, dtype=x.dtype) | ||
shuffled_y = np.empty(y.shape, dtype=y.dtype) | ||
permutation = np.random.permutation(len(x)) | ||
for old_index, new_index in enumerate(permutation): | ||
shuffled_x[new_index] = x[old_index] | ||
shuffled_y[new_index] = y[old_index] | ||
return shuffled_x, shuffled_y | ||
|
||
|
||
class MomentGrad(Gradient): | ||
def __init__(self, lossObj: LG, **kwargs: Any) -> None: | ||
super().__init__(lossObj, **kwargs) | ||
self._prev_coef = float(kwargs.get("prev_coef", 0.5)) | ||
print(self._prev_coef) | ||
self._prev_g = 0 | ||
|
||
def _upd_weights(self, | ||
g: np.ndarray, | ||
w: np.matrix, | ||
**kwargs: Any) -> np.matrix: | ||
lr = kwargs['lr'] | ||
delta_w = lr * (self._prev_coef * self._prev_g + g) | ||
self._prev_g = g | ||
return w - delta_w |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
# -*- coding: utf-8 -*- | ||
from typing import Any, Dict, Tuple, Union, List | ||
|
||
import numpy as np | ||
|
||
from .Optimization import Linear as OL | ||
|
||
np.seterr(all='raise') | ||
|
||
|
||
class Regression: | ||
def fit(self, *args: Any, **kwargs: Any) -> Any: | ||
raise RuntimeError("fit() was not specified!") | ||
|
||
|
||
class LinearRegression(Regression): | ||
_fitted: bool | ||
_weights: np.matrix | ||
|
||
def __init__(self) -> None: | ||
self._fitted = False | ||
|
||
def fit(self, | ||
x: np.matrix, | ||
y: np.matrix, | ||
optiObj: OL, | ||
**kwargs: Any) -> Dict[str, list]: | ||
lr = float(kwargs.get("lr", 0.001)) | ||
loss_stop = float(kwargs.get("loss_stop", 0.01)) | ||
delta_loss_stop = float(kwargs.get("delta_loss_stop", 0.0001)) | ||
max_iter = int(kwargs.get("max_iter", 2000)) | ||
hot_start = bool(kwargs.get("hot_start", False)) | ||
|
||
fit_history: Dict[str, List[Union[int, float]]] = { | ||
"i": [], | ||
"loss": [], | ||
"delta_loss": [], | ||
"weights": [], | ||
"lr": [] | ||
} | ||
|
||
if not isinstance(optiObj, OL): | ||
raise TypeError("optiObj is not a Linear Optimization object") | ||
|
||
x, y = self._perpare_xy(x, y) | ||
if not hot_start: | ||
self._weights = np.random.uniform(np.min(x), np.max(x), x.shape[1]) | ||
self._weights = np.matrix(self._weights.reshape(x.shape[1], 1)) | ||
|
||
loss = optiObj.loss(self._weights, x, y) | ||
delta_loss = delta_loss_stop + 1 | ||
i = 0 | ||
try: | ||
for i in range(max_iter): | ||
if loss <= loss_stop: | ||
break | ||
if delta_loss <= delta_loss_stop and delta_loss > 0: | ||
break | ||
new_lr = self._one_train(x, y, optiObj.step, lr=lr) | ||
new_loss = optiObj.loss(self._weights, x, y) | ||
|
||
delta_loss = loss - new_loss | ||
loss = new_loss | ||
|
||
fit_history['i'].append(i) | ||
fit_history['loss'].append(loss) | ||
fit_history['delta_loss'].append(delta_loss) | ||
fit_history['weights'].append(self._weights) | ||
fit_history['lr'].append(new_lr) | ||
|
||
self._fitted = True | ||
except Exception as e: | ||
raise e | ||
finally: | ||
return fit_history | ||
|
||
def _one_train(self, | ||
x: np.matrix, | ||
y: np.matrix, | ||
optiFunc: OL, | ||
**kwargs: float) -> float: | ||
self._weights, lr = optiFunc(self._weights, x, y, **kwargs) | ||
return lr | ||
|
||
def _perpare_xy(self, | ||
x: np.matrix, | ||
y: np.matrix) -> Tuple[np.matrix, np.matrix]: | ||
if not (isinstance(x, np.ndarray) or isinstance(x, np.matrix)): | ||
raise TypeError("x is not an np.array/np.matrix type") | ||
if not (isinstance(y, np.ndarray) or isinstance(y, np.matrix)): | ||
raise TypeError("y is not an np.array/np.matrix type") | ||
|
||
x, y = np.matrix(x), np.matrix(y) | ||
x = np.hstack((x, np.ones((x.shape[0], 1)))) | ||
|
||
try: | ||
if x.shape[0] != y.shape[0] or y.shape[1] != 1: | ||
raise ValueError(f"x{x.shape} not compatible with y{y.shape}") | ||
except IndexError: | ||
raise ValueError(f"wrong: x{x.shape}, y{y.shape}: x(m,n), y(m,1)") | ||
|
||
return x, y | ||
|
||
|
||
class LinearRandom(LinearRegression): | ||
def fit(self, | ||
x: np.matrix, | ||
y: np.matrix, | ||
optiObj: OL, | ||
**kwargs: Any) -> Dict[str, list]: | ||
x, y = self._perpare_xy(x, y) | ||
self._weights = np.random.uniform(np.min(x), np.max(x), x.shape[1]) | ||
self._weights = np.matrix(self._weights.reshape(x.shape[1], 1)) | ||
|
||
loss = optiObj.loss(self._weights, x, y) | ||
|
||
fit_history = { | ||
"i": [1], | ||
"loss": [loss], | ||
"delta_loss": [0.0], | ||
"weights": [self._weights], | ||
"lr": [0] | ||
} | ||
|
||
return fit_history |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
# -*- coding: utf-8 -*- | ||
|
||
# Form implementation generated from reading ui file './ExceptionPopup.ui' | ||
# | ||
# Created by: PyQt5 UI code generator 5.9.2 | ||
# | ||
# WARNING! All changes made in this file will be lost! | ||
|
||
from PyQt5 import QtCore, QtWidgets | ||
|
||
class Ui_ExceptionPopup(object): | ||
def setupUi(self, ExceptionPopup): | ||
ExceptionPopup.setObjectName("ExceptionPopup") | ||
ExceptionPopup.resize(818, 300) | ||
self.buttonOk = QtWidgets.QPushButton(ExceptionPopup) | ||
self.buttonOk.setGeometry(QtCore.QRect(330, 270, 105, 30)) | ||
self.buttonOk.setObjectName("buttonOk") | ||
self.textException = QtWidgets.QTextEdit(ExceptionPopup) | ||
self.textException.setGeometry(QtCore.QRect(0, 10, 821, 251)) | ||
self.textException.setReadOnly(True) | ||
self.textException.setObjectName("textException") | ||
|
||
self.retranslateUi(ExceptionPopup) | ||
QtCore.QMetaObject.connectSlotsByName(ExceptionPopup) | ||
|
||
def retranslateUi(self, ExceptionPopup): | ||
_translate = QtCore.QCoreApplication.translate | ||
ExceptionPopup.setWindowTitle(_translate("ExceptionPopup", "Unhandled Exception")) | ||
self.buttonOk.setText(_translate("ExceptionPopup", "OK")) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<ui version="4.0"> | ||
<class>ExceptionPopup</class> | ||
<widget class="QDialog" name="ExceptionPopup"> | ||
<property name="geometry"> | ||
<rect> | ||
<x>0</x> | ||
<y>0</y> | ||
<width>818</width> | ||
<height>300</height> | ||
</rect> | ||
</property> | ||
<property name="windowTitle"> | ||
<string>Unhandled Exception</string> | ||
</property> | ||
<widget class="QPushButton" name="buttonOk"> | ||
<property name="geometry"> | ||
<rect> | ||
<x>330</x> | ||
<y>270</y> | ||
<width>105</width> | ||
<height>30</height> | ||
</rect> | ||
</property> | ||
<property name="text"> | ||
<string>OK</string> | ||
</property> | ||
</widget> | ||
<widget class="QTextEdit" name="textException"> | ||
<property name="geometry"> | ||
<rect> | ||
<x>0</x> | ||
<y>10</y> | ||
<width>821</width> | ||
<height>251</height> | ||
</rect> | ||
</property> | ||
<property name="readOnly"> | ||
<bool>true</bool> | ||
</property> | ||
</widget> | ||
</widget> | ||
<resources/> | ||
<connections/> | ||
</ui> |
Oops, something went wrong.