TensorFlow image binary classifier not working efficiently after training - python

I am experimenting with a binary classifier on images whether it is a bee or not. I have gathered a dataset of 12,000 images of 6 categories, one of which is bees. So I have a column is_bee with values of "0" and "1" matching to "Not a bee" and "It is a bee". I am training the classifier and when I try to apply the trained model on any image, even one of the trained ones, it gives me (almost) exclusively value "0" with 73.11% confidence. My code is as follows:
import pandas as pd
import numpy as np
import sys
import os
import random
from pathlib import Path
import imageio
import skimage
import skimage.io
import skimage.transform
import matplotlib.pyplot as plt
import seaborn as sns
import scipy
from sklearn.model_selection import train_test_split
from sklearn import metrics
from keras import optimizers, losses
from keras.models import Sequential
from keras.layers import Dense, Conv2D, Flatten, MaxPool2D, Dropout, BatchNormalization,LeakyReLU
from keras.preprocessing.image import ImageDataGenerator
from keras.callbacks import ModelCheckpoint, Callback, EarlyStopping, ReduceLROnPlateau
from tensorflow.keras.utils import to_categorical
import tensorflow
np.random.seed(42)
tensorflow.random.set_seed(42)
# Global variables
imgs_folder='images/'
img_width=100
img_height=100
img_channels=3
def read_img(file):
img = skimage.io.imread(file)
img = skimage.transform.resize(img, (img_width, img_height), mode='reflect')
return img[:,:,:img_channels]
images=pd.read_csv('/content/gdrive/MyDrive/Colab Notebooks/beeID/images.csv',
index_col=False, sep=";",
dtype={'type':'category', 'is_bee':'category'})
images['file'] = imgs_folder+images['file']
# Cannot impute nans, drop them
images.dropna(inplace=True)
# Some image files don't exist. Leave only bees with available images.
img_exists = images['file'].apply(lambda f: os.path.exists(f))
images = images[img_exists]
images['type'] = images['type'].astype('category')
images['is_bee'] = images['is_bee'].astype('category')
def split_balance(df, field_name):
train_df, test_df = train_test_split(df, random_state=23)
train_df, val_df = train_test_split(train_df, test_size=0.1, random_state=23)
ncat_bal = int(len(train_df)/train_df[field_name].cat.categories.size)
train_df_bal = train_df.groupby(field_name, as_index=False).apply(lambda g: g.sample(ncat_bal, replace=True)).reset_index(drop=True)
return(train_df_bal, val_df, test_df)
def prepare2train(train_p2t_df, val_p2t_df, test_p2t_df, field_name):
# Train data
train_X = np.stack(train_p2t_df['file'].apply(read_img))
#train_y = to_categorical(train_bees[field_name].values)
train_y = pd.get_dummies(train_p2t_df[field_name], drop_first=False)
# Validation during training data to calc val_loss metric
val_X = np.stack(val_p2t_df['file'].apply(read_img))
#val_y = to_categorical(val_bees[field_name].values)
val_y = pd.get_dummies(val_p2t_df[field_name], drop_first=False)
# Test data
test_X = np.stack(test_p2t_df['file'].apply(read_img))
#test_y = to_categorical(test_bees[field_name].values)
test_y = pd.get_dummies(test_p2t_df[field_name], drop_first=False)
# Data augmentation
generator = ImageDataGenerator(
featurewise_center=False, # set input mean to 0 over the dataset
samplewise_center=False, # set each sample mean to 0
featurewise_std_normalization=False, # divide inputs by std of the dataset
samplewise_std_normalization=False, # divide each input by its std
zca_whitening=False, # apply ZCA whitening
rotation_range=180, # randomly rotate images in the range (degrees, 0 to 180)
zoom_range=0.1, # Randomly zoom image
width_shift_range=0.2, # randomly shift images horizontally (fraction of total width)
height_shift_range=0.2, # randomly shift images vertically (fraction of total height)
horizontal_flip=True, # randomly flip images
vertical_flip=True)
generator.fit(train_X)
return (generator, train_X, val_X, test_X, train_y, val_y, test_y)
def eval_model(training, model, test_X, test_y, field_name):
## Trained model analysis and evaluation
f, ax = plt.subplots(2,1, figsize=(5,5))
ax[0].plot(training.history['loss'], label="Loss")
ax[0].plot(training.history['val_loss'], label="Validation loss")
ax[0].set_title('%s: loss' % field_name)
ax[0].set_xlabel('Epoch')
ax[0].set_ylabel('Loss')
ax[0].legend()
# Accuracy
ax[1].plot(training.history['accuracy'], label="Accuracy")
ax[1].plot(training.history['val_accuracy'], label="Validation accuracy")
ax[1].set_title('%s: accuracy' % field_name)
ax[1].set_xlabel('Epoch')
ax[1].set_ylabel('Accuracy')
ax[1].legend()
plt.tight_layout()
plt.show()
# Accuracy by subspecies
test_pred = model.predict(test_X)
acc_by_subspecies = np.logical_and((test_pred > 0.5), test_y).sum()/test_y.sum()
acc_by_subspecies.plot(kind='bar', title='Accuracy by %s' % field_name)
plt.ylabel('Accuracy')
plt.show()
# Print metrics
print("Classification report")
test_pred = np.argmax(test_pred, axis=1)
test_truth = np.argmax(test_y.values, axis=1)
# Loss function and accuracy
test_res = model.evaluate(test_X, test_y.values, verbose=1)
# Split/balance and plot the result
train_bees_bal, val_bees, test_bees = split_balance(bees, 'health')
# Split/balance and plot the result
train_images_bal, val_images, test_images = split_balance(images, 'type')
# Will use balanced dataset as main
train_images = train_images_bal
generator_images, train_images_X, val_images_X, test_images_X, train_images_y, val_images_y, test_images_y = prepare2train(train_images, val_images, test_images, 'is_bee')
# We'll stop training if no improvement after some epochs
earlystopper_images = EarlyStopping(monitor='val_accuracy', patience=20, verbose=1)
# Save the best model during the training
checkpointer_images = ModelCheckpoint('model_images.h5'
,monitor='val_accuracy'
,verbose=1
,save_best_only=True
,save_weights_only=True)
# Build CNN model
model_images=Sequential()
model_images.add(Conv2D(5, kernel_size=3, input_shape=(img_width, img_height,3), activation='relu', padding='same'))
model_images.add(MaxPool2D(2))
model_images.add(Conv2D(10, kernel_size=3, activation='relu', padding='same'))
model_images.add(Dropout(0.25))
model_images.add(Flatten())
model_images.add(Dropout(0.5))
model_images.add(Dense(train_images_y.columns.size, activation='sigmoid', name='preds'))
# show model summary
model_images.summary()
model_images.compile(loss=losses.binary_crossentropy,optimizer='adam',metrics=['accuracy'])
# Train
training_images = model_images.fit_generator(generator_images.flow(train_images_X,train_images_y, batch_size=60)
,epochs=100
,validation_data=(val_images_X, val_images_y)
,steps_per_epoch=10
,callbacks=[earlystopper_images, checkpointer_images])
# Get the best saved weights
model_images.load_weights('model_images.h5')
eval_model(training_images, model_images, test_images_X, test_images_y, 'is_bee')
scores = model_images.evaluate(test_images_X, test_images_y, verbose=0)
print("Accuracy: %.2f%%" % (scores[1]*100))
import numpy as np
from google.colab import files
from keras.preprocessing import image
for fn in os.listdir('/content/bee_imgs'):
# predicting images
path = '/content/bee_imgs/' + fn
img = image.load_img(path, target_size=(100, 100))
x = image.img_to_array(img)
x = np.expand_dims(x, axis=0)
checkImages = np.vstack([x])
classes_images = model_images.predict(checkImages)
score = tensorflow.nn.softmax(classes_images[0])
print(
"This image {} most likely belongs to {} with a {:.2f} percent confidence."
.format(fn, test_images_y.columns[np.argmax(score)], 100 * np.max(score))
)
The result of the above testing on already trained images (but also occurs when I try it with non trained images) is this:
This image 016_252.png most likely belongs to 0 with a 73.11 percent confidence.
This image 031_117.png most likely belongs to 0 with a 73.11 percent confidence.
This image 019_1026.png most likely belongs to 0 with a 73.11 percent confidence.
This image 008_243.png most likely belongs to 1 with a 73.11 percent confidence.
...
This image 039_016.png most likely belongs to 0 with a 73.11 percent confidence.
This image 022_364.png most likely belongs to 0 with a 73.11 percent confidence.
This image 022_274.png most likely belongs to 0 with a 73.11 percent confidence.
So, despite the fact that the model's accuracy has reached 96% in predicting whether an image is a bee or not, when I apply it on any image of a bee it seldom recognizes it as a bee. Is there something wrong with my model building or when I am trying to apply it?

