pyerualjetwork 1.0.3__tar.gz → 1.0.4__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.
@@ -0,0 +1,1054 @@
1
+ import numpy as np
2
+ import time
3
+ from colorama import Fore,Style
4
+ from typing import List, Union
5
+ import math
6
+ # RUNING -----
7
+ def TrainDPNN(
8
+ Inputs: List[Union[int, float]],
9
+ Labels: List[Union[int, float, str]], # At least two.. and one hot coded
10
+ ClassCount: int,
11
+ Layers: List[str],
12
+ Neurons: List[Union[int, float]],
13
+ ThresholdSigns: List[str],
14
+ ThresholdValues: List[Union[int, float]],
15
+ Normalizations: List[str],
16
+ Activations: List[str]
17
+ ) -> str:
18
+
19
+ infoDPNN = """
20
+ Creates and configures a DPNN model.
21
+
22
+ Args:
23
+ Inputs (list[num]): List of input data.
24
+ Labels (list[num]): List of labels. (one hot encoded)
25
+ ClassCount (int): Number of classes.
26
+ Layers (list[str]): List of layer names. (options: 'fex' (Feature Extraction), 'cat' (Catalyser))
27
+ Neurons (list[num]): List of neuron counts for each layer.
28
+ ThresholdSigns (list[str]): List of threshold signs.
29
+ ThresholdValues (list[num]): List of threshold values.
30
+ Normalizations (List[str]): Whether normalization will be performed at indexed layers ("y" or "n").
31
+ Activations (list[str]): List of activation functions.
32
+
33
+ Returns:
34
+ list([num]): (Weight matrices list, TrainPredictions list.).
35
+ error handled ?: Process status ('e')
36
+ """
37
+
38
+ LastNeuron = Neurons[-1:][0]
39
+ if LastNeuron != ClassCount:
40
+ print(Fore.RED + "ERROR108: Last layer of neuron count must be equal class count. from: TrainDPNN",infoDPNN)
41
+ return 'e'
42
+
43
+ if len(Normalizations) != len(ThresholdValues):
44
+
45
+ print(Fore.RED + "ERROR307: Normalization list length must be equal to length of ThresholdSigns List,ThresholdValues List,Layers List,Neurons List. from: TrainDPNN",infoDPNN)
46
+ return 'e'
47
+
48
+ if len(Inputs) != len(Labels):
49
+ print(Fore.RED + "ERROR301: Inputs list and Labels list must be same length.",infoDPNN)
50
+ return 'e'
51
+
52
+ for i, Value in enumerate(ThresholdValues):
53
+
54
+ if Normalizations[i] != 'y' and Normalizations[i] != 'n':
55
+ print(Fore.RED + "ERROR105: Normalization list must be 'y' or 'n'.",infoDPNN)
56
+ return 'e'
57
+
58
+ if ThresholdSigns[i] == 'none':
59
+ print(Fore.MAGENTA + "WARNING102: We are advise to do not put 'none' Threshold sign. But some cases improves performance of the model from: TrainDPNN",infoDPNN + Style.RESET_ALL)
60
+ time.sleep(3)
61
+
62
+ if isinstance(Value, str):
63
+ print(Fore.RED + "ERROR201: Threshold values must be numeric. from: TrainDPNN")
64
+ return 'e'
65
+
66
+ if isinstance(Neurons[i], str):
67
+ print(Fore.RED + "ERROR202: Neurons list must be numeric.")
68
+ return 'e'
69
+
70
+ if len(ThresholdSigns) != len(ThresholdValues):
71
+ print(Fore.RED + "ERROR302: Threshold signs list and Threshold Values list must be same length. from: TrainDPNN",infoDPNN)
72
+ return 'e'
73
+
74
+ if len(Layers) != len(Neurons):
75
+ print(Fore.RED + "ERROR303: Layers list and Neurons list must same length. from: TrainDPNN",infoDPNN)
76
+ return 'e'
77
+
78
+ if len(ThresholdValues) != len(Layers) or len(ThresholdSigns) != len(Layers):
79
+ print(Fore.RED + "ERROR306: Threshold Values and Threshold Signs lists length must be same Layers list length. from: TrainDPNN",infoDPNN)
80
+ return 'e'
81
+
82
+
83
+ for Activation in Activations:
84
+ if Activation != 'softmax' and Activation != 'sigmoid' and Activation != 'relu' and Activation != 'none':
85
+ print(Fore.RED + "ERROR108: Activations list must be 'sigmoid' or 'softmax' or 'relu' or 'none' from: TrainDPNN",infoDPNN)
86
+ return 'e'
87
+
88
+
89
+ for index, Neuron in enumerate(Neurons):
90
+ if Neuron < 1:
91
+ print(Fore.RED + "ERROR101: Neurons list must be positive non zero integer. from: TrainDPNN",infoDPNN)
92
+ return 'e'
93
+
94
+ if index + 1 != len(Neurons) and Neuron % 2 != 0:
95
+ print(Fore.MAGENTA + "WARNING101: We strongly advise to do Neuron counts be should even numbers. from: TrainDPNN",infoDPNN)
96
+ time.sleep(3)
97
+
98
+ if Neuron < ClassCount:
99
+ print(Fore.RED + "ERROR102: Neuron count must be greater than class count(For DPNN). from: TrainDPNN")
100
+ return 'e'
101
+
102
+ if Layers[index] != 'fex' and Layers[index] != 'cat':
103
+ print(Fore.RED + "ERROR107: Layers list must be 'fex'(Feature Extraction Layer) or 'cat' (Catalyser Layer). from: TrainDPNN",infoDPNN)
104
+ return 'e'
105
+
106
+ if len(ThresholdSigns) != len(ThresholdValues):
107
+ print(Fore.RED + "ERROR305: Threshold signs list and Threshold values list must be same length. from: TrainDPNN",infoDPNN)
108
+ return 'e'
109
+
110
+
111
+ for i, Sign in enumerate(ThresholdSigns):
112
+ if Sign != '>' and Sign != '<' and Sign != '==' and Sign != '!=' and Sign != 'none':
113
+ print(Fore.RED + "ERROR104: Threshold signs must be '>' or '<' or '==' or '!='. or 'none' from: TrainDPNN",infoDPNN)
114
+ return 'e'
115
+
116
+ if Layers[i] == 'fex' and Sign == 'none':
117
+ print(Fore.RED + "ERROR109: at layer type 'fex', pairing with 'none' Threshold is not acceptlable. if you want to 'none' put '==' and make threshold value '0'. from: TrainDPNN ",infoDPNN)
118
+ return 'e'
119
+
120
+ UniqueLabels = set()
121
+ for sublist in Labels:
122
+
123
+ UniqueLabels.add(tuple(sublist))
124
+
125
+
126
+ UniqueLabels = list(UniqueLabels)
127
+
128
+ Labels = [tuple(sublist) for sublist in Labels]
129
+
130
+
131
+ if len(UniqueLabels) != ClassCount:
132
+ print(Fore.RED + "ERROR106: Label variety length must be same Class Count. from: TrainDPNN",infoDPNN)
133
+ return 'e'
134
+
135
+ Inputs[0] = np.array(Inputs[0])
136
+ Inputs[0] = Inputs[0].ravel()
137
+ InputSize = len(Inputs[0])
138
+
139
+ W = WeightIdentification(len(Layers) - 1,ClassCount,Neurons,InputSize)
140
+ Divides = SynapticDividing(ClassCount,W)
141
+ TrainedWs = [1] * len(W)
142
+ print(Fore.GREEN + "Train Started with 0 ERROR" + Style.RESET_ALL,)
143
+ TrainPredictions = [1] * len(Labels)
144
+ true = 0
145
+ Inputs, Labels = AutoBalancer(Inputs, Labels, ClassCount)
146
+ StartTime = time.time()
147
+ for index, inp in enumerate(Inputs):
148
+ UniStartTime = time.time()
149
+ inp = np.array(inp)
150
+ inp = inp.ravel()
151
+
152
+ if InputSize != len(inp):
153
+ print(Fore.RED +"ERROR304: All input matrices or vectors in inputs list, must be same size. from: TrainDPNN",infoDPNN + Style.RESET_ALL)
154
+ return 'e'
155
+
156
+
157
+ for Ulindex, Ul in enumerate(UniqueLabels):
158
+
159
+ if Ul == Labels[index]:
160
+ for Windex, w in enumerate(W):
161
+ for i, ul in enumerate(Ul):
162
+ if ul == 1.0:
163
+ k = i
164
+ Cs = Divides[int(k)][Windex][0]
165
+
166
+ W[Windex] = SynapticPruning(w, Cs, 'row', int(k),ClassCount)
167
+
168
+ NeuralLayer = inp
169
+
170
+ for Lindex, Layer in enumerate(Layers):
171
+
172
+ if Normalizations[Lindex] == 'y':
173
+ NeuralLayer = Normalization(NeuralLayer)
174
+
175
+ if Activations[Lindex] == 'relu':
176
+ NeuralLayer = Relu(NeuralLayer)
177
+ elif Activations[Lindex] == 'sigmoid':
178
+ NeuralLayer = Sigmoid(NeuralLayer)
179
+ elif Activations[Lindex] == 'softmax':
180
+ NeuralLayer = Softmax(NeuralLayer)
181
+
182
+ if Layer == 'fex':
183
+ NeuralLayer,W[Lindex] = Fex(NeuralLayer, W[Lindex], ThresholdSigns[Lindex], ThresholdValues[Lindex])
184
+ elif Layer == 'cat':
185
+ NeuralLayer,W[Lindex] = Cat(NeuralLayer, W[Lindex], ThresholdSigns[Lindex], ThresholdValues[Lindex],1)
186
+
187
+ RealOutput = np.argmax(Labels[index])
188
+ PredictedOutput = np.argmax(NeuralLayer)
189
+ if RealOutput == PredictedOutput:
190
+ true += 1
191
+ Acc = true / len(Labels)
192
+ TrainPredictions[index] = PredictedOutput+1
193
+
194
+ if index == 0:
195
+ for i, w in enumerate(W):
196
+ TrainedWs[i] = w
197
+
198
+ else:
199
+ for i, w in enumerate(W):
200
+ TrainedWs[i] = TrainedWs[i] + w
201
+
202
+
203
+ W = WeightIdentification(len(Layers) - 1,ClassCount,Neurons,InputSize)
204
+
205
+
206
+ UniEndTime = time.time()
207
+
208
+ CalculatingEst = round((UniEndTime - UniStartTime) * (len(Inputs) - index),3)
209
+
210
+ if CalculatingEst < 60:
211
+ print('\rest......(sec):',CalculatingEst,'\n',end= "")
212
+ print('\rTrain Accuracy: ' ,Acc ,"\n", end="")
213
+
214
+ elif CalculatingEst > 60 and CalculatingEst < 3600:
215
+ print('\rest......(min):',CalculatingEst/60,'\n',end= "")
216
+ print('\rTrain Accuracy: ' ,Acc ,"\n", end="")
217
+
218
+ elif CalculatingEst > 3600:
219
+ print('\rest......(h):',CalculatingEst/3600,'\n',end= "")
220
+ print('\rTrain Accuracy: ' ,Acc ,"\n", end="")
221
+
222
+ EndTime = time.time()
223
+
224
+ CalculatingEst = round(EndTime - StartTime,2)
225
+
226
+ print(Fore.GREEN + " \nTrain Finished with 0 ERROR\n")
227
+
228
+ if CalculatingEst < 60:
229
+ print('Total training time(sec): ',CalculatingEst)
230
+
231
+ elif CalculatingEst > 60 and CalculatingEst < 3600:
232
+ print('Total training time(min): ',CalculatingEst/60)
233
+
234
+ elif CalculatingEst > 3600:
235
+ print('Total training time(h): ',CalculatingEst/3600)
236
+
237
+ if Acc > 0.8:
238
+ print(Fore.GREEN + '\nTotal Train Accuracy: ' ,Acc, '\n',Style.RESET_ALL)
239
+
240
+ elif Acc < 0.8 and Acc > 0.6:
241
+ print(Fore.MAGENTA + '\nTotal Train Accuracy: ' ,Acc, '\n',Style.RESET_ALL)
242
+
243
+ elif Acc < 0.6:
244
+ print(Fore.RED+ '\nTotal Train Accuracy: ' ,Acc, '\n',Style.RESET_ALL)
245
+
246
+
247
+
248
+
249
+ return TrainedWs,TrainPredictions
250
+
251
+ # FUNCTIONS -----
252
+
253
+ def WeightIdentification(
254
+ LayerCount, # int: Number of layers in the neural network.
255
+ ClassCount, # int: Number of classes in the classification task.
256
+ Neurons, # list[num]: List of neuron counts for each layer.
257
+ InputSize # int: Size of the input data.
258
+ ) -> str:
259
+ """
260
+ Identifies the weights for a neural network model.
261
+
262
+ Args:
263
+ LayerCount (int): Number of layers in the neural network.
264
+ ClassCount (int): Number of classes in the classification task.
265
+ Neurons (list[num]): List of neuron counts for each layer.
266
+ InputSize (int): Size of the input data.
267
+
268
+ Returns:
269
+ list([numpy_arrays],[...]): Weight matices of the model. .
270
+ """
271
+
272
+
273
+ Wlen = LayerCount + 1
274
+ W = [None] * Wlen
275
+ W[0] = np.ones((Neurons[0],InputSize))
276
+ ws = LayerCount - 1
277
+ for w in range(ws):
278
+ W[w + 1] = np.ones((Neurons[w + 1],Neurons[w]))
279
+ W[LayerCount] = np.ones((ClassCount,Neurons[LayerCount - 1]))
280
+ return W
281
+
282
+ def SynapticPruning(
283
+ w, # list[list[num]]: Weight matrix of the neural network.
284
+ Cs, # list[list[num]]: Synaptic connections between neurons.
285
+ Key, # int: Key for identifying synaptic connections.
286
+ Class, # int: Class label for the current training instance.
287
+ ClassCount # int: Total number of classes in the dataset.
288
+
289
+ ) -> str:
290
+ infoPruning = """
291
+ Performs synaptic pruning in a neural network model.
292
+
293
+ Args:
294
+ w (list[list[num]]): Weight matrix of the neural network.
295
+ Cs (list[list[num]]): Synaptic connections between neurons.
296
+ Key (str): Key for identifying synaptic row or col connections.
297
+ Class (int): Class label for the current training instance.
298
+ ClassCount (int): Total number of classes in the dataset.
299
+
300
+ Returns:
301
+ numpy array: Weight matrix.
302
+ """
303
+
304
+
305
+ Class += 1 # because index start 0
306
+
307
+ if Class != ClassCount and Class != 1:
308
+
309
+ Ce = Cs / Class
310
+
311
+ w[int(Ce)-1::-1,:] = 0
312
+
313
+ w[Cs:,:] = 0
314
+
315
+
316
+ else:
317
+
318
+ if Class == 1:
319
+ if Key == 'row':
320
+
321
+ w[Cs:,:] = 0
322
+
323
+ elif Key == 'col':
324
+
325
+ w[:,Cs] = 0
326
+
327
+ else:
328
+ print(Fore.RED + "ERROR103: SynapticPruning func's Key parameter must be 'row' or 'col' from: SynapticPruning" + infoPruning)
329
+ return 'e'
330
+ else:
331
+ if Key == 'row':
332
+
333
+ w[Cs:,:] = 0
334
+
335
+ Ce = int(round(w.shape[0] - Cs / ClassCount))
336
+ w[Ce-1::-1,:] = 0
337
+
338
+ elif Key == 'col':
339
+
340
+ w[:,Cs] = 0
341
+
342
+ else:
343
+ print(Fore.RED + "ERROR103: SynapticPruning func's Key parameter must be 'row' or 'col' from: SynapticPruning" + infoPruning + Style.RESET_ALL)
344
+ return 'e'
345
+ return w
346
+
347
+ def SynapticDividing(
348
+ ClassCount, # int: Total number of classes in the dataset.
349
+ W # list[list[num]]: Weight matrix of the neural network.
350
+ ) -> str:
351
+ """
352
+ Divides the synaptic weights of a neural network model based on class count.
353
+
354
+ Args:
355
+ ClassCount (int): Total number of classes in the dataset.
356
+ W (list[list[num]]): Weight matrix of the neural network.
357
+
358
+ Returns:
359
+ list: a 3D list holds informations of divided net.
360
+ """
361
+
362
+
363
+ Piece = [1] * len(W)
364
+ #print('Piece:' + Piece)
365
+ #input()
366
+ # Boş bir üç boyutlu liste oluşturma
367
+ Divides = [[[0] for _ in range(len(W))] for _ in range(ClassCount)]
368
+
369
+ for i in range(len(W)):
370
+
371
+
372
+ Piece[i] = int(math.floor(W[i].shape[0] / ClassCount))
373
+
374
+ Cs = 0
375
+ # j = Classes, i = Weights, [0] = CutStart.
376
+
377
+ for i in range(len(W)):
378
+ for j in range(ClassCount):
379
+ Cs = Cs + Piece[i]
380
+ Divides[j][i][0] = Cs
381
+ #print('Divides: ' + j + i + ' = ' + Divides[j][i][0])
382
+ #input()
383
+
384
+ j = 0
385
+ Cs = 0
386
+
387
+ return Divides
388
+
389
+
390
+ def Fex(
391
+ Input, # list[num]: Input data.
392
+ w, # list[list[num]]: Weight matrix of the neural network.
393
+ ThresholdsSign, # str: Sign for threshold comparison ('<', '>', '==', '!=').
394
+ ThresholdValue # num: Threshold value for comparison.
395
+ ) -> tuple:
396
+ """
397
+ Applies feature extraction process to the input data using synaptic pruning.
398
+
399
+ Args:
400
+ Input (list[num]): Input data.
401
+ w (list[list[num]]): Weight matrix of the neural network.
402
+ ThresholdsSign (str): Sign for threshold comparison ('<', '>', '==', '!=').
403
+ ThresholdValue (num): Threshold value for comparison.
404
+
405
+ Returns:
406
+ tuple: A tuple (vector) containing the neural layer result and the updated weight matrix.
407
+ """
408
+
409
+ if ThresholdsSign == '<':
410
+ PruneIndex = np.where(Input < ThresholdValue)
411
+ elif ThresholdsSign == '>':
412
+ PruneIndex = np.where(Input > ThresholdValue)
413
+ elif ThresholdsSign == '==':
414
+ PruneIndex = np.where(Input == ThresholdValue)
415
+ elif ThresholdsSign == '!=':
416
+ PruneIndex = np.where(Input != ThresholdValue)
417
+
418
+ w = SynapticPruning(w, PruneIndex, 'col', 0, 0)
419
+
420
+ NeuralLayer = np.dot(w, Input)
421
+ return NeuralLayer,w
422
+
423
+ def Cat(
424
+ Input, # list[num]: Input data.
425
+ w, # list[list[num]]: Weight matrix of the neural network.
426
+ ThresholdsSign, # str: Sign for threshold comparison ('<', '>', '==', '!=').
427
+ ThresholdValue, # num: Threshold value for comparison.
428
+ isTrain # int: Flag indicating if the function is called during training (1 for training, 0 otherwise).
429
+ ) -> tuple:
430
+ """
431
+ Applies categorization process to the input data using synaptic pruning if specified.
432
+
433
+ Args:
434
+ Input (list[num]): Input data.
435
+ w (list[list[num]]): Weight matrix of the neural network.
436
+ ThresholdsSign (str): Sign for threshold comparison ('<', '>', '==', '!=').
437
+ ThresholdValue (num): Threshold value for comparison.
438
+ isTrain (int): Flag indicating if the function is called during training (1 for training, 0 otherwise).
439
+
440
+ Returns:
441
+ tuple: A tuple containing the neural layer (vector) result and the possibly updated weight matrix.
442
+ """
443
+
444
+ if ThresholdsSign == '<':
445
+ PruneIndex = np.where(Input < ThresholdValue)
446
+ elif ThresholdsSign == '>':
447
+ PruneIndex = np.where(Input > ThresholdValue)
448
+ elif ThresholdsSign == '==':
449
+ PruneIndex = np.where(Input == ThresholdValue)
450
+ elif ThresholdsSign == '!=':
451
+ PruneIndex = np.where(Input != ThresholdValue)
452
+ if isTrain == 1 and ThresholdsSign != 'none':
453
+
454
+ w = SynapticPruning(w, PruneIndex, 'col', 0, 0)
455
+
456
+
457
+ NeuralLayer = np.dot(w, Input)
458
+ return NeuralLayer,w
459
+
460
+
461
+ def Normalization(
462
+ Input # list[num]: Input data to be normalized.
463
+ ):
464
+ """
465
+ Normalizes the input data using maximum absolute scaling.
466
+
467
+ Args:
468
+ Input (list[num]): Input data to be normalized.
469
+
470
+ Returns:
471
+ list[num]: Scaled input data after normalization.
472
+ """
473
+
474
+
475
+ AbsVector = np.abs(Input)
476
+
477
+ MaxAbs = np.max(AbsVector)
478
+
479
+ ScaledInput = Input / MaxAbs
480
+
481
+ return ScaledInput
482
+
483
+
484
+ def Softmax(
485
+ x # list[num]: Input data to be transformed using softmax function.
486
+ ):
487
+ """
488
+ Applies the softmax function to the input data.
489
+
490
+ Args:
491
+ x (list[num]): Input data to be transformed using softmax function.
492
+
493
+ Returns:
494
+ list[num]: Transformed data after applying softmax function.
495
+ """
496
+
497
+
498
+ MaxX = np.max(x)
499
+
500
+ x -= MaxX
501
+
502
+ ExpX = np.exp(x)
503
+
504
+ SumExpX = np.sum(ExpX)
505
+
506
+ SoftmaxX = ExpX / SumExpX
507
+
508
+ return SoftmaxX
509
+
510
+
511
+ def Sigmoid(
512
+ x # list[num]: Input data to be transformed using sigmoid function.
513
+ ):
514
+ """
515
+ Applies the sigmoid function to the input data.
516
+
517
+ Args:
518
+ x (list[num]): Input data to be transformed using sigmoid function.
519
+
520
+ Returns:
521
+ list[num]: Transformed data after applying sigmoid function.
522
+ """
523
+
524
+ PositiveMask = x >= 0
525
+ NegativeMask = ~PositiveMask
526
+
527
+ ExpXPositive = np.exp(-np.clip(x[PositiveMask], -709, None))
528
+ ExpXNegative = np.exp(np.clip(x[NegativeMask], None, 709))
529
+
530
+ SigmoidX = np.zeros_like(x, dtype=float)
531
+ SigmoidX[PositiveMask] = 1 / (1 + ExpXPositive)
532
+ SigmoidX[NegativeMask] = ExpXNegative / (1 + ExpXNegative)
533
+
534
+ return SigmoidX
535
+
536
+
537
+ def Relu(
538
+ x # list[num]: Input data to be transformed using ReLU function.
539
+ ):
540
+ """
541
+ Applies the Rectified Linear Unit (ReLU) function to the input data.
542
+
543
+ Args:
544
+ x (list[num]): Input data to be transformed using ReLU function.
545
+
546
+ Returns:
547
+ list[num]: Transformed data after applying ReLU function.
548
+ """
549
+
550
+
551
+ return np.maximum(0, x)
552
+
553
+
554
+ def TestDPNN(
555
+ TestInputs, # list[list[num]]: Test input data.
556
+ TestLabels, # list[num]: Test labels.
557
+ Layers, # list[str]: List of layer names.
558
+ ThresholdSigns, # list[str]: List of threshold signs for each layer.
559
+ ThresholdValues, # list[num]: List of threshold values for each layer.
560
+ Normalizations, # str: Whether normalization will be performed ("y" or "n").
561
+ Activation, # str: Activation function list for the neural network.
562
+ W # list[list[num]]: Weight matrix of the neural network.
563
+ ) -> tuple:
564
+ infoTestModel = """
565
+ Tests the neural network model with the given test data.
566
+
567
+ Args:
568
+ TestInputs (list[list[num]]): Test input data.
569
+ TestLabels (list[num]): Test labels.
570
+ Layers (list[str]): List of layer names.
571
+ ThresholdSigns (list[str]): List of threshold signs for each layer.
572
+ ThresholdValues (list[num]): List of threshold values for each layer.
573
+ Normalizatios list([str]): Whether normalization will be performed ("yes" or "no").
574
+ Activation (str): Activation function for the neural network.
575
+ W (list[list[num]]): Weight matrix of the neural network.
576
+
577
+ Returns:
578
+ tuple: A tuple containing the predicted labels and the accuracy of the model.
579
+ """
580
+
581
+
582
+ try:
583
+ Wc = [0] * len(W)
584
+ true = 0
585
+ TestPredictions = [1] * len(TestLabels)
586
+ for i, w in enumerate(W):
587
+ Wc[i] = np.copy(w)
588
+ print('\rCopying weights.....',i+1,'/',len(W),end = "")
589
+
590
+ print(Fore.GREEN + "\n\nTest Started with 0 ERROR\n" + Style.RESET_ALL)
591
+ StartTime = time.time()
592
+ for inpIndex,Input in enumerate(TestInputs):
593
+ Input = np.array(Input)
594
+ Input = Input.ravel()
595
+ UniStartTime = time.time()
596
+ NeuralLayer = Input
597
+
598
+ for index, Layer in enumerate(Layers):
599
+ if Normalizations[index] == 'y':
600
+ NeuralLayer = Normalization(NeuralLayer)
601
+ if Activation[index] == 'relu':
602
+ NeuralLayer = Relu(NeuralLayer)
603
+ elif Activation[index] == 'sigmoid':
604
+ NeuralLayer = Sigmoid(NeuralLayer)
605
+ elif Activation[index] == 'softmax':
606
+ NeuralLayer = Softmax(NeuralLayer)
607
+
608
+ if Layers[index] == 'fex':
609
+ NeuralLayer,useless = Fex(NeuralLayer, W[index], ThresholdSigns[index], ThresholdValues[index])
610
+ if Layers[index] == 'cat':
611
+ NeuralLayer,useless = Cat(NeuralLayer, W[index], ThresholdSigns[index], ThresholdValues[index],0)
612
+ for i, w in enumerate(Wc):
613
+ W[i] = np.copy(w)
614
+ RealOutput = np.argmax(TestLabels[inpIndex])
615
+ PredictedOutput = np.argmax(NeuralLayer)
616
+ if RealOutput == PredictedOutput:
617
+ true += 1
618
+ Acc = true / len(TestLabels)
619
+ TestPredictions[inpIndex] = PredictedOutput+1
620
+ UniEndTime = time.time()
621
+
622
+ CalculatingEst = round((UniEndTime - UniStartTime) * (len(TestInputs) - inpIndex),3)
623
+
624
+ if CalculatingEst < 60:
625
+ print('\rest......(sec):',CalculatingEst,'\n',end= "")
626
+ print('\rTest Accuracy: ' ,Acc ,"\n", end="")
627
+
628
+ elif CalculatingEst > 60 and CalculatingEst < 3600:
629
+ print('\rest......(min):',CalculatingEst/60,'\n',end= "")
630
+ print('\rTest Accuracy: ' ,Acc ,"\n", end="")
631
+
632
+ elif CalculatingEst > 3600:
633
+ print('\rest......(h):',CalculatingEst/3600,'\n',end= "")
634
+ print('\rTest Accuracy: ' ,Acc ,"\n", end="")
635
+
636
+ EndTime = time.time()
637
+ for i, w in enumerate(Wc):
638
+ W[i] = np.copy(w)
639
+
640
+ CalculatingEst = round(EndTime - StartTime,2)
641
+
642
+ print(Fore.GREEN + "\nTest Finished with 0 ERROR\n")
643
+
644
+ if CalculatingEst < 60:
645
+ print('Total testing time(sec): ',CalculatingEst)
646
+
647
+ elif CalculatingEst > 60 and CalculatingEst < 3600:
648
+ print('Total testing time(min): ',CalculatingEst/60)
649
+
650
+ elif CalculatingEst > 3600:
651
+ print('Total testing time(h): ',CalculatingEst/3600)
652
+
653
+ if Acc >= 0.8:
654
+ print(Fore.GREEN + '\nTotal Test Accuracy: ' ,Acc, '\n' + Style.RESET_ALL)
655
+
656
+ elif Acc < 0.8 and Acc > 0.6:
657
+ print(Fore.MAGENTA + '\nTotal Test Accuracy: ' ,Acc, '\n' + Style.RESET_ALL)
658
+
659
+ elif Acc <= 0.6:
660
+ print(Fore.RED+ '\nTotal Test Accuracy: ' ,Acc, '\n' + Style.RESET_ALL)
661
+
662
+ except:
663
+
664
+ print(Fore.RED + "ERROR: Testing model parameters like 'Layers' 'ThresholdCounts' must be same as trained model. Check parameters. Are you sure weights are loaded ? from: TestDPNN" + infoTestModel + Style.RESET_ALL)
665
+ return 'e'
666
+
667
+ return TestPredictions,Acc
668
+
669
+ def SaveDPNN(ModelName,
670
+ ModelType,
671
+ Layers,
672
+ ClassCount,
673
+ ThresholdSigns,
674
+ ThresholdValues,
675
+ Normalizations,
676
+ Activations,
677
+ TestAcc,
678
+ LogType,
679
+ WeightsType,
680
+ WeightFormat,
681
+ SavePath,
682
+ W
683
+ ):
684
+
685
+ infoSaveDPNN = """
686
+ Function to save a deep learning model.
687
+
688
+ Arguments:
689
+ ModelName (str): Name of the model.
690
+ ModelType (str): Type of the model.(options: DPNN)
691
+ Layers (list): List containing 'fex' and 'cat' layers.
692
+ ClassCount (int): Number of classes.
693
+ ThresholdSigns (list): List containing threshold signs.
694
+ ThresholdValues (list): List containing threshold values.
695
+ DoNormalization (str): is that normalized data ? 'y' or 'n'.
696
+ Activations (list): List containing activation functions for each layer.
697
+ TestAcc (float): Test accuracy of the model.
698
+ LogType (str): Type of log to save (options: 'csv', 'txt', 'hdf5').
699
+ WeightsType (str): Type of weights to save (options: 'txt', 'npy', 'mat').
700
+ WeightFormat (str): Format of the weights (options: 'd', 'f', 'raw').
701
+ SavePath (str): Path where the model will be saved. For example: C:/Users/beydili/Desktop/denemeDPNN/
702
+ W: Weights of the model.
703
+
704
+ Returns:
705
+ str: Message indicating if the model was saved successfully or encountered an error.
706
+ """
707
+
708
+ # Operations to be performed by the function will be written here
709
+ pass
710
+
711
+ if LogType != 'csv' and LogType != 'txt' and LogType != 'hdf5':
712
+ print(Fore.RED + "ERROR109: Save Log Type (File Extension) must be 'csv' or 'txt' or 'hdf5' from: SaveDPNN" + infoSaveDPNN + Style.RESET_ALL)
713
+ return 'e'
714
+
715
+ if WeightsType != 'txt' and WeightsType != 'npy' and WeightsType != 'mat':
716
+ print(Fore.RED + "ERROR110: Save Weight type (File Extension) Type must be 'txt' or 'npy' or 'mat' from: SaveDPNN" + infoSaveDPNN + Style.RESET_ALL)
717
+ return 'e'
718
+
719
+ if WeightFormat != 'd' and WeightFormat != 'f' and WeightFormat != 'raw':
720
+ print(Fore.RED + "ERROR111: Weight Format Type must be 'd' or 'f' or 'raw' from: SaveDPNN" + infoSaveDPNN + Style.RESET_ALL)
721
+ return 'e'
722
+
723
+ NeuronCount = 0
724
+ SynapseCount = 0
725
+ try:
726
+ for w in W:
727
+ NeuronCount += np.shape(w)[0]
728
+ SynapseCount += np.shape(w)[0] * np.shape(w)[1]
729
+ except:
730
+
731
+ print(Fore.RED + "ERROR: Weight matrices has a problem from: SaveDPNN" + infoSaveDPNN + Style.RESET_ALL)
732
+ return 'e'
733
+ import pandas as pd
734
+ from datetime import datetime
735
+ from scipy import io
736
+
737
+ data = {'MODEL NAME': ModelName,
738
+ 'MODEL TYPE': ModelType,
739
+ 'LAYERS': Layers,
740
+ 'LAYER COUNT': len(Layers),
741
+ 'CLASS COUNT': ClassCount,
742
+ 'THRESHOLD SIGNS': ThresholdSigns,
743
+ 'THRESHOLD VALUES': ThresholdValues,
744
+ 'NORMALIZATION': Normalizations,
745
+ 'ACTIVATIONS': Activations,
746
+ 'NEURON COUNT': NeuronCount,
747
+ 'SYNAPSE COUNT': SynapseCount,
748
+ 'TEST ACCURACY': TestAcc,
749
+ 'SAVE DATE': datetime.now(),
750
+ 'WEIGHTS TYPE': WeightsType,
751
+ 'WEIGHTS FORMAT': WeightFormat,
752
+ 'SAVE PATH': SavePath
753
+ }
754
+ try:
755
+
756
+ df = pd.DataFrame(data)
757
+
758
+ if LogType == 'csv':
759
+
760
+ df.to_csv(SavePath + ModelName + '.csv', sep='\t', index=False)
761
+
762
+ elif LogType == 'txt':
763
+
764
+ df.to_csv(SavePath + ModelName + '.txt', sep='\t', index=False)
765
+
766
+ elif LogType == 'hdf5':
767
+
768
+ df.to_hdf(SavePath + ModelName + '.h5', key='data', mode='w')
769
+
770
+ except:
771
+
772
+ print(Fore.RED + "ERROR: Model log not saved. Check the log parameters from: SaveDPNN" + infoSaveDPNN + Style.RESET_ALL)
773
+ return 'e'
774
+ try:
775
+
776
+ if WeightsType == 'txt' and WeightFormat == 'd':
777
+
778
+ for i, w in enumerate(W):
779
+ np.savetxt(SavePath + ModelName + str(i+1) + 'w.txt' , w, fmt='%d')
780
+
781
+ if WeightsType == 'txt' and WeightFormat == 'f':
782
+
783
+ for i, w in enumerate(W):
784
+ np.savetxt(SavePath + ModelName + str(i+1) + 'w.txt' , w, fmt='%f')
785
+
786
+ if WeightsType == 'txt' and WeightFormat == 'raw':
787
+
788
+ for i, w in enumerate(W):
789
+ np.savetxt(SavePath + ModelName + str(i+1) + 'w.txt' , w)
790
+
791
+
792
+ ###
793
+
794
+
795
+ if WeightsType == 'npy' and WeightFormat == 'd':
796
+
797
+ for i, w in enumerate(W):
798
+ np.save(SavePath + ModelName + str(i+1) + 'w.npy', w.astype(int))
799
+
800
+ if WeightsType == 'npy' and WeightFormat == 'f':
801
+
802
+ for i, w in enumerate(W):
803
+ np.save(SavePath + ModelName + str(i+1) + 'w.npy' , w, w.astype(float))
804
+
805
+ if WeightsType == 'npy' and WeightFormat == 'raw':
806
+
807
+ for i, w in enumerate(W):
808
+ np.save(SavePath + ModelName + str(i+1) + 'w.npy' , w)
809
+
810
+
811
+ ###
812
+
813
+
814
+ if WeightsType == 'mat' and WeightFormat == 'd':
815
+
816
+ for i, w in enumerate(W):
817
+ w = {'w': w.astype(int)}
818
+ io.savemat(SavePath + ModelName + str(i+1) + 'w.mat', w)
819
+
820
+ if WeightsType == 'mat' and WeightFormat == 'f':
821
+
822
+ for i, w in enumerate(W):
823
+ w = {'w': w.astype(float)}
824
+ io.savemat(SavePath + ModelName + str(i+1) + 'w.mat', w)
825
+
826
+ if WeightsType == 'mat' and WeightFormat == 'raw':
827
+
828
+ for i, w in enumerate(W):
829
+ w = {'w': w}
830
+ io.savemat(SavePath + ModelName + str(i+1) + 'w.mat', w)
831
+
832
+ except:
833
+
834
+ print(Fore.RED + "ERROR: Model Weights not saved. Check the Weight parameters. SaveFilePath expl: 'C:/Users/hasancanbeydili/Desktop/denemeDPNN/' from: SaveDPNN" + infoSaveDPNN + Style.RESET_ALL)
835
+ return 'e'
836
+ print(df)
837
+ message = (
838
+ Fore.GREEN + "Model Saved Successfully\n" +
839
+ Fore.MAGENTA + "Don't forget, if you want to load model: model log file and weight files must be in the same directory." +
840
+ Style.RESET_ALL
841
+ )
842
+
843
+ return print(message)
844
+
845
+
846
+ def LoadDPNN(ModelName,
847
+ LoadPath,
848
+ LogType,
849
+ ):
850
+ infoLoadDPNN = """
851
+ Function to load a deep learning model.
852
+
853
+ Arguments:
854
+ ModelName (str): Name of the model.
855
+ LoadPath (str): Path where the model is saved.
856
+ LogType (str): Type of log to load (options: 'csv', 'txt', 'hdf5').
857
+
858
+ Returns:
859
+ lists: W(list[num]), Layers, ThresholdSigns, ThresholdValues, Normalization,Activations
860
+ """
861
+ pass
862
+
863
+
864
+ import pandas as pd
865
+ import scipy.io as sio
866
+
867
+ try:
868
+
869
+ if LogType == 'csv':
870
+ df = pd.read_csv(LoadPath + ModelName + '.' + LogType)
871
+
872
+
873
+ if LogType == 'txt':
874
+ df = pd.read_csv(LoadPath + ModelName + '.' + LogType, delimiter='\t')
875
+
876
+
877
+ if LogType == 'hdf5':
878
+ df = pd.read_hdf(LoadPath + ModelName + '.' + LogType)
879
+ except:
880
+ print(Fore.RED + "ERROR: Model Path error. Accaptable form: 'C:/Users/hasancanbeydili/Desktop/denemeDPNN/' from: LoadDPNN" + infoLoadDPNN + Style.RESET_ALL)
881
+
882
+ ModelName = str(df['MODEL NAME'].iloc[0])
883
+ Layers = df['LAYERS'].tolist()
884
+ LayerCount = int(df['LAYER COUNT'].iloc[0])
885
+ ClassCount = int(df['CLASS COUNT'].iloc[0])
886
+ ThresholdSigns = df['THRESHOLD SIGNS'].tolist()
887
+ ThresholdValues = df['THRESHOLD VALUES'].tolist()
888
+ Normalization = df['NORMALIZATION'].tolist()
889
+ Activations = df['ACTIVATIONS'].tolist()
890
+ NeuronCount = int(df['NEURON COUNT'].iloc[0])
891
+ SynapseCount = int(df['SYNAPSE COUNT'].iloc[0])
892
+ TestAcc = int(df['TEST ACCURACY'].iloc[0])
893
+ ModelType = str(df['MODEL TYPE'].iloc[0])
894
+ WeightType = str(df['WEIGHTS TYPE'].iloc[0])
895
+ WeightFormat = str(df['WEIGHTS FORMAT'].iloc[0])
896
+ SavePath = str(df['SAVE PATH'].iloc[0])
897
+
898
+ W = [0] * LayerCount
899
+
900
+ if WeightType == 'txt':
901
+ for i in range(LayerCount):
902
+ W[i] = np.loadtxt(LoadPath + ModelName + str(i+1) + 'w.txt')
903
+ elif WeightType == 'npy':
904
+ for i in range(LayerCount):
905
+ W[i] = np.load(LoadPath + ModelName + str(i+1) + 'w.npy')
906
+ elif WeightType == 'mat':
907
+ for i in range(LayerCount):
908
+ W[i] = sio.loadmat(LoadPath + ModelName + str(i+1) + 'w.mat')
909
+ else:
910
+ raise ValueError(Fore.RED + "Incorrect weight type value. Value must be 'txt', 'npy' or 'mat' from: LoadDPNN." + infoLoadDPNN + Style.RESET_ALL)
911
+ print(Fore.GREEN + "Model loaded succesfully" + Style.RESET_ALL)
912
+ return W,Layers,ThresholdSigns,ThresholdValues,Normalization,Activations,df
913
+
914
+ def PredictFromDiscDPNN(Input,ModelName,ModelPath,LogType):
915
+ infoPredictFromDİscDPNN = """
916
+ Function to make a prediction using a divided pruning deep learning neural network (DPNN).
917
+
918
+ Arguments:
919
+ Input (list or ndarray): Input data for the model (single vector or single matrix).
920
+ ModelName (str): Name of the model.
921
+ ModelPath (str): Path where the model is saved.
922
+ LogType (str): Type of log to load (options: 'csv', 'txt', 'hdf5').
923
+
924
+ Returns:
925
+ ndarray: Output from the model.
926
+ """
927
+ W,Layers,ThresholdSigns,ThresholdValues,Normalization,Activations = LoadDPNN(ModelName,ModelPath,
928
+ LogType)[0:6]
929
+ Wc = [0] * len(W)
930
+ for i, w in enumerate(W):
931
+ Wc[i] = np.copy(w)
932
+ try:
933
+ NeuralLayer = Input
934
+ NeuralLayer = np.array(NeuralLayer)
935
+ NeuralLayer = NeuralLayer.ravel()
936
+ for index, Layer in enumerate(Layers):
937
+ if Normalization == 'y':
938
+ NeuralLayer = Normalization(NeuralLayer)
939
+ if Activations[index] == 'relu':
940
+ NeuralLayer = Relu(NeuralLayer)
941
+ elif Activations[index] == 'sigmoid':
942
+ NeuralLayer = Sigmoid(NeuralLayer)
943
+ elif Activations[index] == 'softmax':
944
+ NeuralLayer = Softmax(NeuralLayer)
945
+
946
+ if Layers[index] == 'fex':
947
+ NeuralLayer,useless = Fex(NeuralLayer, W[index],
948
+ ThresholdSigns[index],
949
+ ThresholdValues[index])
950
+ if Layers[index] == 'cat':
951
+ NeuralLayer,useless = Cat(NeuralLayer, W[index],
952
+ ThresholdSigns[index],
953
+ ThresholdValues[index],
954
+ 0)
955
+ except:
956
+ print(Fore.RED + "ERROR: The input was probably entered incorrectly. from: PredictFromDiscDPNN" + infoPredictFromDİscDPNN + Style.RESET_ALL)
957
+ return 'e'
958
+ for i, w in enumerate(Wc):
959
+ W[i] = np.copy(w)
960
+ return NeuralLayer
961
+
962
+
963
+ def PredictFromRamDPNN(Input,Layers,ThresholdSigns,ThresholdValues,Normalizations,Activations,W):
964
+ infoPredictFromRamDPNN = """
965
+ Function to make a prediction using a divided pruning learning neural network (DPNN)
966
+ from weights and parameters stored in memory.
967
+
968
+ Arguments:
969
+ Input (list or ndarray): Input data for the model (single vector or single matrix).
970
+ Layers (list): Number and types of layers.
971
+ ThresholdSigns (list): Threshold signs.
972
+ ThresholdValues (list): Threshold values.
973
+ DoNormalization (str): Whether to normalize ('y' or 'n').
974
+ Activations (list): Activation functions for each layer.
975
+ W (list of ndarrays): Weights of the model.
976
+
977
+ Returns:
978
+ ndarray: Output from the model.
979
+ """
980
+
981
+ Wc = [0] * len(W)
982
+ for i, w in enumerate(W):
983
+ Wc[i] = np.copy(w)
984
+ try:
985
+ NeuralLayer = Input
986
+ NeuralLayer = np.array(NeuralLayer)
987
+ NeuralLayer = NeuralLayer.ravel()
988
+ for index, Layer in enumerate(Layers):
989
+ if Normalizations[index] == 'y':
990
+ NeuralLayer = Normalization(NeuralLayer)
991
+ if Activations[index] == 'relu':
992
+ NeuralLayer = Relu(NeuralLayer)
993
+ elif Activations[index] == 'sigmoid':
994
+ NeuralLayer = Sigmoid(NeuralLayer)
995
+ elif Activations[index] == 'softmax':
996
+ NeuralLayer = Softmax(NeuralLayer)
997
+
998
+ if Layers[index] == 'fex':
999
+ NeuralLayer,useless = Fex(NeuralLayer, W[index],
1000
+ ThresholdSigns[index],
1001
+ ThresholdValues[index])
1002
+ if Layers[index] == 'cat':
1003
+ NeuralLayer,useless = Cat(NeuralLayer, W[index],
1004
+ ThresholdSigns[index],
1005
+ ThresholdValues[index],0)
1006
+ except:
1007
+ print(Fore.RED + "ERROR: Unexpected input or wrong model parameters from: PredictFromRamDPNN." + infoPredictFromRamDPNN + Style.RESET_ALL)
1008
+ return 'e'
1009
+ for i, w in enumerate(Wc):
1010
+ W[i] = np.copy(w)
1011
+ return NeuralLayer
1012
+
1013
+
1014
+ def AutoBalancer(TrainInputs, TrainLabels, ClassCount):
1015
+ infoAutoBalancer = """
1016
+ Function to balance the training data across different classes.
1017
+
1018
+ Arguments:
1019
+ TrainInputs (list): Input data for training.
1020
+ TrainLabels (list): Labels corresponding to the input data.
1021
+ ClassCount (int): Number of classes.
1022
+
1023
+ Returns:
1024
+ tuple: A tuple containing balanced input data and labels.
1025
+ """
1026
+ try:
1027
+ ClassIndices = {i: np.where(np.array(TrainLabels)[:, i] == 1)[0] for i in range(ClassCount)}
1028
+ ClassCounts = [len(ClassIndices[i]) for i in range(ClassCount)]
1029
+
1030
+ if len(set(ClassCounts)) == 1:
1031
+ print(Fore.WHITE + "INFO: All training data have already balanced. from: AutoBalancer" + Style.RESET_ALL)
1032
+ time.sleep(1.5)
1033
+ return TrainInputs, TrainLabels
1034
+
1035
+ MinCount = min(ClassCounts)
1036
+
1037
+ BalancedIndices = []
1038
+ for i in range(ClassCount):
1039
+ if len(ClassIndices[i]) > MinCount:
1040
+ SelectedIndices = np.random.choice(ClassIndices[i], MinCount, replace=False)
1041
+ else:
1042
+ SelectedIndices = ClassIndices[i]
1043
+ BalancedIndices.extend(SelectedIndices)
1044
+
1045
+ BalancedInputs = [TrainInputs[idx] for idx in BalancedIndices]
1046
+ BalancedLabels = [TrainLabels[idx] for idx in BalancedIndices]
1047
+
1048
+ print(Fore.GREEN + "All Training Data Succesfully Balanced from: " + str(len(TrainInputs)) + " to: " + str(len(BalancedInputs)) + ". from: AutoBalancer ")
1049
+ time.sleep(1.5)
1050
+ except:
1051
+ print(Fore.RED + "ERROR: Inputs and labels must be same length check parameters" + infoAutoBalancer)
1052
+ return 'e'
1053
+
1054
+ return BalancedInputs, BalancedLabels
@@ -0,0 +1,18 @@
1
+ import pyerualjetwork
2
+ import pyerualjetwork.DPNN
3
+ from pyerualjetwork.DPNN import TrainDPNN
4
+ from pyerualjetwork.DPNN import WeightIdentification
5
+ from pyerualjetwork.DPNN import SynapticPruning
6
+ from pyerualjetwork.DPNN import SynapticDividing
7
+ from pyerualjetwork.DPNN import Fex
8
+ from pyerualjetwork.DPNN import Cat
9
+ from pyerualjetwork.DPNN import Normalization
10
+ from pyerualjetwork.DPNN import Softmax
11
+ from pyerualjetwork.DPNN import Sigmoid
12
+ from pyerualjetwork.DPNN import Relu
13
+ from pyerualjetwork.DPNN import TestDPNN
14
+ from pyerualjetwork.DPNN import SaveDPNN
15
+ from pyerualjetwork.DPNN import LoadDPNN
16
+ from pyerualjetwork.DPNN import PredictFromDiscDPNN
17
+ from pyerualjetwork.DPNN import PredictFromRamDPNN
18
+ from pyerualjetwork.DPNN import AutoBalancer
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pyerualjetwork
3
- Version: 1.0.3
3
+ Version: 1.0.4
4
4
  Summary: Advanced python deep learning library.(More document coming soon..)
5
5
  Author: Hasan Can Beydili
6
6
  Author-email: tchasancan@gmail.com
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pyerualjetwork
3
- Version: 1.0.3
3
+ Version: 1.0.4
4
4
  Summary: Advanced python deep learning library.(More document coming soon..)
5
5
  Author: Hasan Can Beydili
6
6
  Author-email: tchasancan@gmail.com
@@ -1,4 +1,6 @@
1
1
  setup.py
2
+ DPNN/DPNN.py
3
+ DPNN/__init__.py
2
4
  pyerualjetwork.egg-info/PKG-INFO
3
5
  pyerualjetwork.egg-info/SOURCES.txt
4
6
  pyerualjetwork.egg-info/dependency_links.txt
@@ -5,7 +5,7 @@ from setuptools import setup, find_packages
5
5
  setup(
6
6
 
7
7
  name = "pyerualjetwork",
8
- version = "1.0.3",
8
+ version = "1.0.4",
9
9
  author = "Hasan Can Beydili",
10
10
  author_email = "tchasancan@gmail.com",
11
11
  description= "Advanced python deep learning library.(More document coming soon..)",
File without changes