Call `model.predict()` from an externally attached function - python

Using this as reference, I came up with the code below:
import tensorflow as tf
from tensorflow.keras.applications.densenet import DenseNet121
from tensorflow.keras.applications.densenet import preprocess_input as densenet_preprocess_input
import inspect, cv2
import numpy as np
#tf.function(input_signature=[tf.TensorSpec([None, None, 3],dtype=tf.uint8)])
def _preprocess(image_array):
im_arr = tf.image.resize(image_array, (resize_height, resize_width))
im_arr = densenet_preprocess_input(im_arr)
input_batch = tf.expand_dims(im_arr, axis=0)
return input_batch
training_model = DenseNet121(include_top=True, weights='imagenet')
#Assign resize dimensions
resize_height = tf.constant(480, dtype=tf.int64)
resize_width = tf.constant(640, dtype=tf.int64)
#Attach function to Model
training_model.preprocess = _preprocess
#Attach resize dimensions to Model
training_model.resize_height = resize_height
training_model.resize_width = resize_width
training_model.save("saved_model", overwrite=True)
which basically attaches an method called preprocess, to tf.keras.Model defined for DenseNet121.
So that later I can use it as follows to make a prediction:
pred_model = tf.keras.models.load_model('saved_model')
#download image
image_path = tf.keras.utils.get_file("cat.jpg", "https://storage.googleapis.com/download.tensorflow.org/example_images/320px-Felis_catus-cat_on_snow.jpg")
#load and convert the image to tf.uint8 numpy array
image_array = np.array(tf.keras.preprocessing.image.load_img(path=image_path))
#call the custom function bound to the model
preprocessed_image = pred_model.preprocess(image_array)
result = pred_model.predict(preprocessed_image)
print(np.argmax(result, axis=-1), np.amax(result, axis=-1))
My Question:
How can I call the model's predict method from preprocess function. So that
preprocessed_image = pred_model.preprocess(image_array)
result = pred_model.predict(preprocessed_image)
can become
result = pred_model.preprocess_predict(image_array)

Related

I'm trying to extract the features of pretrained resnet50 using dataloader, but it doesn't work

import os
import numpy as np
from google.colab import drive
import csv
import json
import torch
from torch.utils.data import Dataset, DataLoader
import torch.nn as nn
from torch.autograd import Variable
import torchvision
from torchvision import models
import torchvision.transforms as transforms
import pandas as pd
import cv2
import shutil
import time
from tqdm import tqdm
from PIL import Image
def getVector(img):
model = models.resnet50(pretrained = True)
model.eval()
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
img = Image.fromarray(img)
preprocess = transforms.Compose([
transforms.Resize((224,224)),
transforms.ToTensor(),
transforms.Normalize((0.485, 0.456, 0.406), (0.229, 0.224, 0.225)),
])
input_tensor = preprocess(img)
input_tensor = input_tensor.unsqueeze(0)
with torch.no_grad():
my_output = None
def my_hook(m,i,o):
nonlocal my_output
my_output = o
a_hook = model.avgpool.register_forward_hook(my_hook)
model(input_tensor)
a_hook.remove()
return my_output
def makeFeature(filePath):
fpsCount = 0
if os.path.isfile(filePath):
getVideo = cv2.VideoCapture(filePath)
else: print("no file || file name: " + str(filePath))
fps = int(getVideo.get(cv2.CAP_PROP_FPS))
#fps = int(fps/2)
vidInput = []
print(fps)
print(getVideo.isOpened())
while(getVideo.isOpened()):
ret, getImage = getVideo.read()
if ret == False:
break
if(int(getVideo.get(1)) % fps == 0):
#print("fps:" + str(getVideo.get(1)))
#print("get image: ")
feature = getVector(getImage)
vidInput.append(feature)
fpsCount = fpsCount + 1
if fpsCount == 10:
break
break
#name = filePath.replace("mp4","npy")
#np.save(name, vidInput)
#print("working")
getVideo.release()
return vidInput
class CustomDataset(Dataset): #Dataset 상속
def __init__(self):
#self.train_list = glob.glob('*.mp4')
self.train_list = '/content/drive/MyDrive/abseiling_0.mp4'
def __len__(self):
return len(self.train_list)
def __getitem__(self, idx):
return makeFeature(self.train_list)
dataset = CustomDataset()
dataloader = DataLoader(dataset, batch_size=1, shuffle=True)
for i in dataloader:
print(len(i))
np.save('test_save',i)
The code reads the video and reads one frame per second, extracts only the feature value from the last layer in the pretrained resnet, and returns it.
and appends them, and then tries to np.save.
but When I print len ​​in the last line, not only this value is printed several times, but all lens are printed as 0.
please tell me how to solve it πŸ˜₯

