def push(): """ Create a pre-trained model from model store """ model_id = flask.request.args.get('id') model_grand_list = app.config['store_cache'].read() found = False if model_grand_list is not None: for store in model_grand_list: for model in model_grand_list[store]['model_list']: if model['id'] == model_id: url = model_grand_list[store]['base_url'] directory = model['dir_name'] found = True break if found: break if not found: return 'Unable to find requested model', 404 else: progress = Progress(model_id) weights, model, label, meta_data, python_layer = retrieve_files(url, directory, progress) job = PretrainedModelJob( weights, model, label, meta_data['framework'], username=auth.get_username(), name=meta_data['name'] ) scheduler.add_job(job) response = flask.make_response(job.id()) return response
def image_classification_dataset_create(): form = ImageClassificationDatasetForm() if not form.validate_on_submit(): return render_template('datasets/images/classification/new.html', form=form), 400 job = None try: job = ImageClassificationDatasetJob( name = form.dataset_name.data, image_dims = ( int(form.resize_height.data), int(form.resize_width.data), int(form.resize_channels.data), ), resize_mode = form.resize_mode.data ) if form.method.data == 'folder': from_folders(job, form) elif form.method.data == 'textfile': from_files(job, form) scheduler.add_job(job) return redirect(url_for('datasets_show', job_id=job.id())) except: if job: scheduler.delete_job(job) raise
def create(): """ Creates a new ImageClassificationDatasetJob Returns JSON when requested: {job_id,name,status} or {errors:[]} """ form = ImageClassificationDatasetForm() # Is there a request to clone a job with ?clone=<job_id> fill_form_if_cloned(form) if not form.validate_on_submit(): if request_wants_json(): return flask.jsonify({'errors': form.errors}), 400 else: return flask.render_template('datasets/images/classification/new.html', form=form), 400 job = None try: job = ImageClassificationDatasetJob( username=utils.auth.get_username(), name=form.dataset_name.data, group=form.group_name.data, image_dims=( int(form.resize_height.data), int(form.resize_width.data), int(form.resize_channels.data), ), resize_mode=form.resize_mode.data ) if form.method.data == 'folder': from_folders(job, form) elif form.method.data == 'textfile': from_files(job, form) elif form.method.data == 's3': from_s3(job, form) else: raise ValueError('method not supported') # Save form data with the job so we can easily clone it later. save_form_to_job(job, form) scheduler.add_job(job) if request_wants_json(): return flask.jsonify(job.json_dict()) else: return flask.redirect(flask.url_for('digits.dataset.views.show', job_id=job.id())) except: if job: scheduler.delete_job(job) raise
def image_classification_dataset_create(): """ Creates a new ImageClassificationDatasetJob Returns JSON when requested: {job_id,name,status} or {errors:[]} """ form = ImageClassificationDatasetForm() ## Is there a request to clone a job with ?clone=<job_id> fill_form_if_cloned(form) if not form.validate_on_submit(): if request_wants_json(): return flask.jsonify({"errors": form.errors}), 400 else: return flask.render_template("datasets/images/classification/new.html", form=form), 400 job = None try: job = ImageClassificationDatasetJob( name=form.dataset_name.data, image_dims=(int(form.resize_height.data), int(form.resize_width.data), int(form.resize_channels.data)), resize_mode=form.resize_mode.data, bbox_mode=int(form.bbox_mode.data), scale_factor=float(form.scale_factor.data), ) if form.method.data == "folder": from_folders(job, form) elif form.method.data == "textfile": from_files(job, form) elif form.method.data == "jsonfile": from_json(job, form) else: raise ValueError("method not supported") ## Save form data with the job so we can easily clone it later. save_form_to_job(job, form) scheduler.add_job(job) if request_wants_json(): return flask.jsonify(job.json_dict()) else: return flask.redirect(flask.url_for("datasets_show", job_id=job.id())) except: if job: scheduler.delete_job(job) raise
def top_n(): """ Classify many images and show the top N images per category by confidence """ model_job = job_from_request() image_list = flask.request.files['image_list'] if not image_list: raise werkzeug.exceptions.BadRequest('File upload not found') epoch = None if 'snapshot_epoch' in flask.request.form: epoch = float(flask.request.form['snapshot_epoch']) if 'top_n' in flask.request.form and flask.request.form['top_n'].strip(): top_n = int(flask.request.form['top_n']) else: top_n = 9 if 'image_folder' in flask.request.form and flask.request.form['image_folder'].strip(): image_folder = flask.request.form['image_folder'] if not os.path.exists(image_folder): raise werkzeug.exceptions.BadRequest('image_folder "%s" does not exit' % image_folder) else: image_folder = None if 'num_test_images' in flask.request.form and flask.request.form['num_test_images'].strip(): num_test_images = int(flask.request.form['num_test_images']) else: num_test_images = None paths, _ = read_image_list(image_list, image_folder, num_test_images) # create inference job inference_job = ImageInferenceTopNJob( username = utils.auth.get_username(), name = "TopN Image Classification", model = model_job, images = paths, epoch = epoch, layers = 'none', top_n = top_n, ) # schedule tasks scheduler.add_job(inference_job) if request_wants_json(): return flask.jsonify(inference_job.json_dict()) else: return flask.redirect(flask.url_for('digits.inference.views.show', job_id=inference_job.id()))
def create_inference_db(model_job, data_extension_id): # create instance of extension class extension_class = extensions.data.get_extension(data_extension_id) if hasattr(model_job.dataset, 'extension_userdata'): extension_userdata = model_job.dataset.extension_userdata else: extension_userdata = {} extension_userdata.update({'is_inference_db': True}) extension = extension_class(**extension_userdata) extension_form = extension.get_inference_form() extension_form_valid = extension_form.validate_on_submit() if not extension_form_valid: errors = extension_form.errors.copy() raise werkzeug.exceptions.BadRequest(repr(errors)) extension.userdata.update(extension_form.data) # create job job = GenericDatasetJob( username=utils.auth.get_username(), name='Inference dataset', group=None, backend='lmdb', feature_encoding='none', label_encoding='none', batch_size=1, num_threads=1, force_same_shape=0, extension_id=data_extension_id, extension_userdata=extension.get_user_data(), ) # schedule tasks and wait for job to complete scheduler.add_job(job) job.wait_completion() # check for errors if job.status != Status.DONE: msg = "" for task in job.tasks: if task.exception: msg = msg + task.exception if task.traceback: msg = msg + task.exception raise RuntimeError(msg) return job
def image_classification_trial_create(experiment_id): experiment = load_experiment(experiment_id) experiment.load_dataset() experiment.load_model() form = ImageClassificationTrialForm() form.learning_method.choices = get_learning_methods() form.learning_method.default = get_default_learning_method() form.layers.choices = get_layers(copy.copy(experiment.layers)) form.category_names.choices = get_category_names(experiment) if not form.validate_on_submit(): return render_template('trials/images/classification/new.html', form=form, experiment=experiment), 400 category_index = -1 for index, choice in enumerate(form.category_names.choices): if choice[0] == form.category_names.data: category_index = index break job = None try: job = ImageClassificationTrialJob( name = form.trial_name.data, experiment_id = experiment.id(), learning_method = form.learning_method.data, category_name = form.category_names.data, category_index = category_index, layer = form.layers.data, ) if form.learning_method.data == 'dnn': dnn_trial(job, form) elif form.learning_method.data == 'svm': svm_trial(job, form) elif form.learning_method.data == 'adaboost': boosting_trial(job, form) scheduler.add_job(job) return redirect(url_for('trials_show', job_id=job.id())) except: if job: scheduler.delete_job(job) raise
def to_pretrained(job_id): job = scheduler.get_job(job_id) if job is None: raise werkzeug.exceptions.NotFound('Job not found') epoch = -1 # GET ?epoch=n if 'epoch' in flask.request.args: epoch = float(flask.request.args['epoch']) # POST ?snapshot_epoch=n (from form) elif 'snapshot_epoch' in flask.request.form: epoch = float(flask.request.form['snapshot_epoch']) # Write the stats of the job to json, # and store in tempfile (for archive) info = job.json_dict(verbose=False,epoch=epoch) task = job.train_task() snapshot_filename = None snapshot_filename = task.get_snapshot(epoch) # Set defaults: labels_path = None resize_mode = None if "labels file" in info: labels_path = os.path.join(task.dataset.dir(), info["labels file"]) if "image resize mode" in info: resize_mode = info["image resize mode"] job = PretrainedModelJob( snapshot_filename, os.path.join(job.dir(), task.model_file) , labels_path, info["framework"], info["image dimensions"][2], resize_mode, info["image dimensions"][0], info["image dimensions"][1], username = auth.get_username(), name = info["name"] ) scheduler.add_job(job) return flask.redirect(flask.url_for('digits.views.home',tab=3)), 302
def classify_many(): """ Start a new classify_may job """ # kicking off a new inference job model_job = job_from_request() image_list = flask.request.files.get('image_list') if not image_list: raise werkzeug.exceptions.BadRequest('image_list is a required field') if 'image_folder' in flask.request.form and flask.request.form['image_folder'].strip(): image_folder = flask.request.form['image_folder'] if not os.path.exists(image_folder): raise werkzeug.exceptions.BadRequest('image_folder "%s" does not exit' % image_folder) else: image_folder = None if 'num_test_images' in flask.request.form and flask.request.form['num_test_images'].strip(): num_test_images = int(flask.request.form['num_test_images']) else: num_test_images = None epoch = None if 'snapshot_epoch' in flask.request.form: epoch = float(flask.request.form['snapshot_epoch']) paths, ground_truths = read_image_list(image_list, image_folder, num_test_images) # create inference job inference_job = ImageInferenceClassifyManyJob( username = utils.auth.get_username(), name = "Classify Many Images", model = model_job, images = paths, epoch = epoch, layers = 'none', ground_truths = ground_truths, ) # schedule tasks scheduler.add_job(inference_job) if request_wants_json(): return flask.jsonify(inference_job.json_dict()) else: return flask.redirect(flask.url_for('digits.inference.views.show', job_id=inference_job.id()))
def new(): """ Upload a pretrained model """ labels_path = None framework = None form = flask.request.form files = flask.request.files if 'framework' not in form: framework = "caffe" else: framework = form['framework'] if 'job_name' not in flask.request.form: raise werkzeug.exceptions.BadRequest('Missing job name') elif str(flask.request.form['job_name']) is '': raise werkzeug.exceptions.BadRequest('Missing job name') if framework == "caffe": weights_path, model_def_path = validate_caffe_files(files) else: weights_path, model_def_path = validate_torch_files(files) if str(flask.request.files['labels_file'].filename) is not '': labels_path = get_tempfile(flask.request.files['labels_file'],".txt") job = PretrainedModelJob( weights_path, model_def_path, labels_path, framework, form["image_type"], form["resize_mode"], form["width"], form["height"], username = utils.auth.get_username(), name = flask.request.form['job_name'] ) scheduler.add_job(job) return flask.redirect(flask.url_for('digits.views.home', tab=3)), 302
def image_classification_dataset_create(): """ Creates a new ImageClassificationDatasetJob Returns JSON when requested: {job_id,name,status} or {errors:[]} """ form = ImageClassificationDatasetForm() if not form.validate_on_submit(): if request_wants_json(): return flask.jsonify({'errors': form.errors}), 400 else: return flask.render_template('datasets/images/classification/new.html', form=form), 400 job = None try: job = ImageClassificationDatasetJob( name = form.dataset_name.data, image_dims = ( int(form.resize_height.data), int(form.resize_width.data), int(form.resize_channels.data), ), resize_mode = form.resize_mode.data ) if form.method.data == 'folder': from_folders(job, form) elif form.method.data == 'textfile': from_files(job, form) else: raise ValueError('method not supported') scheduler.add_job(job) if request_wants_json(): return flask.jsonify(job.json_dict()) else: return flask.redirect(flask.url_for('datasets_show', job_id=job.id())) except: if job: scheduler.delete_job(job) raise
def classify_one(): """ Classify one image and return the top 5 classifications Returns JSON when requested: {predictions: {category: confidence,...}} """ model_job = job_from_request() if 'image_url' in flask.request.form and flask.request.form['image_url']: image_path = flask.request.form['image_url'] elif 'image_file' in flask.request.files and flask.request.files['image_file']: outfile = tempfile.mkstemp(suffix='.png') flask.request.files['image_file'].save(outfile[1]) image_path = outfile[1] os.close(outfile[0]) else: raise werkzeug.exceptions.BadRequest('must provide image_url or image_file') epoch = None if 'snapshot_epoch' in flask.request.form: epoch = float(flask.request.form['snapshot_epoch']) layers = 'none' if 'show_visualizations' in flask.request.form and flask.request.form['show_visualizations']: layers = 'all' # create inference job inference_job = ImageInferenceClassifyOneJob( username = utils.auth.get_username(), name = "Classify One Image", model = model_job, images = [image_path], epoch = epoch, layers = layers ) # schedule tasks scheduler.add_job(inference_job) if request_wants_json(): return flask.jsonify(inference_job.json_dict()) else: return flask.redirect(flask.url_for('digits.inference.views.show', job_id=inference_job.id()))
def feature_extraction_dataset_create(): """ Creates a new FeatureExtractionDatasetJob Returns JSON when requested: {job_id,name,status} or {errors:[]} """ workspace = get_workspace_details(flask.request.url) form = FeatureExtractionDatasetForm() if not form.validate_on_submit(): if request_wants_json(): return flask.jsonify({'errors': form.errors}), 400 else: return flask.render_template('datasets/images/extraction/new.html', form=form, workspace = workspace), 400 job = None try: job = FeatureExtractionDatasetJob( name = form.dataset_name.data, image_dims = ( int(form.resize_height.data), int(form.resize_width.data), int(form.resize_channels.data), ), resize_mode = form.resize_mode.data, workspace = workspace, ) #if form.method.data == 'folder': # from_folders(job, form) #elif form.method.data == 'textfile': from_files(job, form) scheduler.add_job(job) if request_wants_json(): return flask.jsonify(job.json_dict()) else: return flask.redirect(flask.url_for('datasets_show', job_id=job.id())+'?workspace='+workspace['workspace_hash']) except: if job: scheduler.delete_job(job) raise
def create(): """ Creates a new GenericImageDatasetJob Returns JSON when requested: {job_id,name,status} or {errors:[]} """ form = GenericImageDatasetForm() ## Is there a request to clone a job with ?clone=<job_id> fill_form_if_cloned(form) if not form.validate_on_submit(): if request_wants_json(): return flask.jsonify({'errors': form.errors}), 400 else: return flask.render_template('datasets/images/generic/new.html', form=form), 400 job = None try: job = GenericImageDatasetJob( username = utils.auth.get_username(), name = form.dataset_name.data, mean_file = form.prebuilt_mean_file.data.strip(), ) if form.method.data == 'prebuilt': pass else: raise ValueError('method not supported') force_same_shape = form.force_same_shape.data job.tasks.append( tasks.AnalyzeDbTask( job_dir = job.dir(), database = form.prebuilt_train_images.data, purpose = form.prebuilt_train_images.label.text, force_same_shape = force_same_shape, ) ) if form.prebuilt_train_labels.data: job.tasks.append( tasks.AnalyzeDbTask( job_dir = job.dir(), database = form.prebuilt_train_labels.data, purpose = form.prebuilt_train_labels.label.text, force_same_shape = force_same_shape, ) ) if form.prebuilt_val_images.data: job.tasks.append( tasks.AnalyzeDbTask( job_dir = job.dir(), database = form.prebuilt_val_images.data, purpose = form.prebuilt_val_images.label.text, force_same_shape = force_same_shape, ) ) if form.prebuilt_val_labels.data: job.tasks.append( tasks.AnalyzeDbTask( job_dir = job.dir(), database = form.prebuilt_val_labels.data, purpose = form.prebuilt_val_labels.label.text, force_same_shape = force_same_shape, ) ) ## Save form data with the job so we can easily clone it later. save_form_to_job(job, form) scheduler.add_job(job) if request_wants_json(): return flask.jsonify(job.json_dict()) else: return flask.redirect(flask.url_for('digits.dataset.views.show', job_id=job.id())) except: if job: scheduler.delete_job(job) raise
def infer_db(): """ Infer a database """ model_job = job_from_request() if not 'db_path' in flask.request.form or flask.request.form['db_path'] is None: raise werkzeug.exceptions.BadRequest('db_path is a required field') db_path = flask.request.form['db_path'] if not os.path.exists(db_path): raise werkzeug.exceptions.BadRequest('DB "%s" does not exit' % db_path) epoch = None if 'snapshot_epoch' in flask.request.form: epoch = float(flask.request.form['snapshot_epoch']) if 'dont_resize' in flask.request.form and flask.request.form['dont_resize']: resize = False else: resize = True # create inference job inference_job = ImageInferenceJob( username=utils.auth.get_username(), name="Infer Many Images", model=model_job, images=db_path, epoch=epoch, layers='none', resize=resize, ) # schedule tasks scheduler.add_job(inference_job) # wait for job to complete inference_job.wait_completion() # retrieve inference data inputs, outputs, _ = inference_job.get_data() # set return status code status_code = 500 if inference_job.status == 'E' else 200 # delete job folder and remove from scheduler list scheduler.delete_job(inference_job) if outputs is not None and len(outputs) < 1: # an error occurred outputs = None if inputs is not None: keys = [str(idx) for idx in inputs['ids']] inference_views_html, header_html, app_begin_html, app_end_html = get_inference_visualizations( model_job.dataset, inputs, outputs) else: inference_views_html = None header_html = None keys = None app_begin_html = None app_end_html = None if request_wants_json(): result = {} for i, key in enumerate(keys): result[key] = dict((name, blob[i].tolist()) for name,blob in outputs.iteritems()) return flask.jsonify({'outputs': result}), status_code else: return flask.render_template( 'models/images/generic/infer_db.html', model_job=model_job, job=inference_job, keys=keys, inference_views_html=inference_views_html, header_html=header_html, app_begin_html=app_begin_html, app_end_html=app_end_html, ), status_code
def infer_one(): """ Infer one image """ model_job = job_from_request() remove_image_path = False if 'image_path' in flask.request.form and flask.request.form['image_path']: image_path = flask.request.form['image_path'] elif 'image_file' in flask.request.files and flask.request.files['image_file']: outfile = tempfile.mkstemp(suffix='.bin') flask.request.files['image_file'].save(outfile[1]) image_path = outfile[1] os.close(outfile[0]) remove_image_path = True else: raise werkzeug.exceptions.BadRequest('must provide image_path or image_file') epoch = None if 'snapshot_epoch' in flask.request.form: epoch = float(flask.request.form['snapshot_epoch']) layers = 'none' if 'show_visualizations' in flask.request.form and flask.request.form['show_visualizations']: layers = 'all' if 'dont_resize' in flask.request.form and flask.request.form['dont_resize']: resize = False else: resize = True # create inference job inference_job = ImageInferenceJob( username= utils.auth.get_username(), name= "Infer One Image", model=model_job, images=[image_path], epoch=epoch, layers=layers, resize=resize, ) # schedule tasks scheduler.add_job(inference_job) # wait for job to complete inference_job.wait_completion() # retrieve inference data inputs, outputs, model_visualization = inference_job.get_data() # set return status code status_code = 500 if inference_job.status == 'E' else 200 # delete job folder and remove from scheduler list scheduler.delete_job(inference_job) if remove_image_path: os.remove(image_path) if inputs is not None and len(inputs['data']) == 1: image = utils.image.embed_image_html(inputs['data'][0]) visualizations, header_html, app_begin_html, app_end_html = get_inference_visualizations( model_job.dataset, inputs, outputs) inference_view_html = visualizations[0] else: image = None inference_view_html = None header_html = None app_begin_html = None app_end_html = None if request_wants_json(): return flask.jsonify({'outputs': dict((name, blob.tolist()) for name, blob in outputs.iteritems())}), status_code else: return flask.render_template( 'models/images/generic/infer_one.html', model_job=model_job, job=inference_job, image_src=image, inference_view_html=inference_view_html, header_html=header_html, app_begin_html=app_begin_html, app_end_html=app_end_html, visualizations=model_visualization, total_parameters=sum(v['param_count'] for v in model_visualization if v['vis_type'] == 'Weights'), ), status_code
def classify_many(): """ Classify many images and return the top 5 classifications for each Returns JSON when requested: {classifications: {filename: [[category,confidence],...],...}} """ model_job = job_from_request() image_list = flask.request.files.get('image_list') if not image_list: raise werkzeug.exceptions.BadRequest('image_list is a required field') if 'image_folder' in flask.request.form and flask.request.form['image_folder'].strip(): image_folder = flask.request.form['image_folder'] if not os.path.exists(image_folder): raise werkzeug.exceptions.BadRequest('image_folder "%s" does not exit' % image_folder) else: image_folder = None if 'num_test_images' in flask.request.form and flask.request.form['num_test_images'].strip(): num_test_images = int(flask.request.form['num_test_images']) else: num_test_images = None epoch = None if 'snapshot_epoch' in flask.request.form: epoch = float(flask.request.form['snapshot_epoch']) paths = [] ground_truths = [] for line in image_list.readlines(): line = line.strip() if not line: continue path = None # might contain a numerical label at the end match = re.match(r'(.*\S)\s+(\d+)$', line) if match: path = match.group(1) ground_truth = int(match.group(2)) else: path = line ground_truth = None if not utils.is_url(path) and image_folder and not os.path.isabs(path): path = os.path.join(image_folder, path) paths.append(path) ground_truths.append(ground_truth) if num_test_images is not None and len(paths) >= num_test_images: break # create inference job inference_job = ImageInferenceJob( username = utils.auth.get_username(), name = "Classify Many Images", model = model_job, images = paths, epoch = epoch, layers = 'none' ) # schedule tasks scheduler.add_job(inference_job) # wait for job to complete inference_job.wait_completion() # retrieve inference data inputs, outputs, _ = inference_job.get_data() # delete job scheduler.delete_job(inference_job) if outputs is not None and len(outputs) < 1: # an error occurred outputs = None if inputs is not None: # retrieve path and ground truth of images that were successfully processed paths = [paths[idx] for idx in inputs['ids']] ground_truths = [ground_truths[idx] for idx in inputs['ids']] classifications = None if outputs is not None: # convert to class probabilities for viewing last_output_name, last_output_data = outputs.items()[-1] if len(last_output_data) < 1: raise werkzeug.exceptions.BadRequest( 'Unable to classify any image from the file') scores = last_output_data # take top 5 indices = (-scores).argsort()[:, :5] labels = model_job.train_task().get_labels() classifications = [] for image_index, index_list in enumerate(indices): result = [] for i in index_list: # `i` is a category in labels and also an index into scores result.append((labels[i], round(100.0*scores[image_index, i],2))) classifications.append(result) # replace ground truth indices with labels ground_truths = [labels[x] if x is not None and (0 <= x < len(labels)) else None for x in ground_truths] if request_wants_json(): joined = dict(zip(paths, classifications)) return flask.jsonify({'classifications': joined}) else: return flask.render_template('models/images/classification/classify_many.html', model_job = model_job, job = inference_job, paths = paths, classifications = classifications, show_ground_truth= not(ground_truths == [None]*len(ground_truths)), ground_truths = ground_truths )
def infer_db(): """ Infer a database """ model_job = job_from_request() if not 'db_path' in flask.request.form or flask.request.form['db_path'] is None: raise werkzeug.exceptions.BadRequest('db_path is a required field') db_path = flask.request.form['db_path'] if not os.path.exists(db_path): raise werkzeug.exceptions.BadRequest('DB "%s" does not exit' % db_path) epoch = None if 'snapshot_epoch' in flask.request.form: epoch = float(flask.request.form['snapshot_epoch']) # create inference job inference_job = ImageInferenceJob( username = utils.auth.get_username(), name = "Infer Many Images", model = model_job, images = db_path, epoch = epoch, layers = 'none', ) # schedule tasks scheduler.add_job(inference_job) # wait for job to complete inference_job.wait_completion() # retrieve inference data inputs, outputs, _ = inference_job.get_data() # delete job folder and remove from scheduler list scheduler.delete_job(inference_job) if outputs is not None and len(outputs) < 1: # an error occurred outputs = None if inputs is not None: keys = [str(idx) for idx in inputs['ids']] else: keys = None if request_wants_json(): result = {} for i, key in enumerate(keys): result[key] = dict((name, blob[i].tolist()) for name,blob in outputs.iteritems()) return flask.jsonify({'outputs': result}) else: return flask.render_template('models/images/generic/infer_db.html', model_job = model_job, job = inference_job, keys = keys, network_outputs = outputs, )
def image_classification_model_create(): """ Create a new ImageClassificationModelJob Returns JSON when requested: {job_id,name,status} or {errors:[]} """ form = ImageClassificationModelForm() form.dataset.choices = get_datasets() form.standard_networks.choices = get_standard_networks() form.standard_networks.default = get_default_standard_network() form.previous_networks.choices = get_previous_networks() prev_network_snapshots = get_previous_network_snapshots() if not form.validate_on_submit(): if request_wants_json(): return flask.jsonify({'errors': form.errors}), 400 else: return flask.render_template('models/images/classification/new.html', form = form, previous_network_snapshots = prev_network_snapshots, multi_gpu = config_value('caffe_root')['multi_gpu'], ), 400 datasetJob = scheduler.get_job(form.dataset.data) if not datasetJob: raise werkzeug.exceptions.BadRequest( 'Unknown dataset job_id "%s"' % form.dataset.data) job = None try: job = ImageClassificationModelJob( name = form.model_name.data, dataset_id = datasetJob.id(), ) network = caffe_pb2.NetParameter() pretrained_model = None if form.method.data == 'standard': found = False networks_dir = os.path.join(os.path.dirname(digits.__file__), 'standard-networks') for filename in os.listdir(networks_dir): path = os.path.join(networks_dir, filename) if os.path.isfile(path): match = re.match(r'%s.prototxt' % form.standard_networks.data, filename) if match: with open(path) as infile: text_format.Merge(infile.read(), network) found = True break if not found: raise werkzeug.exceptions.BadRequest( 'Unknown standard model "%s"' % form.standard_networks.data) elif form.method.data == 'previous': old_job = scheduler.get_job(form.previous_networks.data) if not old_job: raise werkzeug.exceptions.BadRequest( 'Job not found: %s' % form.previous_networks.data) network.CopyFrom(old_job.train_task().network) # Rename the final layer # XXX making some assumptions about network architecture here ip_layers = [l for l in network.layer if l.type == 'InnerProduct'] if len(ip_layers) > 0: ip_layers[-1].name = '%s_retrain' % ip_layers[-1].name for choice in form.previous_networks.choices: if choice[0] == form.previous_networks.data: epoch = float(flask.request.form['%s-snapshot' % form.previous_networks.data]) if epoch != 0: for filename, e in old_job.train_task().snapshots: if e == epoch: pretrained_model = filename break if pretrained_model is None: raise werkzeug.exceptions.BadRequest( "For the job %s, selected pretrained_model for epoch %d is invalid!" % (form.previous_networks.data, epoch)) if not (os.path.exists(pretrained_model)): raise werkzeug.exceptions.BadRequest( "Pretrained_model for the selected epoch doesn't exists. May be deleted by another user/process. Please restart the server to load the correct pretrained_model details") break elif form.method.data == 'custom': text_format.Merge(form.custom_network.data, network) pretrained_model = form.custom_network_snapshot.data.strip() else: raise werkzeug.exceptions.BadRequest( 'Unrecognized method: "%s"' % form.method.data) policy = {'policy': form.lr_policy.data} if form.lr_policy.data == 'fixed': pass elif form.lr_policy.data == 'step': policy['stepsize'] = form.lr_step_size.data policy['gamma'] = form.lr_step_gamma.data elif form.lr_policy.data == 'multistep': policy['stepvalue'] = form.lr_multistep_values.data policy['gamma'] = form.lr_multistep_gamma.data elif form.lr_policy.data == 'exp': policy['gamma'] = form.lr_exp_gamma.data elif form.lr_policy.data == 'inv': policy['gamma'] = form.lr_inv_gamma.data policy['power'] = form.lr_inv_power.data elif form.lr_policy.data == 'poly': policy['power'] = form.lr_poly_power.data elif form.lr_policy.data == 'sigmoid': policy['stepsize'] = form.lr_sigmoid_step.data policy['gamma'] = form.lr_sigmoid_gamma.data else: raise werkzeug.exceptions.BadRequest( 'Invalid learning rate policy') if config_value('caffe_root')['multi_gpu']: if form.select_gpu_count.data: gpu_count = form.select_gpu_count.data selected_gpus = None else: selected_gpus = [str(gpu) for gpu in form.select_gpus.data] gpu_count = None else: if form.select_gpu.data == 'next': gpu_count = 1 selected_gpus = None else: selected_gpus = [str(form.select_gpu.data)] gpu_count = None job.tasks.append( tasks.CaffeTrainTask( job_dir = job.dir(), dataset = datasetJob, train_epochs = form.train_epochs.data, snapshot_interval = form.snapshot_interval.data, learning_rate = form.learning_rate.data, lr_policy = policy, gpu_count = gpu_count, selected_gpus = selected_gpus, batch_size = form.batch_size.data, val_interval = form.val_interval.data, pretrained_model= pretrained_model, crop_size = form.crop_size.data, use_mean = bool(form.use_mean.data), network = network, random_seed = form.random_seed.data, solver_type = form.solver_type.data, ) ) scheduler.add_job(job) if request_wants_json(): return flask.jsonify(job.json_dict()) else: return flask.redirect(flask.url_for('models_show', job_id=job.id())) except: if job: scheduler.delete_job(job) raise
def classify_one(): """ Classify one image and return the top 5 classifications Returns JSON when requested: {predictions: {category: confidence,...}} """ model_job = job_from_request() remove_image_path = False if 'image_path' in flask.request.form and flask.request.form['image_path']: image_path = flask.request.form['image_path'] elif 'image_file' in flask.request.files and flask.request.files[ 'image_file']: outfile = tempfile.mkstemp(suffix='.png') flask.request.files['image_file'].save(outfile[1]) image_path = outfile[1] os.close(outfile[0]) remove_image_path = True else: raise werkzeug.exceptions.BadRequest( 'must provide image_path or image_file') epoch = None if 'snapshot_epoch' in flask.request.form: epoch = float(flask.request.form['snapshot_epoch']) layers = 'none' if 'show_visualizations' in flask.request.form and flask.request.form[ 'show_visualizations']: layers = 'all' # create inference job inference_job = ImageInferenceJob(username=utils.auth.get_username(), name="Classify One Image", model=model_job, images=[image_path], epoch=epoch, layers=layers) # schedule tasks scheduler.add_job(inference_job) # wait for job to complete inference_job.wait_completion() # retrieve inference data inputs, outputs, visualizations = inference_job.get_data() # set return status code status_code = 500 if inference_job.status == 'E' else 200 # delete job scheduler.delete_job(inference_job) if remove_image_path: os.remove(image_path) image = None predictions = [] if inputs is not None and len(inputs['data']) == 1: image = utils.image.embed_image_html(inputs['data'][0]) # convert to class probabilities for viewing last_output_name, last_output_data = outputs.items()[-1] if len(last_output_data) == 1: scores = last_output_data[0].flatten() indices = (-scores).argsort() labels = model_job.train_task().get_labels() predictions = [] for i in indices: # ignore prediction if we don't have a label for the corresponding class # the user might have set the final fully-connected layer's num_output to # too high a value if i < len(labels): predictions.append((labels[i], scores[i])) predictions = [(p[0], round(100.0 * p[1], 2)) for p in predictions[:5]] if request_wants_json(): return flask.jsonify({'predictions': predictions}), status_code else: return flask.render_template( 'models/images/classification/classify_one.html', model_job=model_job, job=inference_job, image_src=image, predictions=predictions, visualizations=visualizations, total_parameters=sum(v['param_count'] for v in visualizations if v['vis_type'] == 'Weights'), ), status_code
def create(extension_id=None): """ Create a new GenericImageModelJob Returns JSON when requested: {job_id,name,status} or {errors:[]} """ form = GenericImageModelForm() form.dataset.choices = get_datasets(extension_id) form.standard_networks.choices = [] form.previous_networks.choices = get_previous_networks() prev_network_snapshots = get_previous_network_snapshots() ## Is there a request to clone a job with ?clone=<job_id> fill_form_if_cloned(form) if not form.validate_on_submit(): if request_wants_json(): return flask.jsonify({'errors': form.errors}), 400 else: return flask.render_template( 'models/images/generic/new.html', extension_id=extension_id, extension_title=extensions.data.get_extension( extension_id).get_title() if extension_id else None, form=form, frameworks=frameworks.get_frameworks(), previous_network_snapshots=prev_network_snapshots, previous_networks_fullinfo=get_previous_networks_fulldetails(), multi_gpu=config_value('caffe_root')['multi_gpu'], ), 400 datasetJob = scheduler.get_job(form.dataset.data) if not datasetJob: raise werkzeug.exceptions.BadRequest('Unknown dataset job_id "%s"' % form.dataset.data) # sweeps will be a list of the the permutations of swept fields # Get swept learning_rate sweeps = [{'learning_rate': v} for v in form.learning_rate.data] add_learning_rate = len(form.learning_rate.data) > 1 # Add swept batch_size sweeps = [ dict(s.items() + [('batch_size', bs)]) for bs in form.batch_size.data for s in sweeps[:] ] add_batch_size = len(form.batch_size.data) > 1 n_jobs = len(sweeps) jobs = [] for sweep in sweeps: # Populate the form with swept data to be used in saving and # launching jobs. form.learning_rate.data = sweep['learning_rate'] form.batch_size.data = sweep['batch_size'] # Augment Job Name extra = '' if add_learning_rate: extra += ' learning_rate:%s' % str(form.learning_rate.data[0]) if add_batch_size: extra += ' batch_size:%d' % form.batch_size.data[0] job = None try: job = GenericImageModelJob( username=utils.auth.get_username(), name=form.model_name.data + extra, dataset_id=datasetJob.id(), ) # get framework (hard-coded to caffe for now) fw = frameworks.get_framework_by_id(form.framework.data) pretrained_model = None #if form.method.data == 'standard': if form.method.data == 'previous': old_job = scheduler.get_job(form.previous_networks.data) if not old_job: raise werkzeug.exceptions.BadRequest( 'Job not found: %s' % form.previous_networks.data) use_same_dataset = (old_job.dataset_id == job.dataset_id) network = fw.get_network_from_previous( old_job.train_task().network, use_same_dataset) for choice in form.previous_networks.choices: if choice[0] == form.previous_networks.data: epoch = float( flask.request.form['%s-snapshot' % form.previous_networks.data]) if epoch == 0: pass elif epoch == -1: pretrained_model = old_job.train_task( ).pretrained_model else: for filename, e in old_job.train_task().snapshots: if e == epoch: pretrained_model = filename break if pretrained_model is None: raise werkzeug.exceptions.BadRequest( "For the job %s, selected pretrained_model for epoch %d is invalid!" % (form.previous_networks.data, epoch)) if not (os.path.exists(pretrained_model)): raise werkzeug.exceptions.BadRequest( "Pretrained_model for the selected epoch doesn't exists. May be deleted by another user/process. Please restart the server to load the correct pretrained_model details" ) break elif form.method.data == 'custom': network = fw.get_network_from_desc(form.custom_network.data) pretrained_model = form.custom_network_snapshot.data.strip() else: raise werkzeug.exceptions.BadRequest( 'Unrecognized method: "%s"' % form.method.data) policy = {'policy': form.lr_policy.data} if form.lr_policy.data == 'fixed': pass elif form.lr_policy.data == 'step': policy['stepsize'] = form.lr_step_size.data policy['gamma'] = form.lr_step_gamma.data elif form.lr_policy.data == 'multistep': policy['stepvalue'] = form.lr_multistep_values.data policy['gamma'] = form.lr_multistep_gamma.data elif form.lr_policy.data == 'exp': policy['gamma'] = form.lr_exp_gamma.data elif form.lr_policy.data == 'inv': policy['gamma'] = form.lr_inv_gamma.data policy['power'] = form.lr_inv_power.data elif form.lr_policy.data == 'poly': policy['power'] = form.lr_poly_power.data elif form.lr_policy.data == 'sigmoid': policy['stepsize'] = form.lr_sigmoid_step.data policy['gamma'] = form.lr_sigmoid_gamma.data else: raise werkzeug.exceptions.BadRequest( 'Invalid learning rate policy') if config_value('caffe_root')['multi_gpu']: if form.select_gpu_count.data: gpu_count = form.select_gpu_count.data selected_gpus = None else: selected_gpus = [str(gpu) for gpu in form.select_gpus.data] gpu_count = None else: if form.select_gpu.data == 'next': gpu_count = 1 selected_gpus = None else: selected_gpus = [str(form.select_gpu.data)] gpu_count = None # Python Layer File may be on the server or copied from the client. fs.copy_python_layer_file( bool(form.python_layer_from_client.data), job.dir(), (flask.request.files[form.python_layer_client_file.name] if form.python_layer_client_file.name in flask.request.files else ''), form.python_layer_server_file.data) job.tasks.append( fw.create_train_task( job=job, dataset=datasetJob, train_epochs=form.train_epochs.data, snapshot_interval=form.snapshot_interval.data, learning_rate=form.learning_rate.data[0], lr_policy=policy, gpu_count=gpu_count, selected_gpus=selected_gpus, batch_size=form.batch_size.data[0], batch_accumulation=form.batch_accumulation.data, val_interval=form.val_interval.data, pretrained_model=pretrained_model, crop_size=form.crop_size.data, use_mean=form.use_mean.data, network=network, random_seed=form.random_seed.data, solver_type=form.solver_type.data, shuffle=form.shuffle.data, )) ## Save form data with the job so we can easily clone it later. save_form_to_job(job, form) jobs.append(job) scheduler.add_job(job) if n_jobs == 1: if request_wants_json(): return flask.jsonify(job.json_dict()) else: return flask.redirect( flask.url_for('digits.model.views.show', job_id=job.id())) except: if job: scheduler.delete_job(job) raise if request_wants_json(): return flask.jsonify(jobs=[job.json_dict() for job in jobs]) # If there are multiple jobs launched, go to the home page. return flask.redirect('/')
def infer_many(): """ Infer many images """ model_job = job_from_request() image_list = flask.request.files.get('image_list') if not image_list: raise werkzeug.exceptions.BadRequest('image_list is a required field') if 'image_folder' in flask.request.form and flask.request.form[ 'image_folder'].strip(): image_folder = flask.request.form['image_folder'] if not os.path.exists(image_folder): raise werkzeug.exceptions.BadRequest( 'image_folder "%s" does not exit' % image_folder) else: image_folder = None if 'num_test_images' in flask.request.form and flask.request.form[ 'num_test_images'].strip(): num_test_images = int(flask.request.form['num_test_images']) else: num_test_images = None epoch = None if 'snapshot_epoch' in flask.request.form: epoch = float(flask.request.form['snapshot_epoch']) paths = [] for line in image_list.readlines(): line = line.strip() if not line: continue path = None # might contain a numerical label at the end match = re.match(r'(.*\S)\s+\d+$', line) if match: path = match.group(1) else: path = line if not utils.is_url(path) and image_folder and not os.path.isabs(path): path = os.path.join(image_folder, path) paths.append(path) if num_test_images is not None and len(paths) >= num_test_images: break # create inference job inference_job = ImageInferenceJob(username=utils.auth.get_username(), name="Infer Many Images", model=model_job, images=paths, epoch=epoch, layers='none') # schedule tasks scheduler.add_job(inference_job) # wait for job to complete inference_job.wait_completion() # retrieve inference data inputs, outputs, _ = inference_job.get_data() # set return status code status_code = 500 if inference_job.status == 'E' else 200 # delete job folder and remove from scheduler list scheduler.delete_job(inference_job) if outputs is not None and len(outputs) < 1: # an error occurred outputs = None if inputs is not None: paths = [paths[idx] for idx in inputs['ids']] inference_views_html, header_html = get_inference_visualizations( model_job.dataset, inputs, outputs) else: inference_views_html = None header_html = None if request_wants_json(): result = {} for i, path in enumerate(paths): result[path] = dict( (name, blob[i].tolist()) for name, blob in outputs.iteritems()) return flask.jsonify({'outputs': result}), status_code else: return flask.render_template( 'models/images/generic/infer_many.html', model_job=model_job, job=inference_job, paths=paths, inference_views_html=inference_views_html, header_html=header_html, ), status_code
def infer_db(): """ Infer a database """ model_job = job_from_request() if not 'db_path' in flask.request.form or flask.request.form[ 'db_path'] is None: raise werkzeug.exceptions.BadRequest('db_path is a required field') db_path = flask.request.form['db_path'] if not os.path.exists(db_path): raise werkzeug.exceptions.BadRequest('DB "%s" does not exit' % db_path) epoch = None if 'snapshot_epoch' in flask.request.form: epoch = float(flask.request.form['snapshot_epoch']) # create inference job inference_job = ImageInferenceJob( username=utils.auth.get_username(), name="Infer Many Images", model=model_job, images=db_path, epoch=epoch, layers='none', ) # schedule tasks scheduler.add_job(inference_job) # wait for job to complete inference_job.wait_completion() # retrieve inference data inputs, outputs, _ = inference_job.get_data() # set return status code status_code = 500 if inference_job.status == 'E' else 200 # delete job folder and remove from scheduler list scheduler.delete_job(inference_job) if outputs is not None and len(outputs) < 1: # an error occurred outputs = None if inputs is not None: keys = [str(idx) for idx in inputs['ids']] inference_views_html, header_html = get_inference_visualizations( model_job.dataset, inputs, outputs) else: inference_views_html = None header_html = None keys = None if request_wants_json(): result = {} for i, key in enumerate(keys): result[key] = dict( (name, blob[i].tolist()) for name, blob in outputs.iteritems()) return flask.jsonify({'outputs': result}), status_code else: return flask.render_template( 'models/images/generic/infer_db.html', model_job=model_job, job=inference_job, keys=keys, inference_views_html=inference_views_html, header_html=header_html, ), status_code
def infer_one(): """ Infer one image """ model_job = job_from_request() remove_image_path = False if 'image_path' in flask.request.form and flask.request.form['image_path']: image_path = flask.request.form['image_path'] elif 'image_file' in flask.request.files and flask.request.files[ 'image_file']: outfile = tempfile.mkstemp(suffix='.bin') flask.request.files['image_file'].save(outfile[1]) image_path = outfile[1] os.close(outfile[0]) remove_image_path = True else: raise werkzeug.exceptions.BadRequest( 'must provide image_path or image_file') epoch = None if 'snapshot_epoch' in flask.request.form: epoch = float(flask.request.form['snapshot_epoch']) layers = 'none' if 'show_visualizations' in flask.request.form and flask.request.form[ 'show_visualizations']: layers = 'all' # create inference job inference_job = ImageInferenceJob(username=utils.auth.get_username(), name="Infer One Image", model=model_job, images=[image_path], epoch=epoch, layers=layers) # schedule tasks scheduler.add_job(inference_job) # wait for job to complete inference_job.wait_completion() # retrieve inference data inputs, outputs, model_visualization = inference_job.get_data() # set return status code status_code = 500 if inference_job.status == 'E' else 200 # delete job folder and remove from scheduler list scheduler.delete_job(inference_job) if remove_image_path: os.remove(image_path) if inputs is not None and len(inputs['data']) == 1: image = utils.image.embed_image_html(inputs['data'][0]) visualizations, header_html = get_inference_visualizations( model_job.dataset, inputs, outputs) inference_view_html = visualizations[0] else: image = None inference_view_html = None header_html = None if request_wants_json(): return flask.jsonify({ 'outputs': dict((name, blob.tolist()) for name, blob in outputs.iteritems()) }), status_code else: return flask.render_template( 'models/images/generic/infer_one.html', model_job=model_job, job=inference_job, image_src=image, inference_view_html=inference_view_html, header_html=header_html, visualizations=model_visualization, total_parameters=sum(v['param_count'] for v in model_visualization if v['vis_type'] == 'Weights'), ), status_code
def create(): """ Create a new ImageClassificationModelJob Returns JSON when requested: {job_id,name,status} or {errors:[]} """ form = ImageClassificationModelForm() form.dataset.choices = get_datasets() form.standard_networks.choices = get_standard_networks() form.standard_networks.default = get_default_standard_network() form.previous_networks.choices = get_previous_networks() form.pretrained_networks.choices = get_pretrained_networks() prev_network_snapshots = get_previous_network_snapshots() # Is there a request to clone a job with ?clone=<job_id> fill_form_if_cloned(form) if not form.validate_on_submit(): if request_wants_json(): return flask.jsonify({'errors': form.errors}), 400 else: return flask.render_template( 'models/images/classification/new.html', form=form, frameworks=frameworks.get_frameworks(), previous_network_snapshots=prev_network_snapshots, previous_networks_fullinfo=get_previous_networks_fulldetails(), pretrained_networks_fullinfo= get_pretrained_networks_fulldetails(), multi_gpu=config_value('caffe')['multi_gpu'], ), 400 datasetJob = scheduler.get_job(form.dataset.data) if not datasetJob: raise werkzeug.exceptions.BadRequest('Unknown dataset job_id "%s"' % form.dataset.data) # sweeps will be a list of the the permutations of swept fields # Get swept learning_rate sweeps = [{'learning_rate': v} for v in form.learning_rate.data] add_learning_rate = len(form.learning_rate.data) > 1 # Add swept batch_size sweeps = [ dict(s.items() + [('batch_size', bs)]) for bs in form.batch_size.data for s in sweeps[:] ] add_batch_size = len(form.batch_size.data) > 1 n_jobs = len(sweeps) jobs = [] for sweep in sweeps: # Populate the form with swept data to be used in saving and # launching jobs. form.learning_rate.data = sweep['learning_rate'] form.batch_size.data = sweep['batch_size'] # Augment Job Name extra = '' if add_learning_rate: extra += ' learning_rate:%s' % str(form.learning_rate.data[0]) if add_batch_size: extra += ' batch_size:%d' % form.batch_size.data[0] job = None try: job = ImageClassificationModelJob( username=utils.auth.get_username(), name=form.model_name.data + extra, group=form.group_name.data, dataset_id=datasetJob.id(), ) # get handle to framework object fw = frameworks.get_framework_by_id(form.framework.data) pretrained_model = None if form.method.data == 'standard': found = False # can we find it in standard networks? network_desc = fw.get_standard_network_desc( form.standard_networks.data) if network_desc: found = True network = fw.get_network_from_desc(network_desc) if not found: raise werkzeug.exceptions.BadRequest( 'Unknown standard model "%s"' % form.standard_networks.data) elif form.method.data == 'previous': old_job = scheduler.get_job(form.previous_networks.data) if not old_job: raise werkzeug.exceptions.BadRequest( 'Job not found: %s' % form.previous_networks.data) use_same_dataset = (old_job.dataset_id == job.dataset_id) network = fw.get_network_from_previous( old_job.train_task().network, use_same_dataset) for choice in form.previous_networks.choices: if choice[0] == form.previous_networks.data: epoch = float( flask.request.form['%s-snapshot' % form.previous_networks.data]) if epoch == 0: pass elif epoch == -1: pretrained_model = old_job.train_task( ).pretrained_model else: # verify snapshot exists pretrained_model = old_job.train_task( ).get_snapshot(epoch, download=True) if pretrained_model is None: raise werkzeug.exceptions.BadRequest( "For the job %s, selected pretrained_model for epoch %d is invalid!" % (form.previous_networks.data, epoch)) # the first is the actual file if a list is returned, other should be meta data if isinstance(pretrained_model, list): pretrained_model = pretrained_model[0] if not (os.path.exists(pretrained_model)): raise werkzeug.exceptions.BadRequest( "Pretrained_model for the selected epoch doesn't exist. " "May be deleted by another user/process. " "Please restart the server to load the correct pretrained_model details." ) # get logical path pretrained_model = old_job.train_task( ).get_snapshot(epoch) break elif form.method.data == 'pretrained': pretrained_job = scheduler.get_job( form.pretrained_networks.data) model_def_path = pretrained_job.get_model_def_path() weights_path = pretrained_job.get_weights_path() network = fw.get_network_from_path(model_def_path) pretrained_model = weights_path elif form.method.data == 'custom': network = fw.get_network_from_desc(form.custom_network.data) pretrained_model = form.custom_network_snapshot.data.strip() else: raise werkzeug.exceptions.BadRequest( 'Unrecognized method: "%s"' % form.method.data) policy = {'policy': form.lr_policy.data} if form.lr_policy.data == 'fixed': pass elif form.lr_policy.data == 'step': policy['stepsize'] = form.lr_step_size.data policy['gamma'] = form.lr_step_gamma.data elif form.lr_policy.data == 'multistep': policy['stepvalue'] = form.lr_multistep_values.data policy['gamma'] = form.lr_multistep_gamma.data elif form.lr_policy.data == 'exp': policy['gamma'] = form.lr_exp_gamma.data elif form.lr_policy.data == 'inv': policy['gamma'] = form.lr_inv_gamma.data policy['power'] = form.lr_inv_power.data elif form.lr_policy.data == 'poly': policy['power'] = form.lr_poly_power.data elif form.lr_policy.data == 'sigmoid': policy['stepsize'] = form.lr_sigmoid_step.data policy['gamma'] = form.lr_sigmoid_gamma.data else: raise werkzeug.exceptions.BadRequest( 'Invalid learning rate policy') if config_value('caffe')['multi_gpu']: if form.select_gpus.data: selected_gpus = [str(gpu) for gpu in form.select_gpus.data] gpu_count = None elif form.select_gpu_count.data: gpu_count = form.select_gpu_count.data selected_gpus = None else: gpu_count = 1 selected_gpus = None else: if form.select_gpu.data == 'next': gpu_count = 1 selected_gpus = None else: selected_gpus = [str(form.select_gpu.data)] gpu_count = None # Set up data augmentation structure data_aug = {} data_aug['flip'] = form.aug_flip.data data_aug['quad_rot'] = form.aug_quad_rot.data data_aug['rot'] = form.aug_rot.data data_aug['scale'] = form.aug_scale.data data_aug['noise'] = form.aug_noise.data data_aug['contrast'] = form.aug_contrast.data data_aug['whitening'] = form.aug_whitening.data data_aug['hsv_use'] = form.aug_hsv_use.data data_aug['hsv_h'] = form.aug_hsv_h.data data_aug['hsv_s'] = form.aug_hsv_s.data data_aug['hsv_v'] = form.aug_hsv_v.data # Python Layer File may be on the server or copied from the client. fs.copy_python_layer_file( bool(form.python_layer_from_client.data), job.dir(), (flask.request.files[form.python_layer_client_file.name] if form.python_layer_client_file.name in flask.request.files else ''), form.python_layer_server_file.data) job.tasks.append( fw.create_train_task( job=job, dataset=datasetJob, train_epochs=form.train_epochs.data, snapshot_interval=form.snapshot_interval.data, learning_rate=form.learning_rate.data[0], lr_policy=policy, gpu_count=gpu_count, selected_gpus=selected_gpus, batch_size=form.batch_size.data[0], batch_accumulation=form.batch_accumulation.data, val_interval=form.val_interval.data, traces_interval=form.traces_interval.data, pretrained_model=pretrained_model, crop_size=form.crop_size.data, use_mean=form.use_mean.data, network=network, random_seed=form.random_seed.data, solver_type=form.solver_type.data, rms_decay=form.rms_decay.data, shuffle=form.shuffle.data, data_aug=data_aug, )) # Save form data with the job so we can easily clone it later. save_form_to_job(job, form) jobs.append(job) scheduler.add_job(job) if n_jobs == 1: if request_wants_json(): return flask.jsonify(job.json_dict()) else: return flask.redirect( flask.url_for('digits.model.views.show', job_id=job.id())) except: if job: scheduler.delete_job(job) raise if request_wants_json(): return flask.jsonify(jobs=[j.json_dict() for j in jobs]) # If there are multiple jobs launched, go to the home page. return flask.redirect('/')
def top_n(): """ Classify many images and show the top N images per category by confidence """ model_job = job_from_request() image_list = flask.request.files['image_list'] if not image_list: raise werkzeug.exceptions.BadRequest('File upload not found') epoch = None if 'snapshot_epoch' in flask.request.form: epoch = float(flask.request.form['snapshot_epoch']) if 'top_n' in flask.request.form and flask.request.form['top_n'].strip(): top_n = int(flask.request.form['top_n']) else: top_n = 9 if 'image_folder' in flask.request.form and flask.request.form[ 'image_folder'].strip(): image_folder = flask.request.form['image_folder'] if not os.path.exists(image_folder): raise werkzeug.exceptions.BadRequest( 'image_folder "%s" does not exit' % image_folder) else: image_folder = None if 'num_test_images' in flask.request.form and flask.request.form[ 'num_test_images'].strip(): num_test_images = int(flask.request.form['num_test_images']) else: num_test_images = None paths, _ = read_image_list(image_list, image_folder, num_test_images) # create inference job inference_job = ImageInferenceJob(username=utils.auth.get_username(), name="TopN Image Classification", model=model_job, images=paths, epoch=epoch, layers='none') # schedule tasks scheduler.add_job(inference_job) # wait for job to complete inference_job.wait_completion() # retrieve inference data inputs, outputs, _ = inference_job.get_data() # delete job scheduler.delete_job(inference_job) results = None if outputs is not None and len(outputs) > 0: # convert to class probabilities for viewing last_output_name, last_output_data = outputs.items()[-1] scores = last_output_data if scores is None: raise RuntimeError('An error occurred while processing the images') labels = model_job.train_task().get_labels() images = inputs['data'] indices = (-scores).argsort(axis=0)[:top_n] results = [] # Can't have more images per category than the number of images images_per_category = min(top_n, len(images)) # Can't have more categories than the number of labels or the number of outputs n_categories = min(indices.shape[1], len(labels)) for i in xrange(n_categories): result_images = [] for j in xrange(images_per_category): result_images.append(images[indices[j][i]]) results.append((labels[i], utils.image.embed_image_html( utils.image.vis_square(np.array(result_images), colormap='white')))) return flask.render_template( 'models/images/classification/top_n.html', model_job=model_job, job=inference_job, results=results, )
def infer_extension(): """ Perform inference using the data from an extension inference form """ model_job = job_from_request() inference_db_job = None try: # create an inference database inference_db_job = create_inference_db(model_job) db_path = inference_db_job.get_feature_db_path(constants.TEST_DB) # create database creation job epoch = None if 'snapshot_epoch' in flask.request.form: epoch = float(flask.request.form['snapshot_epoch']) layers = 'none' if 'show_visualizations' in flask.request.form and flask.request.form['show_visualizations']: layers = 'all' # create inference job inference_job = ImageInferenceJob( username=utils.auth.get_username(), name="Inference", model=model_job, images=db_path, epoch=epoch, layers=layers, resize=False, ) # schedule tasks scheduler.add_job(inference_job) # wait for job to complete inference_job.wait_completion() finally: if inference_db_job: scheduler.delete_job(inference_db_job) # retrieve inference data inputs, outputs, model_visualization = inference_job.get_data() # set return status code status_code = 500 if inference_job.status == 'E' else 200 # delete job folder and remove from scheduler list scheduler.delete_job(inference_job) if outputs is not None and len(outputs) < 1: # an error occurred outputs = None if inputs is not None: keys = [str(idx) for idx in inputs['ids']] inference_views_html, header_html, app_begin_html, app_end_html = get_inference_visualizations( model_job.dataset, inputs, outputs) else: inference_views_html = None header_html = None keys = None app_begin_html = None app_end_html = None if request_wants_json(): result = {} for i, key in enumerate(keys): result[key] = dict((name, blob[i].tolist()) for name,blob in outputs.iteritems()) return flask.jsonify({'outputs': result}), status_code else: return flask.render_template( 'models/images/generic/infer_extension.html', model_job=model_job, job=inference_job, keys=keys, inference_views_html=inference_views_html, header_html=header_html, app_begin_html=app_begin_html, app_end_html=app_end_html, visualizations=model_visualization, total_parameters=sum(v['param_count'] for v in model_visualization if v['vis_type'] == 'Weights'), ), status_code
def generic_image_model_create(): """ Create a new GenericImageModelJob Returns JSON when requested: {job_id,name,status} or {errors:[]} """ form = GenericImageModelForm() form.dataset.choices = get_datasets() form.standard_networks.choices = [] form.previous_networks.choices = get_previous_networks() prev_network_snapshots = get_previous_network_snapshots() if not form.validate_on_submit(): if request_wants_json(): return flask.jsonify({'errors': form.errors}), 400 else: return flask.render_template( 'models/images/generic/new.html', form=form, previous_network_snapshots=prev_network_snapshots, previous_networks_fullinfo=get_previous_networks_fulldetails(), multi_gpu=config_value('caffe_root')['multi_gpu'], ), 400 datasetJob = scheduler.get_job(form.dataset.data) if not datasetJob: raise werkzeug.exceptions.BadRequest('Unknown dataset job_id "%s"' % form.dataset.data) job = None try: job = GenericImageModelJob( name=form.model_name.data, dataset_id=datasetJob.id(), ) # get framework (hard-coded to caffe for now) fw = frameworks.get_framework_by_id('caffe') pretrained_model = None #if form.method.data == 'standard': if form.method.data == 'previous': old_job = scheduler.get_job(form.previous_networks.data) if not old_job: raise werkzeug.exceptions.BadRequest( 'Job not found: %s' % form.previous_networks.data) network = fw.get_network_from_previous( old_job.train_task().network) for choice in form.previous_networks.choices: if choice[0] == form.previous_networks.data: epoch = float( flask.request.form['%s-snapshot' % form.previous_networks.data]) if epoch == 0: pass elif epoch == -1: pretrained_model = old_job.train_task( ).pretrained_model else: for filename, e in old_job.train_task().snapshots: if e == epoch: pretrained_model = filename break if pretrained_model is None: raise werkzeug.exceptions.BadRequest( "For the job %s, selected pretrained_model for epoch %d is invalid!" % (form.previous_networks.data, epoch)) if not (os.path.exists(pretrained_model)): raise werkzeug.exceptions.BadRequest( "Pretrained_model for the selected epoch doesn't exists. May be deleted by another user/process. Please restart the server to load the correct pretrained_model details" ) break elif form.method.data == 'custom': network = fw.get_network_from_desc(form.custom_network.data) pretrained_model = form.custom_network_snapshot.data.strip() else: raise werkzeug.exceptions.BadRequest('Unrecognized method: "%s"' % form.method.data) policy = {'policy': form.lr_policy.data} if form.lr_policy.data == 'fixed': pass elif form.lr_policy.data == 'step': policy['stepsize'] = form.lr_step_size.data policy['gamma'] = form.lr_step_gamma.data elif form.lr_policy.data == 'multistep': policy['stepvalue'] = form.lr_multistep_values.data policy['gamma'] = form.lr_multistep_gamma.data elif form.lr_policy.data == 'exp': policy['gamma'] = form.lr_exp_gamma.data elif form.lr_policy.data == 'inv': policy['gamma'] = form.lr_inv_gamma.data policy['power'] = form.lr_inv_power.data elif form.lr_policy.data == 'poly': policy['power'] = form.lr_poly_power.data elif form.lr_policy.data == 'sigmoid': policy['stepsize'] = form.lr_sigmoid_step.data policy['gamma'] = form.lr_sigmoid_gamma.data else: raise werkzeug.exceptions.BadRequest( 'Invalid learning rate policy') if config_value('caffe_root')['multi_gpu']: if form.select_gpu_count.data: gpu_count = form.select_gpu_count.data selected_gpus = None else: selected_gpus = [str(gpu) for gpu in form.select_gpus.data] gpu_count = None else: if form.select_gpu.data == 'next': gpu_count = 1 selected_gpus = None else: selected_gpus = [str(form.select_gpu.data)] gpu_count = None job.tasks.append( fw.create_train_task( job_dir=job.dir(), dataset=datasetJob, train_epochs=form.train_epochs.data, snapshot_interval=form.snapshot_interval.data, learning_rate=form.learning_rate.data, lr_policy=policy, gpu_count=gpu_count, selected_gpus=selected_gpus, batch_size=form.batch_size.data, val_interval=form.val_interval.data, pretrained_model=pretrained_model, crop_size=form.crop_size.data, use_mean=bool(form.use_mean.data), network=network, random_seed=form.random_seed.data, solver_type=form.solver_type.data, )) scheduler.add_job(job) if request_wants_json(): return flask.jsonify(job.json_dict()) else: return flask.redirect(flask.url_for('models_show', job_id=job.id())) except: if job: scheduler.delete_job(job) raise
def image_classification_model_create(): form = ImageClassificationModelForm() form.dataset.choices = get_datasets() form.standard_networks.choices = get_standard_networks() form.standard_networks.default = get_default_standard_network() form.previous_networks.choices = get_previous_networks() set_previous_network_snapshots(form) if not form.validate_on_submit(): return render_template('models/images/classification/new.html', form=form), 400 datasetJob = scheduler.get_job(form.dataset.data) if not datasetJob: return 'Unknown dataset job_id "%s"' % form.dataset.data, 500 job = None try: job = ImageClassificationModelJob( name = form.model_name.data, dataset_id = datasetJob.id(), ) network = caffe_pb2.NetParameter() pretrained_model = None if form.method.data == 'standard': found = False networks_dir = os.path.join(os.path.dirname(digits.__file__), 'standard-networks') for filename in os.listdir(networks_dir): path = os.path.join(networks_dir, filename) if os.path.isfile(path): match = re.match(r'%s.prototxt' % form.standard_networks.data, filename) if match: with open(path) as infile: text_format.Merge(infile.read(), network) found = True break if not found: raise Exception('Unknown standard model "%s"' % form.standard_networks.data) elif form.method.data == 'previous': old_job = scheduler.get_job(form.previous_networks.data) if not old_job: raise Exception('Job not found: %s' % form.previous_networks.data) network.CopyFrom(old_job.train_task().network) for i, choice in enumerate(form.previous_networks.choices): if choice[0] == form.previous_networks.data: epoch = form.previous_network_snapshots[i].data if epoch != 'none': for filename, e in old_job.train_task().snapshots: if e == epoch: pretrained_model = filename break break elif form.method.data == 'custom': text_format.Merge(form.custom_network.data, network) pretrained_model = form.custom_network_snapshot.data.strip() else: raise Exception('Unrecognized method: "%s"' % form.method.data) policy = {'policy': form.lr_policy.data} if form.lr_policy.data == 'fixed': pass elif form.lr_policy.data == 'step': policy['stepsize'] = form.lr_step_size.data policy['gamma'] = form.lr_step_gamma.data elif form.lr_policy.data == 'multistep': policy['stepvalue'] = form.lr_multistep_values.data policy['gamma'] = form.lr_multistep_gamma.data elif form.lr_policy.data == 'exp': policy['gamma'] = form.lr_exp_gamma.data elif form.lr_policy.data == 'inv': policy['gamma'] = form.lr_inv_gamma.data policy['power'] = form.lr_inv_power.data elif form.lr_policy.data == 'poly': policy['power'] = form.lr_poly_power.data elif form.lr_policy.data == 'sigmoid': policy['stepsize'] = form.lr_sigmoid_step.data policy['gamma'] = form.lr_sigmoid_gamma.data else: return 'Invalid policy', 404 job.tasks.append( tasks.CaffeTrainTask( job_dir = job.dir(), dataset = datasetJob, train_epochs = form.train_epochs.data, learning_rate = form.learning_rate.data, lr_policy = policy, batch_size = form.batch_size.data, val_interval = form.val_interval.data, pretrained_model= pretrained_model, crop_size = form.crop_size.data, use_mean = form.use_mean.data, network = network, ) ) scheduler.add_job(job) return redirect(url_for('models_show', job_id=job.id())) except: if job: scheduler.delete_job(job) raise
def create(): """ Creates a new GenericImageDatasetJob Returns JSON when requested: {job_id,name,status} or {errors:[]} """ form = GenericImageDatasetForm() # Is there a request to clone a job with ?clone=<job_id> fill_form_if_cloned(form) if not form.validate_on_submit(): if request_wants_json(): return flask.jsonify({'errors': form.errors}), 400 else: return flask.render_template('datasets/images/generic/new.html', form=form), 400 job = None try: job = GenericImageDatasetJob( username=utils.auth.get_username(), name=form.dataset_name.data, group=form.group_name.data, mean_file=form.prebuilt_mean_file.data.strip(), ) if form.method.data == 'prebuilt': pass else: raise ValueError('method not supported') force_same_shape = form.force_same_shape.data job.tasks.append( tasks.AnalyzeDbTask( job_dir=job.dir(), database=form.prebuilt_train_images.data, purpose=form.prebuilt_train_images.label.text, force_same_shape=force_same_shape, )) if form.prebuilt_train_labels.data: job.tasks.append( tasks.AnalyzeDbTask( job_dir=job.dir(), database=form.prebuilt_train_labels.data, purpose=form.prebuilt_train_labels.label.text, force_same_shape=force_same_shape, )) if form.prebuilt_val_images.data: job.tasks.append( tasks.AnalyzeDbTask( job_dir=job.dir(), database=form.prebuilt_val_images.data, purpose=form.prebuilt_val_images.label.text, force_same_shape=force_same_shape, )) if form.prebuilt_val_labels.data: job.tasks.append( tasks.AnalyzeDbTask( job_dir=job.dir(), database=form.prebuilt_val_labels.data, purpose=form.prebuilt_val_labels.label.text, force_same_shape=force_same_shape, )) # Save form data with the job so we can easily clone it later. save_form_to_job(job, form) scheduler.add_job(job) if request_wants_json(): return flask.jsonify(job.json_dict()) else: return flask.redirect( flask.url_for('digits.dataset.views.show', job_id=job.id())) except: if job: scheduler.delete_job(job) raise
def image_classification_model_create(): """ Create a new ImageClassificationModelJob """ form = ImageClassificationModelForm() form.dataset.choices = get_datasets() form.standard_networks.choices = get_standard_networks() form.standard_networks.default = get_default_standard_network() form.previous_networks.choices = get_previous_networks() prev_network_snapshots = get_previous_network_snapshots() if not form.validate_on_submit(): return render_template('models/images/classification/new.html', form = form, previous_network_snapshots=prev_network_snapshots, multi_gpu = MULTI_GPU, ), 400 datasetJob = scheduler.get_job(form.dataset.data) if not datasetJob: return 'Unknown dataset job_id "%s"' % form.dataset.data, 500 job = None try: job = ImageClassificationModelJob( name = form.model_name.data, dataset_id = datasetJob.id(), ) network = caffe_pb2.NetParameter() pretrained_model = None if form.method.data == 'standard': found = False networks_dir = os.path.join(os.path.dirname(digits.__file__), 'standard-networks') for filename in os.listdir(networks_dir): path = os.path.join(networks_dir, filename) if os.path.isfile(path): match = re.match(r'%s.prototxt' % form.standard_networks.data, filename) if match: with open(path) as infile: text_format.Merge(infile.read(), network) found = True break if not found: raise Exception('Unknown standard model "%s"' % form.standard_networks.data) elif form.method.data == 'previous': old_job = scheduler.get_job(form.previous_networks.data) if not old_job: raise Exception('Job not found: %s' % form.previous_networks.data) network.CopyFrom(old_job.train_task().network) # Rename the final layer # XXX making some assumptions about network architecture here ip_layers = [l for l in network.layer if l.type == 'InnerProduct'] if len(ip_layers) > 0: ip_layers[-1].name = '%s_retrain' % ip_layers[-1].name for i, choice in enumerate(form.previous_networks.choices): if choice[0] == form.previous_networks.data: epoch = float(request.form['%s-snapshot' % form.previous_networks.data]) if epoch != 0: for filename, e in old_job.train_task().snapshots: if e == epoch: pretrained_model = filename break if pretrained_model is None: raise Exception("For the job %s, selected pretrained_model for epoch %d is invalid!" % (form.previous_networks.data, epoch)) if not (os.path.exists(pretrained_model)): raise Exception("Pretrained_model for the selected epoch doesn't exists. May be deleted by another user/process. Please restart the server to load the correct pretrained_model details") break elif form.method.data == 'custom': text_format.Merge(form.custom_network.data, network) pretrained_model = form.custom_network_snapshot.data.strip() else: raise Exception('Unrecognized method: "%s"' % form.method.data) policy = {'policy': form.lr_policy.data} if form.lr_policy.data == 'fixed': pass elif form.lr_policy.data == 'step': policy['stepsize'] = form.lr_step_size.data policy['gamma'] = form.lr_step_gamma.data elif form.lr_policy.data == 'multistep': policy['stepvalue'] = form.lr_multistep_values.data policy['gamma'] = form.lr_multistep_gamma.data elif form.lr_policy.data == 'exp': policy['gamma'] = form.lr_exp_gamma.data elif form.lr_policy.data == 'inv': policy['gamma'] = form.lr_inv_gamma.data policy['power'] = form.lr_inv_power.data elif form.lr_policy.data == 'poly': policy['power'] = form.lr_poly_power.data elif form.lr_policy.data == 'sigmoid': policy['stepsize'] = form.lr_sigmoid_step.data policy['gamma'] = form.lr_sigmoid_gamma.data else: return 'Invalid policy', 404 if MULTI_GPU: if form.select_gpu_count.data: gpu_count = form.select_gpu_count.data selected_gpus = None else: selected_gpus = [str(gpu) for gpu in form.select_gpus.data] gpu_count = None else: if form.select_gpu.data == 'next': gpu_count = 1 selected_gpus = None else: selected_gpus = [str(form.select_gpu.data)] gpu_count = None job.tasks.append( tasks.CaffeTrainTask( job_dir = job.dir(), dataset = datasetJob, train_epochs = form.train_epochs.data, snapshot_interval = form.snapshot_interval.data, learning_rate = form.learning_rate.data, lr_policy = policy, gpu_count = gpu_count, selected_gpus = selected_gpus, batch_size = form.batch_size.data, val_interval = form.val_interval.data, pretrained_model= pretrained_model, crop_size = form.crop_size.data, use_mean = form.use_mean.data, network = network, random_seed = form.random_seed.data, solver_type = form.solver_type.data, ) ) scheduler.add_job(job) return redirect(url_for('models_show', job_id=job.id())) except: if job: scheduler.delete_job(job) raise
def classify_one(): """ Classify one image and return the top 5 classifications Returns JSON when requested: {predictions: {category: confidence,...}} """ model_job = job_from_request() remove_image_path = False if 'image_path' in flask.request.form and flask.request.form['image_path']: image_path = flask.request.form['image_path'] elif 'image_file' in flask.request.files and flask.request.files['image_file']: outfile = tempfile.mkstemp(suffix='.png') flask.request.files['image_file'].save(outfile[1]) image_path = outfile[1] os.close(outfile[0]) remove_image_path = True else: raise werkzeug.exceptions.BadRequest('must provide image_path or image_file') epoch = None if 'snapshot_epoch' in flask.request.form: epoch = float(flask.request.form['snapshot_epoch']) layers = 'none' if 'show_visualizations' in flask.request.form and flask.request.form['show_visualizations']: layers = 'all' # create inference job inference_job = ImageInferenceJob( username=utils.auth.get_username(), name="Classify One Image", model=model_job, images=[image_path], epoch=epoch, layers=layers ) # schedule tasks scheduler.add_job(inference_job) # wait for job to complete inference_job.wait_completion() # retrieve inference data inputs, outputs, visualizations = inference_job.get_data() # set return status code status_code = 500 if inference_job.status == 'E' else 200 # delete job scheduler.delete_job(inference_job) if remove_image_path: os.remove(image_path) image = None predictions = [] if inputs is not None and len(inputs['data']) == 1: image = utils.image.embed_image_html(inputs['data'][0]) # convert to class probabilities for viewing last_output_name, last_output_data = outputs.items()[-1] if len(last_output_data) == 1: scores = last_output_data[0].flatten() indices = (-scores).argsort() labels = model_job.train_task().get_labels() predictions = [] for i in indices: # ignore prediction if we don't have a label for the corresponding class # the user might have set the final fully-connected layer's num_output to # too high a value if i < len(labels): predictions.append((labels[i], scores[i])) predictions = [(p[0], round(100.0 * p[1], 2)) for p in predictions[:5]] if request_wants_json(): return flask.jsonify({'predictions': predictions}), status_code else: return flask.render_template('models/images/classification/classify_one.html', model_job=model_job, job=inference_job, image_src=image, predictions=predictions, visualizations=visualizations, total_parameters=sum(v['param_count'] for v in visualizations if v['vis_type'] == 'Weights'), ), status_code
def create(): """ Create a new GenericImageModelJob Returns JSON when requested: {job_id,name,status} or {errors:[]} """ form = GenericImageModelForm() form.dataset.choices = get_datasets() form.standard_networks.choices = [] form.previous_networks.choices = get_previous_networks() prev_network_snapshots = get_previous_network_snapshots() ## Is there a request to clone a job with ?clone=<job_id> fill_form_if_cloned(form) if not form.validate_on_submit(): if request_wants_json(): return flask.jsonify({'errors': form.errors}), 400 else: return flask.render_template('models/images/generic/new.html', form = form, frameworks = frameworks.get_frameworks(), previous_network_snapshots = prev_network_snapshots, previous_networks_fullinfo = get_previous_networks_fulldetails(), multi_gpu = config_value('caffe_root')['multi_gpu'], ), 400 datasetJob = scheduler.get_job(form.dataset.data) if not datasetJob: raise werkzeug.exceptions.BadRequest( 'Unknown dataset job_id "%s"' % form.dataset.data) # sweeps will be a list of the the permutations of swept fields # Get swept learning_rate sweeps = [{'learning_rate': v} for v in form.learning_rate.data] add_learning_rate = len(form.learning_rate.data) > 1 # Add swept batch_size sweeps = [dict(s.items() + [('batch_size', bs)]) for bs in form.batch_size.data for s in sweeps[:]] add_batch_size = len(form.batch_size.data) > 1 n_jobs = len(sweeps) jobs = [] for sweep in sweeps: # Populate the form with swept data to be used in saving and # launching jobs. form.learning_rate.data = sweep['learning_rate'] form.batch_size.data = sweep['batch_size'] # Augment Job Name extra = '' if add_learning_rate: extra += ' learning_rate:%s' % str(form.learning_rate.data[0]) if add_batch_size: extra += ' batch_size:%d' % form.batch_size.data[0] job = None try: job = GenericImageModelJob( username = utils.auth.get_username(), name = form.model_name.data + extra, dataset_id = datasetJob.id(), ) # get framework (hard-coded to caffe for now) fw = frameworks.get_framework_by_id(form.framework.data) pretrained_model = None #if form.method.data == 'standard': if form.method.data == 'previous': old_job = scheduler.get_job(form.previous_networks.data) if not old_job: raise werkzeug.exceptions.BadRequest( 'Job not found: %s' % form.previous_networks.data) use_same_dataset = (old_job.dataset_id == job.dataset_id) network = fw.get_network_from_previous(old_job.train_task().network, use_same_dataset) for choice in form.previous_networks.choices: if choice[0] == form.previous_networks.data: epoch = float(flask.request.form['%s-snapshot' % form.previous_networks.data]) if epoch == 0: pass elif epoch == -1: pretrained_model = old_job.train_task().pretrained_model else: for filename, e in old_job.train_task().snapshots: if e == epoch: pretrained_model = filename break if pretrained_model is None: raise werkzeug.exceptions.BadRequest( "For the job %s, selected pretrained_model for epoch %d is invalid!" % (form.previous_networks.data, epoch)) if not (os.path.exists(pretrained_model)): raise werkzeug.exceptions.BadRequest( "Pretrained_model for the selected epoch doesn't exists. May be deleted by another user/process. Please restart the server to load the correct pretrained_model details") break elif form.method.data == 'custom': network = fw.get_network_from_desc(form.custom_network.data) pretrained_model = form.custom_network_snapshot.data.strip() else: raise werkzeug.exceptions.BadRequest( 'Unrecognized method: "%s"' % form.method.data) policy = {'policy': form.lr_policy.data} if form.lr_policy.data == 'fixed': pass elif form.lr_policy.data == 'step': policy['stepsize'] = form.lr_step_size.data policy['gamma'] = form.lr_step_gamma.data elif form.lr_policy.data == 'multistep': policy['stepvalue'] = form.lr_multistep_values.data policy['gamma'] = form.lr_multistep_gamma.data elif form.lr_policy.data == 'exp': policy['gamma'] = form.lr_exp_gamma.data elif form.lr_policy.data == 'inv': policy['gamma'] = form.lr_inv_gamma.data policy['power'] = form.lr_inv_power.data elif form.lr_policy.data == 'poly': policy['power'] = form.lr_poly_power.data elif form.lr_policy.data == 'sigmoid': policy['stepsize'] = form.lr_sigmoid_step.data policy['gamma'] = form.lr_sigmoid_gamma.data else: raise werkzeug.exceptions.BadRequest( 'Invalid learning rate policy') if config_value('caffe_root')['multi_gpu']: if form.select_gpu_count.data: gpu_count = form.select_gpu_count.data selected_gpus = None else: selected_gpus = [str(gpu) for gpu in form.select_gpus.data] gpu_count = None else: if form.select_gpu.data == 'next': gpu_count = 1 selected_gpus = None else: selected_gpus = [str(form.select_gpu.data)] gpu_count = None # Python Layer File may be on the server or copied from the client. fs.copy_python_layer_file( bool(form.python_layer_from_client.data), job.dir(), (flask.request.files[form.python_layer_client_file.name] if form.python_layer_client_file.name in flask.request.files else ''), form.python_layer_server_file.data) job.tasks.append(fw.create_train_task( job_dir = job.dir(), dataset = datasetJob, train_epochs = form.train_epochs.data, snapshot_interval = form.snapshot_interval.data, learning_rate = form.learning_rate.data[0], lr_policy = policy, gpu_count = gpu_count, selected_gpus = selected_gpus, batch_size = form.batch_size.data[0], val_interval = form.val_interval.data, pretrained_model= pretrained_model, crop_size = form.crop_size.data, use_mean = form.use_mean.data, network = network, random_seed = form.random_seed.data, solver_type = form.solver_type.data, shuffle = form.shuffle.data, ) ) ## Save form data with the job so we can easily clone it later. save_form_to_job(job, form) jobs.append(job) scheduler.add_job(job) if n_jobs == 1: if request_wants_json(): return flask.jsonify(job.json_dict()) else: return flask.redirect(flask.url_for('digits.model.views.show', job_id=job.id())) except: if job: scheduler.delete_job(job) raise if request_wants_json(): return flask.jsonify(jobs=[job.json_dict() for job in jobs]) # If there are multiple jobs launched, go to the home page. return flask.redirect('/')
def top_n(): """ Classify many images and show the top N images per category by confidence """ model_job = job_from_request() image_list = flask.request.files['image_list'] if not image_list: raise werkzeug.exceptions.BadRequest('File upload not found') epoch = None if 'snapshot_epoch' in flask.request.form: epoch = float(flask.request.form['snapshot_epoch']) if 'top_n' in flask.request.form and flask.request.form['top_n'].strip(): top_n = int(flask.request.form['top_n']) else: top_n = 9 if 'image_folder' in flask.request.form and flask.request.form['image_folder'].strip(): image_folder = flask.request.form['image_folder'] if not os.path.exists(image_folder): raise werkzeug.exceptions.BadRequest('image_folder "%s" does not exit' % image_folder) else: image_folder = None if 'num_test_images' in flask.request.form and flask.request.form['num_test_images'].strip(): num_test_images = int(flask.request.form['num_test_images']) else: num_test_images = None paths, _ = read_image_list(image_list, image_folder, num_test_images) # create inference job inference_job = ImageInferenceJob( username=utils.auth.get_username(), name="TopN Image Classification", model=model_job, images=paths, epoch=epoch, layers='none' ) # schedule tasks scheduler.add_job(inference_job) # wait for job to complete inference_job.wait_completion() # retrieve inference data inputs, outputs, _ = inference_job.get_data() # delete job scheduler.delete_job(inference_job) results = None if outputs is not None and len(outputs) > 0: # convert to class probabilities for viewing last_output_name, last_output_data = outputs.items()[-1] scores = last_output_data if scores is None: raise RuntimeError('An error occurred while processing the images') labels = model_job.train_task().get_labels() images = inputs['data'] indices = (-scores).argsort(axis=0)[:top_n] results = [] # Can't have more images per category than the number of images images_per_category = min(top_n, len(images)) # Can't have more categories than the number of labels or the number of outputs n_categories = min(indices.shape[1], len(labels)) for i in xrange(n_categories): result_images = [] for j in xrange(images_per_category): result_images.append(images[indices[j][i]]) results.append(( labels[i], utils.image.embed_image_html( utils.image.vis_square(np.array(result_images), colormap='white') ) )) return flask.render_template('models/images/classification/top_n.html', model_job=model_job, job=inference_job, results=results, )
def create(): """ Create a new ImageClassificationModelJob Returns JSON when requested: {job_id,name,status} or {errors:[]} """ form = ImageClassificationModelForm() form.dataset.choices = get_datasets() form.standard_networks.choices = get_standard_networks() form.standard_networks.default = get_default_standard_network() form.previous_networks.choices = get_previous_networks() prev_network_snapshots = get_previous_network_snapshots() ## Is there a request to clone a job with ?clone=<job_id> fill_form_if_cloned(form) if not form.validate_on_submit(): if request_wants_json(): return flask.jsonify({'errors': form.errors}), 400 else: return flask.render_template('models/images/classification/new.html', form = form, frameworks = frameworks.get_frameworks(), previous_network_snapshots = prev_network_snapshots, previous_networks_fullinfo = get_previous_networks_fulldetails(), multi_gpu = config_value('caffe_root')['multi_gpu'], ), 400 datasetJob = scheduler.get_job(form.dataset.data) if not datasetJob: raise werkzeug.exceptions.BadRequest( 'Unknown dataset job_id "%s"' % form.dataset.data) job = None try: job = ImageClassificationModelJob( username = utils.auth.get_username(), name = form.model_name.data, dataset_id = datasetJob.id(), ) # get handle to framework object fw = frameworks.get_framework_by_id(form.framework.data) pretrained_model = None if form.method.data == 'standard': found = False # can we find it in standard networks? network_desc = fw.get_standard_network_desc(form.standard_networks.data) if network_desc: found = True network = fw.get_network_from_desc(network_desc) if not found: raise werkzeug.exceptions.BadRequest( 'Unknown standard model "%s"' % form.standard_networks.data) elif form.method.data == 'previous': old_job = scheduler.get_job(form.previous_networks.data) if not old_job: raise werkzeug.exceptions.BadRequest( 'Job not found: %s' % form.previous_networks.data) use_same_dataset = (old_job.dataset_id == job.dataset_id) network = fw.get_network_from_previous(old_job.train_task().network, use_same_dataset) for choice in form.previous_networks.choices: if choice[0] == form.previous_networks.data: epoch = float(flask.request.form['%s-snapshot' % form.previous_networks.data]) if epoch == 0: pass elif epoch == -1: pretrained_model = old_job.train_task().pretrained_model else: for filename, e in old_job.train_task().snapshots: if e == epoch: pretrained_model = filename break if pretrained_model is None: raise werkzeug.exceptions.BadRequest( "For the job %s, selected pretrained_model for epoch %d is invalid!" % (form.previous_networks.data, epoch)) if not (os.path.exists(pretrained_model)): raise werkzeug.exceptions.BadRequest( "Pretrained_model for the selected epoch doesn't exists. May be deleted by another user/process. Please restart the server to load the correct pretrained_model details") break elif form.method.data == 'custom': network = fw.get_network_from_desc(form.custom_network.data) pretrained_model = form.custom_network_snapshot.data.strip() else: raise werkzeug.exceptions.BadRequest( 'Unrecognized method: "%s"' % form.method.data) policy = {'policy': form.lr_policy.data} if form.lr_policy.data == 'fixed': pass elif form.lr_policy.data == 'step': policy['stepsize'] = form.lr_step_size.data policy['gamma'] = form.lr_step_gamma.data elif form.lr_policy.data == 'multistep': policy['stepvalue'] = form.lr_multistep_values.data policy['gamma'] = form.lr_multistep_gamma.data elif form.lr_policy.data == 'exp': policy['gamma'] = form.lr_exp_gamma.data elif form.lr_policy.data == 'inv': policy['gamma'] = form.lr_inv_gamma.data policy['power'] = form.lr_inv_power.data elif form.lr_policy.data == 'poly': policy['power'] = form.lr_poly_power.data elif form.lr_policy.data == 'sigmoid': policy['stepsize'] = form.lr_sigmoid_step.data policy['gamma'] = form.lr_sigmoid_gamma.data else: raise werkzeug.exceptions.BadRequest( 'Invalid learning rate policy') if config_value('caffe_root')['multi_gpu']: if form.select_gpus.data: selected_gpus = [str(gpu) for gpu in form.select_gpus.data] gpu_count = None elif form.select_gpu_count.data: gpu_count = form.select_gpu_count.data selected_gpus = None else: gpu_count = 1 selected_gpus = None else: if form.select_gpu.data == 'next': gpu_count = 1 selected_gpus = None else: selected_gpus = [str(form.select_gpu.data)] gpu_count = None # Python Layer File may be on the server or copied from the client. fs.copy_python_layer_file( bool(form.python_layer_from_client.data), job.dir(), (flask.request.files[form.python_layer_client_file.name] if form.python_layer_client_file.name in flask.request.files else ''), form.python_layer_server_file.data) job.tasks.append(fw.create_train_task( job_dir = job.dir(), dataset = datasetJob, train_epochs = form.train_epochs.data, snapshot_interval = form.snapshot_interval.data, learning_rate = form.learning_rate.data, lr_policy = policy, gpu_count = gpu_count, selected_gpus = selected_gpus, batch_size = form.batch_size.data, val_interval = form.val_interval.data, pretrained_model= pretrained_model, crop_size = form.crop_size.data, use_mean = form.use_mean.data, network = network, random_seed = form.random_seed.data, solver_type = form.solver_type.data, shuffle = form.shuffle.data, ) ) ## Save form data with the job so we can easily clone it later. save_form_to_job(job, form) scheduler.add_job(job) if request_wants_json(): return flask.jsonify(job.json_dict()) else: return flask.redirect(flask.url_for('digits.model.views.show', job_id=job.id())) except: if job: scheduler.delete_job(job) raise
def create(extension_id): """ Creates a new GenericDatasetJob Returns JSON when requested: {job_id,name,status} or {errors:[]} """ form = GenericDatasetForm() form_valid = form.validate_on_submit() extension_class = extensions.data.get_extension(extension_id) extension_form = extension_class.get_dataset_form() extension_form_valid = extension_form.validate_on_submit() if not (extension_form_valid and form_valid): # merge errors errors = form.errors.copy() errors.update(extension_form.errors) template, context = extension_class.get_dataset_template( extension_form) rendered_extension = flask.render_template_string(template, **context) if request_wants_json(): return flask.jsonify({'errors': errors}), 400 else: return flask.render_template( 'datasets/generic/new.html', extension_title=extension_class.get_title(), extension_id=extension_id, extension_html=rendered_extension, form=form, errors=errors), 400 # create instance of extension class extension = extension_class(**extension_form.data) job = None try: # create job job = GenericDatasetJob( username=utils.auth.get_username(), name=form.dataset_name.data, group=form.group_name.data, backend=form.dsopts_backend.data, feature_encoding=form.dsopts_feature_encoding.data, label_encoding=form.dsopts_label_encoding.data, batch_size=int(form.dsopts_batch_size.data), num_threads=int(form.dsopts_num_threads.data), force_same_shape=form.dsopts_force_same_shape.data, extension_id=extension_id, extension_userdata=extension.get_user_data(), ) # Save form data with the job so we can easily clone it later. utils.forms.save_form_to_job(job, form) utils.forms.save_form_to_job(job, extension_form) # schedule tasks scheduler.add_job(job) if request_wants_json(): return flask.jsonify(job.json_dict()) else: return flask.redirect( flask.url_for('digits.dataset.views.show', job_id=job.id())) except: if job: scheduler.delete_job(job) raise
def upload_archive(): """ Upload archive """ files = flask.request.files archive_file = get_tempfile(files["archive"], ".archive") labels_file = None mean_file = None if tarfile.is_tarfile(archive_file): archive = tarfile.open(archive_file, 'r') names = archive.getnames() elif zipfile.is_zipfile(archive_file): archive = zipfile.ZipFile(archive_file, 'r') names = archive.namelist() else: return flask.jsonify({"status": "Incorrect Archive Type"}), 500 if "info.json" in names: # Create a temp directory to storce archive tempdir = tempfile.mkdtemp() labels_file = None archive.extractall(path=tempdir) with open(os.path.join(tempdir, "info.json")) as data_file: info = json.load(data_file) valid, key = validate_archive_keys(info) if valid is False: return flask.jsonify( {"status": "Missing Key '" + key + "' in info.json"}), 500 # Get path to files needed to be uploaded in directory weights_file = os.path.join(tempdir, info["snapshot file"]) if "model file" in info: model_file = os.path.join(tempdir, info["model file"]) elif "network file" in info: model_file = os.path.join(tempdir, info["network file"]) else: return flask.jsonify( {"status": "Missing model definition in info.json"}), 500 if "labels file" in info: labels_file = os.path.join(tempdir, info["labels file"]) if "mean file" in info: mean_file = os.path.join(tempdir, info["mean file"]) # Upload the Model: job = PretrainedModelJob(weights_file, model_file, labels_file, mean_file, info["framework"], info["image dimensions"][2], info["image resize mode"], info["image dimensions"][0], info["image dimensions"][1], username=utils.auth.get_username(), name=info["name"]) scheduler.add_job(job) run_weights_job(job, utils.auth.get_username()) # Delete temp directory shutil.rmtree(tempdir, ignore_errors=True) return flask.jsonify({"status": "success"}), 200 else: return flask.jsonify({"status": "Missing or Incorrect json file"}), 500
def infer_many(): """ Infer many images """ model_job = job_from_request() image_list = flask.request.files.get('image_list') if not image_list: raise werkzeug.exceptions.BadRequest('image_list is a required field') if 'image_folder' in flask.request.form and flask.request.form['image_folder'].strip(): image_folder = flask.request.form['image_folder'] if not os.path.exists(image_folder): raise werkzeug.exceptions.BadRequest('image_folder "%s" does not exit' % image_folder) else: image_folder = None if 'num_test_images' in flask.request.form and flask.request.form['num_test_images'].strip(): num_test_images = int(flask.request.form['num_test_images']) else: num_test_images = None epoch = None if 'snapshot_epoch' in flask.request.form: epoch = float(flask.request.form['snapshot_epoch']) if 'dont_resize' in flask.request.form and flask.request.form['dont_resize']: resize = False else: resize = True paths = [] for line in image_list.readlines(): line = line.strip() if not line: continue path = None # might contain a numerical label at the end match = re.match(r'(.*\S)\s+\d+$', line) if match: path = match.group(1) else: path = line if not utils.is_url(path) and image_folder and not os.path.isabs(path): path = os.path.join(image_folder, path) paths.append(path) if num_test_images is not None and len(paths) >= num_test_images: break # create inference job inference_job = ImageInferenceJob( username=utils.auth.get_username(), name="Infer Many Images", model=model_job, images=paths, epoch=epoch, layers='none', resize=resize, ) # schedule tasks scheduler.add_job(inference_job) # wait for job to complete inference_job.wait_completion() # retrieve inference data inputs, outputs, _ = inference_job.get_data() # set return status code status_code = 500 if inference_job.status == 'E' else 200 # delete job folder and remove from scheduler list scheduler.delete_job(inference_job) if outputs is not None and len(outputs) < 1: # an error occurred outputs = None if inputs is not None: paths = [paths[idx] for idx in inputs['ids']] inference_views_html, header_html, app_begin_html, app_end_html = get_inference_visualizations( model_job.dataset, inputs, outputs) else: inference_views_html = None header_html = None app_begin_html = None app_end_html = None if request_wants_json(): result = {} for i, path in enumerate(paths): result[path] = dict((name, blob[i].tolist()) for name, blob in outputs.iteritems()) return flask.jsonify({'outputs': result}), status_code else: return flask.render_template( 'models/images/generic/infer_many.html', model_job=model_job, job=inference_job, paths=paths, inference_views_html=inference_views_html, header_html=header_html, app_begin_html=app_begin_html, app_end_html=app_end_html, ), status_code
def create(extension_id): """ Creates a new GenericDatasetJob Returns JSON when requested: {job_id,name,status} or {errors:[]} """ form = GenericDatasetForm() form_valid = form.validate_on_submit() extension_class = extensions.data.get_extension(extension_id) extension_form = extension_class.get_dataset_form() extension_form_valid = extension_form.validate_on_submit() if not (extension_form_valid and form_valid): # merge errors errors = form.errors.copy() errors.update(extension_form.errors) template, context = extension_class.get_dataset_template( extension_form) rendered_extension = flask.render_template_string( template, **context) if request_wants_json(): return flask.jsonify({'errors': errors}), 400 else: return flask.render_template( 'datasets/generic/new.html', extension_title=extension_class.get_title(), extension_id=extension_id, extension_html=rendered_extension, form=form, errors=errors), 400 # create instance of extension class extension = extension_class(**extension_form.data) job = None try: # create job job = GenericDatasetJob( username=utils.auth.get_username(), name=form.dataset_name.data, group=form.group_name.data, backend=form.dsopts_backend.data, feature_encoding=form.dsopts_feature_encoding.data, label_encoding=form.dsopts_label_encoding.data, batch_size=int(form.dsopts_batch_size.data), num_threads=int(form.dsopts_num_threads.data), force_same_shape=form.dsopts_force_same_shape.data, extension_id=extension_id, extension_userdata=extension.get_user_data(), ) # Save form data with the job so we can easily clone it later. utils.forms.save_form_to_job(job, form) utils.forms.save_form_to_job(job, extension_form) # schedule tasks scheduler.add_job(job) if request_wants_json(): return flask.jsonify(job.json_dict()) else: return flask.redirect(flask.url_for( 'digits.dataset.views.show', job_id=job.id())) except: if job: scheduler.delete_job(job) raise
def generic_image_model_create(): """ Create a new GenericImageModelJob Returns JSON when requested: {job_id,name,status} or {errors:[]} """ form = GenericImageModelForm() form.dataset.choices = get_datasets() form.standard_networks.choices = [] form.previous_networks.choices = get_previous_networks() prev_network_snapshots = get_previous_network_snapshots() if not form.validate_on_submit(): if request_wants_json(): return flask.jsonify({'errors': form.errors}), 400 else: return flask.render_template('models/images/generic/new.html', form = form, previous_network_snapshots = prev_network_snapshots, previous_networks_fullinfo = get_previous_networks_fulldetails(), multi_gpu = config_value('caffe_root')['multi_gpu'], ), 400 datasetJob = scheduler.get_job(form.dataset.data) if not datasetJob: raise werkzeug.exceptions.BadRequest( 'Unknown dataset job_id "%s"' % form.dataset.data) job = None try: job = GenericImageModelJob( name = form.model_name.data, dataset_id = datasetJob.id(), ) # get framework (hard-coded to caffe for now) fw = frameworks.get_framework_by_id('caffe') pretrained_model = None #if form.method.data == 'standard': if form.method.data == 'previous': old_job = scheduler.get_job(form.previous_networks.data) if not old_job: raise werkzeug.exceptions.BadRequest( 'Job not found: %s' % form.previous_networks.data) network = fw.get_network_from_previous(old_job.train_task().network) for choice in form.previous_networks.choices: if choice[0] == form.previous_networks.data: epoch = float(flask.request.form['%s-snapshot' % form.previous_networks.data]) if epoch == 0: pass elif epoch == -1: pretrained_model = old_job.train_task().pretrained_model else: for filename, e in old_job.train_task().snapshots: if e == epoch: pretrained_model = filename break if pretrained_model is None: raise werkzeug.exceptions.BadRequest( "For the job %s, selected pretrained_model for epoch %d is invalid!" % (form.previous_networks.data, epoch)) if not (os.path.exists(pretrained_model)): raise werkzeug.exceptions.BadRequest( "Pretrained_model for the selected epoch doesn't exists. May be deleted by another user/process. Please restart the server to load the correct pretrained_model details") break elif form.method.data == 'custom': network = fw.get_network_from_desc(form.custom_network.data) pretrained_model = form.custom_network_snapshot.data.strip() else: raise werkzeug.exceptions.BadRequest( 'Unrecognized method: "%s"' % form.method.data) policy = {'policy': form.lr_policy.data} if form.lr_policy.data == 'fixed': pass elif form.lr_policy.data == 'step': policy['stepsize'] = form.lr_step_size.data policy['gamma'] = form.lr_step_gamma.data elif form.lr_policy.data == 'multistep': policy['stepvalue'] = form.lr_multistep_values.data policy['gamma'] = form.lr_multistep_gamma.data elif form.lr_policy.data == 'exp': policy['gamma'] = form.lr_exp_gamma.data elif form.lr_policy.data == 'inv': policy['gamma'] = form.lr_inv_gamma.data policy['power'] = form.lr_inv_power.data elif form.lr_policy.data == 'poly': policy['power'] = form.lr_poly_power.data elif form.lr_policy.data == 'sigmoid': policy['stepsize'] = form.lr_sigmoid_step.data policy['gamma'] = form.lr_sigmoid_gamma.data else: raise werkzeug.exceptions.BadRequest( 'Invalid learning rate policy') if config_value('caffe_root')['multi_gpu']: if form.select_gpu_count.data: gpu_count = form.select_gpu_count.data selected_gpus = None else: selected_gpus = [str(gpu) for gpu in form.select_gpus.data] gpu_count = None else: if form.select_gpu.data == 'next': gpu_count = 1 selected_gpus = None else: selected_gpus = [str(form.select_gpu.data)] gpu_count = None job.tasks.append(fw.create_train_task( job_dir = job.dir(), dataset = datasetJob, train_epochs = form.train_epochs.data, snapshot_interval = form.snapshot_interval.data, learning_rate = form.learning_rate.data, lr_policy = policy, gpu_count = gpu_count, selected_gpus = selected_gpus, batch_size = form.batch_size.data, val_interval = form.val_interval.data, pretrained_model= pretrained_model, crop_size = form.crop_size.data, use_mean = bool(form.use_mean.data), network = network, random_seed = form.random_seed.data, solver_type = form.solver_type.data, ) ) scheduler.add_job(job) if request_wants_json(): return flask.jsonify(job.json_dict()) else: return flask.redirect(flask.url_for('models_show', job_id=job.id())) except: if job: scheduler.delete_job(job) raise
def classify_many(): """ Classify many images and return the top 5 classifications for each Returns JSON when requested: {classifications: {filename: [[category,confidence],...],...}} """ model_job = job_from_request() image_list = flask.request.files.get('image_list') if not image_list: raise werkzeug.exceptions.BadRequest('image_list is a required field') if 'image_folder' in flask.request.form and flask.request.form[ 'image_folder'].strip(): image_folder = flask.request.form['image_folder'] if not os.path.exists(image_folder): raise werkzeug.exceptions.BadRequest( 'image_folder "%s" does not exit' % image_folder) else: image_folder = None if 'num_test_images' in flask.request.form and flask.request.form[ 'num_test_images'].strip(): num_test_images = int(flask.request.form['num_test_images']) else: num_test_images = None epoch = None if 'snapshot_epoch' in flask.request.form: epoch = float(flask.request.form['snapshot_epoch']) paths, ground_truths = read_image_list(image_list, image_folder, num_test_images) # create inference job inference_job = ImageInferenceJob(username=utils.auth.get_username(), name="Classify Many Images", model=model_job, images=paths, epoch=epoch, layers='none') # schedule tasks scheduler.add_job(inference_job) # wait for job to complete inference_job.wait_completion() # retrieve inference data inputs, outputs, _ = inference_job.get_data() # set return status code status_code = 500 if inference_job.status == 'E' else 200 # delete job scheduler.delete_job(inference_job) if outputs is not None and len(outputs) < 1: # an error occurred outputs = None if inputs is not None: # retrieve path and ground truth of images that were successfully processed paths = [paths[idx] for idx in inputs['ids']] ground_truths = [ground_truths[idx] for idx in inputs['ids']] # defaults classifications = None show_ground_truth = None top1_accuracy = None top5_accuracy = None confusion_matrix = None per_class_accuracy = None labels = None if outputs is not None: # convert to class probabilities for viewing last_output_name, last_output_data = outputs.items()[-1] if len(last_output_data) < 1: raise werkzeug.exceptions.BadRequest( 'Unable to classify any image from the file') scores = last_output_data # take top 5 indices = (-scores).argsort()[:, :5] labels = model_job.train_task().get_labels() n_labels = len(labels) # remove invalid ground truth ground_truths = [ x if x is not None and (0 <= x < n_labels) else None for x in ground_truths ] # how many pieces of ground truth to we have? n_ground_truth = len([1 for x in ground_truths if x is not None]) show_ground_truth = n_ground_truth > 0 # compute classifications and statistics classifications = [] n_top1_accurate = 0 n_top5_accurate = 0 confusion_matrix = np.zeros((n_labels, n_labels), dtype=np.dtype(int)) for image_index, index_list in enumerate(indices): result = [] if ground_truths[image_index] is not None: if ground_truths[image_index] == index_list[0]: n_top1_accurate += 1 if ground_truths[image_index] in index_list: n_top5_accurate += 1 if (0 <= ground_truths[image_index] < n_labels) and (0 <= index_list[0] < n_labels): confusion_matrix[ground_truths[image_index], index_list[0]] += 1 for i in index_list: # `i` is a category in labels and also an index into scores # ignore prediction if we don't have a label for the corresponding class # the user might have set the final fully-connected layer's num_output to # too high a value if i < len(labels): result.append( (labels[i], round(100.0 * scores[image_index, i], 2))) classifications.append(result) # accuracy if show_ground_truth: top1_accuracy = round(100.0 * n_top1_accurate / n_ground_truth, 2) top5_accuracy = round(100.0 * n_top5_accurate / n_ground_truth, 2) per_class_accuracy = [] for x in xrange(n_labels): n_examples = sum(confusion_matrix[x]) per_class_accuracy.append( round(100.0 * confusion_matrix[x, x] / n_examples, 2) if n_examples > 0 else None) else: top1_accuracy = None top5_accuracy = None per_class_accuracy = None # replace ground truth indices with labels ground_truths = [ labels[x] if x is not None and (0 <= x < n_labels) else None for x in ground_truths ] if request_wants_json(): joined = dict(zip(paths, classifications)) return flask.jsonify({'classifications': joined}), status_code else: return flask.render_template( 'models/images/classification/classify_many.html', model_job=model_job, job=inference_job, paths=paths, classifications=classifications, show_ground_truth=show_ground_truth, ground_truths=ground_truths, top1_accuracy=top1_accuracy, top5_accuracy=top5_accuracy, confusion_matrix=confusion_matrix, per_class_accuracy=per_class_accuracy, labels=labels, ), status_code
def classify_many(): """ Classify many images and return the top 5 classifications for each Returns JSON when requested: {classifications: {filename: [[category,confidence],...],...}} """ model_job = job_from_request() image_list = flask.request.files.get('image_list') if not image_list: raise werkzeug.exceptions.BadRequest('image_list is a required field') if 'image_folder' in flask.request.form and flask.request.form['image_folder'].strip(): image_folder = flask.request.form['image_folder'] if not os.path.exists(image_folder): raise werkzeug.exceptions.BadRequest('image_folder "%s" does not exit' % image_folder) else: image_folder = None if 'num_test_images' in flask.request.form and flask.request.form['num_test_images'].strip(): num_test_images = int(flask.request.form['num_test_images']) else: num_test_images = None epoch = None if 'snapshot_epoch' in flask.request.form: epoch = float(flask.request.form['snapshot_epoch']) paths, ground_truths = read_image_list(image_list, image_folder, num_test_images) # create inference job inference_job = ImageInferenceJob( username=utils.auth.get_username(), name="Classify Many Images", model=model_job, images=paths, epoch=epoch, layers='none' ) # schedule tasks scheduler.add_job(inference_job) # wait for job to complete inference_job.wait_completion() # retrieve inference data inputs, outputs, _ = inference_job.get_data() # set return status code status_code = 500 if inference_job.status == 'E' else 200 # delete job scheduler.delete_job(inference_job) if outputs is not None and len(outputs) < 1: # an error occurred outputs = None if inputs is not None: # retrieve path and ground truth of images that were successfully processed paths = [paths[idx] for idx in inputs['ids']] ground_truths = [ground_truths[idx] for idx in inputs['ids']] # defaults classifications = None show_ground_truth = None top1_accuracy = None top5_accuracy = None confusion_matrix = None per_class_accuracy = None labels = None if outputs is not None: # convert to class probabilities for viewing last_output_name, last_output_data = outputs.items()[-1] if len(last_output_data) < 1: raise werkzeug.exceptions.BadRequest( 'Unable to classify any image from the file') scores = last_output_data # take top 5 indices = (-scores).argsort()[:, :5] labels = model_job.train_task().get_labels() n_labels = len(labels) # remove invalid ground truth ground_truths = [x if x is not None and (0 <= x < n_labels) else None for x in ground_truths] # how many pieces of ground truth to we have? n_ground_truth = len([1 for x in ground_truths if x is not None]) show_ground_truth = n_ground_truth > 0 # compute classifications and statistics classifications = [] n_top1_accurate = 0 n_top5_accurate = 0 confusion_matrix = np.zeros((n_labels, n_labels), dtype=np.dtype(int)) for image_index, index_list in enumerate(indices): result = [] if ground_truths[image_index] is not None: if ground_truths[image_index] == index_list[0]: n_top1_accurate += 1 if ground_truths[image_index] in index_list: n_top5_accurate += 1 if (0 <= ground_truths[image_index] < n_labels) and (0 <= index_list[0] < n_labels): confusion_matrix[ground_truths[image_index], index_list[0]] += 1 for i in index_list: # `i` is a category in labels and also an index into scores # ignore prediction if we don't have a label for the corresponding class # the user might have set the final fully-connected layer's num_output to # too high a value if i < len(labels): result.append((labels[i], round(100.0 * scores[image_index, i], 2))) classifications.append(result) # accuracy if show_ground_truth: top1_accuracy = round(100.0 * n_top1_accurate / n_ground_truth, 2) top5_accuracy = round(100.0 * n_top5_accurate / n_ground_truth, 2) per_class_accuracy = [] for x in xrange(n_labels): n_examples = sum(confusion_matrix[x]) per_class_accuracy.append( round(100.0 * confusion_matrix[x, x] / n_examples, 2) if n_examples > 0 else None) else: top1_accuracy = None top5_accuracy = None per_class_accuracy = None # replace ground truth indices with labels ground_truths = [labels[x] if x is not None and (0 <= x < n_labels) else None for x in ground_truths] if request_wants_json(): joined = dict(zip(paths, classifications)) return flask.jsonify({'classifications': joined}), status_code else: return flask.render_template('models/images/classification/classify_many.html', model_job=model_job, job=inference_job, paths=paths, classifications=classifications, show_ground_truth=show_ground_truth, ground_truths=ground_truths, top1_accuracy=top1_accuracy, top5_accuracy=top5_accuracy, confusion_matrix=confusion_matrix, per_class_accuracy=per_class_accuracy, labels=labels, ), status_code
def upload_archive(): """ Upload archive """ files = flask.request.files archive_file = get_tempfile(files["archive"],".archive"); if tarfile.is_tarfile(archive_file): archive = tarfile.open(archive_file,'r') names = archive.getnames() elif zipfile.is_zipfile(archive_file): archive = zipfile.ZipFile(archive_file, 'r') names = archive.namelist() else: return flask.jsonify({"status": "Incorrect Archive Type"}), 500 if "info.json" in names: # Create a temp directory to storce archive tempdir = tempfile.mkdtemp() archive.extractall(path=tempdir) with open(os.path.join(tempdir, "info.json")) as data_file: info = json.load(data_file) valid, key = validate_archive_keys(info) if valid is False: return flask.jsonify({"status": "Missing Key '"+ key +"' in info.json"}), 500 # Get path to files needed to be uploaded in directory weights_file = os.path.join(tempdir, info["snapshot file"]) if "model file" in info: model_file = os.path.join(tempdir, info["model file"]) elif "network file" in info: model_file = os.path.join(tempdir, info["network file"]) else: return flask.jsonify({"status": "Missing model definition in info.json"}), 500 labels_file = os.path.join(tempdir, info["labels file"]) # Upload the Model: job = PretrainedModelJob( weights_file, model_file , labels_file, info["framework"], username = utils.auth.get_username(), name = info["name"] ) scheduler.add_job(job) job.wait_completion() # Delete temp directory shutil.rmtree(tempdir, ignore_errors=True) return flask.jsonify({"status": "success"}), 200 else: return flask.jsonify({"status": "Missing or Incorrect json file"}), 500
def create(): """ Create a new ImageClassificationModelJob Returns JSON when requested: {job_id,name,status} or {errors:[]} """ form = ImageClassificationModelForm() form.dataset.choices = get_datasets() form.standard_networks.choices = get_standard_networks() form.standard_networks.default = get_default_standard_network() form.previous_networks.choices = get_previous_networks() form.pretrained_networks.choices = get_pretrained_networks() prev_network_snapshots = get_previous_network_snapshots() # Is there a request to clone a job with ?clone=<job_id> fill_form_if_cloned(form) if not form.validate_on_submit(): if request_wants_json(): return flask.jsonify({'errors': form.errors}), 400 else: return flask.render_template('models/images/classification/new.html', form=form, frameworks=frameworks.get_frameworks(), previous_network_snapshots=prev_network_snapshots, previous_networks_fullinfo=get_previous_networks_fulldetails(), pretrained_networks_fullinfo=get_pretrained_networks_fulldetails(), multi_gpu=config_value('caffe')['multi_gpu'], ), 400 datasetJob = scheduler.get_job(form.dataset.data) if not datasetJob: raise werkzeug.exceptions.BadRequest( 'Unknown dataset job_id "%s"' % form.dataset.data) # sweeps will be a list of the the permutations of swept fields # Get swept learning_rate sweeps = [{'learning_rate': v} for v in form.learning_rate.data] add_learning_rate = len(form.learning_rate.data) > 1 # Add swept batch_size sweeps = [dict(s.items() + [('batch_size', bs)]) for bs in form.batch_size.data for s in sweeps[:]] add_batch_size = len(form.batch_size.data) > 1 n_jobs = len(sweeps) jobs = [] for sweep in sweeps: # Populate the form with swept data to be used in saving and # launching jobs. form.learning_rate.data = sweep['learning_rate'] form.batch_size.data = sweep['batch_size'] # Augment Job Name extra = '' if add_learning_rate: extra += ' learning_rate:%s' % str(form.learning_rate.data[0]) if add_batch_size: extra += ' batch_size:%d' % form.batch_size.data[0] job = None try: job = ImageClassificationModelJob( username=utils.auth.get_username(), name=form.model_name.data + extra, group=form.group_name.data, dataset_id=datasetJob.id(), ) # get handle to framework object fw = frameworks.get_framework_by_id(form.framework.data) pretrained_model = None if form.method.data == 'standard': found = False # can we find it in standard networks? network_desc = fw.get_standard_network_desc(form.standard_networks.data) if network_desc: found = True network = fw.get_network_from_desc(network_desc) if not found: raise werkzeug.exceptions.BadRequest( 'Unknown standard model "%s"' % form.standard_networks.data) elif form.method.data == 'previous': old_job = scheduler.get_job(form.previous_networks.data) if not old_job: raise werkzeug.exceptions.BadRequest( 'Job not found: %s' % form.previous_networks.data) use_same_dataset = (old_job.dataset_id == job.dataset_id) network = fw.get_network_from_previous(old_job.train_task().network, use_same_dataset) for choice in form.previous_networks.choices: if choice[0] == form.previous_networks.data: epoch = float(flask.request.form['%s-snapshot' % form.previous_networks.data]) if epoch == 0: pass elif epoch == -1: pretrained_model = old_job.train_task().pretrained_model else: # verify snapshot exists pretrained_model = old_job.train_task().get_snapshot(epoch, download=True) if pretrained_model is None: raise werkzeug.exceptions.BadRequest( "For the job %s, selected pretrained_model for epoch %d is invalid!" % (form.previous_networks.data, epoch)) # the first is the actual file if a list is returned, other should be meta data if isinstance(pretrained_model, list): pretrained_model = pretrained_model[0] if not (os.path.exists(pretrained_model)): raise werkzeug.exceptions.BadRequest( "Pretrained_model for the selected epoch doesn't exist. " "May be deleted by another user/process. " "Please restart the server to load the correct pretrained_model details.") # get logical path pretrained_model = old_job.train_task().get_snapshot(epoch) break elif form.method.data == 'pretrained': pretrained_job = scheduler.get_job(form.pretrained_networks.data) model_def_path = pretrained_job.get_model_def_path() weights_path = pretrained_job.get_weights_path() network = fw.get_network_from_path(model_def_path) pretrained_model = weights_path elif form.method.data == 'custom': network = fw.get_network_from_desc(form.custom_network.data) pretrained_model = form.custom_network_snapshot.data.strip() else: raise werkzeug.exceptions.BadRequest( 'Unrecognized method: "%s"' % form.method.data) policy = {'policy': form.lr_policy.data} if form.lr_policy.data == 'fixed': pass elif form.lr_policy.data == 'step': policy['stepsize'] = form.lr_step_size.data policy['gamma'] = form.lr_step_gamma.data elif form.lr_policy.data == 'multistep': policy['stepvalue'] = form.lr_multistep_values.data policy['gamma'] = form.lr_multistep_gamma.data elif form.lr_policy.data == 'exp': policy['gamma'] = form.lr_exp_gamma.data elif form.lr_policy.data == 'inv': policy['gamma'] = form.lr_inv_gamma.data policy['power'] = form.lr_inv_power.data elif form.lr_policy.data == 'poly': policy['power'] = form.lr_poly_power.data elif form.lr_policy.data == 'sigmoid': policy['stepsize'] = form.lr_sigmoid_step.data policy['gamma'] = form.lr_sigmoid_gamma.data else: raise werkzeug.exceptions.BadRequest( 'Invalid learning rate policy') if config_value('caffe')['multi_gpu']: if form.select_gpus.data: selected_gpus = [str(gpu) for gpu in form.select_gpus.data] gpu_count = None elif form.select_gpu_count.data: gpu_count = form.select_gpu_count.data selected_gpus = None else: gpu_count = 1 selected_gpus = None else: if form.select_gpu.data == 'next': gpu_count = 1 selected_gpus = None else: selected_gpus = [str(form.select_gpu.data)] gpu_count = None # Set up data augmentation structure data_aug = {} data_aug['flip'] = form.aug_flip.data data_aug['quad_rot'] = form.aug_quad_rot.data data_aug['rot'] = form.aug_rot.data data_aug['scale'] = form.aug_scale.data data_aug['noise'] = form.aug_noise.data data_aug['contrast'] = form.aug_contrast.data data_aug['whitening'] = form.aug_whitening.data data_aug['hsv_use'] = form.aug_hsv_use.data data_aug['hsv_h'] = form.aug_hsv_h.data data_aug['hsv_s'] = form.aug_hsv_s.data data_aug['hsv_v'] = form.aug_hsv_v.data # Python Layer File may be on the server or copied from the client. fs.copy_python_layer_file( bool(form.python_layer_from_client.data), job.dir(), (flask.request.files[form.python_layer_client_file.name] if form.python_layer_client_file.name in flask.request.files else ''), form.python_layer_server_file.data) job.tasks.append(fw.create_train_task( job=job, dataset=datasetJob, train_epochs=form.train_epochs.data, snapshot_interval=form.snapshot_interval.data, learning_rate=form.learning_rate.data[0], lr_policy=policy, gpu_count=gpu_count, selected_gpus=selected_gpus, batch_size=form.batch_size.data[0], batch_accumulation=form.batch_accumulation.data, val_interval=form.val_interval.data, traces_interval=form.traces_interval.data, pretrained_model=pretrained_model, crop_size=form.crop_size.data, use_mean=form.use_mean.data, network=network, random_seed=form.random_seed.data, solver_type=form.solver_type.data, rms_decay=form.rms_decay.data, shuffle=form.shuffle.data, data_aug=data_aug, ) ) # Save form data with the job so we can easily clone it later. save_form_to_job(job, form) jobs.append(job) scheduler.add_job(job) if n_jobs == 1: if request_wants_json(): return flask.jsonify(job.json_dict()) else: return flask.redirect(flask.url_for('digits.model.views.show', job_id=job.id())) except: if job: scheduler.delete_job(job) raise if request_wants_json(): return flask.jsonify(jobs=[j.json_dict() for j in jobs]) # If there are multiple jobs launched, go to the home page. return flask.redirect('/')
def image_classification_model_create(): """ Create a new ImageClassificationModelJob Returns JSON when requested: {job_id,name,status} or {errors:[]} """ form = ImageClassificationModelForm() form.dataset.choices = get_datasets() form.standard_networks.choices = get_standard_networks() form.standard_networks.default = get_default_standard_network() form.previous_networks.choices = get_previous_networks() prev_network_snapshots = get_previous_network_snapshots() ## Is there a request to clone a job with ?clone=<job_id> fill_form_if_cloned(form) if not form.validate_on_submit(): if request_wants_json(): return flask.jsonify({'errors': form.errors}), 400 else: return flask.render_template( 'models/images/classification/new.html', form=form, frameworks=frameworks.get_frameworks(), previous_network_snapshots=prev_network_snapshots, previous_networks_fullinfo=get_previous_networks_fulldetails(), multi_gpu=config_value('caffe_root')['multi_gpu'], ), 400 datasetJob = scheduler.get_job(form.dataset.data) if not datasetJob: raise werkzeug.exceptions.BadRequest('Unknown dataset job_id "%s"' % form.dataset.data) job = None try: job = ImageClassificationModelJob( name=form.model_name.data, dataset_id=datasetJob.id(), ) # get handle to framework object fw = frameworks.get_framework_by_id(form.framework.data) pretrained_model = None if form.method.data == 'standard': found = False # can we find it in standard networks? network_desc = fw.get_standard_network_desc( form.standard_networks.data) if network_desc: found = True network = fw.get_network_from_desc(network_desc) if not found: raise werkzeug.exceptions.BadRequest( 'Unknown standard model "%s"' % form.standard_networks.data) elif form.method.data == 'previous': old_job = scheduler.get_job(form.previous_networks.data) if not old_job: raise werkzeug.exceptions.BadRequest( 'Job not found: %s' % form.previous_networks.data) network = fw.get_network_from_previous( old_job.train_task().network) for choice in form.previous_networks.choices: if choice[0] == form.previous_networks.data: epoch = float( flask.request.form['%s-snapshot' % form.previous_networks.data]) if epoch == 0: pass elif epoch == -1: pretrained_model = old_job.train_task( ).pretrained_model else: for filename, e in old_job.train_task().snapshots: if e == epoch: pretrained_model = filename break if pretrained_model is None: raise werkzeug.exceptions.BadRequest( "For the job %s, selected pretrained_model for epoch %d is invalid!" % (form.previous_networks.data, epoch)) if not (os.path.exists(pretrained_model)): raise werkzeug.exceptions.BadRequest( "Pretrained_model for the selected epoch doesn't exists. May be deleted by another user/process. Please restart the server to load the correct pretrained_model details" ) break elif form.method.data == 'custom': network = fw.get_network_from_desc(form.custom_network.data) pretrained_model = form.custom_network_snapshot.data.strip() else: raise werkzeug.exceptions.BadRequest('Unrecognized method: "%s"' % form.method.data) policy = {'policy': form.lr_policy.data} if form.lr_policy.data == 'fixed': pass elif form.lr_policy.data == 'step': policy['stepsize'] = form.lr_step_size.data policy['gamma'] = form.lr_step_gamma.data elif form.lr_policy.data == 'multistep': policy['stepvalue'] = form.lr_multistep_values.data policy['gamma'] = form.lr_multistep_gamma.data elif form.lr_policy.data == 'exp': policy['gamma'] = form.lr_exp_gamma.data elif form.lr_policy.data == 'inv': policy['gamma'] = form.lr_inv_gamma.data policy['power'] = form.lr_inv_power.data elif form.lr_policy.data == 'poly': policy['power'] = form.lr_poly_power.data elif form.lr_policy.data == 'sigmoid': policy['stepsize'] = form.lr_sigmoid_step.data policy['gamma'] = form.lr_sigmoid_gamma.data else: raise werkzeug.exceptions.BadRequest( 'Invalid learning rate policy') if config_value('caffe_root')['multi_gpu']: if form.select_gpus.data: selected_gpus = [str(gpu) for gpu in form.select_gpus.data] gpu_count = None elif form.select_gpu_count.data: gpu_count = form.select_gpu_count.data selected_gpus = None else: gpu_count = 1 selected_gpus = None else: if form.select_gpu.data == 'next': gpu_count = 1 selected_gpus = None else: selected_gpus = [str(form.select_gpu.data)] gpu_count = None # Python Layer File may be on the server or copied from the client. fs.copy_python_layer_file( bool(form.python_layer_from_client.data), job.dir(), (flask.request.files[form.python_layer_client_file.name] if form.python_layer_client_file.name in flask.request.files else ''), form.python_layer_server_file.data) job.tasks.append( fw.create_train_task( job_dir=job.dir(), dataset=datasetJob, train_epochs=form.train_epochs.data, snapshot_interval=form.snapshot_interval.data, learning_rate=form.learning_rate.data, lr_policy=policy, gpu_count=gpu_count, selected_gpus=selected_gpus, batch_size=form.batch_size.data, val_interval=form.val_interval.data, pretrained_model=pretrained_model, crop_size=form.crop_size.data, use_mean=form.use_mean.data, network=network, random_seed=form.random_seed.data, solver_type=form.solver_type.data, shuffle=form.shuffle.data, )) ## Save form data with the job so we can easily clone it later. save_form_to_job(job, form) scheduler.add_job(job) if request_wants_json(): return flask.jsonify(job.json_dict()) else: return flask.redirect(flask.url_for('models_show', job_id=job.id())) except: if job: scheduler.delete_job(job) raise