-
Notifications
You must be signed in to change notification settings - Fork 43
/
Copy pathexperimental.py
176 lines (150 loc) · 5.89 KB
/
experimental.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
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
ANFIS in torch: some simple functions to supply data and plot results.
@author: James Power <james.power@mu.ie> Apr 12 18:13:10 2019
"""
import matplotlib.pyplot as plt
import torch
import torch.nn.functional as F
dtype = torch.float
class TwoLayerNet(torch.nn.Module):
'''
From the pytorch examples, a simjple 2-layer neural net.
https://pytorch.org/tutorials/beginner/pytorch_with_examples.html
'''
def __init__(self, d_in, hidden_size, d_out):
super(TwoLayerNet, self).__init__()
self.linear1 = torch.nn.Linear(d_in, hidden_size)
self.linear2 = torch.nn.Linear(hidden_size, d_out)
def forward(self, x):
h_relu = self.linear1(x).clamp(min=0)
y_pred = self.linear2(h_relu)
return y_pred
def linear_model(x, y, epochs=200, hidden_size=10):
'''
Predict y from x using a simple linear model with one hidden layer.
https://pytorch.org/tutorials/beginner/pytorch_with_examples.html
'''
assert x.shape[0] == y.shape[0], 'x and y have different batch sizes'
d_in = x.shape[1]
d_out = y.shape[1]
model = TwoLayerNet(d_in, hidden_size, d_out)
criterion = torch.nn.MSELoss(reduction='sum')
optimizer = torch.optim.SGD(model.parameters(), lr=1e-4)
errors = []
for t in range(epochs):
y_pred = model(x)
tot_loss = criterion(y_pred, y)
perc_loss = 100. * torch.sqrt(tot_loss).item() / y.sum()
errors.append(perc_loss)
if t % 10 == 0 or epochs < 20:
print('epoch {:4d}: {:.5f} {:.2f}%'.format(t, tot_loss, perc_loss))
optimizer.zero_grad()
tot_loss.backward()
optimizer.step()
return model, errors
def plotErrors(errors):
'''
Plot the given list of error rates against no. of epochs
'''
plt.plot(range(len(errors)), errors, '-ro', label='errors')
plt.ylabel('Percentage error')
plt.xlabel('Epoch')
plt.show()
def plotResults(y_actual, y_predicted):
'''
Plot the actual and predicted y values (in different colours).
'''
plt.plot(range(len(y_predicted)), y_predicted.detach().numpy(),
'r', label='trained')
plt.plot(range(len(y_actual)), y_actual.numpy(), 'b', label='original')
plt.legend(loc='upper left')
plt.show()
def _plot_mfs(var_name, fv, x):
'''
A simple utility function to plot the MFs for a variable.
Supply the variable name, MFs and a set of x values to plot.
'''
# Sort x so we only plot each x-value once:
xsort, _ = x.sort()
for mfname, yvals in fv.fuzzify(xsort):
plt.plot(xsort.tolist(), yvals.tolist(), label=mfname)
plt.xlabel('Values for variable {} ({} MFs)'.format(var_name, fv.num_mfs))
plt.ylabel('Membership')
plt.legend(bbox_to_anchor=(1., 0.95))
plt.show()
def plot_all_mfs(model, x):
for i, (var_name, fv) in enumerate(model.layer.fuzzify.varmfs.items()):
_plot_mfs(var_name, fv, x[:, i])
def calc_error(y_pred, y_actual):
with torch.no_grad():
tot_loss = F.mse_loss(y_pred, y_actual)
rmse = torch.sqrt(tot_loss).item()
perc_loss = torch.mean(100. * torch.abs((y_pred - y_actual)
/ y_actual))
return(tot_loss, rmse, perc_loss)
def test_anfis(model, data, show_plots=False):
'''
Do a single forward pass with x and compare with y_actual.
'''
x, y_actual = data.dataset.tensors
if show_plots:
plot_all_mfs(model, x)
print('### Testing for {} cases'.format(x.shape[0]))
y_pred = model(x)
mse, rmse, perc_loss = calc_error(y_pred, y_actual)
print('MS error={:.5f}, RMS error={:.5f}, percentage={:.2f}%'
.format(mse, rmse, perc_loss))
if show_plots:
plotResults(y_actual, y_pred)
def train_anfis_with(model, data, optimizer, criterion,
epochs=500, show_plots=False):
'''
Train the given model using the given (x,y) data.
'''
errors = [] # Keep a list of these for plotting afterwards
# optimizer = torch.optim.Adam(model.parameters(), lr=1e-4)
print('### Training for {} epochs, training size = {} cases'.
format(epochs, data.dataset.tensors[0].shape[0]))
for t in range(epochs):
# Process each mini-batch in turn:
for x, y_actual in data:
y_pred = model(x)
# Compute and print loss
loss = criterion(y_pred, y_actual)
# Zero gradients, perform a backward pass, and update the weights.
optimizer.zero_grad()
loss.backward()
optimizer.step()
# Epoch ending, so now fit the coefficients based on all data:
x, y_actual = data.dataset.tensors
with torch.no_grad():
model.fit_coeff(x, y_actual)
# Get the error rate for the whole batch:
y_pred = model(x)
mse, rmse, perc_loss = calc_error(y_pred, y_actual)
errors.append(perc_loss)
# Print some progress information as the net is trained:
if epochs < 30 or t % 10 == 0:
print('epoch {:4d}: MSE={:.5f}, RMSE={:.5f} ={:.2f}%'
.format(t, mse, rmse, perc_loss))
# End of training, so graph the results:
if show_plots:
plotErrors(errors)
y_actual = data.dataset.tensors[1]
y_pred = model(data.dataset.tensors[0])
plotResults(y_actual, y_pred)
def train_anfis(model, data, epochs=500, show_plots=False):
'''
Train the given model using the given (x,y) data.
'''
optimizer = torch.optim.SGD(model.parameters(), lr=1e-4, momentum=0.99)
criterion = torch.nn.MSELoss(reduction='sum')
train_anfis_with(model, data, optimizer, criterion, epochs, show_plots)
if __name__ == '__main__':
x = torch.arange(1, 100, dtype=dtype).unsqueeze(1)
y = torch.pow(x, 3)
model, errors = linear_model(x, y, 100)
plotErrors(errors)
plotResults(y, model(x))