I'm trying to convert this python interface to tensorflow serving into golang:
image = cv2.imread("1.jpg")
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
image = cv2.resize(image, (256, 256))
image = np.expand_dims(image, axis=0)
image = np.true_divide(image, 255)
np.shape(image)
What I'm came up with is:
package main
import (
"log"
"image"
"gocv.io/x/gocv"
)
func main() {
imageFilePath := "./a.jpg"
mat := gocv.IMRead(imageFilePath, gocv.IMReadAnyColor)
if mat.Empty() {
log.Panic("Can not read Image file : ", imageFilePath)
return
}
resizeImage := gocv.NewMat()
gocv.Resize(mat, &resizeImage, image.Point{X: 256, Y: 256}, 0, 0, gocv.InterpolationNearestNeighbor)
img := resizeImage.Clone()
gocv.CvtColor(resizeImage, &img, gocv.ColorBGRToRGB)
// equivalent to np.expand_dims(image, axis=0) ?
}
I've tried to get help from gonum but had no luck plugging it to gocv, so I'm left clueless and appreciate your help about this.
Related
I'm trying to connect to my modified resnet model which is served using tensorflowÙ€model_serving
tensorflow_model_server --port=8500 --rest_api_port=8501 \
--model_name=resnet_model \
--model_base_path=/home/pc3/deeplearning/models/resnet
My model has an additional layer to the original resnet model which I got from tensorflow hub.
It expects 256x256 pixel images to classify and has only two output nodes.
Here is the go.cv interface that I could came up with with the help of the docs here:
package main
import (
"fmt"
"image"
"log"
"gocv.io/x/gocv"
)
func main() {
net := gocv.ReadNetFromTensorflow("/home/pc3/deeplearing/models/resnet/1")
imageFilePath := "./1.jpg"
img := gocv.IMRead(imageFilePath, gocv.IMReadAnyColor)
if img.Empty() {
log.Panic("Can not read Image file : ", imageFilePath)
return
}
blob := gocv.BlobFromImage(img, 1.0, image.Pt(256, 256), gocv.NewScalar(0, 0, 0, 0), true, false)
defer blob.Close()
// feed the blob into the classifier
net.SetInput(blob, "input")
// run a forward pass thru the network
prob := net.Forward("softmax")
defer prob.Close()
// reshape the results into a 1x1000 matrix
probMat := prob.Reshape(1, 2)
defer probMat.Close()
// determine the most probable classification, and display it
_, maxVal, _, maxLoc := gocv.MinMaxLoc(probMat)
fmt.Printf("maxLoc: %v, maxVal: %v\n", maxLoc, maxVal)
}
But get this runtime error:
terminate called after throwing an instance of 'cv::Exception'
what(): OpenCV(4.6.0) /tmp/opencv/opencv-4.6.0/modules/dnn/src/tensorflow/tf_importer.cpp:2986: error: (-215:Assertion failed) netBinSize || netTxtSize in function 'populateNet'
SIGABRT: abort
PC=0x7fe95f86b00b m=0 sigcode=18446744073709551610
signal arrived during cgo execution
goroutine 1 [syscall]:
runtime.cgocall(0x4abc50, 0xc00005fda8)
/usr/local/go/src/runtime/cgocall.go:157 +0x5c fp=0xc00005fd80 sp=0xc00005fd48 pc=0x41f39c
gocv.io/x/gocv._Cfunc_Net_ReadNetFromTensorflow(0x223a020)
_cgo_gotypes.go:6044 +0x49 fp=0xc00005fda8 sp=0xc00005fd80 pc=0x4a7569
gocv.io/x/gocv.ReadNetFromTensorflow({0x4e7fcf?, 0x428d87?})
/home/pc3/go/pkg/mod/gocv.io/x/gocv#v0.31.0/dnn.go:280 +0x5e fp=0xc00005fde8 sp=0xc00005fda8 pc=0x4a815e
main.main()
/home/pc3/go/src/test-go-ml/main.go:13 +0x51 fp=0xc00005ff80 sp=0xc00005fde8 pc=0x4a89b1
runtime.main()
/usr/local/go/src/runtime/proc.go:250 +0x212 fp=0xc00005ffe0 sp=0xc00005ff80 pc=0x44f892
runtime.goexit()
/usr/local/go/src/runtime/asm_amd64.s:1571 +0x1 fp=0xc00005ffe8 sp=0xc00005ffe0 pc=0x4780a1
I can communicate with the model seamlessly using this python snippet:
from urllib import response
import requests
import base64
import cv2
import json
import numpy as np
from keras.applications.imagenet_utils import decode_predictions
image = cv2.imread("10.jpg")
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
image = cv2.resize(image, (256, 256))
image = np.expand_dims(image, axis=0)
image = np.true_divide(image, 255)
data = json.dumps({"signature_name":"serving_default", "instances": image.tolist()})
url = "http://localhost:8501/v1/models/resnet_model:predict"
response = requests.post(url, data=data, headers = {"content_type": "application/json"})
predictions = json.loads(response.text)
Appreciate your help to resolve this, as the official docs is really lacking and I could not find any tutorial about this.
In case anyone interested, here is the complete solution that we found:
package main
import (
"bytes"
"encoding/json"
"image"
"io"
"log"
"net/http"
"os"
"github.com/barnex/matrix"
"gocv.io/x/gocv"
"gorgonia.org/tensor"
)
type Data struct {
Signature_name string `json:"signature_name"`
Instances []interface{} `json:"instances"`
}
func main() {
imageFilePath := "1.jpeg"
mat := gocv.IMRead(imageFilePath, gocv.IMReadAnyColor)
if mat.Empty() {
log.Panic("Can not read Image file : ", imageFilePath)
return
}
resizeImage := gocv.NewMat()
gocv.Resize(mat, &resizeImage, image.Point{X: 256, Y: 256}, 0, 0, gocv.InterpolationNearestNeighbor)
img := resizeImage.Clone()
gocv.CvtColor(resizeImage, &img, gocv.ColorBGRToRGB)
a := tensor.New(tensor.WithBacking(img.ToBytes()))
backing := a.Data().([]byte)
backing2 := make([]float64, len(backing))
for i := range backing {
x := float64(backing[i]) / 255
backing2[i] = x
}
matrix := matrix.ReshapeD3(backing2, [3]int{256, 256, 3})
var dim []interface{}
dim = append(dim, []interface{}{matrix}...)
data := Data{
Signature_name: "serving_default",
Instances: dim,
}
// send marshalled `data` to the Model
url := "http://localhost:8501/v1/models/resnet_model:predict"
payloadBuf := new(bytes.Buffer)
json.NewEncoder(payloadBuf).Encode(data)
req, _ := http.NewRequest("POST", url, payloadBuf)
client := &http.Client{}
res, err := client.Do(req)
if err != nil {
log.Fatal(err)
return
}
defer res.Body.Close()
io.Copy(os.Stdout, res.Body)
}
Basically I want to convert this code snippet to code that opens a tflite model and does not use keras. I can not install keras on my raspberry pi 4 as it needs Tensorflow 2+.
model = keras.models.load_model( saved_model_path )
image_url = tf.keras.utils.get_file('Court', origin='https://squashvideo.site/share/court3.jpg' )
img = tf.keras.preprocessing.image.load_img(image_url, target_size=( 224, 224 ) )
os.remove(image_url) # Remove the cached file
img_array = tf.keras.preprocessing.image.img_to_array(img)
prediction_scores = model.predict(np.expand_dims(img_array, axis=0)/255)
score = tf.nn.softmax(prediction_scores[0])
print(
"This image most likely belongs to {} with a {:.2f} percent confidence."
.format(class_names[np.argmax(score)], 100 * np.max(score))
)
Here's what I have tried which gives the error below:
from PIL import Image
def classify_image(interpreter, image, top_k=1):
tensor_index = interpreter.get_input_details()[0]['index']
input_tensor = interpreter.tensor(tensor_index)()[0]
input_tensor[:, :] = image
interpreter.invoke()
output_details = interpreter.get_output_details()[0]
output = np.squeeze(interpreter.get_tensor(output_details['index']))
scale, zero_point = output_details['quantization']
output = scale * (output - zero_point)
ordered = np.argpartition(-output, top_k)
return [(i, output[i]) for i in ordered[:top_k]][0]
interpreter = Interpreter('/var/www/html/share/AI/court.tflite')
interpreter.allocate_tensors()
_, height, width, _ = interpreter.get_input_details()[0]['shape']
print("Image Shape (", width, ",", height, ")")
data_folder = "/var/www/html/share/"
image = Image.open(data_folder + "court1.jpg").convert('RGB').resize((width, height))
label_id, prob = classify_image(interpreter, image)
Running gives the error:
squash#court1:/var/www/html/share/AI $ python3 test.py
Image Shape ( 224 , 224 )
Traceback (most recent call last):
File "test.py", line 44, in <module>
label_id, prob = classify_image(interpreter, image)
File "test.py", line 22, in classify_image
interpreter.invoke()
File "/home/squash/.local/lib/python3.7/site-packages/tflite_runtime/interpreter.py", line 539, in invoke
self._ensure_safe()
File "/home/squash/.local/lib/python3.7/site-packages/tflite_runtime/interpreter.py", line 287, in _ensure_safe
data access.""")
RuntimeError: There is at least 1 reference to internal data
in the interpreter in the form of a numpy array or slice. Be sure to
only hold the function returned from tensor() if you are using raw
data access.
The error is in the way you are feeding data to the tflite Interpreter here:
input_tensor = interpreter.tensor(tensor_index)()[0]
input_tensor[:, :] = image
The Image.open function return an Image object. You need to convert it into binary data before feeding it to a tensor. An you should use:
interpreter.set_tensor(0, image_data)
to set the data instead of above assignment.
Think I fixed it by doing this:
img = Image.open( image_url ).convert('RGB').resize((224, 224))
img_array = np.array ( img, dtype=np.float32 )
probs_lite = lite_model( np.expand_dims(img_array, axis=0)/255 )[0]
print ( probs_lite )
print (np.argmax(probs_lite))
score = tf.nn.softmax(probs_lite)
print(
"This image most likely belongs to {} with a {:.2f} percent confidence."
.format(class_names[np.argmax(score)], 100 * np.max(score))
)
Here is my Colab notebook which anyone should be able to run in 5 seconds. The predictions are always 0. I suspect the problem is in these two lines. Or perhaps my tflite model is corrupt or wrong?
label_id, prob = classify_image(interpreter, np.expand_dims(img_array, axis=0)/255 )
#label_id, prob = classify_image(interpreter, img )
Think I figured it out. Basically the output from the classify_image() function needs furthur processing to be useable. So I need to do this on the output:
label_index= np.argmax(probs_lite)
score = tf.nn.softmax(probs_lite)
print(
"This image most likely belongs to {} with a {:.2f} percent confidence."
.format(class_names[label_index], 100 * np.max(score))
)
And here's my full script in case anyone has similiar issue in the future:
import itertools, time, os, numpy as np,sys
from PIL import Image
import tensorflow as tf
def lite_model(images):
interpreter.allocate_tensors()
interpreter.set_tensor(interpreter.get_input_details()[0]['index'], images)
interpreter.invoke()
return interpreter.get_tensor(interpreter.get_output_details()[0]['index'])
class_names = ['empty_court', 'occupied_court' ]
path_to_tflite = tf.keras.utils.get_file(
"court.tflite",
"https://mysite.site/AI/court.tflite",
untar=False)
interpreter = tf.lite.Interpreter( path_to_tflite )
interpreter.allocate_tensors()
_, height, width, _ = interpreter.get_input_details()[0]['shape']
print("Image Shape (", width, ",", height, ")")
image_url = tf.keras.utils.get_file('Court', origin='https://mysite.site/share/court4.jpg' )
img = tf.keras.preprocessing.image.load_img(image_url, target_size=( width, height ) )
os.remove(image_url) # Remove the cached file
img_array = tf.keras.preprocessing.image.img_to_array(img)
probs_lite = lite_model( np.expand_dims(img_array, axis=0)/255 )[0]
print ( probs_lite )
label_index= np.argmax(probs_lite)
score = tf.nn.softmax(probs_lite)
print(
"This image most likely belongs to {} with a {:.2f} percent confidence."
.format(class_names[label_index], 100 * np.max(score))
)
I want to concatenate three images with size [1024,1024,3] to make a batch with size [3,1024,1024,3]. I wrote this code with TensorFlow but it doesn't work. It returns the error "InaccessibleTensorError: The tensor 'Tensor("truediv:0", shape=(1024, 1024, 3), dtype=float32)' cannot be accessed here: it is defined in another function or code block. Use return values, explicit Python locals or TensorFlow collections to access it.".
def decode_img(filename):
image = tf.ones((3,1024,1024,3),dtype=tf.dtypes.float32)
cnt=0
slices = []
for fi in filename:
bits = tf.io.read_file(fi)
img = tf.image.decode_jpeg(bits, channels=3)
img = tf.image.resize(img, (1024,1024))
slices.append(tf.cast(img, tf.float32) / 255.0)
cnt +=1
image = tf.stack(slices)
return image
#-----------------------
filenames = ['img1.png', 'img2.png', 'img3.png']
dataset = tf.data.Dataset.from_tensor_slices(filenames)
dataset = dataset.map(decode_img, num_parallel_calls=AUTO)
In general, tensorflow does not support item assignment. Rather, generate all the img layers you want and then use tf.stack() or tf.concatenate.
filename = [img1.png, img2.png, img3.png]
cnt=0
slices = []
for fi in filename:
bits = tf.io.read_file(fi)
img = tf.image.decode_jpeg(bits, channels=3)
img = tf.image.resize(img, (1024,1024))
slices.append(tf.cast(img, tf.float32) / 255.0)
cnt +=1
image = tf.stack(slices)
In converting this line of code to Pytorch from Tensor Flow, I am having trouble
datagen = ImageDataGenerator(
shear_range=0.2,
zoom_range=0.2,
)
def read_img(filename, size, path):
img = image.load_img(os.path.join(path, filename), target_size=size)
#convert image to array
img = img_to_array(img) / 255
return img
and then
corona_df = final_train_data[final_train_data['Label_2_Virus_category'] == 'COVID-19']
with_corona_augmented = []
#create a function for augmentation
def augment(name):
img = read_img(name, (255,255), train_img_dir)
i = 0
for batch in tqdm(datagen.flow(tf.expand_dims(img, 0), batch_size=32)):
with_corona_augmented.append(tf.squeeze(batch).numpy())
if i == 20:
break
i =i+1
#apply the function
corona_df['X_ray_image_name'].apply(augment)
I tried doing
transform = transforms.Compose([transforms.Resize(255*255)
])
train_loader = torch.utils.data.DataLoader(os.path.join(train_dir,corona_df),transform = transform,batch_size =32)
def read_img(path):
img = train_loader()
img = np.asarray(img,dtype='int32')
img = img/255
return img
I tried continuing but got soo confused by the errors.
I welcome any feedback. Tell me If i miss something
Even a small advice would work, thanks !
You can create a custom dataset to read the images. If you have a directory full of images you can use ImageFolder default dataset. Otherwise if you have different folder placement you can write your own custom dataset class. You can look to this link for custom datasets. What dataloader does is, it automatically gets the data from your dataset and read the images according to your dataset __getitem__ function and apply transformation. So you don't need anything fancy to apply augmentation.
transform = transforms.Compose([ transforms.RandomAffine(20,shear=20,scale=(-0.2,0.2)),
transforms.Resize(255*255)
])
dataset = torchvision.datasets.ImageFolder(train_img_dir, transform=transform)
loader = torch.utils.data.DataLoader(dataset,batch_size =32,shuffle=True)
for batch in loader:
output = model(batch)