torch dataset error -- 'numpy.int32' is not callable

I'm preparing a set of medical imaging volumes and segmentation masks to be input into a multi-label segmentation neural network for training. I am recieving the following error message when I attempt to load my 5D tensors into a torch TensorDataset:
Traceback (most recent call last):
File (path/project.py), line 122, in <module>
train_dataset = torch.utils.data.TensorDataset(timg, tmask)
File (path/dataset.py), line 365, in __init__
assert all(tensors[0].size(0) == tensor.size(0) for tensor in tensors), "Size mismatch between tensors"
File (path/dataset.py)", line 365, in <genexpr>
assert all(tensors[0].size(0) == tensor.size(0) for tensor in tensors), "Size mismatch between tensors"
TypeError: 'numpy.int32' object is not callable
My original assumption was that the size mismatch was due to the difference in the dimensions of my tensors -- the feature tensor had dimensions 60x128x128x64x1 and the label tensor had dimensions 60x128x128x64x5. However, making the shape and size of these tensors equal has not resolved the issue. My other theory was that the issue was related to this line of code:
def transt(list):
array = np.asarray(list, ->np.int32<-)
changing the dtype did not seem to have an effect. I also tried casting the tensor into different dtypes, again to seemingly no effect on the problem.
Attached is the code. Unsure of how to proceed and any advice would be very appreciated.
import numpy as np
import os
import tensorflow as tf
import nibabel as nib
import matplotlib.pyplot as plt
from VNet import VNet
import Layers
import torchvision
from torchvision.transforms import ToTensor
import torch
from torch.utils.data import TensorDataset, DataLoader
from tensorflow.python.ops.numpy_ops import np_config
np_config.enable_numpy_behavior()
# Setting path
dirname = os.path.dirname(__file__)
path = os.path.join(dirname, 'Liver_MR_Dataset')
# Loading images/masks
img_list = []
gall_list = []
IVC_list = []
kidney_list = []
liver_list = []
rib_list = []
os.chdir(path + '/Image')
image_path = sorted(os.listdir(path + '/Image'))
for image in image_path:
img = nib.load(image).get_fdata()
img_list.append(img)
print(len(img_list))
train_img = img_list[:60]
print(len(train_img))
val_img = img_list[60:]
print(len(val_img))
os.chdir(path + '/Gall')
gall_path = sorted(os.listdir(path + '/Gall'))
for image in gall_path:
mask = nib.load(image).get_fdata()
gall_list.append(mask)
train_gall = gall_list[:60]
val_gall = gall_list[60:]
os.chdir(path + '/IVC')
IVC_path = sorted(os.listdir(path + '/IVC'))
for image in IVC_path:
mask = nib.load(image).get_fdata()
IVC_list.append(mask)
train_IVC = IVC_list[:60]
val_IVC = IVC_list[60:]
os.chdir(path + '/Kidney')
kidney_path = sorted(os.listdir(path + '/Kidney'))
for image in kidney_path:
mask = nib.load(image).get_fdata()
kidney_list.append(mask)
train_kidney = kidney_list[:60]
val_kidney = kidney_list[60:]
os.chdir(path + '/Liver')
liver_path = sorted(os.listdir(path + '/Liver'))
for image in liver_path:
mask = nib.load(image).get_fdata()
liver_list.append(mask)
train_liver = liver_list[:60]
val_liver = liver_list[60:]
os.chdir(path + '/Rib')
rib_path = sorted(os.listdir(path + '/Rib'))
for image in rib_path:
mask = nib.load(image).get_fdata()
rib_list.append(mask)
train_rib = rib_list[:60]
val_rib = rib_list[60:]
os.chdir(path)
# Transformations
def transt(list):
array = np.asarray(list, np.int32)
resize = np.resize(array, [60,128,128,64])
tensor = tf.convert_to_tensor(resize)
return tensor
def transv(list):
array = np.asarray(list, np.int32)
resize = np.resize(array, [7,128,128,64])
tensor = tf.convert_to_tensor(resize)
return tensor
tgall = transt(train_gall)
vgall = transv(val_gall)
tIVC = transt(train_IVC)
vIVC = transv(val_IVC)
tkidney = transt(train_kidney)
vkidney = transv(val_kidney)
tliver = transt(train_liver)
vliver = transv(val_liver)
trib = transt(train_rib)
vrib = transv(val_rib)
timg4d = transt(train_img)
vimg4d = transv(val_img)
timg = tf.stack([timg4d, timg4d, timg4d, timg4d, timg4d], axis=4)
print(timg.shape)
print(timg.size)
vimg = tf.stack([timg4d, timg4d, timg4d, timg4d, timg4d], axis=4)
tmask = tf.stack([tgall, tIVC, tkidney, tliver, trib], axis=4)
print(tmask.shape)
print(tmask.size)
vmask = tf.stack([vgall, vIVC, vkidney, vliver, vrib], axis=4)
# Create Datasets
train_dataset = torch.utils.data.TensorDataset(timg, tmask)
train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=60)
#val_dataset = torch.utils.data.TensorDataset(vimg, vmask)
#val_loader = torch.utils.data.DataLoader(val_dataset, batch_size=60)
size is a tuple, all(tensors[0].size[0] == tensor.size[0] for tensor in tensors),

