-
Notifications
You must be signed in to change notification settings - Fork 0
/
sunspotts.py
358 lines (224 loc) · 9.69 KB
/
sunspotts.py
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
#!/usr/bin/env python
# coding: utf-8
# In[1]:
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
import numpy as np
import tensorflow as tf
import warnings
warnings.filterwarnings("ignore")
# In[2]:
data=pd.read_csv(r"C:\Users\raibh\Desktop\sunspotts prediction\sunspots.csv")
data.head()
# In[3]:
data.tail()
# In[4]:
data.describe()
# In[5]:
data.info()
# In[6]:
sunspots = data.iloc[:,-1]
sunspots.values
# In[7]:
plt.figure(figsize=(28,6))
plt.plot(sunspots)
plt.ylabel(data.columns[-1], fontsize = 12, color = 'm')
plt.xlabel("Months from Jan 1749 to Jan 2021", fontsize = 12, color = 'm')
plt.title("Visualize the Data", fontsize = 18, color = 'r', weight = 'bold')
plt.show()
# In[8]:
plt.figure(figsize=(28,6))
plt.plot(sunspots) # The whole data
plt.plot(sunspots[:72]) # Data from 1749, actual cycles started from 1755 --> 6 years means 72 months
plt.plot(sunspots[72:72+132]) # Showing the first cycle
plt.plot(sunspots[-13:]) # Displaying the current cycle
plt.ylabel(data.columns[-1], fontsize = 12, color = 'm')
plt.xlabel("Months from Jan 1749 to Jan 2021", fontsize = 12, color = 'm')
plt.title("Understanding the Sunspots data", fontsize = 18, color = 'r', weight = 'bold')
plt.legend(["Full data", "Before 1755 - The first cycle", "The first cycle", "After 2019 - The currect cycle"], fontsize = 12)
plt.show()
# In[9]:
years = []
start = 1755
for i in range(0, len(data.iloc[:,-1][72:]),132):
years.append(start)
start+=11
plt.figure(figsize = (28, 6))
plt.plot(sunspots[72:])
plt.title("Visualize Solar Cycle 1 till Solar Cycle 24", weight = 'bold', color = 'r', fontsize = 18)
plt.xlim(72, 3265-12)
plt.xticks(range(72, len(sunspots),132))
plt.gca().set_xticklabels(years)
plt.show()
# In[10]:
plt.figure(figsize = (15,6))
plt.subplot(2, 1, 1)
sns.distplot(sunspots)
plt.title("Variation in the data distribution", fontsize = 15, color = 'r', weight = 'bold')
plt.subplot(2, 1, 2)
sns.boxplot(sunspots)
plt.title("Boxplot of data", fontsize = 15, color = 'r', weight = 'bold')
plt.tight_layout()
plt.show()
# In[11]:
def windowed_dataset(series, window_size, batch_size, shuffle_buffer):
series = series[:, np.newaxis] # Adding new dimension to the series array in the position where np.newaxis is written
ds = tf.data.Dataset.from_tensor_slices(series) # In order to use window of tensorflow convert numpy array to tensor
ds = ds.window(window_size + 1, shift=1, drop_remainder=True) # Creating window for generating sequence (yet not seperating it with the future values) - LSTM
ds = ds.flat_map(lambda w: w.batch(window_size + 1)) # Flatten a dataset of batches into a dataset of their elements
ds = ds.shuffle(shuffle_buffer) # To reduce the variance and making sure that the model remain general and less overfits
ds = ds.map(lambda w: (w[:-1], w[-1])) # In a window, last value is the future value that our model needs to learn and predict while testing it
return ds.batch(batch_size).prefetch(1)
# In[12]:
dum_series = sunspots[:10].values # Numpy array
dum_series, dum_series.shape
# In[13]:
dum_series=dum_series[:, np.newaxis] # Shape now should be 10x1
dum_series, dum_series.shape
# In[14]:
ds = tf.data.Dataset.from_tensor_slices(dum_series) # Window method of tensorflow won't work on numpy array
# Display the content of the above dataset
for i in ds:
for val in i:
print(val)
# In[15]:
window_size = 3 # Sequence Length
ds = ds.window(window_size + 1, shift=1, drop_remainder=True) # Drop remainder if True ensures the same shape of the tensor
# Display the changes
for i in ds:
for val in i:
print(val)
# In[16]:
ds = ds.flat_map(lambda w: w.batch(window_size + 1)) # Batch of 4 is what we want for this example
ds = ds.map(lambda w: (w[:-1], w[-1])) # Two different outputs we should get ---> Sequence of 3 and 1 label
# Display the change
for i in ds:
for val in i:
print(val)
# In[17]:
ds = ds.batch(10).prefetch(1)
for i in ds:
for val in i:
print(val)
print("\n")
# In[18]:
def model_forecast(model, series, window_size):
ds = tf.data.Dataset.from_tensor_slices(series)
ds = ds.window(window_size, shift=1, drop_remainder=True)
ds = ds.flat_map(lambda w: w.batch(window_size))
ds = ds.batch(batch_size).prefetch(1)
forecast = model.predict(ds) # To predict
return forecast
# In[19]:
series = data['Monthly Mean Total Sunspot Number'].values
time = data['Unnamed: 0'].values
# Splitting the data into train and test
split_time = int(len(series)*0.9) # 90% of the original data is for training
time_train = time[:split_time]
x_train = series[:split_time]
time_valid = time[split_time:]
x_valid = series[split_time:]
print(f"There are {len(x_train)} training samples and {len(x_valid)} validation samples.")
# Parameters
delta = 1 # Huber loss
window_size = 60 # For dataset
batch_size = 145 # For dataset
shuffle_buffer_size= 900 # Shuffling the dataset randomly
epochs = 100 # For optimal learning rate
train_epochs = epochs + 100 # Training epochs
momentum_sgd = 0.9 # For optimizer
# In[20]:
tf.keras.backend.clear_session()
# To produce same sequence of results each time the code runs
tf.random.set_seed(42)
np.random.seed(42)
# Calling the window_dataset function to generate the training data
train_set = windowed_dataset(x_train, window_size, batch_size, shuffle_buffer_size)
# Building the model
model = tf.keras.models.Sequential([
# Conv1D layers smoothens out the input time-series so we don't have to add the rolling mean or rolling standard deviation values in the input features
tf.keras.layers.Conv1D(filters=132, kernel_size=4,strides=1, padding="causal", activation="relu",input_shape=[None, 1]),
tf.keras.layers.LSTM(256, return_sequences=True), # Return sequence if set to true will return the outputs for each time step as explained above
tf.keras.layers.LSTM(132, return_sequences=False),# Setting it as False will only output the last time step which will then be feeded into the fully connected layers
tf.keras.layers.Dense(80, activation="relu"),
tf.keras.layers.Dense(10, activation="relu"),
tf.keras.layers.Dense(1),
tf.keras.layers.Lambda(lambda x: x * 400) # To push the values in the range of the original data after getting passed from different activations
])
# Display this model summary
model.summary()
# Using callbacks - Learning rate scheduler to find the optimal value to be used in the final model
lr_schedule = tf.keras.callbacks.LearningRateScheduler(lambda epoch: 1e-8 * 10**(epoch / 20), verbose = 0) # lr --> starting lr * 10^(0/20), starting lr * 10^(1/20), so on..
# Stochastic Gradient Desect as the optimizer
optimizer = tf.keras.optimizers.SGD(learning_rate=1e-8, momentum=momentum_sgd)
model.compile(loss=tf.keras.losses.Huber(delta),
optimizer=optimizer,
metrics=["mae"])
# In[21]:
history = model.fit(train_set, epochs=epochs, callbacks=[lr_schedule])
# In[22]:
lrs = 1e-8 * (10**(np.arange(epochs)/20))
lrs
# In[23]:
min_loss = min(history.history['loss'])
idx_min_loss = history.history['loss'].index(min_loss)
opt_lr = lrs[idx_min_loss]
first = str(round(float(str(opt_lr).split('e')[0])))
second = str(opt_lr).split('e')[-1]
final = [first, second]
x = "e".join(final)
x = float(x)
print(f"Optimal Learning Rate was --> {x}.")
# In[24]:
fig = plt.figure(figsize=(15, 6))
plt.semilogx(lrs, history.history["loss"]) # Learning rates are increasing exponentially and hence for an omptimal sized plot we use semilogx plot
plt.grid(True, ls="--")
plt.plot(opt_lr,min_loss, color = 'r', marker = 'x', markersize = 7)
plt.title(f"Looking for Optimum Learning Rate", color = 'm', fontsize = 15)
plt.ylabel("Losses", fontsize = 13, color = 'g')
plt.xlabel("Learining Rates", fontsize = 13, color = 'g')
plt.annotate(f"lr = {x}", (opt_lr,min_loss+2), (opt_lr+0.05e-5, min_loss+15), arrowprops = dict(facecolor ='k', width = 2, headwidth = 8), fontsize = 12)
plt.show()
# In[25]:
tf.keras.backend.clear_session()
tf.random.set_seed(42)
np.random.seed(42)
model = tf.keras.models.Sequential([
tf.keras.layers.Conv1D(filters=132, kernel_size=4,strides=1, padding="causal", activation="relu",input_shape=[None, 1]),
tf.keras.layers.LSTM(256, return_sequences=True),
tf.keras.layers.LSTM(132, return_sequences=False),
tf.keras.layers.Dense(80, activation="relu"),
tf.keras.layers.Dense(10, activation="relu"),
tf.keras.layers.Dense(1),
tf.keras.layers.Lambda(lambda x: x * 400)
])
optimizer = tf.keras.optimizers.SGD(learning_rate=opt_lr, momentum=momentum_sgd)
model.compile(loss=tf.keras.losses.Huber(delta),
optimizer=optimizer,
metrics=["mae"])
history = model.fit(train_set,epochs=train_epochs)
# In[26]:
mae=history.history['mae']
loss=history.history['loss']
# Plot MAE and Huber Loss
fig = plt.figure(figsize=(15, 6))
plt.plot(mae, 'r')
plt.plot(loss, 'b')
plt.title('MAE and Loss')
plt.xlabel("Epochs")
plt.legend(["MAE", "Loss"])
# In[27]:
rnn_forecast = model_forecast(model, series[:, np.newaxis], window_size)
rnn_forecast = rnn_forecast[split_time - window_size:-1, 0] # rnn_forecast[-328:-1, 0]
# Plots
plt.figure(figsize=(15, 6))
plt.plot(time_valid, x_valid)
plt.plot(time_valid, rnn_forecast)
plt.title("")
plt.legend(["Validation Data", "Predicted Data"])
plt.show()
# In[28]:
val_mae=tf.keras.metrics.mae(x_valid, rnn_forecast).numpy()
print(f"MAE on the validation data:- {val_mae}")
# In[ ]: