# -*- coding: utf-8 -*-
from __future__ import absolute_import, division, print_function
import functools
import six
import numpy as np
import utool as ut
from wbia_cnn import ingest_data
from Lasagne.lasagne import init, layers, nonlinearities
from theano import tensor as T # NOQA
from wbia_cnn.models import abstract_models, pretrained
from os.path import exists
print, rrr, profile = ut.inject2(__name__)
[docs]def augment_parallel(X, y):
return augment_wrapper([X], None if y is None else [y])
[docs]def augment_wrapper(Xb, yb=None):
import random
import cv2
for index in range(len(Xb)):
X = np.copy(Xb[index])
y = None if yb is None else yb[index]
# Adjust the exposure
X_Lab = cv2.cvtColor(X, cv2.COLOR_BGR2LAB)
X_L = X_Lab[:, :, 0].astype(dtype=np.float32)
# margin = np.min([np.min(X_L), 255.0 - np.max(X_L), 64.0])
margin = 64.0
exposure = random.uniform(-margin, margin)
X_L += exposure
X_L = np.around(X_L)
X_L[X_L < 0.0] = 0.0
X_L[X_L > 255.0] = 255.0
X_Lab[:, :, 0] = X_L.astype(dtype=X_Lab.dtype)
X = cv2.cvtColor(X_Lab, cv2.COLOR_LAB2BGR)
# Rotate, Scale, Skew
h, w, c = X.shape
degree = random.randint(-15, 15)
scale = random.uniform(0.90, 1.10)
skew_x = random.uniform(0.90, 1.10)
skew_y = random.uniform(0.90, 1.10)
skew_x_offset = abs(1.0 - skew_x)
skew_y_offset = abs(1.0 - skew_y)
skew_offset = np.sqrt(
skew_x_offset ** skew_x_offset + skew_y_offset ** skew_y_offset
)
skew_scale = 1.0 + skew_offset
padding = np.sqrt((w) ** 2 / 4 - 2 * (w) ** 2 / 16)
padding /= scale
padding *= skew_scale
padding = int(np.ceil(padding))
for channel in range(c):
X_ = X[:, :, channel]
X_ = np.pad(X_, padding, 'reflect', reflect_type='even')
h_, w_ = X_.shape
# Calculate Affine transform
center = (w_ // 2, h_ // 2)
A = cv2.getRotationMatrix2D(center, degree, scale)
# Add skew
A[0][0] *= skew_x
A[1][0] *= skew_x
A[0][1] *= skew_y
A[1][1] *= skew_y
# Apply Affine
X_ = cv2.warpAffine(X_, A, (w_, h_), flags=cv2.INTER_LANCZOS4, borderValue=0)
X_ = X_[padding : -1 * padding, padding : -1 * padding]
X[:, :, channel] = X_
# Horizontal flip
if random.uniform(0.0, 1.0) <= 0.5:
X = cv2.flip(X, 1)
# Blur
if random.uniform(0.0, 1.0) <= 0.01:
X = cv2.blur(X, (3, 3))
# Reshape
X = X.reshape(Xb[index].shape)
X = X.astype(Xb[index].dtype)
# Show image
canvas_filepath = '/home/jason/Desktop/temp-%s-%d.png' % (
y,
random.randint(0, 100),
)
if False and not exists(canvas_filepath):
canvas = np.hstack((Xb[index], X))
cv2.imwrite(canvas_filepath, canvas)
# Save
Xb[index] = X
if yb is not None:
yb[index] = y
return Xb, yb
[docs]@six.add_metaclass(ut.ReloadingMetaclass)
class Classifier2Model(abstract_models.AbstractVectorModel):
def __init__(
model,
autoinit=False,
batch_size=128,
data_shape=(64, 64, 3),
name='classifier2',
**kwargs
):
super(Classifier2Model, model).__init__(
batch_size=batch_size, data_shape=data_shape, name=name, **kwargs
)
[docs] def augment(model, Xb, yb=None, parallel=True):
if not parallel:
return augment_wrapper(Xb, yb)
# Run in parallel
if yb is None:
yb = [None] * len(Xb)
arg_iter = list(zip(Xb, yb))
result_list = ut.util_parallel.generate2(
augment_parallel, arg_iter, ordered=True, verbose=False
)
result_list = list(result_list)
X = [result[0][0] for result in result_list]
X = np.array(X)
if yb is None:
y = None
else:
y = [result[1] for result in result_list]
y = np.vstack(y)
return X, y
[docs] def get_classifier2_def(model, verbose=ut.VERBOSE, **kwargs):
# _CaffeNet = abstract_models.PretrainedNetwork('caffenet')
_P = functools.partial
_CaffeNet = pretrained.PretrainedNetwork('caffenet_conv')
hidden_initkw = {
'nonlinearity': nonlinearities.LeakyRectify(leakiness=(1.0 / 10.0)),
}
from wbia_cnn import custom_layers
Conv2DLayer = custom_layers.Conv2DLayer
MaxPool2DLayer = custom_layers.MaxPool2DLayer
# DenseLayer = layers.DenseLayer
network_layers_def = [
_P(layers.InputLayer, shape=model.input_shape),
_P(
Conv2DLayer,
num_filters=16,
filter_size=(11, 11),
name='C0',
W=_CaffeNet.get_pretrained_layer(0),
**hidden_initkw
), # NOQA
_P(MaxPool2DLayer, pool_size=(2, 2), stride=(2, 2), name='P0'),
_P(
Conv2DLayer,
num_filters=32,
filter_size=(5, 5),
name='C1',
W=_CaffeNet.get_pretrained_layer(2),
**hidden_initkw
), # NOQA
_P(MaxPool2DLayer, pool_size=(2, 2), stride=(2, 2), name='P1'),
_P(
Conv2DLayer,
num_filters=64,
filter_size=(3, 3),
name='C2',
W=_CaffeNet.get_pretrained_layer(4),
**hidden_initkw
), # NOQA
_P(MaxPool2DLayer, pool_size=(2, 2), stride=(2, 2), name='P2'),
_P(
Conv2DLayer,
num_filters=128,
filter_size=(3, 3),
name='C3',
W=init.Orthogonal('relu'),
**hidden_initkw
),
_P(MaxPool2DLayer, pool_size=(2, 2), stride=(2, 2), name='P3'),
_P(
Conv2DLayer,
num_filters=128,
filter_size=(3, 3),
name='C4',
W=init.Orthogonal('relu'),
**hidden_initkw
),
_P(
Conv2DLayer,
num_filters=128,
filter_size=(3, 3),
name='C5',
W=init.Orthogonal('relu'),
**hidden_initkw
),
_P(layers.DenseLayer, num_units=256, name='F0', **hidden_initkw),
_P(layers.FeaturePoolLayer, pool_size=2, name='FP0'),
_P(layers.DropoutLayer, p=0.5, name='D1'),
_P(layers.DenseLayer, num_units=256, name='F1', **hidden_initkw),
_P(
layers.DenseLayer,
num_units=model.output_dims,
name='F2',
nonlinearity=nonlinearities.sigmoid,
),
]
return network_layers_def
[docs] def init_arch(model, verbose=ut.VERBOSE, **kwargs):
r""""""
(_, input_channels, input_width, input_height) = model.input_shape
if verbose or True:
print('[model] Initialize classifier2 model architecture')
print('[model] * batch_size = %r' % (model.batch_size,))
print('[model] * input_width = %r' % (input_width,))
print('[model] * input_height = %r' % (input_height,))
print('[model] * input_channels = %r' % (input_channels,))
print('[model] * output_dims = %r' % (model.output_dims,))
network_layers_def = model.get_classifier2_def(verbose=verbose, **kwargs)
# connect and record layers
from wbia_cnn import custom_layers
network_layers = custom_layers.evaluate_layer_list(
network_layers_def, verbose=verbose
)
# model.network_layers = network_layers
output_layer = network_layers[-1]
model.output_layer = output_layer
return output_layer
[docs]def train_classifier2(output_path, data_fpath, labels_fpath, purge=True):
r"""
CommandLine:
python -m wbia_cnn.train --test-train_classifier2
Example:
>>> # DISABLE_DOCTEST
>>> from wbia_cnn.train import * # NOQA
>>> result = train_classifier2()
>>> print(result)
"""
era_size = 32
max_epochs = 256
hyperparams = ut.argparse_dict(
{
'era_size': era_size,
'batch_size': 128,
'learning_rate': 0.01,
'rate_schedule': 0.75,
'momentum': 0.9,
'weight_decay': 0.0001,
'augment_on': True,
'augment_weights': False,
'whiten_on': True,
'class_weight': None,
'max_epochs': max_epochs,
}
)
ut.colorprint('[netrun] Ensuring Dataset', 'yellow')
dataset = ingest_data.get_numpy_dataset2(
'classifier2', data_fpath, labels_fpath, output_path, cache=False
)
X_train, y_train = dataset.subset('train')
X_valid, y_valid = dataset.subset('valid')
print('dataset.training_dpath = %r' % (dataset.training_dpath,))
if purge:
model = Classifier2Model(
data_shape=dataset.data_shape,
training_dpath=dataset.training_dpath,
**hyperparams
)
model.init_output_dims(y_train)
model.init_arch()
ut.delete(model.arch_dpath)
ut.colorprint('[netrun] Architecture Specification', 'yellow')
model = Classifier2Model(
data_shape=dataset.data_shape,
training_dpath=dataset.training_dpath,
**hyperparams
)
ut.colorprint('[netrun] Init output_dims', 'yellow')
model.init_output_dims(y_train)
ut.colorprint('[netrun] Initialize archchitecture', 'yellow')
model.init_arch()
ut.colorprint('[netrun] * Initializing new weights', 'lightgray')
if model.has_saved_state():
model.load_model_state()
# else:
# model.reinit_weights()
# ut.colorprint('[netrun] Need to initialize training state', 'yellow')
# X_train, y_train = dataset.subset('train')
# model.ensure_data_params(X_train, y_train)
ut.colorprint('[netrun] Training Requested', 'yellow')
# parse training arguments
config = ut.argparse_dict(
dict(
monitor=False,
monitor_updates=False,
show_confusion=False,
era_size=era_size,
max_epochs=max_epochs,
)
)
model.monitor_config.update(**config)
if getattr(model, 'encoder', None) is not None:
class_list = list(model.encoder.classes_)
y_train = np.array([class_list.index(_) for _ in y_train])
y_valid = np.array([class_list.index(_) for _ in y_valid])
print('\n[netrun] Model Info')
model.print_layer_info()
ut.colorprint('[netrun] Begin training', 'yellow')
model.fit(X_train, y_train, X_valid=X_valid, y_valid=y_valid)
model_path = model.save_model_state()
return model_path
if __name__ == '__main__':
"""
CommandLine:
python -m wbia_cnn.models.classifier2
python -m wbia_cnn.models.classifier2 --allexamples
python -m wbia_cnn.models.classifier2 --allexamples --noface --nosrc
"""
import multiprocessing
multiprocessing.freeze_support() # for win32
import utool as ut # NOQA
ut.doctest_funcs()