# Deep Learning Lab 2021 - Team 8
[Klick: Zu Teil 3](https://hackmd.io/Rs1zef_hQAKyKPDmWNbdPQ)
## Teil 2: SVM
#### Q6
Get familiar with the structure of the script. It is divided into the following six sections:
(1) Headers
(2) Importing Libraries / Modules etc.
(3) SVM parameters
(4) Definition of functions
(5) Generating/importing (artifically generated) datasets
(6) Training the SVM
Can you explain what happens in each section?
*Im Bereich **Headers:** Alle Infos zum File, Autor und Maintainer
**Imports:** hier werden verschiedene Module importiert
SVM Parameters: Die spezifischen Parameter als boolean, string, int oder float
**Training Parameters:** hier geht es mehr ins Detail. Insbesondere Arrays mit Werten, Trainingsdaten, penalty und Kernel-Funktion. Im Anschluss werden die Arrays für das Testset vorbereitet.
**Function Definitions:** Noch keine Funktionen hier!
**Create/ Import Datasets:** Import der Datensets mit einer Vielzahl an Error-Handling-Schritten. Die Eingaben von den weiter oben gemachten Parametern werden hier nochmal überprüft, bevor sie umgesetzt werden.
**Training of SVM:** Hier geschieht das eigentliche Training und insbesondere die 2D-Darstellung der Trainingsergebnisse (z.B. Entschiedungsgrenze, ...)*
### Gaussian Kernel and the Relaxed Error Case
#### Q8
Proceed with SCRIPT svm_train.py and make yourself familiar with the Gauss and swissroll generator. Test both generators by setting gen_Mode to 'gauss' or 'roll'.
Determine the corresponding cases from figure 2.5 for both datasets. How can you modify the generator’s parameters to get the other two cases?
Gauss + RBF Kernel --> Case 3 (non linear + zero Error) :


Roll+ RBF Kernel --> Case 4 (non linear + Relaxed Error) :


Gauss + Linear Kernel --> Case 1 (linear + zero error )

Roll + Linear Kernel --> Case 2 (linear + Relaxed Error)

#### Q9
Now try to generate a dataset with the Gaussian data generator that is similar to figure 2.6. Don’t forget to set the generator of the test set to the same parameters. How do you generate the data?
Tip: Use multiple clusters per class.
"Schwerpunkte" der Datenpunkte:
means_test = np.array([[-2.5,
2.5],
[2.5,
2.5],
[2.5,
-2.5],
[-2.5,
-2.5],
[2.5,
0],
[-2.5,
0],
[0,
-2.5],
[0,
2.5]
])
"Streuung" um jew. "Schwerpunkte":
covs_test = np.array([[[0.5,0],
[0,0.5]],
[[0.5,0],
[0,0.5]],
[[0.5,0],
[0,0.5]],
[[0.5,0],
[0,0.5]],
[[1,0],
[0,0.1]],
[[1, 0],
[0, 0.1]],
[[0.1, 0],
[0, 1]],
[[0.1, 0],
[0, 1]]
])
labels_test = np.array([0,0,0,0,1,1,1,1])

#### Q10
Use the data set you generated and train a recognizer model for it. Vary the parameters penalty and kernel_coeff. Pay attention to generalization/specialization in the training result. Choose the one you think is the best and save this parameterization. What is the influence of a lower or higher penalty?
Gewählte Parameter: Penalty: 15 kernel_coeff: "scale"
Der Parameter "penalty" steuert, wie stark Fehlklassifzierungen im Training gewichtet werden, sprich ein hoher Wert führt zu einer höheren Accuracy im Training allerdings wird die SVM vermutlich dann nicht so gut auf ungesehenen Daten generalisieren, weil sie zu sehr auf die Trainingsdaten zugeschnitten ist.
Anzahl Support-Vektoren ausgeben lassen:
```
print("Anzahl Support-Vektoren je Klasse:",clf.n_support_)
```

penalty 15.0, kernel_function rbf, kernel_coeff scale --> SVen[39 43]

penalty 1.0, kernel_function rbf, kernel_coeff auto --> SVen[57 53]:

penalty 15.0, kernel_function rbf, kernel_coeff auto --> SVen[33 29]:

#### Q11
When could it be useful to choose a generalizing/specializing training result as the best result (practice)?
Wenn man ein große Anzahl Trainingsdaten hat und davon ausgehen kann, dass dieses Trainingsmaterial die Realität im vollen Umfang abbildet macht es Sinn, die SVM ziemlich genau auf dieses Material zu tranieren, sprich Fehler zu hoch zu gewichten.
Hat man hingegen weniger Trainingsmaterial, dass die Realität nicht um vollen Umfang abbilden kann, sollten man eher Fehlklassifikationen im Training zulassen, damit die SVM auf ungesehenen Daten besser generalisiert.
#### Q13
Train models that use a polynomial or sigmoid kernel. Set:
kernel_function=poly or kernel_function=sigmoid
Also, use data that you have previously tried to classify using a different kernel and compare the results.
How does the classification result change?
Gauss Poly:

Gauss Sigmoid:

Roll Poly:

Roll Sigmoid:

Clusters Poly:

Clusters RBF:

Clusters Sigmoid:

#### Q14
What influence does the parameter zero-coeff have on the formation of the decision boundary when choosing a sigmoidal kernel (kernel_function=sigmoid)?
Erinnerung: zero_coeff ist der unabhängige Term in der Kern-Funktion, Parameter $r$:
$$k(x,x')=(\gamma x^Tx'+r)^p$$
Man bekommt eine geradere Entscheidungsgrenze, da die Terme mit niedriger Potenz hierdurch höher gewichtet werden.
Und für positive $r$ bzw. zero_coeff eine Verschiebung in den Bereich der weißen Klasse (Class 1) (Stichwort "Bias" hier angebracht?)
Zero_coeff = 0

Zero_coeff = 1

Zero_coeff = 10

#### Q16
Try different values for the parameters in table 2.1. What do you observe for the training result?
Keine Änderungen:

Resultion: 150

Fast mode: False, deutlich höhere Rechendauer

Color: False

Mit Fast mode: False UND Resolution: 200 sehr lange Rechendauer. Insbesondere daher, weil (bei mir) nur ein Prozessorkern zum Training verwendet wird.
#### Q17
Why can it be difficult to classify high-dimensional data (d > 3)?
Sind die Daten nicht linear separierbar, müssen sie in einen höherdimensionalen Raum transformiert werden. Dies ist mit hohem Rechenaufwand verbunden. Die Theorie sagt aber, dass für beliebig hohe Dimensionen die Daten irgendwann separierbar werden.
Das Hauptproblem liegt in der Interpretierbarkeit der Daten (und Enscheidungsgrenzen) für den Menschen. Höher als 3 Dimensionen können wir weder darstellen noch uns vorstellen. Somit ist die Bewertbarkeit durch den Menschen für Dimensionen größer 3 nicht mehr gegeben.
### Extension: Multiclass Problems
#### Q19
Select the Gauss data generator and create a data set with multiple classes. To generate these, select different values for `labels_train`
The assignment of the parameters to the labels is shown in the figure 2.9. In this task it is entirely up to you how you choose the parameterization. What parameterization do you choose? What kind of result do you observe?
Dies hier sind die Ergebnisse der Preset-Einstellungen:
Daten aus drei Klassen 0,1,2:

Ergebnis nach dem Training:

Zwei Klassen mit `labels_train = np.array([0,1,1])`:

Zwei Klassen mit `labels_train = np.array([0,1,0])`:

Drei Klassen, means-Vektor mit 4ern gefüllt:

Vier Klassen, sonst preset-Einstellungen:


Erzeugung:
```
amount_samples_train = np.array([100,100,100,100]) # Amount samples for training (Generator)
means_train = np.array([[-2,
2,],
[2,
2,],
[2,
-2],
[-2,
-2]]) # Array, consists out of mean vectors with same dimension, e.g. [[2,4,3],[2,4,2]] for two 3-dimensionals
# Array, consists out of corresponding covariance matrices, e.g. [[[1,0,-2],[2,1,0],[3,2,1]],[[1,0,-2],[2,1,0],[3,2,1]]]
# for two 3-dimensionals
covs_train = np.array([[[1,0],
[0,1]],
[[1,0],
[0,1]],
[[1,0],
[0,1]],
[[1,0],
[0,1]]])
# Array, consists out of labels for data clusters, e.g. [0,1] for two clusters with labels for class 0 and 1
# If labels shall be generated automatically, just let array empty! -> np.array([])
labels_train = np.array([0,1,2,3])
```
### Part 2.2: Training of SVMs on handwritten numbers (MNIST)
#### Q21
Use the Default parameterization and start the script for a training of an SVM and a neural network. Adjust
`P training_method = 'svm' or training_method = 'nnet'`
to change the underlying recognition method. What do you notice regarding the recognition rates between SVM and NNET?
SVM:
Result svm-Training - Accuracy on training data = 100%
Result svm-Training - Accuracy on test data = 77.4569%
NNET:
Result nnet-Training - Accuracy on training data = 100%
Result nnet-Training - Accuracy on test data = 88.3485%
Im vorliegenden Fall ist das NNET höherperformant. Auf den (im Training ungesehenen) Testdaten hat es eine um elf Prozentpunkte höhere Accuracy.
#### Q22
Why can it be difficult to distinguish these numbers cleanly and classify them correctly?

Werden die Bilder dieser Ziffern in ihrer Matrixform notiert, so zeigt sich, dass die Einträge an vielen Stellen der Matrizen oftmals gleich sind.
#### Q23
##### a)
Vary the selection of digits by setting `selected_classes` to two other digits.
Wahl: `selected_classes = [1, 6]`
SVM:
Result svm-Training - Accuracy on training data = 100%
Result svm-Training - Accuracy on test data = 95.8631%
NNET:
Result nnet-Training - Accuracy on training data = 100%
Result nnet-Training - Accuracy on test data = 98.9275%
Auch hier performt das Neuronale Netz besser auf den ungesehenen Testdaten! Aufgrund der besseren Unterscheidbarkeit der Ziffern sind beide Accuracy-Werte aber sehr hoch und unterscheiden sich nur um drei Prozentpunkte
##### b)
Then expand `getSubset()` to allow more than two digits. Test your implementation with (1/2/3/4). How does the recognition rate correspond with the selection of similar digits (e.g. 0/8/9), as with
dissimilar ones?
Code-Snippet:
```
def getSubset(X, Y, classes):
X_N = np.concatenate((X[Y==classes[0], :], X[Y==classes[1], :], X[Y==classes[2], :], X[Y==classes[3], :]))
Y_N = np.concatenate((Y[Y==classes[0]], Y[Y==classes[1]], Y[Y==classes[2]], Y[Y==classes[3]]))
X_N, Y_N = shuffleSet(X_N, Y_N)
return X_N, Y_N
```
Wahl: `selected_classes = [1, 2, 3, 4]`
SVM:
esult svm-Training - Accuracy on training data = 100%
Result svm-Training - Accuracy on test data = 85.8865%
NNET:
Result nnet-Training - Accuracy on training data = 100%
Result nnet-Training - Accuracy on test data = 86.5645%
Bei sehr unterschiedlichen Zahlen performt das Netz leicht besser.
Wahl: `selected_classes = [0, 3, 8, 9]`
SVM:
Result svm-Training - Accuracy on training data = 100%
Result svm-Training - Accuracy on test data = 84.5726%
NNET:
Result nnet-Training - Accuracy on training data = 100%
Result nnet-Training - Accuracy on test data = 82.9034%
Bei ähnlichen Zahlen ist die SVM performanter als das Netz!
#### Q24
Vary the size of the reduced data set for both SVM and NNET training. Also measure the time with the `timeit` package. Set
`selected_classes = [3, 8]`
`data_reduction = 1`
and then change the value of
`train_samples_per_class`
Start with 5 samples per class and increase in slow steps (e.g.: 10, 50, 100, 500, 1000, 5000). How does the recognition rate behave in the training/test of the two procedures (SVM/NNET)?
Code-Snippet for time measurement:
```
starttime = timeit.default_timer()
...(Training SVM)...
print("The Training time for the SVM was:", timeit.default_timer() - starttime)
```
Wahl: `train_samples_per_class = 5 `
SVM:
Result svm-Training - Accuracy on training data = 100%
Result svm-Training - Accuracy on test data = 74.772%
Time: 0.02929
NNET:
Result nnet-Training - Accuracy on training data = 100%
Result nnet-Training - Accuracy on test data = 86.4235%
Time: 0.6112
Wahl: `train_samples_per_class = 10`
SVM:
Result svm-Training - Accuracy on training data = 100%
Result svm-Training - Accuracy on test data = 90.4762%
Time: 0.03289
NNET:
Result nnet-Training - Accuracy on training data = 100%
Result nnet-Training - Accuracy on test data = 84.2958%
Time: 0.71288
Wahl: `train_samples_per_class = 100`
SVM:
Result svm-Training - Accuracy on training data = 100%
Result svm-Training - Accuracy on test data = 92.1479%
Time: 0.09980
NNET:
Result nnet-Training - Accuracy on training data = 97%
Result nnet-Training - Accuracy on test data = 94.2249%
Time: 1.3911
Wahl: `train_samples_per_class = 1000`
SVM:
Result svm-Training - Accuracy on training data = 99.7%
Result svm-Training - Accuracy on test data = 94.3262%
Time: 10.15212
NNET:
Result nnet-Training - Accuracy on training data = 98.3%
Result nnet-Training - Accuracy on test data = 96.6565%
Time: 12.1353
Fazit: Es kann festgehalten werden, dass die Trainingszeiten der SVM i.A. kürzer, z.T. signifikant kürzer sind. Die Überlegenheit (bei der Accuracy) der SVM dem NNET gegenüber konnten wir nur bei 10 Samples pro Klasse feststellen.
In unseren Versuchen hätten wir korrekterweise mehrere hundert Durchläufe zur sicheren Bestimmung der Trainingszeit durchführen müssen (und hiervon den Minimalwert gewählt). Allerdings hat dies die Zeit nicht hergegeben.
[Klick: Zu Teil 3](https://hackmd.io/Rs1zef_hQAKyKPDmWNbdPQ)