Prediction failed: Error when checking input: expected dense_input to have shape (2898,) but got array with shape (1,)

I am using the following script predictor.py in order to get predictions from a Keras model hosted in GCP AI Platform.
import os
import pickle
import tensorflow as tf
import numpy as np
import logging
class MyPredictor(object):
def __init__(self, model, bow_model):
self._model = model
self._bow_model = bow_model
def predict(self, instances, **kwargs):
vectors = self.embedding([instances])
vectors = vectors.tolist()
output = self._model.predict(vectors)
return output
def embedding(self, statement):
vector = self._bow_model.transform(statement).toarray()
#vector = vector.to_list()
return vector
#classmethod
def from_path(cls, model_dir):
model_path = os.path.join(model_dir, 'model.h5')
model = tf.keras.models.load_model(model_path, compile = False)
preprocessor_path = os.path.join(model_dir, 'bow.pkl')
with open(preprocessor_path, 'rb') as f:
bow_model = pickle.load(f)
return cls(model, bow_model)
However i get
Prediction failed: Error when checking input: expected dense_input to have shape (2898,) but got array with shape (1,)
The problem seems to be due to the dimensions of my input data when trying to do the actual predictions, in line output = self._model.predict([vectors]). The model is expecting a vector of shape (2898, )
I am finding this quite odd... since when I print the shape and dimensions of the vector I get the following
This is the shape
(1, 2898)
This is the dim number
2
This is the vector
[[0 0 0 ... 0 0 0]]
So the dimensions and the shape is fine and it should really be working....
Furthermore, I did a test to get the predictions of the model stored locally and it works fine. This is the test file:
import os
import pickle
import tensorflow as tf
import numpy as np
class MyPredictor(object):
def __init__(self, model, bow_model):
self._model = model
self._bow_model = bow_model
def predict(self, instances, **kwargs):
print("These are the instances ", instances)
vector = self.embedding([instances])
output = self._model.predict(vector)
return output
def embedding(self, statement):
vector = self._bow_model.transform(statement).toarray()
#vector = vector.to_list()
return vector
model_path = 'model.h5'
model = tf.keras.models.load_model(model_path, compile = False)
preprocessor_path = 'bow.pkl'
with open(preprocessor_path, 'rb') as f:
bow_model = pickle.load(f)
instances = 'test'
predictor = MyPredictor(model, bow_model)
outputs = predictor.predict(instances)
print(outputs)
Solved it!
It was as silly as adding a set of parenthesis to this line output = self._model.predict([vectors])
After that I got another error regarding the output of the prediction not being json serializable. This I solved simply by adding .tolist() to the return return output.to_list()
import os
import pickle
import tensorflow as tf
import numpy as np
import logging
class MyPredictor(object):
def __init__(self, model, bow_model):
self._model = model
self._bow_model = bow_model
def predict(self, instances, **kwargs):
vectors = self.embedding([instances])
vectors = vectors.tolist()
output = self._model.predict([vectors])
return output.to_list()
def embedding(self, statement):
vector = self._bow_model.transform(statement).toarray()
#vector = vector.to_list()
return vector
#classmethod
def from_path(cls, model_dir):
model_path = os.path.join(model_dir, 'model.h5')
model = tf.keras.models.load_model(model_path, compile = False)
preprocessor_path = os.path.join(model_dir, 'bow.pkl')
with open(preprocessor_path, 'rb') as f:
bow_model = pickle.load(f)
return cls(model, bow_model)

