eaglelandsonce commited on
Commit
ffc2d4a
·
verified ·
1 Parent(s): 75e4b59

Create 3_WithExercises.py

Browse files
Files changed (1) hide show
  1. pages/3_WithExercises.py +390 -0
pages/3_WithExercises.py ADDED
@@ -0,0 +1,390 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import torch
3
+ import io
4
+ import sys
5
+
6
+ # Function to execute the input code and capture print statements
7
+ def execute_code(code):
8
+ # Redirect stdout to capture print statements
9
+ old_stdout = sys.stdout
10
+ sys.stdout = mystdout = io.StringIO()
11
+
12
+ global_vars = {"torch": torch}
13
+ local_vars = {}
14
+ try:
15
+ exec(code, global_vars, local_vars)
16
+ output = mystdout.getvalue()
17
+ except Exception as e:
18
+ output = str(e)
19
+ finally:
20
+ # Reset redirect.
21
+ sys.stdout = old_stdout
22
+
23
+ return output, local_vars
24
+
25
+ # Dictionary with exercise details
26
+ exercises = {
27
+ "Exercise 1: Create and Manipulate Tensors": {
28
+ "description": "Tensors are the core data structure in PyTorch, similar to arrays in NumPy but with additional capabilities for GPU acceleration. This exercise introduces how to create tensors from various data sources such as lists and NumPy arrays. It also covers basic tensor operations like addition, subtraction, and element-wise multiplication, which are fundamental for manipulating data in PyTorch.",
29
+ "code": '''
30
+ import torch
31
+ import numpy as np
32
+
33
+ # Creating tensors from Python lists
34
+ # This creates a 1D tensor from the list [1, 2, 3]
35
+ tensor_from_list = torch.tensor([1, 2, 3])
36
+ print("Tensor from list:", tensor_from_list)
37
+
38
+ # Creating tensors from NumPy arrays
39
+ # This converts a NumPy array to a tensor
40
+ numpy_array = np.array([4, 5, 6])
41
+ tensor_from_numpy = torch.tensor(numpy_array)
42
+ print("Tensor from NumPy array:", tensor_from_numpy)
43
+
44
+ # Performing basic tensor operations
45
+ tensor1 = torch.tensor([1, 2, 3])
46
+ tensor2 = torch.tensor([4, 5, 6])
47
+
48
+ # Addition
49
+ addition = tensor1 + tensor2
50
+ print("Addition:", addition)
51
+
52
+ # Subtraction
53
+ subtraction = tensor1 - tensor2
54
+ print("Subtraction:", subtraction)
55
+
56
+ # Element-wise multiplication
57
+ elementwise_multiplication = tensor1 * tensor2
58
+ print("Element-wise Multiplication:", elementwise_multiplication)
59
+ '''
60
+ },
61
+ "Exercise 2: Tensor Indexing and Slicing": {
62
+ "description": "Indexing and slicing allow you to access and manipulate specific elements and sub-tensors. This is crucial for tasks such as data preprocessing and manipulation in machine learning workflows. This exercise demonstrates how to index and slice tensors to extract and modify elements efficiently.",
63
+ "code": '''
64
+ import torch
65
+
66
+ # Creating a 2D tensor (matrix)
67
+ tensor = torch.tensor([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
68
+
69
+ # Indexing elements
70
+ # Accessing the element at the 2nd row and 3rd column (indexing starts at 0)
71
+ element = tensor[1, 2]
72
+ print("Element at index [1, 2]:", element)
73
+
74
+ # Slicing sub-tensors
75
+ # Extracting the entire second row
76
+ row = tensor[1, :]
77
+ print("Second row:", row)
78
+
79
+ # Extracting the entire third column
80
+ column = tensor[:, 2]
81
+ print("Third column:", column)
82
+
83
+ # Modifying elements
84
+ # Changing the first element of the tensor to 10
85
+ tensor[0, 0] = 10
86
+ print("Modified tensor:\n", tensor)
87
+ '''
88
+ },
89
+ "Exercise 3: Tensor Reshaping and Transposing": {
90
+ "description": "Reshaping and transposing tensors are common operations when preparing data for neural networks. Reshaping allows you to change the layout of tensor data without altering its data. Transposing changes the orientation of the data, which is useful for operations like matrix multiplication. This exercise covers reshaping using `view()` and `reshape()`, and transposing using `transpose()` and `permute()`.",
91
+ "code": '''
92
+ import torch
93
+
94
+ # Creating a 2D tensor
95
+ tensor = torch.tensor([[1, 2, 3], [4, 5, 6]])
96
+
97
+ # Reshaping the tensor
98
+ # Changing the shape of the tensor to (3, 2)
99
+ reshaped_tensor = tensor.view(3, 2)
100
+ print("Reshaped tensor:\n", reshaped_tensor)
101
+
102
+ # Another way to reshape using reshape()
103
+ reshaped_tensor2 = tensor.reshape(-1) # Flattening the tensor
104
+ print("Reshaped tensor (flattened):\n", reshaped_tensor2)
105
+
106
+ # Transposing the tensor
107
+ # Swapping the dimensions of the tensor (transpose rows and columns)
108
+ transposed_tensor = tensor.t()
109
+ print("Transposed tensor:\n", transposed_tensor)
110
+
111
+ # Using permute for higher-dimensional tensors
112
+ tensor_3d = torch.randn(2, 3, 4) # Creating a random 3D tensor
113
+ # Permuting dimensions
114
+ permuted_tensor = tensor_3d.permute(2, 0, 1)
115
+ print("Permuted tensor shape:", permuted_tensor.shape)
116
+ '''
117
+ },
118
+ "Exercise 4: Tensor Operations and Broadcasting": {
119
+ "description": "Broadcasting in PyTorch allows you to perform arithmetic operations on tensors of different shapes. This can simplify code and reduce the need for explicit reshaping. This exercise demonstrates matrix multiplication, the concept of broadcasting, and the application of element-wise functions like sine and exponential.",
120
+ "code": '''
121
+ import torch
122
+
123
+ # Matrix multiplication
124
+ tensor1 = torch.tensor([[1, 2], [3, 4]])
125
+ tensor2 = torch.tensor([[5, 6], [7, 8]])
126
+
127
+ # Performing matrix multiplication using matmul
128
+ matmul_result = torch.matmul(tensor1, tensor2)
129
+ print("Matrix multiplication result:\n", matmul_result)
130
+
131
+ # Broadcasting example
132
+ # Broadcasting allows tensor3 and tensor4 to be added despite their different shapes
133
+ tensor3 = torch.tensor([1, 2, 3])
134
+ tensor4 = torch.tensor([[1], [2], [3]])
135
+ broadcast_result = tensor3 + tensor4
136
+ print("Broadcasting result:\n", broadcast_result)
137
+
138
+ # Element-wise functions
139
+ # Applying sine function element-wise
140
+ sin_result = torch.sin(tensor3)
141
+ print("Sine of tensor3:", sin_result)
142
+
143
+ # Applying exponential function element-wise
144
+ exp_result = torch.exp(tensor3)
145
+ print("Exponential of tensor3:", exp_result)
146
+
147
+ # Applying square root function element-wise
148
+ # Note: sqrt requires the tensor to be of floating-point type
149
+ sqrt_result = torch.sqrt(tensor3.float())
150
+ print("Square root of tensor3:", sqrt_result)
151
+ '''
152
+ },
153
+ "Exercise 5: Tensor Initialization": {
154
+ "description": "Proper initialization of tensors is crucial for neural network training and other machine learning tasks. This exercise explores various methods to initialize tensors, such as filling them with zeros, ones, random values, and specific distributions. Understanding these methods helps in setting up model parameters and test data.",
155
+ "code": '''
156
+ import torch
157
+
158
+ # Creating tensors filled with zeros and ones
159
+ zeros_tensor = torch.zeros(3, 3)
160
+ print("Zeros tensor:\n", zeros_tensor)
161
+
162
+ ones_tensor = torch.ones(3, 3)
163
+ print("Ones tensor:\n", ones_tensor)
164
+
165
+ # Randomly initialized tensors
166
+ # Uniform distribution in the range [0, 1)
167
+ rand_tensor = torch.rand(3, 3)
168
+ print("Uniform random tensor:\n", rand_tensor)
169
+
170
+ # Normal distribution with mean 0 and variance 1
171
+ randn_tensor = torch.randn(3, 3)
172
+ print("Normal random tensor:\n", randn_tensor)
173
+
174
+ # Random integers in the range [0, 10)
175
+ randint_tensor = torch.randint(0, 10, (3, 3))
176
+ print("Random integer tensor:\n", randint_tensor)
177
+
178
+ # Initializing tensors with specific distributions
179
+ # Normal distribution with custom mean and standard deviation
180
+ normal_tensor = torch.normal(mean=0, std=1, size=(3, 3))
181
+ print("Normal distribution tensor:\n", normal_tensor)
182
+
183
+ # Uniform distribution in a custom range [0, 1)
184
+ uniform_tensor = torch.empty(3, 3).uniform_(0, 1)
185
+ print("Uniform distribution tensor:\n", uniform_tensor)
186
+ '''
187
+ },
188
+ "Exercise 6: Tensor Arithmetic Operations": {
189
+ "description": "Arithmetic operations on tensors are essential for numerous tasks in machine learning, including data preprocessing and neural network computations. This exercise covers basic arithmetic with tensors, in-place operations, and aggregation functions that compute summaries over tensor elements.",
190
+ "code": '''
191
+ import torch
192
+
193
+ # Creating a 1D tensor
194
+ tensor = torch.tensor([1.0, 2.0, 3.0])
195
+
196
+ # Scalar-tensor operations
197
+ # Adding a scalar to each element of the tensor
198
+ add_scalar = tensor + 5
199
+ print("Addition with scalar:", add_scalar)
200
+
201
+ # Multiplying each element by a scalar
202
+ mul_scalar = tensor * 2
203
+ print("Multiplication with scalar:", mul_scalar)
204
+
205
+ # In-place operations (modify the original tensor)
206
+ # Adding 5 to each element of the tensor
207
+ tensor.add_(5)
208
+ print("In-place addition:", tensor)
209
+
210
+ # Tensor aggregation operations
211
+ tensor = torch.tensor([[1, 2], [3, 4]])
212
+
213
+ # Summing all elements
214
+ sum_all = tensor.sum()
215
+ print("Sum of all elements:", sum_all)
216
+
217
+ # Computing the mean of all elements
218
+ mean_all = tensor.mean()
219
+ print("Mean of all elements:", mean_all)
220
+
221
+ # Finding the maximum element
222
+ max_all = tensor.max()
223
+ print("Maximum element:", max_all)
224
+ '''
225
+ },
226
+ "Exercise 7: Tensor Comparison and Logical Operations": {
227
+ "description": "Comparison and logical operations enable you to make conditional selections and perform logical checks on tensors. This is crucial for tasks such as filtering data and implementing decision-based logic in machine learning workflows. This exercise demonstrates the use of comparison operators and logical functions, which are often used in neural network training and data analysis.",
228
+ "code": '''
229
+ import torch
230
+
231
+ # Creating two tensors for comparison
232
+ tensor1 = torch.tensor([1, 2, 3])
233
+ tensor2 = torch.tensor([3, 2, 1])
234
+
235
+ # Comparison operations
236
+ # Checking if elements in tensor1 are greater than corresponding elements in tensor2
237
+ greater_than = tensor1 > tensor2
238
+ print("Greater than comparison:", greater_than)
239
+
240
+ # Checking if elements in tensor1 are equal to corresponding elements in tensor2
241
+ equal = tensor1 == tensor2
242
+ print("Equality comparison:", equal)
243
+
244
+ # Logical operations
245
+ # Logical AND operation between comparison results
246
+ logical_and = torch.logical_and(tensor1 > 1, tensor2 < 3)
247
+ print("Logical AND:", logical_and)
248
+
249
+ # Logical OR operation between comparison results
250
+ logical_or = torch.logical_or(tensor1 < 3, tensor2 > 1)
251
+ print("Logical OR:", logical_or)
252
+
253
+ # Logical NOT operation
254
+ logical_not = torch.logical_not(tensor1 < 3)
255
+ print("Logical NOT:", logical_not)
256
+
257
+ # Conditional selection using torch.where
258
+ # Selecting elements from tensor1 if condition is True, otherwise from tensor2
259
+ selected_tensor = torch.where(tensor1 > 2, tensor1, tensor2)
260
+ print("Conditional selection:", selected_tensor)
261
+ '''
262
+ },
263
+ "Exercise 8: Tensor Reduction Operations": {
264
+ "description": "Reduction operations aggregate tensor elements along specified dimensions, providing summarized results like sums, means, and indices of maximum or minimum values. This exercise covers essential reduction operations, which are commonly used in loss functions and performance metrics in machine learning.",
265
+ "code": '''
266
+ import torch
267
+
268
+ # Creating a 2D tensor (matrix)
269
+ tensor = torch.tensor([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
270
+
271
+ # Reduction operations along dimensions
272
+ # Summing elements along dimension 0 (rows)
273
+ sum_dim0 = tensor.sum(dim=0)
274
+ print("Sum along dimension 0:", sum_dim0)
275
+
276
+ # Computing the mean along dimension 1 (columns)
277
+ mean_dim1 = tensor.mean(dim=1)
278
+ print("Mean along dimension 1:", mean_dim1)
279
+
280
+ # Computing the product of all elements in the tensor
281
+ prod_all = tensor.prod()
282
+ print("Product of all elements:", prod_all)
283
+
284
+ # Advanced reduction operations
285
+ # Finding the index of the maximum element in the flattened tensor
286
+ argmax_all = tensor.argmax()
287
+ print("Index of maximum element:", argmax_all)
288
+
289
+ # Finding the indices of the minimum elements along dimension 0
290
+ argmin_dim0 = tensor.argmin(dim=0)
291
+ print("Indices of minimum elements along dimension 0:", argmin_dim0)
292
+ '''
293
+ },
294
+ "Exercise 9: Tensor Cloning and Detachment": {
295
+ "description": "Cloning and detaching tensors are important when working with gradients in neural networks. Cloning creates a copy of a tensor, while detaching removes it from the computation graph to prevent gradient tracking. This exercise demonstrates these operations, which are crucial for managing tensor operations in complex neural networks.",
296
+ "code": '''
297
+ import torch
298
+
299
+ # Creating a tensor with gradient tracking enabled
300
+ tensor = torch.tensor([1.0, 2.0, 3.0], requires_grad=True)
301
+
302
+ # Cloning the tensor
303
+ # This creates a new tensor with the same data but no gradient history
304
+ cloned_tensor = tensor.clone()
305
+ print("Original tensor:", tensor)
306
+ print("Cloned tensor:", cloned_tensor)
307
+
308
+ # Detaching the tensor from the computation graph
309
+ # This removes the tensor from the gradient computation graph
310
+ detached_tensor = tensor.detach()
311
+ print("Detached tensor:", detached_tensor)
312
+
313
+ # Comparing original and detached tensors
314
+ # Modifying the original tensor (note that in-place operations modify the tensor in place)
315
+ tensor.add_(1)
316
+ print("Modified original tensor:", tensor)
317
+ print("Detached tensor remains unchanged:", detached_tensor)
318
+ '''
319
+ },
320
+ "Exercise 10: GPU Operations with Tensors": {
321
+ "description": "Utilizing GPUs can significantly speed up tensor operations, which is crucial for training large neural networks. This exercise covers checking for GPU availability, moving tensors to GPU, and performing operations on GPU to compare performance with CPU operations.",
322
+ "code": '''
323
+ import torch
324
+ import time
325
+
326
+ # Check for GPU availability
327
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
328
+ print("Using device:", device)
329
+
330
+ # Creating a tensor and moving it to GPU if available
331
+ tensor = torch.tensor([1.0, 2.0, 3.0])
332
+ tensor = tensor.to(device)
333
+ print("Tensor on GPU:", tensor)
334
+
335
+ # Perform operations on GPU
336
+ # Adding a scalar to each element of the tensor on GPU
337
+ tensor_add = tensor + 5
338
+ print("Tensor after addition on GPU:", tensor_add)
339
+
340
+ # Compare speed of operations on CPU vs GPU
341
+ # Creating a large tensor for performance comparison
342
+ cpu_tensor = torch.randn(10000, 10000)
343
+
344
+ # CPU operation
345
+ start_time = time.time()
346
+ cpu_result = cpu_tensor @ cpu_tensor.T # Matrix multiplication
347
+ end_time = time.time()
348
+ print("CPU operation time:", end_time - start_time, "seconds")
349
+
350
+ # GPU operation (if available)
351
+ if torch.cuda.is_available():
352
+ gpu_tensor = cpu_tensor.to(device)
353
+ start_time = time.time()
354
+ gpu_result = gpu_tensor @ gpu_tensor.T # Matrix multiplication
355
+ torch.cuda.synchronize() # Wait for GPU operation to finish
356
+ end_time = time.time()
357
+ print("GPU operation time:", end_time - start_time, "seconds")
358
+ '''
359
+ }
360
+ }
361
+
362
+ st.title('PyTorch Code Runner')
363
+
364
+ # Side menu for exercises
365
+ exercise_choice = st.sidebar.radio("Choose an exercise", list(exercises.keys()))
366
+
367
+ # Display the chosen exercise description
368
+ st.subheader(exercise_choice)
369
+ st.write(exercises[exercise_choice]["description"])
370
+
371
+ # Text area for inputting the PyTorch code
372
+ code_input = st.text_area("Enter your PyTorch code here", height=300, value=exercises[exercise_choice]["code"])
373
+
374
+ # Button to execute the code
375
+ if st.button("Run Code"):
376
+ # Prepend the import statement
377
+ code_to_run = "import torch\n" + code_input
378
+
379
+ # Execute the code and capture the output
380
+ output, variables = execute_code(code_to_run)
381
+
382
+ # Display the output
383
+ st.subheader('Output')
384
+ st.text(output)
385
+
386
+ # Display returned variables
387
+ if variables:
388
+ st.subheader('Variables')
389
+ for key, value in variables.items():
390
+ st.text(f"{key}: {value}")