On the project I am currently working on, my goal is to train a neural network to convert images of circles to ellipses in a way that models convolution/blurring in real imaging processes.
What remains is to construct a neural network, preferably a CNN, that has the desired results - i.e. takes an image with circles as an input and returns an image with ellipses. However, I have not been able to do this. At best, neural nets (including CNNs) that I have used so far have at best returned blurred images of the circles. I can't tell whether it is the fault of the neural network or the fault of the preprocessing code I am using.
I am a beginner in machine learning, and I read that convolutional neural networks are the best architecture to use for image processing. Hence, I have attempted to develop a CNN for this purpose. Somebody suggested to use an encoder/decoder model for this problem, but I do not know how to do this.
#First, importing the necessary modules:
import keras
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten, Activation, Reshape
from keras.layers import Input, Conv2D, MaxPooling2D, UpSampling2D
import numpy as np
import pandas as pd
from collections import OrderedDict
import itertools
import matplotlib.pyplot as plt
import matplotlib.patches as patches
import random
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import OneHotEncoder
import math
from math import sqrt
from keras.models import Model, load_model
#Next, creating and storing the input (circle) and output (ellipse) images:
def create_blank_image(size):
data = np.ndarray(shape=(size, size))
for i in range(0, size):
for j in range(0, size):
data[[i], [j]] = 0
#print(data)
return data
def circle_randomizer():
number_of_circles = random.randint(4,10)
intensity = np.ndarray(shape=(128, 128))
#print(number_of_circles)
radius_list = []
for i in range(number_of_circles):
radius_list.append(random.uniform(8, 10))
#print(radius_list)
center_coords = np.zeros((2,1))
center_coords[[0],[0]] = random.uniform(0,size)
center_coords[[1],[0]] = random.uniform(0,size)
for i in range(number_of_circles):
#temp_array = np.ndarray(shape=(2,1))
#temp_array[[0],[0]] = random.uniform(0,size)
#temp_array[[1],[0]] = random.uniform(0,size)
if i > 0:
j = 0
#print(i,j)
while j in range(i):
#print(i,j)
#print(center_coords)
temp_array = np.ndarray(shape=(2,1))
temp_array[[0],[0]] = random.uniform(0,size)
temp_array[[1],[0]] = random.uniform(0,size)
#while sqrt((center_coords[[0],[i]] - center_coords[[0],[j]])**2 + (center_coords[[1],[i]] - center_coords[[1],[j]])**2) < radius_list[i] + radius_list[j]:
while sqrt((temp_array[[0],[0]] - center_coords[[0],[j]])**2 + (temp_array[[1],[0]] - center_coords[[1],[j]])**2) < radius_list[i] + radius_list[j]:
temp_array[[0],[0]] = random.uniform(0,size)
temp_array[[1],[0]] = random.uniform(0,size)
j = 0
center_coords = np.concatenate((center_coords,temp_array), axis = 1)
j = j + 1
#print('loop ran ' + str(j) + ' times')
return radius_list, center_coords
def image_creator(centers, radii, img_data, size):
x = np.arange(1, size, 1)
y = np.arange(1, size, 1)
for c in range(len(centers)):
x0 = centers[[c],[0]]
y0 = centers[[c],[1]]
radius = radii[c]
for i in range(0, size-1):
for j in range(0, size-1):
height2 = radius**2 - (x[i]-x0)**2 - (y[j]-y0)**2
if height2 >= 0:
img_data[[i], [j]] = sqrt(radius**2 - (x[i]-x0)**2 - (y[j]-y0)**2)
return img_data
def make_ellipses(size, radii, center_coords):
# idea: use a random number generator to create a random rotation of the x,y axes for the ellipse
# size is the length of a side of the square
# length is the length of the ellipse
# defined as equal to the radius of the circle later
my_label = np.ndarray(shape=(size, size))
x = np.arange(1, size, 1)
y = np.arange(1, size, 1)
# inefficiently zero the array
for i in range(0, size):
for j in range(0, size):
my_label[[i], [j]] = 0
# print(my_label)
for c in range(len(center_coords)):
x0 = center_coords[[c],[0]]
y0 = center_coords[[c],[1]]
#theta = random.uniform(0, 6.28318)
theta = 0.775
for i in range(0, size - 1):
for j in range(0, size - 1):
xprime = (x[i] - x0) * math.cos(theta) + (y[j] - y0) * math.sin(theta)
yprime = -(x[i] - x0) * math.sin(theta) + (y[j] - y0) * math.cos(theta)
height2 = (0.5 * radii[c]) ** 2 - 0.25 * xprime ** 2 - yprime ** 2
if height2 >= 0:
my_label[[i], [j]] = sqrt((0.5 * radii[c]) ** 2 - 0.25 * xprime ** 2 - yprime ** 2)
return my_label
size = 128
radii, centers = circle_randomizer()
#print(radii)
#print(centers)
#Make labels and samples consistent with rest of code
N = 100
circle_images = []
ellipse_images = []
coords = []
for sample in range(0, N):
blank_image = create_blank_image(size)
radii, centers = circle_randomizer()
temp_image = image_creator(centers, radii, blank_image, size)
circle_images.append(temp_image)
temp_output = make_ellipses(size, radii, centers)
ellipse_images.append(temp_output)
coords.append(centers)
#print(labels)
#print(samples[0][40])
#Storing the images in files:
filenames = []
for i in range(0,N):
np.save('ellipses_' + str(i) + '.npy', ellipse_images[i])
filenames.append('ellipses_' + str(i) + '.npy')
np.save('circles_' + str(i) + '.npy', circle_images[i])
circles_stack = np.stack(circle_images,axis=0)
ellipses_stack = np.stack(ellipse_images,axis=0)
np.save('ellipses_stack.npy', ellipses_stack)
np.save('circles_stack.npy', circles_stack)
#Loading the images:
# load training images and corresponding "labels"
# training samples
training_images_path = 'circles_stack.npy'
labels_path = 'ellipses_stack.npy'
X = np.load(training_images_path,'r')/20.
y = np.load(labels_path,'r')/20.
#Defining the image preprocessing functions:
#(I'm not sure why preprocessing_X and preprocessing_y are different; this is
#code I've partially adopted from a research paper.)
# Preprocessing for training images
def preprocessing_X(image_data, image_size):
image_data = image_data.reshape(image_data.shape[0], image_size[0], image_size[1], 1)
image_data = image_data.astype('float32')
image_data = (image_data - np.amin(image_data))/(np.amax(image_data) - np.amin(image_data))
return image_data
# preprocessing for "labels" (ground truth)
def preprocessing_Y(image_data, image_size):
n_images = 0
label = np.array([])
for idx in range(image_data.shape[0]):
img = image_data[idx,:,:]
n, m = img.shape
img = np.array(OneHotEncoder(n_values=nb_classes).fit_transform(img.reshape(-1,1)).todense())
img = img.reshape(n, m, nb_classes)
label = np.append(label, img)
n_images += 1
label_4D = label.reshape(n_images, image_size[0], image_size[1], nb_classes)
return label_4D
Preprocessing the images:
# Split into train/test and make the shapes of tensors compatible with tensorflow format
nb_classes = 10
target_size = (128, 128)
#Below line randomizes which images are picked for train/test sets. ~20% will go to test.
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state = 42)
X_train = preprocessing_X(X_train, target_size)
X_test = preprocessing_X(X_test, target_size)
y_train = preprocessing_Y(y_train, target_size)
y_test = preprocessing_Y(y_test, target_size)
#The encoder-decoder model that I'm using right now:
def model_shape(input_img, nb_classes = 2):
x = Convolution2D(2, (3, 3), activation='relu', padding='same')(input_img)
x = MaxPooling2D((2, 2), padding='same')(x)
x = Convolution2D(4, (3, 3), activation='relu', padding='same')(x)
x = MaxPooling2D((2, 2), padding='same')(x)
x = Convolution2D(4, (3, 3), activation='relu', padding='same')(x)
x = UpSampling2D((2, 2))(x)
x = Convolution2D(2, (3, 3), activation='relu', padding='same')(x)
x = UpSampling2D((2, 2))(x)
x = Convolution2D(nb_classes, (3, 3), activation = 'linear', padding='same')(x)
x = Convolution2D(nb_classes, (1, 1), activation = 'linear', padding='same')(x)
#x = Reshape((target_size[0] * target_size[1], nb_classes))(x)
output = Activation('softmax')(x)
return Model(input_img, output)
#Defining dice loss:
smooth = 1
def dice_coef(y_true, y_pred):
y_true_f = K.flatten(y_true)
y_pred_f = K.flatten(y_pred)
intersection = K.sum(y_true_f * y_pred_f)
return (2. * intersection + smooth) / (K.sum(y_true_f) + K.sum(y_pred_f) + smooth)
def dice_coef_loss(y_true, y_pred):
return -dice_coef(y_true, y_pred)
#Compiling the model:
nb_classes = 2
input_img = Input(shape=(target_size[0], target_size[1], 1))
model = model_shape(input_img)
model.compile(optimizer='adam', loss=dice_coef_loss, metrics = [dice_coef])
callback_tb = TensorBoard(log_dir='/tmp/Deconvoluter', histogram_freq=0,
write_graph=True, write_images=False)
model.fit(X_train, y_train, epochs=10, batch_size=32,
validation_data=(X_test, y_test))
model.save("/content/artificial_label_train.h5")
model.save_weights("/content/artificial_label_train_weights.h5")
print('Saved model and weights to disk.\n')
The code will compile up until this point, but returns an error after the following block of code:
# Loading models and obtaining softmax output (pixel-wise predictions)
def get_decoded_imgs(input_imgs, filepath, nb_channels = 2):
model = load_model(filepath)
decoded_imgs = model.predict(input_imgs)
decoded_imgs = decoded_imgs.reshape(input_imgs.shape[0], target_size[0], target_size[1], nb_channels)
print("FCN output obtained\n")
return decoded_imgs
decoded_imgs = get_decoded_imgs(X_test, '/content/artificial_label_train.h5')
Outputs = {}
for i in range(X_test.shape[0]):
decoded_img = decoded_imgs[i,:,:,1]
#dictionary = OrderedDict()
Outputs[i] = decoded_img
print('Plotting the results...\n')
plt.figure(figsize=(16, 8), dpi = 96)
for i in range(1, 5):
FCN_output = Outputs[i-1]
ax = plt.subplot(3, 5, i)
plt.imshow(output,cmap='gray')
print(FCN_output.shape)
plt.title('output {0}'.format(i), fontsize = 10)
ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)
plt.tight_layout()
print('output' + str(i) + '\n' + str(output))
print(np.max(y_test[i-1]),np.max(output))
plt.show()
The error is "Unknown loss function:dice_coef_loss" even though dice_coef_loss is clearly defined.
The input is supposed to be images of circles; the ground truth on which the neural network is trained is supposed to be images of ellipses.
The most recent encoder-decoder Keras model that I have used so far is shown in the code above; it returns ~55% val_dice_coeff, but this can probably be improved by adding more epochs. I used to use a simple CNN with mse loss which only returned lower-resolution images of the inputs.
What I am having problems with now is understanding why I am getting the error when I try to use model.predict() with dice loss as the loss function.
Related
I modified the code from here. What I'm trying to do is combine the two matrices to predict the output matrix. The output matrix is built from the two input matrices. The problem seems to be associated to:
self.Combined_dense_1 = tf.keras.layers.Dense(units=32, activation="relu")
self.Combined_dense_2 = tf.keras.layers.Dense(units=16, activation="softmax")
The linked medium tutorial only predicting a single number based on the combined mixed input. I however am trying to predict a whole matrix but don't know how to structure the combined layer (if this is even the problem).
The error: "ValueError: Shape mismatch: The shape of labels (received (40,)) should equal the shape of logits except for the last dimension (received (10, 16))."
The code:
import warnings
import sys
if not sys.warnoptions:
warnings.simplefilter("ignore")
import numpy as np
import os
import random
import tensorflow as tf
from tensorflow import keras
from IPython.display import clear_output
class model(keras.Model):
def __init__(self):
super().__init__()
# The layers to process our image
self.Conv2D_1 = tf.keras.layers.Conv2D(filters=32,
kernel_size=(1, 1),
strides=(1, 1)
)
self.Conv2D_2 = tf.keras.layers.Conv2D(filters=32,
kernel_size=(3, 3),
strides=(1, 1)
)
# our combined layers
self.Combined_dense_1 = tf.keras.layers.Dense(units=32, activation="relu")
self.Combined_dense_2 = tf.keras.layers.Dense(units=16, activation="softmax")
def call(self, input_image_one, input_image_two):
# Image model
I = self.Conv2D_1(input_image_one)
I = self.Conv2D_2(I)
# Flatten I so we can merge our data.
I = tf.keras.layers.Flatten()(I)
N = self.Conv2D_1(input_image_two)
N = self.Conv2D_2(N)
N = tf.keras.layers.Flatten()(N)
# Combined model
x = tf.concat([N, I], 1) # Concatenate through axis #1
x = self.Combined_dense_1(x)
x = self.Combined_dense_2(x)
return x
network = model()
optimizer = tf.keras.optimizers.Adam()
loss_function = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)
def train_step(model, optimizer, loss_function,
images_one_batch, images_two_batch,
labels):
with tf.GradientTape() as tape:
model_output = model(images_one_batch, images_two_batch)
print(model_output)
loss = loss_function(labels, model_output) # our labels vs our predictions
grads = tape.gradient(loss, model.trainable_variables)
optimizer.apply_gradients(zip(grads, model.trainable_variables))
return loss
def train(model, optimizer, loss_function, epochs,
images_one_batch, images_two_batch,
labels):
loss_array = []
for epoch in range(epochs):
loss = train_step(model, optimizer, loss_function, images_one_batch, images_two_batch, labels)
loss_array.append(loss)
if ((epoch + 1) % 20 == 0):
# Calculating accuracy
network_output = network(images_one_batch, images_two_batch)
preds = np.argmax(network_output, axis=1)
acc = 0
for i in range(len(images_one_batch)):
if (preds[i] == labels[i]):
acc += 1
print(" loss:", loss, " Accuracy: ", acc / len(images_one_batch) * 100, "%")
clear_output(wait=True)
NumberofVars = 2;
width= NumberofVars; height = NumberofVars
NumberOfComputationSets = 10
CM_MatrixArr1 = []
CM_MatrixArr2 = []
for j in range(NumberOfComputationSets):
Theta1 = list(np.reshape(np.random.randint(2, size=4), (1,4))[0])
Theta1 = list(np.float_(Theta1))
CM_MatrixArr1.append(Theta1)
Theta2 = list(np.reshape(np.random.randint(2, size=4), (1,4))[0])
Theta2 = list(np.float_(Theta2))
CM_MatrixArr2.append(Theta2)
combinedCM_MatrixArr = []
combinedCM_toIntArr = []
for x,y in zip(CM_MatrixArr1, CM_MatrixArr2):
combinedCM = []
combinedCM_toInt = 0
for a,b in zip(x,y):
LogVal = (a == b)
combinedCM.append(float(LogVal == True))
combinedCM_MatrixArr.append(combinedCM)
combinedCM_MatrixArr = np.array(combinedCM_MatrixArr)
combinedCM_MatrixArr = combinedCM_MatrixArr.reshape(NumberOfComputationSets,2,2)
CM_MatrixArr1 = np.array(CM_MatrixArr1)
CM_MatrixArr1 = CM_MatrixArr1.reshape(NumberOfComputationSets,2,2)
CM_MatrixArr1 = CM_MatrixArr1.reshape(NumberOfComputationSets, 2,2,1)
CM_MatrixArr2 = np.array(CM_MatrixArr2)
CM_MatrixArr2 = CM_MatrixArr2.reshape(NumberOfComputationSets,2,2)
CM_MatrixArr2 = CM_MatrixArr2.reshape(NumberOfComputationSets, 2,2,1)
train(network,optimizer,loss_function,300,CM_MatrixArr1,CM_MatrixArr2,combinedCM_MatrixArr)
import numpy as np
from keras.datasets import mnist
import time
# Functions
def sigmoid(x):
return 1.0/(1.0 + np.exp(-x))
def sigmoid_derivative(x):
return sigmoid(x)*(1-sigmoid(x))
def relu(x):
return np.maximum(0,x)
def relu_derivative(x):
return np.greater(x, 0).astype(int)
def softmax(x):
exps = np.exp(x - x.max())
return exps / np.sum(exps)
# Import and Create Dataset
(x_train, y_train), (x_test, y_test) = mnist.load_data()
# Setup
np.random.seed(seed=12345)
alpha = 0.05
# Initialize Network Values
# Layers
input_layer = np.zeros(shape=(28,28))
convolutional_layer = np.zeros(shape=(10,24,24))
pooling_layer = np.zeros(shape=(10,12,12))
flattened_layer = np.reshape(pooling_layer,newshape=(1440,1))
dense_layer = np.zeros(shape=(100,1))
output_layer = np.zeros(shape=(10,1))
# Filters and Weights
convolution_filters = np.random.rand(10,5,5)
weights1 = np.random.rand(100,1440)
weights2 = np.random.rand(10,100)
# Bias
dense_layer_bias = np.ones(shape=(100,1))
output_layer_bias = np.ones(shape=(10,1))
convolution_bias = np.ones(shape=(10,5,5))
for epoch in range(1):
print(np.mean(weights1),np.mean(weights2),np.mean(convolution_filters))
for sample in range(20):
# Get Input Data
input = x_train[sample]
# Target Data
target = np.zeros((10,1))
target[y_train[sample]][0] = 1
# Feed Forward Input to Convolution Layer
i=j=k=0
for i in range(10):
for j in range(24):
for k in range(24):
minimatrix = input[j:j+5, k:k+5]
convolutional_layer[i][j][k] = np.sum(minimatrix * convolution_filters[i] + convolution_bias[i])
# Pooling Layer
i=j=k=0
for i in range(10):
for j in range(12):
for k in range(12):
minimatrix = convolutional_layer[i,j*2:j*2+2,k*2:k*2+2]
pooling_layer[i][j][k] = relu(minimatrix.max())
# Flattening Layer
flattened_layer = np.reshape(pooling_layer,newshape=(1440,1))
# Feed Forward - DENSE_LAYER
dense_layer = relu(np.dot(weights1,flattened_layer) + dense_layer_bias)
# Feed Forward - OUTPUT_LAYER
output_layer = softmax(np.dot(weights2,dense_layer) + output_layer_bias)
# Backpropogation - OUTPUT_LAYER
delta = output_layer - target
weights2gradient = np.dot(delta,dense_layer.T)
output_layer_bias_gradient = delta
# Backpropogation - DENSE_LAYER
delta = np.dot(weights2.T,delta) * relu_derivative(dense_layer)
weights1gradient = np.dot(delta,flattened_layer.T)
dense_layer_bias_gradient = delta
# Backpropogation - POOLING_LAYER
delta = np.reshape(np.dot(weights1.T,delta),newshape=(10,12,12)) * relu_derivative(pooling_layer) # find delta at pooling layer
# Backpropagation - TRANSPOSE FOR CALCULATIONS
delta = np.array([delta[i].T for i in range(len(delta))]) # Math says this has to happen
# Gradient For Backward Pass
pooling_backward_pass = np.zeros(shape=(10,24,24)) # matrix for passing adjusted cost
# BACKWARD POOLING GRADIENT PASS
i=j=k=0
for i in range(10):
for j in range(12):
for k in range(12):
minimatrix = convolutional_layer[i,j*2:j*2+2,k*2:k*2+2]
maxvalindex = np.argmax(minimatrix)
pooling_backward_pass[i, j*2+(maxvalindex // 2), k+(maxvalindex % 2)] += delta[i,j,k]
# Backpropogation - CONVOLUTION LAYER
convolution_gradient = np.zeros(shape=(10,5,5))
convolution_bias_gradient = np.zeros(shape=(10,5,5))
i=j=k=0
for i in range(10):
for j in range(24):
for k in range(24):
minimatrix = input[j:j+5, k:k+5]
convolution_gradient[i] += pooling_backward_pass[i,j,k] * minimatrix
convolution_bias_gradient[i] += pooling_backward_pass[i,j,k]
# Weight and Filter Adjustments
weights2 -= weights2gradient * alpha
weights1 -= weights1gradient * alpha
convolution_filters -= convolution_gradient * alpha
# Bias Adjustments
dense_layer_bias -= dense_layer_bias_gradient * alpha
output_layer_bias -= output_layer_bias_gradient * alpha
convolution_bias -= convolution_gradient * alpha
print(np.mean(weights1),np.mean(weights2),np.mean(convolution_filters))
I have been working on this code for a while now and I am (almost) certain the basic functionality should work, but I am getting no changes to the weights of the network. I am specifically trying to understand neural networks without the abstraction offered by the actual frameworks. Is there a Python scope issue that is keeping the weights from updating?
I'm currently using a LSTM model to make timeserie predictions with Tensorflow 2.2.0
I've been using a large dataset and everything works nicely.
However, the dataset creation takes a lot of RAM and I wanted to use a tensorflow.keras.utils.Sequence to solve the issue, my problem is the following:
When using a Sequence, my model doesn't learn anymore (it predicts the average of the real signal over the whole dataset)
My dataset is created from two python lists x_train_flights and y_train_flights, each containing pandas DataFrames. For each (x_train_flight, y_train_flight) of this list:
x_train_flight of shape (-1, features) containing features signals
y_train_flight of shape (-1, 1) containing one signal being aligned in time with the ones from x_train_flights
The system looks like as follow (I am not allowed to share the real data, I've recreated the graph using pseudo-random signals instead):
Here, features=2 (the blue and orange lines), and look_back=5. That is to say, the 10 points (from x_train_flights) in the rectangle are used to predict the golden point (which is compared to the corresponding point in y_train_flights during the training phase). The gray points are previous predictions.
To create my dataset, I've been using these functions:
def lstm_shapify(sequence, look_back, features):
res = np.empty((look_back, len(sequence), features), dtype=np.float32)
for i in range(look_back):
res[i] = np.roll(sequence, -i * features)
return np.transpose(res, axes=(1, 0, 2))[:-look_back + 1]
def make_dataset(x_flights, y_flights, look_back, features):
x = np.empty((0, look_back, features), dtype=np.float32)
y = np.empty((0, 1), dtype=np.float32)
for i in range(len(x_flights)):
x_sample = x_flights[i].values
y_sample = y_flights[i].values[look_back - 1:]
x = np.concatenate([x, lstm_shapify(x_sample, look_back, features)])
y = np.concatenate([y, y_sample])
return x, y
And I fit my network with the following:
model.fit(
x_train,
y_train,
epochs=7,
batch_size=batch_size
)
So, I've created this custom Sequence:
class LSTMGenerator(Sequence):
def __init__(
self,
x_flights: List[DataFrame],
y_flights: List[DataFrame],
look_back: int,
batch_size: int,
features: int
):
self.x_flights = x_flights
self.y_flights = []
self.look_back = look_back
self.batch_size = batch_size
self.features = features
self.length = 0
for y_flight in y_flights:
y = y_flight.iloc[look_back - 1:].to_numpy()
self.y_flights.append(y)
self.length += len(y) // batch_size
def __getitem__(self, index):
flight_index = 0
while True:
n = len(self.y_flights[flight_index]) // self.batch_size
if index < n:
break
flight_index += 1
index = index - n
start_index = index * self.batch_size
x_batch = lstm_shapify(
self.x_flights[flight_index]
.iloc[start_index:start_index + self.batch_size + self.look_back - 1]
.to_numpy(),
self.look_back,
self.features
)
y_batch = self.y_flights[flight_index][start_index:start_index + self.batch_size]
return x_batch, y_batch
def __len__(self):
return self.length
Each tuple (x, y) it returns are two numpy arrays of shape (batch_size, look_back, features) and (batch_size, 1) respectively.
And now I'm trying to fit it with:
model.fit(
LSTMGenerator(x_train_flights, y_train_flights, look_back, batch_size, features),
epochs=epochs
)
Here is my model:
model = Sequential()
model.add(LSTM(
100,
input_shape=(look_back, features),
kernel_regularizer=regularizers.l2(1e-3),
bias_regularizer=regularizers.l2(1e-4)
))
model.add(Dropout(0.2))
model.add(BatchNormalization())
model.add(Dense(1, activation='tanh'))
model.compile(optimizer='adam', loss='mse')
Hope you can help me
EDIT: more details about the datasets
I solved it by taking a break and looking at the code once again (and I realized it was a silly mistake): the issue of my Sequence comes from the samples in each batch being consecutive samples in time, whereas my compute-everything-dataset's batches where nicely shuffled.
My Sequence was problematic because the batches were selected at a random index from a random dataset. Now I select each sample at a random index from a random dataset to create a single batch.
Here is a working example:
from tensorflow.keras import *
from tensorflow.keras.layers import *
from tensorflow.keras.utils import *
import numpy as np
import tensorflow as tf
np.random.seed(1234)
tf.random.set_seed(1234)
features = 3
lookback = 7
model = Sequential()
model.add(LSTM(500, input_shape = (lookback, features)))
model.add(Dense(1, activation='tanh'))
XS = np.random.randn(200, features)
YS = np.random.randn(200)
class LookbackSeq(Sequence):
def __init__(self, XS, YS, batch_size, lookback):
self.XS = XS
self.YS = YS
self.batch_size = batch_size
self.lookback = lookback
def __len__(self):
n_windows = self.XS.shape[0] - self.lookback
return int(np.ceil(n_windows / self.batch_size))
def __getitem__(self, i):
base = i * self.batch_size
n_windows = self.XS.shape[0] - self.lookback
batch_size = min(n_windows - base, self.batch_size)
X = np.zeros((batch_size, self.lookback, self.XS.shape[1]))
Y = np.zeros((batch_size, 1))
for i in range(batch_size):
for j in range(self.lookback):
X[i, j] = self.XS[base + i + j]
Y[i] = self.YS[base + i + self.lookback]
return X, Y
model.compile(optimizer='adam', loss='mse')
# ALL SAMPLES IN MEMORY
X, Y = [], []
for i in range(len(XS) - lookback):
X.append(XS[i:i+lookback])
Y.append(YS[i+lookback])
X, Y = np.array(X), np.array(Y)
model.fit(X, Y, epochs = 10, batch_size = 4, shuffle = False)
# GENERATED ON THE FLY
# gen = LookbackSeq(XS, YS, 4, lookback)
# model.fit(x = gen,
# steps_per_epoch = len(gen),
# shuffle = False,
# epochs = 10)
I'm assuming your input data has the shape X = (n_points, n_features) and Y = (n_points,). LookbackSeq does the batching and windowing (lookback) for you.
You can comment and uncomment the relevant lines to either train with samples generated on the fly or with them all stored in memory. You should get identical results.
This question already has answers here:
How do I create a variable-length input LSTM in Keras?
(4 answers)
Closed 5 years ago.
Despite going through multiple examples, I still don't understand how to classify sequences of varying length using Keras, similar to this question. I can train a network that detects frequencies of sinusoid with varying length, by using masking:
from keras import models
from keras.layers.recurrent import LSTM
from keras.layers import Dense, Masking
from keras.optimizers import RMSprop
from keras.losses import categorical_crossentropy
from keras.preprocessing.sequence import pad_sequences
import numpy as np
def gen_noise(noise_len, mag):
return np.random.uniform(size=noise_len) * mag
def gen_sin(t_val, freq):
return 2 * np.sin(2 * np.pi * t_val * freq)
def train_rnn(x_train, y_train, max_len, mask, number_of_categories):
epochs = 3
batch_size = 500
# three hidden layers of 256 each
vec_dims = 1
hidden_units = 256
in_shape = (max_len, vec_dims)
model = models.Sequential()
model.add(Masking(mask, name="in_layer", input_shape=in_shape,))
model.add(LSTM(hidden_units, return_sequences=False))
model.add(Dense(number_of_categories, input_shape=(number_of_categories,),
activation='softmax', name='output'))
model.compile(loss=categorical_crossentropy, optimizer=RMSprop())
model.fit(x_train, y_train, batch_size=batch_size, epochs=epochs,
validation_split=0.05)
return model
def gen_sig_cls_pair(freqs, t_stops, num_examples, noise_magnitude):
x = []
y = []
num_cat = len(freqs)
dt = 0.01
max_t = int(np.max(t_stops) / dt)
for f_i, f in enumerate(freqs):
for t_stop in t_stops:
t_range = np.arange(0, t_stop, dt)
t_len = t_range.size
for _ in range(num_examples):
sig = gen_sin(f, t_range) + gen_noise(t_len, noise_magnitude)
x.append(sig)
one_hot = np.zeros(num_cat, dtype=np.bool)
one_hot[f_i] = 1
y.append(one_hot)
pad_kwargs = dict(padding='post', maxlen=max_t, value=np.NaN, dtype=np.float32)
return pad_sequences(x, **pad_kwargs), np.array(y)
if __name__ == '__main__':
noise_mag = 0.01
mask_val = -10
frequencies = (5, 7, 10)
signal_lengths = (0.8, 0.9, 1)
x_in, y_in = gen_sig_cls_pair(frequencies, signal_lengths, 50, noise_mag)
mod = train_rnn(x_in[:, :, None], y_in, 100, mask_val, len(frequencies))
However, I don't understand how I'm supposed to tell Keras about the other sequences. I thought I could mask them too, but when I try, they just output NaN.
testing_dat, expected = gen_sig_cls_pair(frequencies, signal_lengths, 1, 0)
res = mod.predict(testing_dat[:, :, None])
fig, axes = plt.subplots(3)
axes[0].plot(np.concatenate(testing_dat), label="input")
axes[1].plot(np.argmax(res, axis=1), "ro", label="result", alpha=0.2)
axes[1].plot(np.argmax(expected, axis=1), "bo", label="expected", alpha=0.2)
axes[1].legend(bbox_to_anchor=(1.1, 1))
axes[2].plot(res)
plt.show()
How do I make a network that can evaluate inputs of varying lengths?
You can pad the input sequences (usually with zeros) or you can use batches of size 1 with varying input size, as outlined in fchollet's answer on the Keras github:
for seq, label in zip(sequences, y):
model.train(np.array([seq]), [label])
Alternatively, if your type of problem allows it, you extract subsequences of the original time series with length less than the length of the shortest sequences. The third option also allows you to add redundancy to the dataset if you have few samples, and reduce the chances of overfitting.
EDIT:
Seanny123 (OP) pointed out that fchollet's lines above contain model.train, which is not valid code.
He solved the problem using batches of size 1 and the following code:
from keras.models import Sequential
from keras.layers import LSTM, Dense
import numpy as np
def gen_sig(num_samples, seq_len):
one_indices = np.random.choice(a=num_samples, size=num_samples // 2, replace=False)
x_val = np.zeros((num_samples, seq_len), dtype=np.bool)
x_val[one_indices, 0] = 1
y_val = np.zeros(num_samples, dtype=np.bool)
y_val[one_indices] = 1
return x_val, y_val
N_train = 100
N_test = 10
recall_len = 20
X_train, y_train = gen_sig(N_train, recall_len)
X_test, y_test = gen_sig(N_train, recall_len)
print('Build STATEFUL model...')
model = Sequential()
model.add(LSTM(10, batch_input_shape=(1, 1, 1), return_sequences=False, stateful=True))
model.add(Dense(1, activation='sigmoid'))
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
print('Train...')
for epoch in range(15):
mean_tr_acc = []
mean_tr_loss = []
for seq_idx in range(X_train.shape[0]):
start_val = X_train[seq_idx, 0]
assert y_train[seq_idx] == start_val
assert tuple(np.nonzero(X_train[seq_idx, :]))[0].shape[0] == start_val
y_in = np.array([y_train[seq_idx]], dtype=np.bool)
for j in range(np.random.choice(a=np.arange(5, recall_len+1))):
x_in = np.array([[[X_train[seq_idx][j]]]])
tr_loss, tr_acc = model.train_on_batch(x_in, y_in)
mean_tr_acc.append(tr_acc)
mean_tr_loss.append(tr_loss)
model.reset_states()
print('accuracy training = {}'.format(np.mean(mean_tr_acc)))
print('loss training = {}'.format(np.mean(mean_tr_loss)))
print('___________________________________')
mean_te_acc = []
mean_te_loss = []
for seq_idx in range(X_test.shape[0]):
start_val = X_test[seq_idx, 0]
assert y_test[seq_idx] == start_val
assert tuple(np.nonzero(X_test[seq_idx, :]))[0].shape[0] == start_val
y_in = np.array([y_test[seq_idx]], dtype=np.bool)
for j in range(np.random.choice(a=np.arange(5, recall_len+1))):
te_loss, te_acc = model.test_on_batch(np.array([[[X_test[seq_idx][j]]]], dtype=np.bool), y_in)
mean_te_acc.append(te_acc)
mean_te_loss.append(te_loss)
model.reset_states()
print('accuracy testing = {}'.format(np.mean(mean_te_acc)))
print('loss testing = {}'.format(np.mean(mean_te_loss)))
print('___________________________________')
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import image
from keras.datasets import mnist
from keras.layers import Dense
from keras.models import Sequential
import os
from scipy.misc import imread, imresize
import skimage.io
import skimage.transform
from keras.layers.normalization import BatchNormalization
# Load Training Imgs from Folder
cwd_tr = os.getcwd()
path_tr = cwd_tr + "/Train400"
valid_exts = [".jpg",".gif",".png",".tga", ".jpeg"]
# print training imgs
print ("%d files in %s" % (len(os.listdir(path_tr)), path_tr))
# Append Training Images and their Names to Lists
imgs_tr = np.empty((400, 180, 180))
for f in range(1, 400):
imgs_tr[f] = image.imread(path_tr + "/test_%03d.png" % (f))
print ("%d images loaded" % (len(imgs_tr)))
# Load Test Imgs from Folder
cwd_tt = os.getcwd()
path_tt = cwd_tt + "/Train400"
# Print test imgs
print("%d files in %s" % (len(os.listdir(path_tt)), path_tt))
# Append Test Images and their Names to Lists
imgs_tt = np.empty((9, 180, 180))
for f in range(1, 9):
imgs_tt[f] = image.imread(path_tt + "/test_%03d.png" % (f))
print ("%d images loaded" % (len(imgs_tt)))
print("Type is %s" % (type(imgs_tt)))
# Data normalization and Reshape
x_train = imgs_tr
x_test = imgs_tt
x_train = np.reshape(x_train, (len(x_train), 32400))
x_test = np.reshape(x_test, (len(x_test), 32400))
patch_train = np.empty((len(x_train) * 400, 81))
patch_test = np.empty((len(x_test) * 400, 81))
# Making Patch
for m in range(1, len(x_train)):
for n in range(1, 400):
for p in range(1, 81):
patch_train[(m - 1) * (400) + n, p] = x_train[m, 81 * (n - 1) + p]
for m in range(1, len(x_test)):
for n in range(1, 400):
for p in range(1, 81):
patch_test[(m - 1) * (400) + n, p] = x_test[m, 81 * (n - 1) + p]
# Model
model = Sequential()
model.add(Dense(81, activation='relu', input_dim=81))
model.add(BatchNormalization())
model.add(Dense(81, activation='relu'))
model.add(BatchNormalization())
model.add(Dense(81, activation='relu'))
model.add(BatchNormalization())
model.add(Dense(81, activation='sigmoid'))
model.compile(optimizer='adam', loss='binary_crossentropy')
# Learning
model.fit(patch_train, patch_train,
nb_epoch=50,
batch_size=81,
shuffle=True,
validation_data=(patch_test, patch_test))
# Results
decoded_imgs = model.predict(patch_test)
recover_test = np.empty((len(x_test), 32400))
for k in range(1, len(x_test)):
for j in range(1, 400):
for l in range(1, 81):
recover_test[k, (j - 1) * 81 + l] = decoded_imgs[(k - 1) * 400 + j, l]
# Print 9 pics
n = 9
for i in range(1, n):
ax = plt.subplot(2, n, i)
plt.imshow(x_test[i].reshape(180, 180))
plt.gray()
ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)
# display reconstruction
ax = plt.subplot(2, n, i + n)
plt.imshow(recover_test[i].reshape(180, 180))
plt.gray()
ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)
plt.show()
enter image description here
Hello. I am making a code for neural-network reconstructing natural images. And I am trying to make it patch-based but it made dot-patterns that I don't want to get. I think I made some mistakes in making patches but failed to find what is wrong. So if anyone can find my faults, please help me.