ducky-python-module 1.0.0__tar.gz → 1.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.
- {ducky_python_module-1.0.0 → ducky_python_module-1.0.1}/PKG-INFO +2 -2
- {ducky_python_module-1.0.0 → ducky_python_module-1.0.1}/README.md +1 -1
- {ducky_python_module-1.0.0 → ducky_python_module-1.0.1}/pyproject.toml +1 -1
- ducky_python_module-1.0.1/src/ducky/__init__.py +2 -0
- ducky_python_module-1.0.1/src/ducky/backend.py +16 -0
- {ducky_python_module-1.0.0 → ducky_python_module-1.0.1}/src/ducky/main.py +238 -141
- {ducky_python_module-1.0.0 → ducky_python_module-1.0.1}/src/ducky_python_module.egg-info/PKG-INFO +2 -2
- {ducky_python_module-1.0.0 → ducky_python_module-1.0.1}/src/ducky_python_module.egg-info/SOURCES.txt +1 -0
- ducky_python_module-1.0.0/src/ducky/__init__.py +0 -7
- {ducky_python_module-1.0.0 → ducky_python_module-1.0.1}/LICENSE.txt +0 -0
- {ducky_python_module-1.0.0 → ducky_python_module-1.0.1}/setup.cfg +0 -0
- {ducky_python_module-1.0.0 → ducky_python_module-1.0.1}/src/ducky_python_module.egg-info/dependency_links.txt +0 -0
- {ducky_python_module-1.0.0 → ducky_python_module-1.0.1}/src/ducky_python_module.egg-info/requires.txt +0 -0
- {ducky_python_module-1.0.0 → ducky_python_module-1.0.1}/src/ducky_python_module.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ducky-python-module
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.1
|
|
4
4
|
Summary: Ducky Python module
|
|
5
5
|
Author: Tom
|
|
6
6
|
License: Creative Commons Attribution-NonCommercial 4.0 International Public
|
|
@@ -345,7 +345,7 @@ Requires-Dist: numpy>=1.26.0
|
|
|
345
345
|
Dynamic: license-file
|
|
346
346
|
|
|
347
347
|
# Ducky-Python-Module
|
|
348
|
-
A collection of tools for python
|
|
348
|
+
A collection of QOL and specialised tools for python
|
|
349
349
|
Still in progress and will be releasing fully soon
|
|
350
350
|
Credit:
|
|
351
351
|
Turtle library has been used and modified. I did not make it and I did include the text from the original library explaining rights to the Turtle program which I am not allowed to remove.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# Ducky-Python-Module
|
|
2
|
-
A collection of tools for python
|
|
2
|
+
A collection of QOL and specialised tools for python
|
|
3
3
|
Still in progress and will be releasing fully soon
|
|
4
4
|
Credit:
|
|
5
5
|
Turtle library has been used and modified. I did not make it and I did include the text from the original library explaining rights to the Turtle program which I am not allowed to remove.
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "ducky-python-module"
|
|
7
|
-
version = "1.0.0
|
|
7
|
+
version = "1.0.1" #changed version number already. Last pypi release uses 1.0.0
|
|
8
8
|
description = "Ducky Python module"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.8"
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import numpy as _numpy
|
|
2
|
+
_backend = _numpy
|
|
3
|
+
def set_backend(name: str):
|
|
4
|
+
global _backend
|
|
5
|
+
if name == "numpy":
|
|
6
|
+
import numpy
|
|
7
|
+
_backend = numpy
|
|
8
|
+
elif name == "cupy":
|
|
9
|
+
import cupy
|
|
10
|
+
_backend = cupy
|
|
11
|
+
|
|
12
|
+
else:
|
|
13
|
+
raise ValueError("Backend must be numpy or cupy")
|
|
14
|
+
|
|
15
|
+
def backend():
|
|
16
|
+
return _backend
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import random, time, os, nltk, tkinter as TK, types, math, inspect, sys, requests, json,
|
|
1
|
+
import random, time, os, nltk, tkinter as TK, types, math, inspect, sys, requests, json, ast, logging, abc
|
|
2
2
|
from os.path import isfile, split, join
|
|
3
3
|
from copy import deepcopy
|
|
4
4
|
from tkinter import simpledialog
|
|
5
5
|
from turtle import Turtle
|
|
6
6
|
from nltk.tokenize import word_tokenize
|
|
7
|
+
from ducky.backend import backend
|
|
7
8
|
from nltk.stem import LancasterStemmer
|
|
8
|
-
logging.basicConfig(level=logging.INFO)
|
|
9
9
|
|
|
10
10
|
#matrix functions
|
|
11
11
|
|
|
12
12
|
def matrix(x,y,fill=0):
|
|
13
|
-
mat = [[fill for
|
|
13
|
+
mat = [[fill for _ in range(x)] for _ in range(y)]
|
|
14
14
|
return mat
|
|
15
15
|
|
|
16
16
|
def draw(mat,x,y,val=1,errors=True): #draws a certain value to all specified positions
|
|
@@ -72,7 +72,34 @@ def render(mat):
|
|
|
72
72
|
print("------------------------------------------------------")
|
|
73
73
|
|
|
74
74
|
#my functions
|
|
75
|
-
|
|
75
|
+
|
|
76
|
+
def download_nltk():
|
|
77
|
+
nltk.download('punkt', quiet=True)
|
|
78
|
+
|
|
79
|
+
def download_to_path(url, path, file_name, quiet=False):
|
|
80
|
+
try:
|
|
81
|
+
r = requests.get(url)
|
|
82
|
+
r.raise_for_status()
|
|
83
|
+
|
|
84
|
+
with open(f"{path}/{file_name}", "wb") as f:
|
|
85
|
+
f.write(r.content)
|
|
86
|
+
|
|
87
|
+
except requests.exceptions.RequestException as e:
|
|
88
|
+
if not quiet:
|
|
89
|
+
print("Download failed:", e)
|
|
90
|
+
|
|
91
|
+
def low_ram_download(url,path,file_name,quiet=False):
|
|
92
|
+
try:
|
|
93
|
+
with requests.get(url, stream=True) as r:
|
|
94
|
+
r.raise_for_status()
|
|
95
|
+
with open(f"{path}/{file_name}", "wb") as f:
|
|
96
|
+
for chunk in r.iter_content(chunk_size=8192):
|
|
97
|
+
if chunk:
|
|
98
|
+
f.write(chunk)
|
|
99
|
+
except requests.exceptions.RequestException as e:
|
|
100
|
+
if not quiet:
|
|
101
|
+
print("Download failed:", e)
|
|
102
|
+
|
|
76
103
|
def rand_int(minimum,maximum):
|
|
77
104
|
return random.randint(minimum,maximum)
|
|
78
105
|
|
|
@@ -91,7 +118,7 @@ def current_minute():
|
|
|
91
118
|
def current_second():
|
|
92
119
|
return time.localtime()[5]
|
|
93
120
|
|
|
94
|
-
def
|
|
121
|
+
def tokenise(string):
|
|
95
122
|
tokens = word_tokenize(string)
|
|
96
123
|
return tokens
|
|
97
124
|
|
|
@@ -100,16 +127,16 @@ def stem(string):
|
|
|
100
127
|
return lancaster.stem(string)
|
|
101
128
|
|
|
102
129
|
def array(lst):
|
|
103
|
-
return
|
|
130
|
+
return backend().array(lst)
|
|
104
131
|
|
|
105
132
|
def dot_product(mat1,mat2):
|
|
106
|
-
return
|
|
133
|
+
return backend().dot(mat1,mat2)
|
|
107
134
|
|
|
108
135
|
def scale_matrices(mat,val):
|
|
109
136
|
return mat*val
|
|
110
137
|
|
|
111
138
|
def average_matrices(mat):
|
|
112
|
-
return
|
|
139
|
+
return backend().average(mat)
|
|
113
140
|
|
|
114
141
|
def calc(param):
|
|
115
142
|
try:
|
|
@@ -397,7 +424,7 @@ class Chatbot:
|
|
|
397
424
|
|
|
398
425
|
def reply(self,reply_input):
|
|
399
426
|
score = [0, 0, 0, 0, 0]
|
|
400
|
-
tokens =
|
|
427
|
+
tokens = tokenise(reply_input)
|
|
401
428
|
stemmed_words = []
|
|
402
429
|
for token in tokens:
|
|
403
430
|
stemmed_words.append((stem(token)))
|
|
@@ -433,85 +460,48 @@ class Chatbot:
|
|
|
433
460
|
return None
|
|
434
461
|
|
|
435
462
|
|
|
436
|
-
#AI
|
|
463
|
+
#AI class templates
|
|
437
464
|
|
|
438
|
-
import mnist
|
|
439
|
-
import numpy
|
|
440
|
-
import abc
|
|
441
|
-
|
|
442
|
-
class ActivationFunction:
|
|
443
|
-
tanh = 0
|
|
444
|
-
sigmoid = 1
|
|
445
|
-
softmax = 2
|
|
446
|
-
@staticmethod
|
|
447
|
-
def __tanh(x: numpy.ndarray) -> numpy.ndarray:
|
|
448
|
-
return numpy.tanh(x)
|
|
449
|
-
|
|
450
|
-
@staticmethod
|
|
451
|
-
def __tanh_derivative(x: numpy.ndarray) -> numpy.ndarray:
|
|
452
|
-
return 1 - numpy.tanh(x) ** 2
|
|
453
465
|
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
return ActivationFunction.tanh, ActivationFunction.__tanh, ActivationFunction.__tanh_derivative
|
|
466
|
+
import abc
|
|
467
|
+
import random
|
|
457
468
|
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
469
|
+
import ducky
|
|
470
|
+
import numpy
|
|
471
|
+
import numpy
|
|
461
472
|
|
|
462
|
-
@staticmethod
|
|
463
|
-
def __sigmoid_derivative(x):
|
|
464
|
-
s = 1 / (1 + numpy.exp(-x))
|
|
465
|
-
return s * (1 - s)
|
|
466
473
|
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
return ActivationFunction.sigmoid, ActivationFunction.__sigmoid, ActivationFunction.__sigmoid_derivative
|
|
474
|
+
class ActivationFunctions:
|
|
475
|
+
TANH = 0
|
|
470
476
|
|
|
471
477
|
@staticmethod
|
|
472
|
-
def
|
|
473
|
-
|
|
474
|
-
e_x = numpy.exp(x - numpy.max(x))
|
|
475
|
-
return e_x / e_x.sum(axis=-1, keepdims=True)
|
|
478
|
+
def __tanh(x: numpy.ndarray):
|
|
479
|
+
return numpy.tanh(x)
|
|
476
480
|
|
|
477
481
|
@staticmethod
|
|
478
|
-
def
|
|
479
|
-
|
|
480
|
-
return numpy.diagflat(s) - numpy.dot(s, s.T)
|
|
482
|
+
def __tanh_derived(x: numpy.ndarray):
|
|
483
|
+
return 1 - (numpy.tanh(x) ** 2)
|
|
481
484
|
|
|
482
485
|
@staticmethod
|
|
483
|
-
def
|
|
484
|
-
return
|
|
486
|
+
def use_tanh():
|
|
487
|
+
return ActivationFunctions.TANH, ActivationFunctions.__tanh, ActivationFunctions.__tanh_derived
|
|
485
488
|
|
|
486
489
|
|
|
487
490
|
class CostFunctions:
|
|
488
|
-
|
|
489
|
-
cross_entropy = 1
|
|
490
|
-
@staticmethod
|
|
491
|
-
def __mean_squared_error(actual: numpy.ndarray, predicted: numpy.ndarray):
|
|
492
|
-
return numpy.mean(numpy.power((actual - predicted), 2))
|
|
493
|
-
|
|
494
|
-
@staticmethod
|
|
495
|
-
def __mean_squared_error_derivative(actual: numpy.ndarray, predicted: numpy.ndarray) -> numpy.ndarray:
|
|
496
|
-
return 2 * (predicted - actual)/actual.size
|
|
491
|
+
MSE = 0
|
|
497
492
|
|
|
498
493
|
@staticmethod
|
|
499
|
-
def
|
|
500
|
-
return
|
|
494
|
+
def __mse(actual: numpy.ndarray, prediction: numpy.ndarray):
|
|
495
|
+
return numpy.mean(numpy.power(actual - prediction, 2))
|
|
501
496
|
|
|
502
497
|
@staticmethod
|
|
503
|
-
def
|
|
504
|
-
|
|
505
|
-
predicted = numpy.clip(predicted, epsilon, 1. - epsilon)
|
|
506
|
-
return -numpy.mean(numpy.sum(actual * numpy.log(predicted), axis=1))
|
|
498
|
+
def __mse_derived(actual: numpy.ndarray, prediction: numpy.ndarray):
|
|
499
|
+
return (2 * (prediction - actual)) / actual.size
|
|
507
500
|
|
|
508
501
|
@staticmethod
|
|
509
|
-
def
|
|
510
|
-
return
|
|
502
|
+
def use_mse():
|
|
503
|
+
return CostFunctions.MSE, CostFunctions.__mse, CostFunctions.__mse_derived
|
|
511
504
|
|
|
512
|
-
@staticmethod
|
|
513
|
-
def use_categorical_cross_entropy():
|
|
514
|
-
return CostFunctions.cross_entropy, CostFunctions.__categorical_cross_entropy, CostFunctions.__categorical_cross_entropy_derivative
|
|
515
505
|
|
|
516
506
|
class Layer(abc.ABC):
|
|
517
507
|
def __init__(self):
|
|
@@ -519,133 +509,240 @@ class Layer(abc.ABC):
|
|
|
519
509
|
self.output = None
|
|
520
510
|
|
|
521
511
|
@abc.abstractmethod
|
|
522
|
-
def feed_forward(self,
|
|
512
|
+
def feed_forward(self, input_values: numpy.ndarray):
|
|
523
513
|
pass
|
|
524
514
|
|
|
525
515
|
@abc.abstractmethod
|
|
526
|
-
def back_propagate(self,
|
|
516
|
+
def back_propagate(self, output_error: numpy.ndarray, learning_rate: float):
|
|
527
517
|
pass
|
|
528
518
|
|
|
519
|
+
@abc.abstractmethod
|
|
520
|
+
def copy(self):
|
|
521
|
+
pass
|
|
522
|
+
|
|
523
|
+
|
|
529
524
|
class FullyConnectedLayer(Layer):
|
|
530
525
|
def __init__(self, input_size: int, output_size: int):
|
|
531
|
-
|
|
526
|
+
Layer.__init__(self)
|
|
532
527
|
random_bound = 1.0 / numpy.sqrt(input_size)
|
|
533
528
|
self.weights = numpy.random.uniform(-random_bound, random_bound, (input_size, output_size))
|
|
534
529
|
self.bias = numpy.zeros((1, output_size))
|
|
530
|
+
self.input_size = input_size
|
|
531
|
+
self.output_size = output_size
|
|
535
532
|
|
|
536
|
-
def feed_forward(self,
|
|
537
|
-
self.input =
|
|
538
|
-
self.output = numpy.dot(
|
|
533
|
+
def feed_forward(self, input_values):
|
|
534
|
+
self.input = input_values
|
|
535
|
+
self.output = numpy.dot(self.input, self.weights) + self.bias
|
|
539
536
|
return self.output
|
|
540
537
|
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
self.
|
|
546
|
-
self.bias -= learning_rate * numpy.mean(error, axis=0, keepdims=True)
|
|
538
|
+
def back_propagate(self, output_error, learning_rate):
|
|
539
|
+
input_error = numpy.dot(output_error, self.weights.T)
|
|
540
|
+
weights_error = numpy.dot(self.input.T, output_error)
|
|
541
|
+
self.weights -= (learning_rate * weights_error)
|
|
542
|
+
self.bias -= (learning_rate * numpy.mean(output_error, axis=0, keepdims=True))
|
|
547
543
|
return input_error
|
|
548
544
|
|
|
545
|
+
def copy(self):
|
|
546
|
+
copied_layer = FullyConnectedLayer(self.input_size, self.output_size)
|
|
547
|
+
weights = self.weights.copy()
|
|
548
|
+
bias = self.bias.copy()
|
|
549
|
+
copied_layer.weights = weights
|
|
550
|
+
copied_layer.bias = bias
|
|
551
|
+
return copied_layer
|
|
552
|
+
|
|
549
553
|
|
|
550
554
|
class ActivationLayer(Layer):
|
|
551
|
-
def __init__(self,
|
|
552
|
-
|
|
553
|
-
self.
|
|
554
|
-
self.
|
|
555
|
-
self.
|
|
556
|
-
|
|
557
|
-
def feed_forward(self,
|
|
558
|
-
self.input =
|
|
559
|
-
self.output = self.
|
|
555
|
+
def __init__(self, activation_id, activation, activation_derived):
|
|
556
|
+
Layer.__init__(self)
|
|
557
|
+
self.activation_id = activation_id
|
|
558
|
+
self.activation = activation
|
|
559
|
+
self.activation_derived = activation_derived
|
|
560
|
+
|
|
561
|
+
def feed_forward(self, input_values):
|
|
562
|
+
self.input = input_values
|
|
563
|
+
self.output = self.activation(self.input)
|
|
560
564
|
return self.output
|
|
561
565
|
|
|
562
|
-
def back_propagate(self,
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
566
|
+
def back_propagate(self, output_error, learning_rate):
|
|
567
|
+
return self.activation_derived(self.input) * output_error
|
|
568
|
+
|
|
569
|
+
def copy(self):
|
|
570
|
+
copied_layer = ActivationLayer(self.activation_id, self.activation, self.activation_derived)
|
|
571
|
+
return copied_layer
|
|
572
|
+
|
|
567
573
|
|
|
568
574
|
class NeuralNetwork:
|
|
569
|
-
def __init__(self,
|
|
570
|
-
self.ID = ID
|
|
575
|
+
def __init__(self, cost_function_id, cost_function, cost_function_derived):
|
|
571
576
|
self.layers = []
|
|
577
|
+
self.cost_function_id = cost_function_id
|
|
572
578
|
self.cost_function = cost_function
|
|
573
|
-
self.
|
|
579
|
+
self.cost_function_derived = cost_function_derived
|
|
574
580
|
|
|
575
|
-
def add_layer(self, layer
|
|
581
|
+
def add_layer(self, layer):
|
|
576
582
|
self.layers.append(layer)
|
|
577
583
|
|
|
578
|
-
def predict(self,
|
|
584
|
+
def predict(self, input_data):
|
|
585
|
+
output = input_data
|
|
579
586
|
for layer in self.layers:
|
|
580
|
-
|
|
581
|
-
return
|
|
587
|
+
output = layer.feed_forward(output)
|
|
588
|
+
return output
|
|
582
589
|
|
|
583
|
-
def train(self,
|
|
590
|
+
def train(self, train_input, train_output, n_epochs, batch_size, learning_rate):
|
|
584
591
|
for epoch in range(n_epochs):
|
|
585
592
|
batch_index = 0
|
|
586
|
-
while batch_index <
|
|
587
|
-
if batch_index + batch_size <
|
|
588
|
-
output =
|
|
589
|
-
actual =
|
|
593
|
+
while batch_index < train_input.shape[0]:
|
|
594
|
+
if batch_index + batch_size < train_input.shape[0]:
|
|
595
|
+
output = train_input[batch_index:batch_index + batch_size, ]
|
|
596
|
+
actual = train_output[batch_index:batch_index + batch_size, ]
|
|
590
597
|
else:
|
|
591
|
-
output =
|
|
592
|
-
actual =
|
|
593
|
-
|
|
598
|
+
output = train_input[batch_index:, ]
|
|
599
|
+
actual = train_output[batch_index:, ]
|
|
600
|
+
for layer in self.layers:
|
|
601
|
+
output = layer.feed_forward(output)
|
|
594
602
|
cost = self.cost_function(actual, output)
|
|
595
|
-
error = self.
|
|
603
|
+
error = self.cost_function_derived(actual, output)
|
|
596
604
|
for layer in reversed(self.layers):
|
|
597
605
|
error = layer.back_propagate(error, learning_rate)
|
|
598
|
-
print(f"Epoch
|
|
606
|
+
print(f"Epoch {epoch + 1}/{n_epochs} | Batch = {(batch_index + 1) * batch_size} | Cost = {cost}")
|
|
599
607
|
batch_index += batch_size
|
|
600
608
|
|
|
601
|
-
def save(self,
|
|
602
|
-
with open(f"{
|
|
603
|
-
save_file.write(f"{self.
|
|
609
|
+
def save(self, file_path):
|
|
610
|
+
with open(f"{file_path}.nn", "w") as save_file:
|
|
611
|
+
save_file.write(f"{self.cost_function_id}\n")
|
|
604
612
|
for index, layer in enumerate(self.layers):
|
|
605
613
|
if isinstance(layer, FullyConnectedLayer):
|
|
606
|
-
save_file.write(f"
|
|
607
|
-
numpy.save(f"{
|
|
608
|
-
numpy.save(f"{
|
|
614
|
+
save_file.write(f"{index}|F|{layer.weights.shape}|{layer.bias.shape}\n")
|
|
615
|
+
numpy.save(f"{file_path}_{index}_w", layer.weights)
|
|
616
|
+
numpy.save(f"{file_path}_{index}_b", layer.bias)
|
|
609
617
|
elif isinstance(layer, ActivationLayer):
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
elif layer.ID == ActivationFunction.sigmoid:
|
|
613
|
-
save_file.write(f"A|{index}|{ActivationFunction.sigmoid}\n")
|
|
614
|
-
elif layer.ID == ActivationFunction.softmax:
|
|
615
|
-
save_file.write(f"A|{index}|{ActivationFunction.softmax}\n")
|
|
616
|
-
else:
|
|
617
|
-
save_file.write(f"A|{index}|{ActivationFunction.tanh}\n")
|
|
618
|
+
save_file.write(f"{index}|A|{layer.activation_id}\n")
|
|
619
|
+
|
|
618
620
|
@staticmethod
|
|
619
|
-
def
|
|
620
|
-
with open(f"{
|
|
621
|
-
lines =
|
|
621
|
+
def load_from_file(file_path):
|
|
622
|
+
with open(f"{file_path}.nn", "r") as load_file:
|
|
623
|
+
lines = load_file.readlines()
|
|
622
624
|
cost_function_id = int(lines[0])
|
|
623
|
-
if cost_function_id == CostFunctions.
|
|
624
|
-
neural_network = NeuralNetwork(*CostFunctions.
|
|
625
|
+
if cost_function_id == CostFunctions.MSE:
|
|
626
|
+
neural_network = NeuralNetwork(*CostFunctions.use_mse())
|
|
625
627
|
else:
|
|
626
|
-
neural_network = NeuralNetwork(*CostFunctions.
|
|
628
|
+
neural_network = NeuralNetwork(*CostFunctions.use_mse())
|
|
627
629
|
for line in lines[1:]:
|
|
628
630
|
if line != "":
|
|
629
631
|
parts = line.split("|")
|
|
630
|
-
if parts[
|
|
631
|
-
weights = numpy.load(f"{
|
|
632
|
-
bias = numpy.load(f"{
|
|
632
|
+
if parts[1] == "F":
|
|
633
|
+
weights = numpy.load(f"{file_path}_{int(parts[0])}_w.npy")
|
|
634
|
+
bias = numpy.load(f"{file_path}_{int(parts[0])}_b.npy")
|
|
633
635
|
layer = FullyConnectedLayer(weights.shape[0], weights.shape[1])
|
|
634
636
|
layer.weights = weights
|
|
635
637
|
layer.bias = bias
|
|
636
638
|
neural_network.add_layer(layer)
|
|
637
|
-
elif parts[
|
|
639
|
+
elif parts[1] == "A":
|
|
638
640
|
activation_id = int(parts[2])
|
|
639
|
-
if activation_id ==
|
|
640
|
-
neural_network.add_layer(ActivationLayer(*
|
|
641
|
-
elif activation_id == ActivationFunction.sigmoid:
|
|
642
|
-
neural_network.add_layer(ActivationLayer(*ActivationFunction.use_sigmoid()))
|
|
643
|
-
elif activation_id == ActivationFunction.softmax:
|
|
644
|
-
neural_network.add_layer(ActivationLayer(*ActivationFunction.use_softmax()))
|
|
641
|
+
if activation_id == ActivationFunctions.TANH:
|
|
642
|
+
neural_network.add_layer(ActivationLayer(*ActivationFunctions.use_tanh()))
|
|
645
643
|
else:
|
|
646
|
-
neural_network.add_layer(ActivationLayer(*
|
|
644
|
+
neural_network.add_layer(ActivationLayer(*ActivationFunctions.use_tanh()))
|
|
647
645
|
return neural_network
|
|
648
646
|
|
|
647
|
+
def copy_network(self):
|
|
648
|
+
copied_network = NeuralNetwork(self.cost_function_id, self.cost_function, self.cost_function_derived)
|
|
649
|
+
for layer in self.layers:
|
|
650
|
+
copied_network.add_layer(layer.copy())
|
|
651
|
+
return copied_network
|
|
652
|
+
|
|
653
|
+
|
|
654
|
+
class Agent:
|
|
655
|
+
def __init__(self):
|
|
656
|
+
self.gamma = 0.99
|
|
657
|
+
|
|
658
|
+
|
|
659
|
+
class QTable:
|
|
660
|
+
def __init__(self, state, actions):
|
|
661
|
+
self.table = numpy.zeros((state,actions))
|
|
662
|
+
self.actions = actions
|
|
663
|
+
self.state = state
|
|
664
|
+
|
|
665
|
+
def update_table(self, state_row, action, value):
|
|
666
|
+
self.table[state_row, action] += value
|
|
667
|
+
|
|
668
|
+
def get_action(self, state_row):
|
|
669
|
+
return numpy.argmax(self.table[state_row])
|
|
670
|
+
|
|
671
|
+
|
|
672
|
+
class QTableAgent(Agent):
|
|
673
|
+
def __init__(self, table, num_possible_values):
|
|
674
|
+
Agent.__init__(self)
|
|
675
|
+
self.table = table
|
|
676
|
+
self.num_possible_values = num_possible_values
|
|
677
|
+
self.epsilon = 1
|
|
678
|
+
|
|
679
|
+
def state_to_row(self,state):
|
|
680
|
+
return int("".join([str(s) for s in state.astype(int)]), self.num_possible_values)
|
|
681
|
+
|
|
682
|
+
def predict(self, state):
|
|
683
|
+
self.epsilon *= 0.99
|
|
684
|
+
if random.random() > self.epsilon:
|
|
685
|
+
return self.table.get_action(self.state_to_row(state))
|
|
686
|
+
else:
|
|
687
|
+
return random.randint(0,self.table.actions-1)
|
|
688
|
+
|
|
689
|
+
def train(self, state, action, reward):
|
|
690
|
+
self.table.update_table(self.state_to_row(state), action, reward)
|
|
691
|
+
|
|
692
|
+
|
|
693
|
+
class DeepQAgent(Agent):
|
|
694
|
+
def __init__(self, layer_sizes):
|
|
695
|
+
Agent.__init__(self)
|
|
696
|
+
self.memory = Memory()
|
|
697
|
+
self.counter = 0
|
|
698
|
+
try:
|
|
699
|
+
self.neural_network = NeuralNetwork.load_from_file("deepq-nn")
|
|
700
|
+
except FileNotFoundError:
|
|
701
|
+
self.neural_network = NeuralNetwork(*CostFunctions.use_mse())
|
|
702
|
+
for i, size in enumerate(layer_sizes[:-1]):
|
|
703
|
+
self.neural_network.add_layer(FullyConnectedLayer(size, layer_sizes[i+1]))
|
|
704
|
+
self.neural_network.add_layer(ActivationLayer(*ActivationFunctions.use_tanh()))
|
|
705
|
+
|
|
706
|
+
def predict(self, state):
|
|
707
|
+
return int(self.neural_network.predict(state)[0].argmax())
|
|
708
|
+
|
|
709
|
+
def train(self, discount_rate):
|
|
710
|
+
training_input_data = []
|
|
711
|
+
training_output_data = []
|
|
712
|
+
for i in range(len(self.memory.states)):
|
|
713
|
+
prediction = self.neural_network.predict(self.memory.states[i])
|
|
714
|
+
prediction[0] += self.memory.rewards[i - 1]
|
|
715
|
+
if i > 0:
|
|
716
|
+
prediction[0] += self.memory.rewards[i-1] * discount_rate
|
|
717
|
+
training_input_data = numpy.array(training_input_data)
|
|
718
|
+
training_output_data = numpy.array(training_output_data)
|
|
719
|
+
self.neural_network.train(training_input_data, training_output_data, n_epochs=500, batch_size=10, learning_rate=0.1)
|
|
720
|
+
if self.counter >= 10:
|
|
721
|
+
self.neural_network.save("deepq-nn")
|
|
722
|
+
self.counter = 0
|
|
723
|
+
else:
|
|
724
|
+
self.counter += 1
|
|
725
|
+
|
|
726
|
+
def update_memory(self, state, action, reward):
|
|
727
|
+
self.memory.update(state, action, reward)
|
|
728
|
+
|
|
729
|
+
|
|
730
|
+
class Memory:
|
|
731
|
+
def __init__(self):
|
|
732
|
+
self.states = []
|
|
733
|
+
self.actions = []
|
|
734
|
+
self.rewards = []
|
|
735
|
+
|
|
736
|
+
def update(self, state, action, reward):
|
|
737
|
+
self.states.append(state)
|
|
738
|
+
self.actions.append(action)
|
|
739
|
+
self.rewards.append(reward)
|
|
740
|
+
|
|
741
|
+
def clear(self):
|
|
742
|
+
self.states = []
|
|
743
|
+
self.actions = []
|
|
744
|
+
self.rewards = []
|
|
745
|
+
|
|
649
746
|
|
|
650
747
|
#turtlel
|
|
651
748
|
|
{ducky_python_module-1.0.0 → ducky_python_module-1.0.1}/src/ducky_python_module.egg-info/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ducky-python-module
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.1
|
|
4
4
|
Summary: Ducky Python module
|
|
5
5
|
Author: Tom
|
|
6
6
|
License: Creative Commons Attribution-NonCommercial 4.0 International Public
|
|
@@ -345,7 +345,7 @@ Requires-Dist: numpy>=1.26.0
|
|
|
345
345
|
Dynamic: license-file
|
|
346
346
|
|
|
347
347
|
# Ducky-Python-Module
|
|
348
|
-
A collection of tools for python
|
|
348
|
+
A collection of QOL and specialised tools for python
|
|
349
349
|
Still in progress and will be releasing fully soon
|
|
350
350
|
Credit:
|
|
351
351
|
Turtle library has been used and modified. I did not make it and I did include the text from the original library explaining rights to the Turtle program which I am not allowed to remove.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|