After removing the softmax function and np.argmax, you should just use the same read_img function that was used during training for predictions and it should be fine.

Related

How to display Predictive model graph on Django framework?

I've made a predictive model using LSTM which predicts future prices for raw materials like cotton,fibre,yarn etc. At the end of code I used matplotlib library to plot graph which displays the original prices, predicted prices and future predicted prices.
This is the graph which shows future prices according to dates
How do I display this graph on Django framework? Because I need to deploy this model on a web application using Django but the tutorials I've seen so far show predictive models which take user input and don't really show anything related to plots or graphs.
Following is the code:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import datetime as dt
from datetime import datetime
import warnings
warnings.simplefilter(action='ignore', category=FutureWarning)
from keras.callbacks import EarlyStopping, ReduceLROnPlateau, ModelCheckpoint, TensorBoard
import os
import glob
import pandas
import numpy
from sklearn import preprocessing
import numpy as np
# Importing Training Set
dataset_train = pd.read_csv('201222-yarn-market-price-china--034.csv1.csv')
dataset_train.info()
# Select features (columns) to be involved intro training and predictions
cols = list(dataset_train)[1:5]
# Extract dates (will be used in visualization)
datelist_train = list(dataset_train.iloc[0])
datelist_train = [dt.datetime.strptime(date, '%m/%d/%Y').date() for date in datelist_train]
print('Training set shape == {}'.format(dataset_train.shape))
print('All timestamps == {}'.format(len(datelist_train)))
print('Featured selected: {}'.format(cols))
dataset_train = dataset_train[cols].astype(str)
for i in cols:
for j in range(0, len(dataset_train)):
dataset_train[i][j] = dataset_train[i][j].replace(',', '')
dataset_train = dataset_train.astype(float)
# Using multiple features (predictors)
training_set = dataset_train.values
print('Shape of training set == {}.'.format(training_set.shape))
training_set
# Feature Scaling
from sklearn.preprocessing import StandardScaler
sc = StandardScaler()
training_set_scaled = sc.fit_transform(training_set)
sc_predict = StandardScaler()
sc_predict.fit_transform(training_set[:, 0:1])
# Creating a data structure with 90 timestamps and 1 output
X_train = []
y_train = []
n_future = 60 # Number of days we want top predict into the future
n_past = 90 # Number of past days we want to use to predict the future
for i in range(n_past, len(training_set_scaled) - n_future +1):
X_train.append(training_set_scaled[i - n_past:i, 0:dataset_train.shape[1] - 1])
y_train.append(training_set_scaled[i + n_future - 1:i + n_future, 0])
X_train, y_train = np.array(X_train), np.array(y_train)
print('X_train shape == {}.'.format(X_train.shape))
print('y_train shape == {}.'.format(y_train.shape))
# Import Libraries and packages from Keras
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import LSTM
from keras.layers import Dropout
from tensorflow.keras.optimizers import Adam
# Initializing the Neural Network based on LSTM
model = Sequential()
# Adding 1st LSTM layer
model.add(LSTM(units=64, return_sequences=True, input_shape=(n_past, dataset_train.shape[1]-1)))
# Adding 2nd LSTM layer
model.add(LSTM(units=10, return_sequences=False))
# Adding Dropout
model.add(Dropout(0.25))
# Output layer
model.add(Dense(units=1, activation='linear'))
# Compiling the Neural Network
model.compile(optimizer = Adam(learning_rate=0.01), loss='mean_squared_error')
es = EarlyStopping(monitor='val_loss', min_delta=1e-10, patience=10, verbose=1)
rlr = ReduceLROnPlateau(monitor='val_loss', factor=0.5, patience=10, verbose=1)
mcp = ModelCheckpoint(filepath='weights.h5', monitor='val_loss', verbose=1,
save_best_only=True, save_weights_only=True)
tb = TensorBoard('logs')
history = model.fit(X_train, y_train, shuffle=True, epochs=30, callbacks=[es, rlr, mcp, tb],
validation_split=0.2, verbose=1, batch_size=256)
# Generate list of sequence of days for predictions
datelist_future = pd.date_range(datelist_train[-1], periods=n_future, freq='1d').tolist()
'''
Remeber, we have datelist_train from begining.
'''
# Convert Pandas Timestamp to Datetime object (for transformation) --> FUTURE
datelist_future_ = []
for this_timestamp in datelist_future:
datelist_future_.append(this_timestamp.date())
# Perform predictions
predictions_future = model.predict(X_train[-n_future:])
predictions_train = model.predict(X_train[n_past:])
# Inverse the predictions to original measurements
# ---> Special function: convert <datetime.date> to <Timestamp>
def datetime_to_timestamp(x):
'''
x : a given datetime value (datetime.date)
'''
return datetime.strptime(x.strftime('%m%d%Y'), '%m%d%Y')
y_pred_future = sc_predict.inverse_transform(predictions_future)
y_pred_train = sc_predict.inverse_transform(predictions_train)
a=dataset_train.iloc[:, 3]
print(a)
PREDICTIONS_FUTURE = pd.DataFrame(y_pred_future, columns=['Cotton
Yarn1']).set_index(pd.Series(datelist_future))
PREDICTION_TRAIN = pd.DataFrame(y_pred_train, columns=['Cotton
Yarn1']).set_index(pd.Series(datelist_train[2 * n_past + n_future -1:]))
# Convert <datetime.date> to <Timestamp> for PREDCITION_TRAIN
PREDICTION_TRAIN.index = PREDICTION_TRAIN.index.to_series().apply(datetime_to_timestamp)
print(PREDICTION_TRAIN.head(3))
#plt.rcParams["figure.figsize"] = (20,3)
#rcParams['figure.figsize'] = 14, 5
# Plot parameters
START_DATE_FOR_PLOTTING = '12/24/2019'
dataset_train = pd.DataFrame(dataset_train, columns=cols)
dataset_train.index = datelist_train
dataset_train.index = pd.to_datetime(dataset_train.index)
plt.plot(PREDICTIONS_FUTURE.index, PREDICTIONS_FUTURE['Cotton Yarn1'], color='r',
label='Predicted Stock Price')
plt.plot(PREDICTION_TRAIN.loc[START_DATE_FOR_PLOTTING:].index,
PREDICTION_TRAIN.loc[START_DATE_FOR_PLOTTING:]['Cotton Yarn1'], color='orange',
label='Training predictions')
plt.plot(dataset_train.loc[START_DATE_FOR_PLOTTING:].index,
dataset_train.loc[START_DATE_FOR_PLOTTING:]['Cotton Yarn1'], color='b', label='Actual Stock
Price')
plt.axvline(x = min(PREDICTIONS_FUTURE.index), color='green', linewidth=2, linestyle='--')
plt.grid(which='major', color='#cccccc', alpha=0.5)
plt.legend(shadow=True)
plt.title('Predcitions and Acutal Stock Prices', family='Arial', fontsize=12)
plt.xlabel('Timeline', family='Arial', fontsize=10)
plt.ylabel('Stock Price Value', family='Arial', fontsize=10)
plt.xticks(rotation=45, fontsize=8)
plt.show()

How to extend a binary transfer learning model with Pytorch to multiple image categories?

I'm working with some code that classifies the infamous dog vs cat image classification using a ResNet-18 model and I'd like to extend it to be able to classify for greater than two image categories (like dog vs cat vs hamster vs ....). In particular I've got 5 categories. I'm new at transfer learning and I'm not sure what I have to change in my code to make this work.
import torch
import numpy as np
import torch.nn.functional as F
from torch.nn import Linear
from torch.utils.data import DataLoader, random_split
from torch.optim import Adam
from torchvision.transforms import Compose, Resize, ToTensor
from torchvision.datasets import ImageFolder
from torchvision.models import resnet18
from matplotlib import pyplot as plt
import random
transform = Compose([Resize((128,128)), ToTensor()])
ds = ImageFolder("*Image_Folder*", transform=transform)
ds_train, ds_val = random_split(ds, [3250, 1073])
dl_train = DataLoader(ds_train, batch_size= 32, shuffle=True)
dl_val = DataLoader(ds_val, batch_size= len(ds_val), shuffle= True)
model = resnet18(pretrained=True)
model.requires_grad_(False)
model.fc = Linear(model.fc.in_features, 5)
X_val, y_val = next(dl_val.__iter__())
opt = torch.optim.Adam(model.parameters(), lr=0.001)
def accuracy(yy, y):
return torch.mean(1.0*(yy == y))
X_val.shape, y_val.shape
y_val = y_val.reshape(-1, 1).float()
for epoch in range(10):
losses = []
accs = []
losses_val = []
accs_val = []
model.train()
for X, y in dl_train:
y = y.reshape(-1, 1).float()
yy = torch.sigmoid(model(X))
loss = F.binary_cross_entropy(yy, y)
losses.append(loss.item())
loss.backward()
opt.step()
opt.zero_grad()
acc = accuracy(torch.round(yy), y)
accs.append(acc.item())
model.eval()
with torch.no_grad():
yy_val = torch.sigmoid(model(X_val))
loss_val = F.binary_cross_entropy(yy_val, y_val)
losses_val.append(loss_val.item())
acc_val = accuracy(torch.round(yy_val), y_val)
accs_val.append(acc_val.item())
print(f"Epoch {epoch}: t-loss = {np.mean(losses):.4f}, t-acc = {np.mean(accs):.4f}, v-loss = {loss_val:.4f}, v-acc = {acc_val:.4f}")
I believe the code is fine up to the for loop, however it could be something I need to add or alter. Currently the line loss = F.binary_cross_entropy(yy, y) is what's giving me an error ValueError: Using a target size (torch.Size([32, 1])) that is different to the input size (torch.Size([32, 5])) is deprecated. Please ensure they have the same size.
This is the data I'm working from: https://www.kaggle.com/alxmamaev/flowers-recognition
Binary Cross Entropy is a loss function designed for binary classification tasks.
In order to convert this model into one capable of 5-class classification, in addition to changing the final layer's width to 5, you need to change the loss function to a multinomial scorer e.g. CrossEntropyLoss().

Unexpected results when using tfrecords loaded using tf.data.Dataset.list_files() with shuffle argument

I'm hoping to get clarification on how the shuffle argument in tf.data.Dataset.list_files() works. The documentation states that when shuffle=True, the filenames will be shuffled randomly. I've made model predictions using a tfrecords dataset that has been loaded using tf.data.Dataset.list_files(), and I would've expected the accuracy metric to be the same no matter the order of the files (i.e. whether shuffle is True or False), but am seeing otherwise.
Is this expected behavior or is there something wrong with my code or intepretation? I have reproducible example code below.
Oddly, as long as tf.random.set_random_seed() is set initially (and it seems it doesn't even matter what seed value is set), then the predictions results are the same no matter whether shuffle is True or False in list_files().
tensorflow==1.13.1, keras==2.2.4
Thanks for any clarifications!
Edit: re-thinking it through and wondering if Y = [y[0] for _ in range(steps) for y in sess.run(Y)] is a separate and independent call?
# Fit and Save a Dummy Model
import numpy as np
import tensorflow as tf
from keras.models import Sequential
from keras.layers import Dense
from keras.utils import np_utils
from sklearn import datasets, metrics
seed = 7
np.random.seed(seed)
tf.random.set_random_seed(seed)
dataset = datasets.load_iris()
X = dataset.data
Y = dataset.target
dummy_Y = np_utils.to_categorical(Y)
# 150 rows
print(len(X))
model = Sequential()
model.add(Dense(8, input_dim=4, activation='relu'))
model.add(Dense(3, activation='softmax'))
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
model.fit(X, dummy_Y, epochs=10, batch_size=10, verbose=2)
model.save('./iris/iris_model')
predictions = model.predict(X)
predictions = np.argmax(predictions, axis=1)
# returns accuracy = 0.3466666666666667
print(metrics.accuracy_score(y_true=Y, y_pred=predictions))
Split dataset into multiple tfrecords files so we can reload it with list_files() later:
numrows = 15
for i, j in enumerate(range(0, len(X), numrows)):
with tf.python_io.TFRecordWriter('./iris/iris{}.tfrecord'.format(i)) as writer:
for x, y in zip(X[j:j+numrows, ], Y[j:j+numrows, ]):
features = tf.train.Features(feature=
{'X': tf.train.Feature(float_list=tf.train.FloatList(value=x)),
'Y': tf.train.Feature(int64_list=tf.train.Int64List(value=[y]))
})
example = tf.train.Example(features=features)
writer.write(example.SerializeToString())
At this point, I exit (ipython) and restart again:
import numpy as np
import tensorflow as tf
from keras.models import load_model
from sklearn import metrics
model = load_model('./iris/iris_model')
batch_size = 10
steps = int(150/batch_size)
file_pattern = './iris/iris*.tfrecord'
feature_description = {
'X': tf.FixedLenFeature([4], tf.float32),
'Y': tf.FixedLenFeature([1], tf.int64)
}
def _parse_function(example_proto):
return tf.parse_single_example(example_proto, feature_description)
def load_data(filenames, batch_size):
raw_dataset = tf.data.TFRecordDataset(filenames)
dataset = raw_dataset.map(_parse_function)
dataset = dataset.batch(batch_size, drop_remainder=True)
dataset = dataset.prefetch(2)
iterator = dataset.make_one_shot_iterator()
record = iterator.get_next()
return record['X'], record['Y']
def get_predictions_accuracy(filenames):
X, Y = load_data(filenames=filenames, batch_size=batch_size)
predictions = model.predict([X], steps=steps)
predictions = np.argmax(predictions, axis=1)
print(len(predictions))
with tf.Session() as sess:
Y = [y[0] for _ in range(steps) for y in sess.run(Y)]
print(metrics.accuracy_score(y_true=Y, y_pred=predictions))
# No shuffle results:
# Returns expected accuracy = 0.3466666666666667
filenames_noshuffle = tf.data.Dataset.list_files(file_pattern=file_pattern, shuffle=False)
get_predictions_accuracy(filenames_noshuffle)
# Shuffle results, no seed value set:
# Returns UNEXPECTED accuracy (non-deterministic value)
filenames_shuffle_noseed = tf.data.Dataset.list_files(file_pattern=file_pattern, shuffle=True)
get_predictions_accuracy(filenames_shuffle_noseed)
# Shuffle results, seed value set:
# Returns expected accuracy = 0.3466666666666667
# It seems like it doesn't even matter what seed value you set, as long as you you set it
seed = 1000
tf.random.set_random_seed(seed)
filenames_shuffle_seed = tf.data.Dataset.list_files(file_pattern=file_pattern, shuffle=True)
get_predictions_accuracy(filenames_shuffle_seed)

How do I visualize the predicted and training data with time series data from a keras-built LSTM model?

I've been putting together a sample LSTM loosely based on this tutorial:
https://machinelearningmastery.com/multivariate-time-series-forecasting-lstms-keras/
However, the tutorial does not visualize the actual datapoints, only the error. Here is all of my data and then what happens when I try to put the training and predicted data on the same plot:
Plot1
Plot2
The second is simply made with:
plt.plot(yhat)
plt.plot(test_y)
plt.plot(train_y)
I know it is due to the normalization of the data but I'm not exactly sure if there is a way to get back to something like my first graph except with the predicted rather than historical data. Is there a way to use the time-stamp independent variable I had before changing it all up to run the model? Ideally I would visualize the values over time from training to prediction.
(I'm also trying to figure out how to predict beyond the training set with LSTM but that's a very different topic!)
Full code here:
from math import sqrt
import numpy as np
from numpy import concatenate
from matplotlib import pyplot
import pandas as pd
from pandas import read_csv
from pandas import DataFrame
from pandas import concat
from sklearn.preprocessing import MinMaxScaler
from sklearn.preprocessing import LabelEncoder
from sklearn.metrics import mean_squared_error
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import LSTM
# convert series to supervised learning
def series_to_supervised(data, n_in=1, n_out=1, dropnan=True):
n_vars = 1 if type(data) is list else data.shape[1]
df = DataFrame(data)
cols, names = list(), list()
# input sequence (t-n, ... t-1)
for i in range(n_in, 0, -1):
cols.append(df.shift(i))
names += [('var%d(t-%d)' % (j+1, i)) for j in range(n_vars)]
# forecast sequence (t, t+1, ... t+n)
for i in range(0, n_out):
cols.append(df.shift(-i))
if i == 0:
names += [('var%d(t)' % (j+1)) for j in range(n_vars)]
else:
names += [('var%d(t+%d)' % (j+1, i)) for j in range(n_vars)]
# put it all together
agg = concat(cols, axis=1)
agg.columns = names
# drop rows with NaN values
if dropnan:
agg.dropna(inplace=True)
return agg
# load dataset
dataset = read_csv('weeklyTrends-growthUnderlying.csv', header=0, index_col=0)
values = dataset.values
# ensure all data is float
values = values.astype('float32')
# normalize features
scaler = MinMaxScaler(feature_range=(0, 1))
scaled = scaler.fit_transform(values)
# frame as supervised learning
reframed = series_to_supervised(scaled, 1, 1)
print(reframed.head())
# Visualize/plot data
%matplotlib inline
import matplotlib.pyplot as plt
# x = dataset['timestamp'].values
y = dataset['value'].values
plt.plot(y)
plt.show()
# split into train and test sets
# 26,207 observations
values = reframed.values
n_train = 13000
train = values[:n_train, :]
test = values[n_train:, :]
# split into input and outputs
train_X, train_y = train[:, :-1], train[:, -1]
test_X, test_y = test[:, :-1], test[:, -1]
# reshape input to be 3D [samples, timesteps, features]
train_X = train_X.reshape((train_X.shape[0], 1, train_X.shape[1]))
test_X = test_X.reshape((test_X.shape[0], 1, test_X.shape[1]))
print(train_X.shape, train_y.shape, test_X.shape, test_y.shape)
# design network
model = Sequential()
model.add(LSTM(32, return_sequences=True, input_shape=(train_X.shape[1], train_X.shape[2])))
model.add(LSTM(32))
model.add(Dense(1))
model.compile(loss='mae', optimizer='adam')
# fit network
history = model.fit(train_X, train_y, epochs=5, batch_size=72, validation_data=(test_X, test_y), verbose=2, shuffle=False)
# plot history
pyplot.plot(history.history['loss'], label='train')
pyplot.plot(history.history['val_loss'], label='test')
pyplot.legend()
pyplot.show()
# make a prediction
# change predict from (train_X) to range of test and future data
yhat = model.predict(test_X)
test_X = test_X.reshape((test_X.shape[0], test_X.shape[2]))
plt.plot(yhat)
plt.plot(test_y)
plt.plot(train_y)
# invert scaling for forecast
inv_yhat = concatenate((yhat, test_X[:, 1:]), axis=1)
inv_yhat = scaler.inverse_transform(inv_yhat)
inv_yhat = inv_yhat[:,0]
# invert scaling for actual
test_y = test_y.reshape((len(test_y), 1))
inv_y = concatenate((test_y, test_X[:, 1:]), axis=1)
inv_y = scaler.inverse_transform(inv_y)
inv_y = inv_y[:,0]
# calculate RMSE
rmse = sqrt(mean_squared_error(inv_y, inv_yhat))
print('Test RMSE: %.3f' % rmse)
model.summary()

Keras Image classifier for CoreML image input asks MultiArray instead of Image

I'm new to machine learning and I built my first neural network using help of code and guidance from https://www.pyimagesearch.com/2017/12/11/image-classification-with-keras-and-deep-learning
Now, when I try to convert the model generated by this network, it asks me MultiArray input instead of image input like other models that Apple has introduced.
Where 'am I losing the track?
My training code is below:
# USAGE
# python train_network.py --dataset images --model santa_not_santa.model
# set the matplotlib backend so figures can be saved in the background
import matplotlib
matplotlib.use("Agg")
# import the necessary packages
from keras.preprocessing.image import ImageDataGenerator
from keras.optimizers import Adam
from sklearn.model_selection import train_test_split
from keras.preprocessing.image import img_to_array
from keras.utils import to_categorical
from pyimagesearch.lenet import LeNet
from imutils import paths
import matplotlib.pyplot as plt
import numpy as np
import argparse
import random
import cv2
import os
# construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-d", "--dataset", required=True,
help="path to input dataset")
ap.add_argument("-m", "--model", required=True,
help="path to output model")
ap.add_argument("-p", "--plot", type=str, default="peacock.png",
help="path to output loss/accuracy plot")
args = vars(ap.parse_args())
# initialize the number of epochs to train for, initia learning rate,
# and batch size
EPOCHS = 25
INIT_LR = 1e-3
BS = 32
# initialize the data and labels
print("[INFO] loading images...")
data = []
labels = []
# grab the image paths and randomly shuffle them
imagePaths = sorted(list(paths.list_images(args["dataset"])))
random.seed(42)
random.shuffle(imagePaths)
# loop over the input images
for imagePath in imagePaths:
# load the image, pre-process it, and store it in the data list
image = cv2.imread(imagePath)
image = cv2.resize(image, (28, 28))
image = img_to_array(image)
data.append(image)
# extract the class label from the image path and update the
# labels list
label = imagePath.split(os.path.sep)[-2]
label = 1 if label == "santa" else 0
labels.append(label)
# scale the raw pixel intensities to the range [0, 1]
data = np.array(data, dtype="float") / 255.0
labels = np.array(labels)
# partition the data into training and testing splits using 75% of
# the data for training and the remaining 25% for testing
(trainX, testX, trainY, testY) = train_test_split(data,
labels, test_size=0.25, random_state=42)
# convert the labels from integers to vectors
trainY = to_categorical(trainY, num_classes=2)
testY = to_categorical(testY, num_classes=2)
# construct the image generator for data augmentation
aug = ImageDataGenerator(rotation_range=30, width_shift_range=0.1,
height_shift_range=0.1, shear_range=0.2, zoom_range=0.2,
horizontal_flip=True, fill_mode="nearest")
# initialize the model
print("[INFO] compiling model...")
model = LeNet.build(width=28, height=28, depth=3, classes=2)
opt = Adam(lr=INIT_LR, decay=INIT_LR / EPOCHS)
model.compile(loss="binary_crossentropy", optimizer=opt,
metrics=["accuracy"])
# train the network
print("[INFO] training network...")
H = model.fit_generator(aug.flow(trainX, trainY, batch_size=BS),
validation_data=(testX, testY), steps_per_epoch=len(trainX) // BS,
epochs=EPOCHS, verbose=1)
# save the model to disk
print("[INFO] serializing network...")
model.save(args["model"])
import coremltools
# coremll = coremltools.converters.keras.convert(args["model"], output_names='bool',image_input_names='camera frame', is_bgr= True)
coremll = coremltools.converters.keras.convert('/home/tarak/Documents/keras_image_classifier/peacocknopeacock.model', image_input_names='camera', is_bgr= True, output_names='Output_names')
# coremll.input_description['camera frame'] = 'A 28x28 pixel Image'
# coremll.output_description['bool'] = 'A one-hot Multiarray were the index with the biggest float value (0-1) is the recognized digit. '
coremll.save('peacocknotpeacok.mlmodel')
print('MLmodel converted')
# plot the training loss and accuracy
plt.style.use("ggplot")
plt.figure()
N = EPOCHS
plt.plot(np.arange(0, N), H.history["loss"], label="train_loss")
plt.plot(np.arange(0, N), H.history["val_loss"], label="val_loss")
plt.plot(np.arange(0, N), H.history["acc"], label="train_acc")
plt.plot(np.arange(0, N), H.history["val_acc"], label="val_acc")
plt.title("Training Loss and Accuracy on Peacock/Not Peacock")
plt.xlabel("Epoch #")
plt.ylabel("Loss/Accuracy")
plt.legend(loc="lower left")
plt.savefig(args["plot"])
When converting your model to Core ML you also need to add input_names='camera frame' when you call coremltools.converters.keras.convert(), in addition to image_input_names='camera frame'. Otherwise coremltools won't see this input and doesn't know you want to treat it as an image.

Categories

Resources