Is there a way to pass 8-channel image to keras for CNN?

The problem: I am unable to process CNN model for training 8-channel .TIF images.
Expected Output: Map training data (train_ds) via gdal and train model.
data (images):
n = 600
shape = (256, 256, 8)
data structure:
project_photos/
....classes/
......barren/
......agriculture/
......wooded/
import numpy as np
import os
import PIL
import PIL.Image
import tensorflow as tf
import tensorflow_datasets as tfds
import pathlib
>print (tf.__version__)
2.1.0
data_dir = ".\projects\keras\projectA\project_photos\classes")
data_dir = pathlib.Path(data_dir)
image_count = len(list(data_dir.glob('*/*.tif')))
>print(image_count)
600
list_ds = tf.data.Dataset.list_files(str(data_dir/'*/*'), shuffle=False)
list_ds = list_ds.shuffle(image_count, reshuffle_each_iteration=False)
batch_size = 32
img_height = 256
img_width = 256
>for f in list_ds.take(5):
> print(f.numpy())
b'/home/projects/keras/projectA/project_photos/classes/barren/12345_b0001.tif'
b'/home/projects/keras/projectA/project_photos/classes/wooded//12345_w0001.tif'
b'/home/projects/keras/projectA/project_photos/classes/barren/12345_b0002.tif'
b'/home/projects/keras/projectA/project_photos/classes/agriculture//12345_a0001.tif'
b'/home/projects/keras/projectA/project_photos/classes/wooded/12345_w0002.tif'
# tree structure
>class_names = np.array(sorted([item.name for item in data_dir.glob('*')]))
print(class_names)
['barren' 'agriculture' 'wooded']
# train/validation split
val_size = int(image_count * 0.2)
train_ds = list_ds.skip(val_size)
val_ds = list_ds.take(val_size)
def get_label(file_path):
# convert the path to a list of path components
parts = tf.strings.split(file_path, os.path.sep)
# The second to last is the class-directory
one_hot = parts[-2] == class_names
# Integer encode the label
return tf.argmax(one_hot)
def decode_img(img):
# convert the compressed string to a 3D uint8 tensor
img = tf.image.decode_jpeg(img, channels=3)
# resize the image to the desired size
return tf.image.resize(img, [img_height, img_width])
def process_path(file_path):
label = get_label(file_path)
# load the raw data from the file as a string
img = tf.io.read_file(file_path)
img = decode_img(img)
return img, label
# Set `num_parallel_calls` so multiple images are loaded/processed in parallel.
train_ds = train_ds.map(process_path, num_parallel_calls=AUTOTUNE)
val_ds = val_ds.map(process_path, num_parallel_calls=AUTOTUNE)
I understand that tensorflow has limited support (experimental) for decode_tiff, and even if that did work - I am unable to use the latest version of TF that has that update.
This leaves me with attempting workarounds, the following - which have not succeeded:
"""
Updating decode_img(img) in attempt to process 8-channel .TIF raster
"""
#attempt, adding gdal_Open variable to decode_img
## fails due to image path (train_ds) being stored as byte.
x = gdal.Open(file_path)
Error: Not a string.
#attempt, modifying to extract PATH as str().
def process_path(file_path):
label = get_label(file_path)
# load the raw data from the file as a string
img = ''
for fpath in file_path:
img = fpath.numy()
img = decode_img(img)
return img, label
>train_ds = train_ds.map(process_path, num_parallel_calls=AUTOTUNE)
ValueError: len requires a non-scalar tensor, got one of shape Tensor("Shape:0", shape=(0,), dtype=int32)
#attempt, processing outside of `.map`, works just fine.
imgList = []
for elem in train_ds:
img = elem.numpy()
img = img.decode()
imgList.append(img)
file_path = imgList[0]
raster = gdal.Open(file_path)
bands = [raster.GetRasterBand(k + 1).ReadAsArray() for k in range (raster.RasterCount)]
n_bands = len(bands)
img_array = np.stack(bands,2)
img = tf.convert_to_tensor(img_array, dtype = tf.float32)
img = tf.image.resize(img, [img_height, img_width])
print(type(img))
print(img.numpy().shape)
<class: 'tensorflow.python.framework.ops.EagerTensor'>
(256, 256, 8)
So, any ideas on how I can get this to work within the TF framework - getting TF to process the raster via .map?

