Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Code Refactor, add webcam demo...lots of stuff #70

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 59 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,61 @@
# Data files and directories common in repo root
datasets/
logs/
*.h5
*.weights
results/
temp/
test/
*.jpg
*.jpeg
*.weights
*.h5

# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# VS Studio Code
.vscode

# PyCharm
.idea/

# Dropbox
.dropbox.attr

# Jupyter Notebook
.ipynb_checkpoints

# pyenv
.python-version

# dotenv
.env

# virtualenv
.venv
venv/
ENV/
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,26 @@ VOC (20 classes) (http://host.robots.ox.ac.uk/pascal/VOC/voc2012/) | 72% | check

Grab the pretrained weights of yolo3 from https://pjreddie.com/media/files/yolov3.weights.

```wget -c https://pjreddie.com/media/files/yolov3.weights```

Environment setup:

```pip install -r requirements.txt```

If Nvidia GPU is available:

```pip uninstall tensorflow```

```pip install tensorflow-gpu```

Detection on single image:

```python yolo3_one_file_to_detect_them_all.py -w yolo3.weights -i dog.jpg```

If your webcam is available:

```python yolo3_cam.py -w yolov3.weights```

## Training

### 1. Data preparation
Expand Down
223 changes: 223 additions & 0 deletions RMS/RMS_yolo3.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
import base64
import os
import sys
import argparse
import warnings
warnings.filterwarnings("ignore")
os.environ.setdefault('PATH', '')
import numpy as np
import redis
import time
import json
from io import BytesIO
from multiprocessing import Process, Pipe, current_process, Lock
import GPUtil
from skimage.measure import find_contours
import struct
import cv2
import numpy as np
import config

# connect to Redis server
redispool = redis.ConnectionPool(host=config.REDIS_HOST,
port=config.REDIS_PORT,
db=config.REDIS_DB,
socket_keepalive=True)

try:
print('Testing Redis Connection')
redisdbSession = redis.StrictRedis(connection_pool=redispool)
response = redisdbSession.client_list()
print('Redis Connection Established')
except redis.ConnectionError as e:
print(e)
sys.exit(1)

np.set_printoptions(threshold=np.nan)
os.environ["CUDA_DEVICE_ORDER"]="PCI_BUS_ID"
os.environ["CUDA_VISIBLE_DEVICES"]="0"

# set some parameters
net_h, net_w = 416, 416
obj_thresh, nms_thresh = 0.7, 0.7
anchors = [[116,90, 156,198, 373,326], [30,61, 62,45, 59,119], [10,13, 16,30, 33,23]]
labels = ["person", "bicycle", "car", "motorbike", "aeroplane", "bus", "train", "truck", \
"boat", "traffic light", "fire hydrant", "stop sign", "parking meter", "bench", \
"bird", "cat", "dog", "horse", "sheep", "cow", "elephant", "bear", "zebra", "giraffe", \
"backpack", "umbrella", "handbag", "tie", "suitcase", "frisbee", "skis", "snowboard", \
"sports ball", "kite", "baseball bat", "baseball glove", "skateboard", "surfboard", \
"tennis racket", "bottle", "wine glass", "cup", "fork", "knife", "spoon", "bowl", "banana", \
"apple", "sandwich", "orange", "broccoli", "carrot", "hot dog", "pizza", "donut", "cake", \
"chair", "sofa", "pottedplant", "bed", "diningtable", "toilet", "tvmonitor", "laptop", "mouse", \
"remote", "keyboard", "cell phone", "microwave", "oven", "toaster", "sink", "refrigerator", \
"book", "clock", "vase", "scissors", "teddy bear", "hair drier", "toothbrush"]

class mlWorker(Process):
def __init__(self, LOCK, GPU="", FRAC=0):
Process.__init__(self)
self.lock = LOCK
if GPU:
print('{} using GPUid: {}, Name: {}'.format(self.name, str(GPU.id), str(GPU.name)))
os.environ["CUDA_VISIBLE_DEVICES"] = str(GPU.id)
self.device = '/device:GPU:0'
else:
self.device = ''
self.GPU = GPU
self.frac = FRAC
self.counter = 0
self.dt = 0.0

def run(self):
from utils.weightreader import WeightReader
from utils.bbox import BoundBox
from utils.tools import preprocess_input, decode_netout
from utils.tools import correct_yolo_boxes, do_nms, draw_boxes
from model.yolo3 import make_yolov3_model
import tensorflow as tf
from PIL import Image
self.Image = Image
self.preprocess_input = preprocess_input
self.decode_netout = decode_netout
self.correct_yolo_boxes = correct_yolo_boxes
self.do_nms = do_nms
self.draw_boxes = draw_boxes
if self.GPU:
print('ML Process: {} starting, using GPU: {}, frac: {}'.format(self.name,self.GPU.id,self.frac))
keras.backend.clear_session()
conf = tf.ConfigProto()
conf.gpu_options.per_process_gpu_memory_fraction = self.frac
set_session(tf.Session(config=conf))
# make the yolov3 model to predict 80 classes on COCO
_model = make_yolov3_model()

# load the weights trained on COCO into the model
weight_reader = WeightReader(config.MODEL_PATH)
weight_reader.load_weights(_model)

graph = tf.get_default_graph()
print('ML Process: {} started'.format(self.name))
self.mainloop(model=_model, graph=graph)

def mainloop(self, model='', graph=''):
while True:
# attempt to grab a batch of images from the database, then
# initialize the image IDs and batch of images themselves
try:
redisdbSession = redis.StrictRedis(connection_pool=redispool)
self.lock.acquire()
query = redisdbSession.lrange(config.IMAGE_QUEUE, 0, config.BATCH_SIZE - 1)
redisdbSession.ltrim(config.IMAGE_QUEUE, len(query), -1)
self.lock.release()
imageIDs = []
thresholds = {}
batch = []
# loop over the queue
# deserialize the object and obtain the input image
if query:
for item in query:
data = json.loads(item)
image = self.base64_decode_image(data["image"])
image = self.preprocess_input(image, net_h, net_w)
# check to see if the batch list is None
batch.append(image)
# update the list of image IDs
imageIDs.append(data["id"])
thresholds[data["id"]] = data["threshold"]

# check to see if we need to process the batch
if len(imageIDs) > 0:
#print('{}: Procesing {} images!'.format(self.name, len(imageIDs)))
start = time.time()
with graph.as_default():
results = model.predict(batch[0])
end = time.time()
et = end - start
self.dt += float(et)
self.counter += 1
adt = float(self.dt)/float(self.counter)
print('avg dt: %f' % adt)
# loop over the image IDs and their corresponding set of
# results from our model
output = []
output = self.extract_result(results, labels,
throttle=float(thresholds[imageID]))
redisdbSession.set(imageID, json.dumps(output))
# sleep for a small amount
time.sleep(config.SERVER_SLEEP*2)
except Exception as e:
print(e)
time.sleep(config.SERVER_SLEEP)
continue

def extract_result(self, results, labels, throttle='0.95'):
boxes = []

for i in range(len(yolos)):
# decode the output of the network
boxes.append(decode_netout(yolos[i][0], anchors[i], obj_thresh, net_h, net_w))
# correct the sizes of the bounding boxes
correct_yolo_boxes(boxes, image_h, image_w, net_h, net_w)
# suppress non-maximal boxes
do_nms(boxes, nms_thresh)
output = []
for box in boxes:
label_str = ''
label = -1
for i in range(len(labels)):
if box.classes[i] > obj_thresh:
label_str += labels[i]
label = i
if label >= 0:
output.append({
bbox: [box.xmin,box.ymin,box.xmax,box.ymax],
label: label_str
score: str(box.get_score())
})
return output

def base64_decode_image(self, a):
"""
return: <ndarray>
"""
img = self.Image.open(BytesIO(base64.b64decode(a)))
if img.mode != "RGB":
img = img.convert("RGB")
img = np.array(img)
return img



if __name__ == "__main__":
LOCK = Lock()
AVAIL_DEVICE_LIST = config.AVAIL_DEVICE_LIST
AVAIL_DEVICE_MEMFRAC = config.AVAIL_DEVICE_MEMFRAC
AVAIL_DEVICE_MAXTHREAD = config.AVAIL_DEVICE_MAXTHREAD

proc_list = []
print('{} GPUs Available'.format(len(AVAIL_DEVICE_LIST)))
if AVAIL_DEVICE_LIST:
for index, device in enumerate(AVAIL_DEVICE_LIST):
thread_count = int(AVAIL_DEVICE_MAXTHREAD[index])
mem_frac = float(AVAIL_DEVICE_MEMFRAC[index])
if config.MAX_FRAC < mem_frac:
mem_frac = config.MAX_FRAC
print('Preparing {} process on GPU: {}, frac: {}'.format(thread_count, device.id, mem_frac))
if config.MAX_THREADS < thread_count:
thread_count = config.MAX_THREADS
for thread in range(thread_count):
p = mlWorker(LOCK, GPU=device, FRAC=mem_frac)
p.daemon = True
proc_list.append(p)
print('Starting total: {} processes'.format(len(proc_list)))
for proc in proc_list:
proc.start()
print('All processes started')
else:
p = mlWorker(LOCK)
p.daemon = True
p.start()
p.join()

if proc_list:
for proc in proc_list:
proc.join()
83 changes: 83 additions & 0 deletions RMS/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import os
import urllib.request
import shutil
from mrcnn.tools.config import Config


ALLOWED_EXTENSIONS = set(['jpg', 'jpeg'])

ROOT_DIR = os.getcwd()
UPLOAD_FOLDER = os.path.join(ROOT_DIR, "images")
if not os.path.exists(UPLOAD_FOLDER):
os.makedirs(UPLOAD_FOLDER)
MODEL_DIR = os.path.join(ROOT_DIR, "logs")
if not os.path.exists(MODEL_DIR):
os.makedirs(MODEL_DIR)
# Local path to trained weights file
MODEL_DIR = os.path.join(ROOT_DIR, "weights")
if not os.path.exists(COCO_MODEL_DIR):
os.makedirs(COCO_MODEL_DIR)
MODEL_PATH = os.path.join(ROOT_DIR, "weights/mask_rcnn_coco.h5")

def download_trained_weights(coco_model_path, verbose=1):
"""Download COCO trained weights from Releases.

coco_model_path: local path of COCO trained weights
"""
MODEL_URL = "https://pjreddie.com/media/files/yolov3.weights"
if verbose > 0:
print("Downloading pretrained model to " + MODEL_PATH + " ...")
with urllib.request.urlopen(MODEL_URL) as resp, open(MODEL_PATH, 'wb') as out:
shutil.copyfileobj(resp, out)
if verbose > 0:
print("... done downloading pretrained model!")

# Download COCO trained weights from Releases if needed
if not os.path.exists(MODEL_PATH):
download_trained_weights(MODEL_PATH, verbose=VERBOSE)

import GPUtil

LEAST_GMEM = 2250 # MB
MAX_THREADS = 1
MIN_FRAC = 0.3
MAX_FRAC = 0.3
GPU_LAOD = 0.5
GMEM_LAOD_LIMIT = 1.0
AVAIL_DEVICE_LIST = []
AVAIL_DEVICE_MAT = []
AVAIL_DEVICE_MEMFRAC = []
AVAIL_DEVICE_MAXTHREAD = []
try:
GPUs = GPUtil.getGPUs()
Gall = ''
Gfree = ''
for GPU in GPUs:
Gall = GPU.memoryTotal
Gfree = GPU.memoryFree
GMEM_LAOD_LIMIT = float(format(float(LEAST_GMEM / Gall), '.2f'))
if int(GPUtil.getAvailability([GPU], maxLoad=GPU_LAOD, maxMemory=GMEM_LAOD_LIMIT)) == 1:
AVAIL_DEVICE_LIST.append(GPU)
if GMEM_LAOD_LIMIT < MIN_FRAC:
GMEM_LAOD_LIMIT = MIN_FRAC
if GMEM_LAOD_LIMIT > MAX_FRAC:
GMEM_LAOD_LIMIT = MAX_FRAC
AVAIL_DEVICE_MEMFRAC.append(GMEM_LAOD_LIMIT)
AVAIL_DEVICE_MAXTHREAD.append(int(1.0/GMEM_LAOD_LIMIT))
except Exception as e:
print(e)

# initialize Redis connection settings
REDIS_HOST = "localhost"
REDIS_PORT = 6379
REDIS_DB = 0

BATCH_SIZE = 1
# initialize constants used for server queuing
IMAGE_QUEUE = "yolo3_queue"

SERVER_SLEEP = 0.1
CLIENT_SLEEP = 0.1

# Output Throttle
THROTTLE = 0.9
Loading