Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"id": "194EMZeTSLIk"
},
"source": [
"#0. Imports und Helper"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "6IoTrfAlzktH",
"outputId": "f9bdc25e-4895-436b-91ab-00d3a38af883"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Defaulting to user installation because normal site-packages is not writeable\n",
"Requirement already satisfied: torchinfo in /home/niko/.local/lib/python3.10/site-packages (1.8.0)\n",
"Defaulting to user installation because normal site-packages is not writeable\n",
"Requirement already satisfied: tqdm in /home/niko/.local/lib/python3.10/site-packages (4.66.1)\n"
]
}
],
"source": [
"!pip install torchinfo\n",
"!pip install matplotlib --quiet\n",
"!pip install tqdm"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"id": "dPt0DPgfLjEQ"
},
"outputs": [],
"source": [
"# Imports\n",
"import copy\n",
"\n",
"import ipywidgets as widgets\n",
"import matplotlib.pyplot as plt\n",
"import numpy as np\n",
"\n",
"import time\n",
"import torch\n",
"import torchvision\n",
"#import torchvision.datasets as datasets\n",
"import torch.nn.functional as F\n",
"import torch.nn as nn\n",
"import torch.optim as optim\n",
"import tqdm\n",
"\n",
"import random\n",
"import keras.datasets.imdb\n",
"\n",
"from torch.autograd import Variable\n",
"from tqdm.auto import tqdm as tqdmauto\n",
"import timeit"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "U6niQp1RNHxp",
"outputId": "f07ba931-b6c5-4157-df21-91a429ff70a1"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Random seed 2021 has been set.\n"
]
}
],
"source": [
"def set_seed(seed=None, seed_torch=True):\n",
" \"\"\"\n",
" Handles variability by controlling sources of randomness\n",
" through set seed values\n",
"\n",
" Args:\n",
" seed: Integer\n",
" Set the seed value to given integer.\n",
" If no seed, set seed value to random integer in the range 2^32\n",
" seed_torch: Bool\n",
" Seeds the random number generator for all devices to\n",
" offer some guarantees on reproducibility\n",
"\n",
" Returns:\n",
" Nothing\n",
" \"\"\"\n",
" if seed is None:\n",
" seed = np.random.choice(2 ** 32)\n",
" random.seed(seed)\n",
" np.random.seed(seed)\n",
" if seed_torch:\n",
" torch.manual_seed(seed)\n",
" torch.cuda.manual_seed_all(seed)\n",
" torch.cuda.manual_seed(seed)\n",
" torch.backends.cudnn.benchmark = False\n",
" torch.backends.cudnn.deterministic = True\n",
" print(f'Random seed {seed} has been set.')\n",
"SEED = 2021\n",
"set_seed(seed=SEED)\n",
"DEVICE = \"cuda\"\n",
"\n",
"def zero_grad(params):\n",
" \"\"\"\n",
" Clear gradients as they accumulate on successive backward calls\n",
"\n",
" Args:\n",
" params: an iterator over tensors\n",
" i.e., updating the Weights and biases\n",
"\n",
" Returns:\n",
" Nothing\n",
" \"\"\"\n",
" for par in params:\n",
" if not(par.grad is None):\n",
" par.grad.data.zero_()\n",
"\n",
"\n",
"def print_params(model):\n",
" \"\"\"\n",
" Lists the name and current value of the model's\n",
" named parameters\n",
"\n",
" Args:\n",
" model: an nn.Module inherited model\n",
" Represents the ML/DL model\n",
"\n",
" Returns:\n",
" Nothing\n",
" \"\"\"\n",
" for name, param in model.named_parameters():\n",
" if param.requires_grad:\n",
" print(name, param.data)\n",
"\n",
"def sample_minibatch(input_data, target_data, num_points=100):\n",
" \"\"\"\n",
" Sample a minibatch of size num_point from the provided input-target data\n",
"\n",
" Args:\n",
" input_data: Tensor\n",
" Multi-dimensional tensor containing the input data\n",
" target_data: Tensor\n",
" 1D tensor containing the class labels\n",
" num_points: Integer\n",
" Number of elements to be included in minibatch with default=100\n",
"\n",
" Returns:\n",
" batch_inputs: Tensor\n",
" Minibatch inputs\n",
" batch_targets: Tensor\n",
" Minibatch targets\n",
" \"\"\"\n",
" # Sample a collection of IID indices from the existing data\n",
" batch_indices = np.random.choice(len(input_data), num_points)\n",
" # Use batch_indices to extract entries from the input and target data tensors\n",
" batch_inputs = input_data[batch_indices, :]\n",
" batch_targets = target_data[batch_indices]\n",
"\n",
" return batch_inputs, batch_targets\n",
"\n",
"\n",
"def gradient_update(loss, params, lr=1e-3):\n",
" \"\"\"\n",
" Perform a gradient descent update on a given loss over a collection of parameters\n",
"\n",
" Args:\n",
" loss: Tensor\n",
" A scalar tensor containing the loss through which the gradient will be computed\n",
" params: List of iterables\n",
" Collection of parameters with respect to which we compute gradients\n",
" lr: Float\n",
" Scalar specifying the learning rate or step-size for the update\n",
"\n",
" Returns:\n",
" Nothing\n",
" \"\"\"\n",
" # Clear up gradients as Pytorch automatically accumulates gradients from\n",
" # successive backward calls\n",
" zero_grad(params)\n",
"\n",
" # Compute gradients on given objective\n",
" loss.backward()\n",
"\n",
" with torch.no_grad():\n",
" for par in params:\n",
" # Here we work with the 'data' attribute of the parameter rather than the\n",
" # parameter itself.\n",
" # Hence - use the learning rate and the parameter's .grad.data attribute to perform an update\n",
" par.data -= lr * par.grad.data"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "tNDNF10dyqUm",
"outputId": "f654597c-411a-45ac-f694-aba79e025aa8"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" this film was just brilliant casting location scenery story direction everyone's really suited the part they played and you could just imagine being there robert is an amazing actor and now the same being director father came from the same scottish island as myself so i loved the fact there was a real connection with this film the witty remarks throughout the film were great it was just brilliant so much that i bought the film as soon as it was released for and would recommend it to everyone to watch and the fly fishing was amazing really cried at the end it was so sad and you know what they say if you cry at a film it must have been good and this definitely was also to the two little boy's that played the of norman and paul they were just brilliant children are often left out of the list i think because the stars that play them all grown up are such a big profile for the whole film but these children are amazing and should be praised for what they have done don't you think the whole story was so lovely because it was true and was someone's life after all that was shared with us all \n",
"17121\n",
"17588\n",
"x_train shape: torch.Size([17121, 10000])\n",
"y_train shape: torch.Size([17121])\n",
"17121 train samples\n",
"17588 test samples\n"
]
}
],
"source": [
"(x_train, y_train), (x_test, y_test) = keras.datasets.imdb.load_data(num_words=10000, maxlen=250,)\n",
"\n",
"# print the first comment\n",
"word_indizes_orig = keras.datasets.imdb.get_word_index(path=\"imdb_word_index.json\")\n",
"word_indizes = {v: k for k, v in word_indizes_orig.items()}\n",
"for i in x_train[0]:\n",
" print(f\"{word_indizes.get(i-3, '')}\", end=\" \")\n",
"print()\n",
"\n",
"def vectorize_sequences(sequences, dimension=10000):\n",
" # all zero matrix of shape (len(sequences), dimension)\n",
" result = np.zeros((len(sequences), dimension))\n",
" for i,sequence in enumerate(sequences):\n",
" result[i, sequence] = 1\n",
" return result\n",
"\n",
"print(len(x_train))\n",
"print(len(x_test))\n",
"\n",
"x_train = vectorize_sequences(x_train)\n",
"x_test = vectorize_sequences(x_test)\n",
"#x_train = np.expand_dims(x_train, -1)\n",
"#x_test = np.expand_dims(x_test, -1)\n",
"\n",
"x_train = Variable(torch.from_numpy(x_train)).float().to(DEVICE)\n",
"y_train = Variable(torch.from_numpy(y_train)).long().to(DEVICE)\n",
"x_test = Variable(torch.from_numpy(x_test)).float().to(DEVICE)\n",
"y_test = Variable(torch.from_numpy(y_test)).long().to(DEVICE)\n",
"\n",
"print(\"x_train shape:\", x_train.shape)\n",
"print(\"y_train shape:\", y_train.shape)\n",
"print(x_train.shape[0], \"train samples\")\n",
"print(x_test.shape[0], \"test samples\")"
]
},
{
"cell_type": "code",
"execution_count": 66,
"metadata": {},
"outputs": [],
"source": [
"# Why so many data? I thought the imdb dataset consists only of 25000 reviews?"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "tKJZz5YsSSyT"
},
"source": [
"# 1. Softmax Implementieren\n",
"Implementieren Sie die Softmax Funktion mit Numpy und stellen Sie zunächst sicher, dass diese die selben Ergebnisse liefert wie die Pytorch-Funktion im Beispiel. Vergleichen Sie dann Ihre Implementierungen mit anderen Gruppen und diskutieren Sie auch über Performance und numerische Stabilität. Erstellen Sie ein kleines Benchmark, um Performance und numerische Stabilität zu testen."
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"id": "_80I03V8ogds"
},
"outputs": [],
"source": [
"def softmax(vector):\n",
" exp_vec = np.exp(vector)\n",
" vec_sum = exp_vec.sum()\n",
" return exp_vec / vec_sum\n",
" \n",
"def softmax_save(vector):\n",
" norm_vec = vector - torch.max(vector)\n",
" exp_vec = np.exp(norm_vec)\n",
" vec_sum = exp_vec.sum()\n",
" return exp_vec / vec_sum"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [],
"source": [
"# test softmax\n",
"m = nn.Softmax(dim=1)\n",
"tolerance = 1e-6\n",
"for i in range(1000):\n",
" input = torch.randn(1, 3)\n",
" soft1 = softmax(input)\n",
" soft2 = m(input)\n",
" soft3 = softmax_save(input)\n",
" if not np.allclose(soft1, soft2, tolerance) or not np.allclose(soft2, soft3, tolerance):\n",
" raise Exception(f\"Error with Tensor: {input}\")"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {
"id": "x0VacAxQu5JS"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"tensor([ 3.4028e+38, -3.4028e+38])\n",
"tensor([1., 0.])\n",
"Avg time torch: 0.00021779541100002574 vs own save implementation: 0.0004932853010000429 vs unsafe: 0.00040290728599981664\n"
]
}
],
"source": [
"# Numerical Stability\n",
"info = torch.finfo(torch.float32)\n",
"max_min_test = torch.tensor([info.max, info.min])\n",
"print(max_min_test)\n",
"print(softmax_save(max_min_test))\n",
"\n",
"# test performance\n",
"counter = 1000\n",
"times_torch = np.zeros(counter)\n",
"times_own_safe = np.zeros(counter)\n",
"times_own_unsafe = np.zeros(counter)\n",
"m = nn.Softmax(dim=1)\n",
"for i in range(counter):\n",
" input = torch.randn(1, 200000)\n",
" time_torch = timeit.timeit(lambda: m(input), number=1)\n",
" time_own_safe = timeit.timeit(lambda: softmax_save(input), number=1)\n",
" time_own = timeit.timeit(lambda: softmax(input), number=1)\n",
" times_torch[i] = time_torch\n",
" times_own_safe[i] = time_own_safe\n",
" times_own_unsafe[i] = time_own\n",
"print(f\"Avg time torch: {times_torch.mean()} vs own save implementation: {times_own_safe.mean()} vs unsafe: {times_own_unsafe.mean()}\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "c0u-OqU8U-sL"
},
"source": [
"# 2. Regularisierung Implementieren\n",
"\n",
"Unten finden Sie einen Pytorch-SGD Schritt mit eingebauter L2-Regularisierung und ohne. Interpretieren Sie die unterschiedlichen Ausgaben. Modifizieren Sie den ersten Codabschnitt mit einer eigenen L2-Regularisierung so, dass identische Ergebnisse erzeugt werden. Sie können dazu die noch nicht verwendete und noch falsch definierte Variable \"regtermwrong\" umdefinieren und zu einem späteren Zeitpunkt im Code darauf zurückgreifen. ACHTUNG: weight_decay*2=lambda."
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {
"id": "O0Hn585ETRWD"
},
"outputs": [],
"source": [
"#Datendefinition\n",
"np.random.seed(123)\n",
"np.set_printoptions(8, suppress=True)\n",
"\n",
"x_numpy = np.random.random((3, 4)).astype(np.double)\n",
"w_numpy = np.random.random((4, 5)).astype(np.double)\n",
"w_numpy[0,0] =9.9\n",
"x_torch = torch.tensor(x_numpy, requires_grad=True)\n"
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {
"id": "S5XEpjWFTTzi"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Original weights tensor([[9.9000, 0.0597, 0.3980, 0.7380, 0.1825],\n",
" [0.1755, 0.5316, 0.5318, 0.6344, 0.8494],\n",
" [0.7245, 0.6110, 0.7224, 0.3230, 0.3618],\n",
" [0.2283, 0.2937, 0.6310, 0.0921, 0.4337]], dtype=torch.float64,\n",
" requires_grad=True)\n",
"0 weight decay tensor([[ 7.7303, -0.1419, 0.1287, 0.4007, -0.0437],\n",
" [ 0.0302, 0.3151, 0.3153, 0.3974, 0.5694],\n",
" [ 0.4245, 0.3337, 0.4229, 0.1033, 0.1344],\n",
" [-0.0139, 0.0385, 0.3083, -0.1228, 0.1504]], dtype=torch.float64,\n",
" requires_grad=True)\n"
]
}
],
"source": [
"# ohne Regularisierung\n",
"w_torch = torch.tensor(w_numpy, requires_grad=True)\n",
"print('Original weights', w_torch)\n",
"\n",
"lr = 0.1\n",
"sgd = torch.optim.SGD([w_torch], lr=lr, weight_decay=0)\n",
"omega = w_torch.square().sum()\n",
"y_torch = torch.matmul(x_torch, w_torch)\n",
"loss = y_torch.sum() + 1 * omega #\n",
"\n",
"\n",
"sgd.zero_grad()\n",
"loss.backward()\n",
"sgd.step()\n",
"\n",
"w_grad = w_torch.grad.data.numpy()\n",
"print('0 weight decay', w_torch)\n"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {
"id": "WiQW-Y4VkH7v"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Reset Original weights tensor([[9.9000, 0.0597, 0.3980, 0.7380, 0.1825],\n",
" [0.1755, 0.5316, 0.5318, 0.6344, 0.8494],\n",
" [0.7245, 0.6110, 0.7224, 0.3230, 0.3618],\n",
" [0.2283, 0.2937, 0.6310, 0.0921, 0.4337]], dtype=torch.float64,\n",
" requires_grad=True)\n",
"1 weight decay tensor([[ 7.7303, -0.1419, 0.1287, 0.4007, -0.0437],\n",
" [ 0.0302, 0.3151, 0.3153, 0.3974, 0.5694],\n",
" [ 0.4245, 0.3337, 0.4229, 0.1033, 0.1344],\n",
" [-0.0139, 0.0385, 0.3083, -0.1228, 0.1504]], dtype=torch.float64,\n",
" requires_grad=True)\n"
]
}
],
"source": [
"#mit Regularisierung\n",
"\n",
"\n",
"w_torch = torch.tensor(w_numpy, requires_grad=True)\n",
"\n",
"print('Reset Original weights', w_torch)\n",
"\n",
"sgd = torch.optim.SGD([w_torch], lr=lr, weight_decay=2)\n",
"\n",
"y_torch = torch.matmul(x_torch, w_torch)\n",
"loss = y_torch.sum()\n",
"\n",
"sgd.zero_grad()\n",
"loss.backward()\n",
"sgd.step()\n",
"\n",
"w_grad = w_torch.grad.data.numpy()\n",
"print('1 weight decay', w_torch)"
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {},
"outputs": [],
"source": [
"# FRAGE:\n",
"# Wieso ist der weight_decay hier doppelt? also warum etspricht alpha * 2 = lambda?"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "sQk-ciLBYGnu"
},
"source": [
"# 3. Einfaches MLP in Pytorch\n",
"Machen Sie sich ein wenig mit dem IMDB Datensatz und den für Sie erstellten Datenstrukturen in x/y_train/test vertraut."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "mLeOKvUxMunF"
},
"source": [
"## 3.1 Modell erstellen und Angaben zur Modellgröße verstehen\n",
"Definieren Sie ein Pytorch Multilayer Perzeptron mit der Größe des IMDB-Dictionaries für one-hot-encodierte Wörte als Eingabe (Sigmoid Aktivierung), 50 Neuronen im Hidden Layer und 2 Ausgabeneuronen. Layer 1 und 2 Ihres Netzes verwendet die Sigmoid-Aktivierungsfunktion, Layer 3 die Softmax-Aktivierungsfunktion.\n",
"\n",
"Generieren Sie Modell-Summary mit torchinfo und erklären Sie, was die ausgegebenen Werte bedeuten und wie diese zustande kommen."
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {
"id": "TikQht7LmNnc"
},
"outputs": [],
"source": [
"#Ihr Code hier\n",
"class Model(nn.Module):\n",
" def __init__(self):\n",
" super().__init__()\n",
" self.layers = nn.Sequential(\n",
" nn.Linear(10000, 50),\n",
" nn.Sigmoid(),\n",
" nn.Linear(50,50),\n",
" nn.Sigmoid(),\n",
" nn.Linear(50,2),\n",
" nn.Softmax()\n",
" )\n",
" def forward(self, x):\n",
" return self.layers(x)\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "GUoAJo8WMzfb"
},
"source": [
"## 3.2 Modell trainieren und Performancekurven interpretieren\n",
"Nutzen Sie den untenstehenedn Code um Ihr Modell zu trainieren. Interpretieren und diskutieren Sie die entstehenden Performancekurven. Falls Sie einen unerwarteten Anstieg Ihres Losses beobachten, recherchieren Sie wie Sie diese mit dem Einbau einer einzelnen Verbesserung innerhalb des gegebenen SGD Lernverfahrens beheben können. ACHTUNG: Wenn Sie Ihr Modell nicht oben neu initialisieren, optimieren Sie weiter auf den schon veränderten Parametern."
]
},
{
"cell_type": "code",
"execution_count": 45,
"metadata": {
"id": "JD2AkGHGrpGV"
},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"100%|█████████████████████████████████████████████████████████████████████████████████| 290/290 [00:06<00:00, 44.49it/s]\n"
]
},
{
"data": {
"image/png": "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ThMnTlT79u0VHByshx56SMePH/dgxfAGn3/+uR544AFFR0fLz89Pn3zyicu4MUZz5sxRVFSUgoKClJ6ersOHD7vMOXHihDIzM2W32xUSEqInn3xSp0+fduNewBtcL0uPP/74VWvUkCFDXOaQpeYtOztbd9xxh9q0aaMOHTpoxIgRKikpcZnTmGNZeXm5hg0bptatW6tDhw6aNm2aLl265M5dgYc1Jkv33HPPVWvSU0895TKHLDVvS5cuVVJSkux2u+x2uxwOhz799FNr3J3rEU29j/rggw80ZcoUzZ07V19//bWSk5M1ePBgVVZWero0eLFbb71Vx44ds25ffPGFNTZ58mStX79ea9asUV5enn755ReNHDnSg9XCG5w5c0bJycl68803GxxftGiRlixZomXLlmn37t266aabNHjwYJ07d86ak5mZqeLiYm3ZskUbNmzQ559/rgkTJrhrF+AlrpclSRoyZIjLGrVy5UqXcbLUvOXl5WnixInatWuXtmzZoosXL2rQoEE6c+aMNed6x7L6+noNGzZMFy5c0Jdffqn33ntPOTk5mjNnjid2CR7SmCxJ0vjx413WpEWLFlljZAkxMTFauHChCgsLVVBQoHvvvVfDhw9XcXGxJDevRwY+qW/fvmbixInW3/X19SY6OtpkZ2d7sCp4s7lz55rk5OQGx6qrq03Lli3NmjVrrMcOHTpkJJn8/Hw3VQhvJ8msXbvW+tvpdJrIyEjz8ssvW49VV1cbm81mVq5caYwx5uDBg0aS2bNnjzXn008/NX5+fubnn392W+3wLldmyRhjsrKyzPDhw//yOWQJV6qsrDSSTF5enjGmcceyTZs2GX9/f1NRUWHNWbp0qbHb7eb8+fPu3QF4jSuzZIwxAwYMMM8+++xfPocsoSHt2rUz77zzjtvXI87U+6ALFy6osLBQ6enp1mP+/v5KT09Xfn6+ByuDtzt8+LCio6PVpUsXZWZmqry8XJJUWFioixcvumTqlltuUadOncgU/lJZWZkqKipcctO2bVulpqZaucnPz1dISIj69OljzUlPT5e/v792797t9prh3XJzc9WhQwclJCTo6aefVlVVlTVGlnClmpoaSVJoaKikxh3L8vPz1atXL0VERFhzBg8erFOnTlln19D8XJmly95//32FhYWpZ8+emjlzpurq6qwxsoQ/q6+v16pVq3Tm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",
"text/plain": [
"<Figure size 1200x600 with 3 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"model = Model().to(DEVICE)\n",
"\n",
"EPOCHS = 290 #@param {type:\"slider\", min:2, max:1000, step:1}\n",
"RATE = 0.9 #@param {type:\"slider\", min:0.001, max:2, step:0.001}\n",
"optimizer = torch.optim.SGD(model.parameters(), lr=RATE, weight_decay=0)\n",
"loss_fn = nn.CrossEntropyLoss()\n",
"loss_list = np.zeros((EPOCHS,))\n",
"accuracy_list = np.zeros((EPOCHS,))\n",
"accuracy_list_test = np.zeros((EPOCHS,))\n",
"\n",
"\n",
"\n",
"for epoch in tqdm.trange(EPOCHS):\n",
" y_pred = model(x_train)\n",
" #loss = loss_fn(y_pred, y_train)\n",
" loss = loss_fn(y_pred, y_train)# + 0.01 *l2_reg(model)\n",
" loss_list[epoch] = loss.item()\n",
"\n",
" # Zero gradients\n",
" optimizer.zero_grad()\n",
"\n",
" loss.backward()\n",
" #torch.nn.utils.clip_grad_norm_(model.parameters(), 0.5)#, args.clip)\n",
" optimizer.step()\n",
"\n",
" with torch.no_grad():\n",
" y_pred = model(x_train)\n",
" correct = (torch.argmax(y_pred, dim=1) == y_train).type(torch.FloatTensor)\n",
" accuracy_list[epoch] = correct.mean()\n",
" y_pred = model(x_test)\n",
" correct = (torch.argmax(y_pred, dim=1) == y_test).type(torch.FloatTensor)\n",
" accuracy_list_test[epoch] = correct.mean()\n",
"\n",
"\n",
"\n",
"\n",
"fig, (ax1, ax2, ax3) = plt.subplots(3, figsize=(12, 6), sharex=True)\n",
"\n",
"ax1.plot(accuracy_list)\n",
"ax1.set_ylabel(\"train accuracy\")\n",
"ax2.plot(loss_list)\n",
"ax2.set_ylabel(\"train loss\")\n",
"ax3.plot(accuracy_list_test)\n",
"ax3.set_ylabel(\"test acc\")\n",
"ax3.set_xlabel(\"epochs\");"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "F3kyvbJaTjZ7"
},
"source": [
"## 3.3. Momentum Implementieren\n",
"Vervollständigen Sie Methode momentum_update. Überlegen Sie sich, wie Sie die Korrektheit mit einem Durchlauf inkl. Momentum Update auf Ihrem oben definierten Modell prüfen können"
]
},
{
"cell_type": "code",
"execution_count": 46,
"metadata": {
"id": "36whMhqnMKuc"
},
"outputs": [],
"source": [
"def momentum_update(loss, params, grad_vel, lr=1e-3, beta=0.8):\n",
" # Clear up gradients as Pytorch automatically accumulates gradients from\n",
" # successive backward calls\n",
" zero_grad(params)\n",
" # Compute gradients on given objective\n",
" loss.backward()\n",
"\n",
" with torch.no_grad():\n",
" for (par, vel) in zip(params, grad_vel):\n",
" if vel != None:\n",
" par.grad.data += beta * vel\n",
" par.data -= lr * par.grad.data"
]
},
{
"cell_type": "code",
"execution_count": 48,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"100%|█████████████████████████████████████████████████████████████████████████████████| 300/300 [00:06<00:00, 45.36it/s]\n"
]
},
{
"data": {
"image/png": "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",
"text/plain": [
"<Figure size 1200x600 with 3 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"model = Model().to(DEVICE)\n",
"\n",
"EPOCHS = 300 #@param {type:\"slider\", min:2, max:1000, step:1}\n",
"RATE = 0.9 #@param {type:\"slider\", min:0.001, max:2, step:0.001}\n",
"optimizer = torch.optim.SGD(model.parameters(), lr=RATE, weight_decay=0)\n",
"loss_fn = nn.CrossEntropyLoss()\n",
"loss_list = np.zeros((EPOCHS,))\n",
"accuracy_list = np.zeros((EPOCHS,))\n",
"accuracy_list_test = np.zeros((EPOCHS,))\n",
"\n",
"params = list(model.parameters())\n",
"\n",
"for epoch in tqdm.trange(EPOCHS):\n",
" y_pred = model(x_train)\n",
" #loss = loss_fn(y_pred, y_train)\n",
" loss = loss_fn(y_pred, y_train)# + 0.01 *l2_reg(model)\n",
" loss_list[epoch] = loss.item()\n",
"\n",
"\n",
" vel = [param.grad for param in params]\n",
" # Zero gradients\n",
" optimizer.zero_grad()\n",
"\n",
" #loss.backward()\n",
" \n",
" #momentum_update(loss, params, vel)\n",
" gradient_update(loss, params)\n",
" #torch.nn.utils.clip_grad_norm_(model.parameters(), 0.5)#, args.clip)\n",
" #optimizer.step()\n",
"\n",
" with torch.no_grad():\n",
" y_pred = model(x_train)\n",
" correct = (torch.argmax(y_pred, dim=1) == y_train).type(torch.FloatTensor)\n",
" accuracy_list[epoch] = correct.mean()\n",
" y_pred = model(x_test)\n",
" correct = (torch.argmax(y_pred, dim=1) == y_test).type(torch.FloatTensor)\n",
" accuracy_list_test[epoch] = correct.mean()\n",
"\n",
"\n",
"\n",
"\n",
"fig, (ax1, ax2, ax3) = plt.subplots(3, figsize=(12, 6), sharex=True)\n",
"\n",
"ax1.plot(accuracy_list)\n",
"ax1.set_ylabel(\"train accuracy\")\n",
"ax2.plot(loss_list)\n",
"ax2.set_ylabel(\"train loss\")\n",
"ax3.plot(accuracy_list_test)\n",
"ax3.set_ylabel(\"test acc\")\n",
"ax3.set_xlabel(\"epochs\");"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "OPLRI_RKn2Mc"
},
"source": [
"## 3.4 Experimente zum Lernverhalten mit Momentum und Batch Size\n",
"Im folgenden können Sie für ein festgelegtes Zeitbudget schauen, wie sich der Loss Ihres neuronalen Netzes innerhalb dieser Zeit entwickelt.\n",
"Experimentieren Sie zunächst mit den Voreinstellungen mit und ohne Momentum, probieren Sie dann eigene Einstellungen aus. Diskutieren Sie das visualisierte Lernverhalten insbesondere bzgl. unterschiedlicher Batch Sizes."
]
},
{
"cell_type": "code",
"execution_count": 30,
"metadata": {
"id": "ebevIBNQt4-l"
},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "b30f006d8a304a5f9fc519439876c549",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"interactive(children=(Text(value='1, 20, 500, 17000', continuous_update=False, description='batch_sizes'), Tex…"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"@widgets.interact_manual\n",
"def minibatch_experiment(batch_sizes='1, 20, 500, 17000',\n",
" lrs='0.9, 0.9, 0.9, 0.9',\n",
" time_budget=widgets.Dropdown(options=[\"0.05\", \"0.5\", \"2.0\", \"5.0\", \"7.5\"],\n",
" value=\"5.0\"),\n",
" use_momentum = widgets.ToggleButton(value=True)):\n",
"\n",
" \"\"\"\n",
" Demonstration of minibatch experiment\n",
"\n",
" Args:\n",
" batch_sizes: String\n",
" Size of minibatches\n",
" lrs: String\n",
" Different learning rates\n",
" time_budget: widget dropdown instance\n",
" Different time budgets with default=2.5s\n",
"\n",
" Returns:\n",
" Nothing\n",
" \"\"\"\n",
" batch_sizes = [int(s) for s in batch_sizes.split(',')]\n",
" lrs = [float(s) for s in lrs.split(',')]\n",
"\n",
" LOSS_HIST = {_:[] for _ in batch_sizes}\n",
"\n",
" #X, y = train_set.data, train_set.targets\n",
" base_model = Model().to(DEVICE)\n",
" #base_model = MLP(in_dim=784, out_dim=10, hidden_dims=[100, 100])\n",
"\n",
" for id, batch_size in enumerate(tqdm.auto.tqdm(batch_sizes)):\n",
" start_time = time.time()\n",
" # Create a new copy of the model for each batch size\n",
" model = copy.deepcopy(base_model)\n",
" params = list(model.parameters())\n",
" lr = lrs[id]\n",
" # Fixed budget per choice of batch size\n",
" #initial_vel = [torch.randn_like(p) for p in model.parameters()]\n",
" aux_tensors = [torch.zeros_like(_) for _ in params]\n",
" while (time.time() - start_time) < float(time_budget):\n",
" data, labels = sample_minibatch(x_train, y_train, batch_size)\n",
" loss = loss_fn(model(data), labels)\n",
" if use_momentum:\n",
" momentum_update(loss, params, grad_vel=aux_tensors, lr=lr, beta=0.5)\n",
" else:\n",
" gradient_update(loss, params, lr=lr)\n",
" LOSS_HIST[batch_size].append([time.time() - start_time,\n",
" loss.item()])\n",
"\n",
" fig, axs = plt.subplots(1, len(batch_sizes), figsize=(10, 3))\n",
" for ax, batch_size in zip(axs, batch_sizes):\n",
" plot_data = np.array(LOSS_HIST[batch_size])\n",
" ax.plot(plot_data[:, 0], plot_data[:, 1], label=batch_size,\n",
" alpha=0.8)\n",
" #ax.set_title('Batch size: ' + str(batch_size) + ' #: ' + str(batch_size*len(LOSS_HIST[batch_size])))\n",
" ax.set_title(' #: ' + str(batch_size*len(LOSS_HIST[batch_size])))\n",
" ax.set_xlabel('Seconds')\n",
" ax.set_ylabel('Loss')\n",
" plt.show()\n",
" #return(LOSS_HIST)\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "e9yCfSXR1The"
},
"source": [
""
]
}
],
"metadata": {
"accelerator": "GPU",
"colab": {
"gpuType": "T4",
"provenance": [],
"toc_visible": true
},
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.12"
}
},
"nbformat": 4,
"nbformat_minor": 4
}