-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy path07.custom-keras-layer.py
97 lines (75 loc) · 3.1 KB
/
07.custom-keras-layer.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
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
tf.random.set_seed(1)
np.random.seed(1)
x = np.random.uniform(low=-1, high=1, size=(200, 2))
y = np.ones(len(x))
y[x[:, 0] * x[:, 1] < 0] = 0
x_train = x[:100, :]
y_train = y[:100]
x_valid = x[100:, :]
y_valid = y[100:]
class NoisyLinear(tf.keras.layers.Layer):
def __init__(self, output_dim, noise_stddev=0.1, **kwargs):
self.output_dim = output_dim
self.noise_stddev = noise_stddev
super(NoisyLinear, self).__init__(**kwargs)
def build(self, input_shape):
self.w = self.add_weight(name='weights', shape=(input_shape[1], self.output_dim), initializer='random_normal', trainable=True)
self.b = self.add_weight(shape=(self.output_dim, ), initializer='zeros', trainable=True)
def call(self, inputs, training=False):
if training:
batch = tf.shape(inputs)[0]
dim = tf.shape(inputs)[1]
noise = tf.random.normal(shape=(batch, dim), mean=0.0, stddev=self.noise_stddev)
noisy_inputs = tf.add(inputs, noise)
else:
# Do not modify the inputs during prediction
noisy_inputs = inputs
z = tf.matmul(noisy_inputs, self.w) + self.b
return tf.keras.activations.relu(z)
def get_config(self):
config = super(NoisyLinear, self).get_config()
config.update({'output_dim': self.output_dim, 'noise_stddev': self.noise_stddev})
return config
# Test the custom layer
tf.random.set_seed(2)
noisy_layer = NoisyLinear(4)
noisy_layer.build(input_shape=(None, 4))
x = tf.zeros(shape=(1, 4))
tf.print('Noisy layer adding noise:', noisy_layer(x, training=True))
config = noisy_layer.get_config()
new_layer = NoisyLinear.from_config(config)
tf.print('Loaded from config adding noise:', new_layer(x, training=True))
# Use the custom layer in our model
model = tf.keras.Sequential([
NoisyLinear(4, noise_stddev=0.1),
tf.keras.layers.Dense(4, activation='relu'),
tf.keras.layers.Dense(4, activation='relu'),
tf.keras.layers.Dense(1, activation='sigmoid')
])
model.build(input_shape=(None, 2))
model.summary()
model.compile(optimizer=tf.keras.optimizers.SGD(), loss=tf.keras.losses.BinaryCrossentropy(), metrics=[tf.keras.metrics.BinaryAccuracy()])
hist = model.fit(x_train, y_train, validation_data=(x_valid, y_valid), epochs=200, batch_size=2)
history = hist.history
from mlxtend.plotting import plot_decision_regions
fig = plt.figure(figsize=(16, 4))
ax = fig.add_subplot(1, 3, 1)
plt.plot(history['loss'], lw=4)
plt.plot(history['val_loss'], lw=4)
plt.legend(['Train loss', 'Validation loss'], fontsize=15)
ax.set_xlabel('Epochs', size=15)
ax = fig.add_subplot(1, 3, 2)
plt.plot(history['binary_accuracy'], lw=4)
plt.plot(history['val_binary_accuracy'], lw=4)
plt.legend(['Train acc', 'Validation acc'], fontsize=15)
ax.set_xlabel('Epochs', size=15)
ax = fig.add_subplot(1, 3, 3)
plot_decision_regions(X=x_valid, y=y_valid.astype(np.integer), clf=model)
ax.set_xlabel(r'$x_1$', size=15)
ax.xaxis.set_label_coords(1, -0.025)
ax.set_ylabel(r'$x_2$', size=15)
ax.yaxis.set_label_coords(-0.025, 1)
plt.show()