KeyError: 'data' in Caffe

While I was following the deepdream iPython notebook which is here: https://github.com/google/deepdream/blob/master/dream.ipynb, I successfully ran the code and initialized the network until i get this error:
I0218 20:53:01.108750 12174 net.cpp:283] Network initialization done.
I0218 20:53:06.017426 12174 net.cpp:816] Ignoring source layer data
I0218 20:53:06.139768 12174 net.cpp:816] Ignoring source layer loss
Traceback (most recent call last):
File "/home/andrew/PycharmProjects/deepmeme/deepmeme.py", line 122, in <module>
<IPython.core.display.Image object>
frame = deepdream(net, frame)
File "/home/andrew/PycharmProjects/deepmeme/deepmeme.py", line 78, in deepdream
octaves = [preprocess(net, base_img)]
File "/home/andrew/PycharmProjects/deepmeme/deepmeme.py", line 43, in preprocess
return np.float32(np.rollaxis(img, 2)[::-1]) - net.transformer.mean['data']
KeyError: 'data'
This is my code for the python file:
import sys
sys.path.append("/home/andrew/caffe/python")
from cStringIO import StringIO
import numpy as np
import scipy.ndimage as nd
import PIL.Image
from IPython.display import clear_output, Image, display
from google.protobuf import text_format
import caffe
# If your GPU supports CUDA and Caffe was built with CUDA support,
# uncomment the following to run Caffe operations on the GPU.
# caffe.set_mode_gpu()
# caffe.set_device(0) # select GPU device if multiple devices exist
def showarray(a, fmt='jpeg'):
a = np.uint8(np.clip(a, 0, 255))
f = StringIO()
PIL.Image.fromarray(a).save(f, fmt)
display(Image(data=f.getvalue()))
model_path = '/home/andrew/caffe/models/bvlc_reference_caffenet/' # substitute your path here
net_fn = model_path + 'deploy.prototxt'
param_fn = model_path + 'caffe_train_iter_500.caffemodel'
# Patching model to be able to compute gradients.
# Note that you can also manually add "force_backward: true" line to "deploy.prototxt".
model = caffe.io.caffe_pb2.NetParameter()
text_format.Merge(open(net_fn).read(), model)
model.force_backward = True
open('deploy.prototxt', 'w').write(str(model))
net = caffe.Classifier('/home/andrew/caffe/models/bvlc_reference_caffenet/deploy.prototxt', '/home/andrew/caffe/models/bvlc_reference_caffenet/caffenet_train_iter_500.caffemodel', caffe.TEST)
# a couple of utility functions for converting to and from Caffe's input image layout
def preprocess(net, img):
return np.float32(np.rollaxis(img, 2)[::-1]) - net.transformer.mean['data']
def deprocess(net, img):
return np.dstack((img + net.transformer.mean['data'])[::-1])
def objective_L2(dst):
dst.diff[:] = dst.data
def make_step(net, step_size=1.5, end='inception_4c/output',
jitter=32, clip=True, objective=objective_L2):
'''Basic gradient ascent step.'''
src = net.blobs['data'] # input image is stored in Net's 'data' blob
dst = net.blobs[end]
ox, oy = np.random.randint(-jitter, jitter+1, 2)
src.data[0] = np.roll(np.roll(src.data[0], ox, -1), oy, -2) # apply jitter shift
net.forward(end=end)
objective(dst) # specify the optimization objective
net.backward(start=end)
g = src.diff[0]
# apply normalized ascent step to the input image
src.data[:] += step_size/np.abs(g).mean() * g
src.data[0] = np.roll(np.roll(src.data[0], -ox, -1), -oy, -2) # unshift image
if clip:
bias = net.transformer.mean['data']
src.data[:] = np.clip(src.data, -bias, 255-bias)
def deepdream(net, base_img, iter_n=10, octave_n=4, octave_scale=1.4,
end='inception_4c/output', clip=True, **step_params):
# prepare base images for all octaves
octaves = [preprocess(net, base_img)]
for i in xrange(octave_n-1):
octaves.append(nd.zoom(octaves[-1], (1, 1.0/octave_scale,1.0/octave_scale), order=1))
src = net.blobs['data']
detail = np.zeros_like(octaves[-1]) # allocate image for network-produced details
for octave, octave_base in enumerate(octaves[::-1]):
h, w = octave_base.shape[-2:]
if octave > 0:
# upscale details from the previous octave
h1, w1 = detail.shape[-2:]
detail = nd.zoom(detail, (1, 1.0*h/h1,1.0*w/w1), order=1)
src.reshape(1,3,h,w) # resize the network's input image size
src.data[0] = octave_base+detail
for i in xrange(iter_n):
make_step(net, end=end, clip=clip, **step_params)
# visualization
vis = deprocess(net, src.data[0])
if not clip: # adjust image contrast if clipping is disabled
vis = vis*(255.0/np.percentile(vis, 99.98))
showarray(vis)
print octave, i, end, vis.shape
clear_output(wait=True)
# extract details produced on the current octave
detail = src.data[0]-octave_base
# returning the resulting image
return deprocess(net, src.data[0])
img = np.float32(PIL.Image.open('/home/andrew/caffe/examples/images/cat.jpg'))
showarray(img)
net.blobs.keys()
frame = img
frame_i = 0
h, w = frame.shape[:2]
s = 0.05 # scale coefficient
for i in xrange(100):
frame = deepdream(net, frame)
PIL.Image.fromarray(np.uint8(frame)).save("frames/%04d.jpg"%frame_i)
frame = nd.affine_transform(frame, [1-s,1-s,1], [h*s/2,w*s/2,0], order=1)
frame_i += 1
Image(filename='frames/0029.jpg')
Does anybody know what's happening? I am using my own data that I successfully trained a model with.
From the deepdream iPython notebook:
net = caffe.Classifier('tmp.prototxt', param_fn,
mean = np.float32([104.0, 116.0, 122.0]), # ImageNet mean, training set dependent
channel_swap = (2,1,0)) # the reference model has channels in BGR order instead of RGB
vs your:
net = caffe.Classifier('/home/andrew/caffe/models/bvlc_reference_caffenet/deploy.prototxt', '/home/andrew/caffe/models/bvlc_reference_caffenet/caffenet_train_iter_500.caffemodel', caffe.TEST)
You do not seem to include a mean when you create a caffe.Classifier.
See the definition of caffe.Classifier.
If you don't have a mean, you could probably just remove the mention of mean from preprocess/deprocess:
def preprocess(net, img):
return np.float32(np.rollaxis(img, 2)[::-1])
def deprocess(net, img):
return np.dstack((img)[::-1])

Categories

Resources