提交 6c0f23db authored 作者: notoraptor's avatar notoraptor

Update tests script.

Add a script to quickly run specific tests.
上级 ef9095f9
......@@ -122,27 +122,34 @@ class CuDNNV51(object):
# empty list of enum to don't crash with cudnn 5
cudnnReduceTensorOp_t = CEnumType()
def get_supported_dtype_configs(self):
def get_supported_dtype_configs(self, check_runtime=None):
"""
Return the tuple of data type configurations supported by this version of cuDNN.
This is currently convenient for both cuDNN V5.1 and V6, as Theano does not
yet support new data types (like INT8, INT8x4, etc.).
``check_runtime`` may be a function that tests if a data type configuration is supported.::
is_supported = check_runtime(dtype, precision)
.. warning::
From documentation for cudnnConvolutionForward (for both v5.1 and v6):
.. code-block::
TRUE_HALF_CONFIG is only supported on architectures with true fp16 support
(compute capability 5.3 and 6.0)
This seems to be a general remark about f16 support (not only for FWD).
It can be checked at runtime only.
"""
return (TRUE_HALF_CONFIG, PSEUDO_HALF_CONFIG, FLOAT_CONFIG, DOUBLE_CONFIG)
def get_fwd_dtype_configs(self, check_runtime=None):
# NB: "TRUE_HALF_CONFIG is only supported on architectures with true fp16 support
# (compute capability 5.3 and 6.0)". Can be checked at runtime only.
if check_runtime is None or check_runtime(*TRUE_HALF_CONFIG):
return self.get_supported_dtype_configs()
return (TRUE_HALF_CONFIG, PSEUDO_HALF_CONFIG, FLOAT_CONFIG, DOUBLE_CONFIG)
return (PSEUDO_HALF_CONFIG, FLOAT_CONFIG, DOUBLE_CONFIG)
def get_bwd_filter_dtype_configs(self, check_runtime=None):
return self.get_supported_dtype_configs()
def get_bwd_data_dtype_configs(self, check_runtime=None):
return self.get_supported_dtype_configs()
def fwd_algo_supports_dtype_config(self, algo, dtype, precision, ndim):
algorithms = self.cudnnConvolutionFwdAlgo_t
algo = algorithms.fromalias(algo)
......@@ -209,7 +216,7 @@ class CuDNNV51(object):
if ndim == 3:
return not is_true_half_config(dtype, precision)
if algo == algorithms.CUDNN_CONVOLUTION_BWD_DATA_ALGO_WINOGRAD:
return ndim == 2 and is_pseudo_half_config(dtype, precision) or is_float_config(dtype, precision)
return ndim == 2 and (is_pseudo_half_config(dtype, precision) or is_float_config(dtype, precision))
if algo == algorithms.CUDNN_CONVOLUTION_BWD_DATA_ALGO_WINOGRAD_NONFUSED:
# NB: "If wDesc 's filter (height, width) is (5,5), data type config TRUE_HALF_CONFIG is not supported".
# We could not check it before being in C code.
......
#!/usr/bin/env python
# Without args, this script executes all its tests like `nosetests -vs`
# python check_dnn.py # nosetests mode.
# python check_dnn_conv.py
# You can pass args for nosetests as long as your first arg is not in `help, infos, fwd, bwd-filter, bwd-data`.
# python check_dnn.py -xvs # nosetests: verbose mode, capture output, exit at first error.
# If there is only one arg `infos`, this script prints some infos about
# supported algorithms and data type configurations for current GPU and cuDNN version.
# python check_dnn_conv.py infos
# Else, this script uses its own args and can be used to run a specific test case.
# python check_dnn.py help # Print help for script mode.
# python check_dnn.py infos # Print infos about algorithms and number of test cases.
# python check_dnn.py {fwd|bwd-filter|bwd-data} {2d|3d} -a <algo> -i <inputShape> -f <filterShape> ...
# If there is only one arg `list`, this script prints all tests without running them.
# python check_dnn_conv.py list
# Else, any arg will be directly passed to nosetests.
# python check_dnn_conv.py -xvs # nosetests: verbose mode, capture output, exit at first error.
from __future__ import absolute_import, print_function, division
import argparse
import sys
from itertools import product, chain
from itertools import product
import nose
import numpy as np
......@@ -23,6 +24,7 @@ from nose.plugins.skip import SkipTest
import theano
import theano.tests.unittest_tools as utt
from theano.compat import ifilter
from theano.compile.ops import shape_i_op
from theano.configdefaults import SUPPORTED_DNN_CONV_ALGO_RUNTIME
from theano.gpuarray import cudnn_defs
......@@ -32,28 +34,114 @@ from theano.gpuarray.tests.config import mode_with_gpu, ref_cast
from theano.tensor.nnet.abstract_conv import get_conv_output_shape, assert_conv_shape
from theano.tensor.opt import Assert
cudnn = cudnn_defs.get_definitions(version(raises=False))
# We provide a special implementation of dnn_conv, dnn_gradweight and dnn_gradinput
# that support alpha, beta and out as parameters.
def ifilter(function, sequence):
# For compatibility with Python 3.
return (element for element in sequence if function(element))
def dnn_conv(img, kerns, alpha=1, beta=0, out=None, border_mode='valid', subsample=(1, 1), dilation=(1, 1),
conv_mode='conv', algo=None, precision=None):
ctx_name = infer_context_name(img, kerns)
img = gpu_contiguous(as_gpuarray_variable(img, ctx_name))
kerns = gpu_contiguous(as_gpuarray_variable(kerns, ctx_name))
class DnnCase:
"""
Help class to generate special test cases quickly.
precision = get_precision(precision, [img, kerns])
desc = GpuDnnConvDesc(border_mode=border_mode, subsample=subsample, dilation=dilation,
conv_mode=conv_mode, precision=precision)(kerns.shape)
desc_op = desc.owner.op
# We can use Shape_i and bypass the infer_shape here as this is on
# the input of node and it will always be present.
ishape = [shape_i_op(i)(img) for i in range(img.ndim)]
kshape = [shape_i_op(i)(kerns) for i in range(kerns.ndim)]
out_shp = get_conv_output_shape(ishape, kshape, desc_op.border_mode, desc_op.subsample, filter_dilation=dilation)
out_shp = assert_conv_shape(out_shp)
if beta == 0:
real_out = GpuAllocEmpty(dtype=img.dtype, context_name=ctx_name)(*out_shp)
else:
assert out is not None
out = gpu_contiguous(as_gpuarray_variable(out, ctx_name))
check = Assert('GpuDnnConv: qiven output (for beta not null) does not have expected shape')
real_out = check(out, theano.tensor.all(theano.tensor.eq(out.shape, out_shp)))
return GpuDnnConv(algo=algo)(img, kerns, real_out, desc, alpha, beta)
def dnn_gradweight(img, topgrad, kerns_shp, alpha=1, beta=0, out=None, border_mode='valid', subsample=(1, 1),
dilation=(1, 1), conv_mode='conv', algo=None, precision=None):
ctx_name = infer_context_name(img, topgrad)
img = gpu_contiguous(as_gpuarray_variable(img, ctx_name))
topgrad = gpu_contiguous(as_gpuarray_variable(topgrad, ctx_name))
kerns_shp = theano.tensor.as_tensor_variable(kerns_shp)
precision = get_precision(precision, [img, topgrad])
desc = GpuDnnConvDesc(border_mode=border_mode, subsample=subsample, dilation=dilation,
conv_mode=conv_mode, precision=precision)(kerns_shp)
if beta == 0:
real_out = GpuAllocEmpty(dtype=img.dtype, context_name=ctx_name)(*kerns_shp)
else:
assert out is not None
out = gpu_contiguous(as_gpuarray_variable(out, ctx_name))
check = Assert('GpuDnnConvGradW: qiven output (for beta not null) does not have expected shape')
real_out = check(out, theano.tensor.all(theano.tensor.eq(out.shape, kerns_shp)))
return GpuDnnConvGradW(algo=algo)(img, topgrad, real_out, desc, alpha, beta)
def dnn_gradinput(kerns, topgrad, img_shp, alpha=1, beta=0, out=None, border_mode='valid', subsample=(1, 1),
dilation=(1, 1), conv_mode='conv', algo=None, precision=None):
ctx_name = infer_context_name(kerns, topgrad)
kerns = gpu_contiguous(as_gpuarray_variable(kerns, ctx_name))
topgrad = gpu_contiguous(as_gpuarray_variable(topgrad, ctx_name))
img_shp = theano.tensor.as_tensor_variable(img_shp)
precision = get_precision(precision, [kerns, topgrad])
desc = GpuDnnConvDesc(border_mode=border_mode, subsample=subsample, dilation=dilation,
conv_mode=conv_mode, precision=precision)(kerns.shape)
if beta == 0:
real_out = GpuAllocEmpty(dtype=kerns.dtype, context_name=ctx_name)(*img_shp)
else:
assert out is not None
out = gpu_contiguous(as_gpuarray_variable(out, ctx_name))
check = Assert('GpuDnnConvGradI: qiven output (for beta not null) does not have expected shape')
real_out = check(out, theano.tensor.all(theano.tensor.eq(out.shape, img_shp)))
return GpuDnnConvGradI(algo=algo)(kerns, topgrad, real_out, desc, alpha, beta)
def check_dtype_config_support(dtype, precision):
# We use FWD 2D to check it.
# Based on documentation, algo small (CUDNN_CONVOLUTION_FWD_ALGO_IMPLICIT_PRECOMP_GEMM)
# should support all configurations, for both v5.1 and v6.
inputs = theano.shared(np.zeros((1, 1, 2, 2), dtype=dtype))
filters = theano.shared(np.zeros((1, 1, 2, 2), dtype=dtype))
conv = dnn_conv(inputs, filters, precision=precision, algo='small')
f = theano.function([], conv, mode=mode_with_gpu)
try:
f()
except RuntimeError as e:
assert 'CUDNN_STATUS_ARCH_MISMATCH' in e.message
return False
return True
cudnn = cudnn_defs.get_definitions(version(raises=False))
class ConvCase:
"""
Help class to describe a special test case quickly.
This handles only 2D and 3D cases.
"""
def __init__(self,
type, inputs_shape, filters_shape,
FWD, GRADINPUT, GRADWEIGHT = 0, 1, 2
def __init__(self, type,
inputs_shape, filters_shape,
algo=None, dtype=None, precision=None,
subsample=None, dilation=None, border_mode='valid',
conv_mode='conv', alpha=1, beta=0,
should_fail=False):
assert type in ('fwd', 'bwd-filter', 'bwd-data')
assert len(inputs_shape) == len(filters_shape) > 2
assert type in (ConvCase.FWD, ConvCase.GRADINPUT, ConvCase.GRADWEIGHT)
assert len(inputs_shape) == len(filters_shape) in (4, 5)
ndim = len(inputs_shape) - 2
if dtype is None:
dtype = theano.config.floatX
......@@ -66,7 +154,8 @@ class DnnCase:
assert dtype in ('float16', 'float32', 'float64')
assert precision in ('float16', 'float32', 'float64')
assert len(subsample) == len(dilation) == ndim
assert border_mode in ('valid', 'full', 'half') or len(border_mode) == ndim
assert (border_mode in ('valid', 'full', 'half') or
(isinstance(border_mode, (list, tuple)) and len(border_mode) == ndim))
assert conv_mode in ('conv', 'cross')
assert alpha != 0
......@@ -86,13 +175,13 @@ class DnnCase:
self.should_fail = bool(should_fail)
def is_fwd(self):
return self.type == 'fwd'
return self.type == ConvCase.FWD
def is_bwd_filter(self):
return self.type == 'bwd-filter'
return self.type == ConvCase.GRADWEIGHT
def is_bwd_data(self):
return self.type == 'bwd-data'
return self.type == ConvCase.GRADINPUT
def get_case(self):
return (self.algo, self.dtype, self.precision,
......@@ -102,29 +191,30 @@ class DnnCase:
@staticmethod
def fwd(*args, **kwargs):
return DnnCase('fwd', *args, **kwargs)
return ConvCase(ConvCase.FWD, *args, **kwargs)
@staticmethod
def bwd_filter(*args, **kwargs):
return DnnCase('bwd-filter', *args, **kwargs)
return ConvCase(ConvCase.GRADWEIGHT, *args, **kwargs)
@staticmethod
def bwd_data(*args, **kwargs):
return DnnCase('bwd-data', *args, **kwargs)
return ConvCase(ConvCase.GRADINPUT, *args, **kwargs)
class DnnCaseGenerator:
class ConvCaseGenerator:
"""
Main class used to generate test cases.
This handles only 2D and 3D cases.
"""
def as_tuple_of_tuples(self, iterable):
def _as_tuple_of_tuples(self, iterable):
return tuple(tuple(sequence) for sequence in iterable)
def __init__(self,
ndim=2, alpha=2, beta=-3, batch_size=2, input_channels=3, inputs_sizes=None, output_channels=2,
filters_sizes=None, borders=None, subsamples=None, dilations=None):
def __init__(self, ndim,
alpha=2, beta=-3, batch_size=2, input_channels=3, inputs_sizes=None, output_channels=2,
filters_sizes=None, subsamples=None, dilations=None, borders=None,
with_border_valid=True, with_border_half=True, with_border_full=True):
self.ndim = int(ndim)
self.alpha = float(alpha)
self.beta = float(beta)
......@@ -132,12 +222,19 @@ class DnnCaseGenerator:
self.input_channels = int(input_channels)
self.output_channels = int(output_channels)
assert self.ndim >= 2
assert self.ndim in (2, 3)
assert self.alpha != 0
assert self.batch_size > 0
assert self.input_channels > 0
assert self.output_channels > 0
# NB: it is a bit arbitrary to choose default values for inputs sizes and filters sizes.
# Here, we just put some values that may generate errors in some cases, but that should be OK for other cases.
# For instance, input size 300 is > 256, that is a limit for certain algorithms (cf. documentation).
# Filter size 40 is > 32 and > 16, that are limits for certain algorithms (cf. documentation).
# We should either manually specify sizes, or give an appropriate filter to this generator
# (see `self.get_cases()`) before testing values.
if inputs_sizes is None:
inputs_sizes = ((5,) * self.ndim,
(300, 5) + (2,) * (self.ndim - 2))
......@@ -158,30 +255,41 @@ class DnnCaseGenerator:
for sequence_list in (inputs_sizes, filters_sizes, borders, subsamples, dilations):
assert (isinstance(sequence_list, (tuple, list)) and
all(isinstance(sequence, (tuple, list)) and len(sequence) == self.ndim
for sequence in sequence_list)), sequence_list
self.inputs_sizes = self.as_tuple_of_tuples(inputs_sizes)
self.filters_sizes = self.as_tuple_of_tuples(filters_sizes)
self.borders = self.as_tuple_of_tuples(borders)
self.subsamples = self.as_tuple_of_tuples(subsamples)
self.dilations = self.as_tuple_of_tuples(dilations)
for sequence in sequence_list)), (self.ndim, sequence_list)
self.auto_borders = tuple()
if with_border_valid:
self.auto_borders += ('valid',)
if with_border_half:
self.auto_borders += ('half',)
if with_border_full:
self.auto_borders += ('full',)
self.inputs_sizes = self._as_tuple_of_tuples(inputs_sizes)
self.filters_sizes = self._as_tuple_of_tuples(filters_sizes)
self.borders = self._as_tuple_of_tuples(borders)
self.subsamples = self._as_tuple_of_tuples(subsamples)
self.dilations = self._as_tuple_of_tuples(dilations)
@staticmethod
def get_if_valid_conv_output_shape(case_tuple):
# Filter function to keep only cases that produce valid convolution output shapes.
out_shp = get_conv_output_shape(case_tuple[0], # input shape
case_tuple[1], # filter shape
case_tuple[4], # border mode
case_tuple[2], # subsample
case_tuple[3] # dilation
)
case_tuple[3]) # dilation
try:
return assert_conv_shape(out_shp)
except ValueError:
return False
def get_cases(self):
def get_cases(self, filter=None):
# Generate an iterator of tuples with format:
# (input shape, filter shape, subsample, dilation, border mode, convolution mode, alpha, beta)
# filter may be a callable that gets one tuple (with format specified above) and returns
# a boolean, so that tuple is kept only if filter(tuple) is True.
all_batch_sizes = (self.batch_size,)
all_input_channels = (self.input_channels,)
all_input_sizes = self.inputs_sizes
......@@ -189,7 +297,7 @@ class DnnCaseGenerator:
all_filter_sizes = self.filters_sizes
all_subsamples = self.subsamples
all_dilations = self.dilations
all_border_modes = ('valid', 'full', 'half') + self.borders
all_border_modes = self.auto_borders + self.borders
all_conv_modes = ('conv', 'cross')
all_alphas = (self.alpha,)
all_betas = (0,) if self.beta == 0 else (0, self.beta)
......@@ -198,122 +306,176 @@ class DnnCaseGenerator:
for bs in all_batch_sizes for ic in all_input_channels for ins in all_input_sizes)
all_filter_shapes = ((oc, ic) + fis
for oc in all_output_channels for ic in all_input_channels for fis in all_filter_sizes)
return ifilter(DnnCaseGenerator.get_if_valid_conv_output_shape,
if callable(filter):
def local_filter(case_tuple):
return ConvCaseGenerator.get_if_valid_conv_output_shape(case_tuple) and filter(case_tuple)
else:
local_filter = ConvCaseGenerator.get_if_valid_conv_output_shape
return ifilter(local_filter,
product(all_input_shapes, all_filter_shapes, all_subsamples, all_dilations,
all_border_modes, all_conv_modes, all_alphas, all_betas))
# We provide a special implementation of dnn_conv, dnn_gradweight and dnn_gradinput
# that take algo, alpha, beta and out as parameters.
def dnn_conv(img, kerns, alpha=1, beta=0, out=None, border_mode='valid', subsample=(1, 1), dilation=(1, 1),
conv_mode='conv', algo=None, precision=None):
# Establish dtype in which to perform the computation of the convolution
precision = get_precision(precision, [img, kerns])
ctx_name = infer_context_name(img, kerns)
img = gpu_contiguous(img)
kerns = gpu_contiguous(kerns)
desc = GpuDnnConvDesc(border_mode=border_mode, subsample=subsample, dilation=dilation,
conv_mode=conv_mode, precision=precision)(kerns.shape)
desc_op = desc.owner.op
# We can use Shape_i and bypass the infer_shape here as this is on
# the input of node and it will always be present.
ishape = [shape_i_op(i)(img) for i in range(img.ndim)]
kshape = [shape_i_op(i)(kerns) for i in range(kerns.ndim)]
out_shp = get_conv_output_shape(ishape, kshape,
desc_op.border_mode,
desc_op.subsample,
filter_dilation=dilation)
out_shp = assert_conv_shape(out_shp)
if beta == 0:
real_out = GpuAllocEmpty(dtype=img.dtype, context_name=ctx_name)(*out_shp)
else:
assert out is not None
out = as_gpuarray_variable(out, ctx_name)
out = gpu_contiguous(out)
check = Assert('GpuDnnConv: qiven output (for beta not null) does not have expected shape')
real_out = check(out, theano.tensor.all(theano.tensor.eq(out.shape, out_shp)))
return GpuDnnConv(algo=algo)(img, kerns, real_out, desc, alpha, beta)
def dnn_gradweight(img, topgrad, kerns_shp, alpha=1, beta=0, out=None, border_mode='valid', subsample=(1, 1),
dilation=(1, 1), conv_mode='conv', algo=None, precision=None):
ctx_name = infer_context_name(img, topgrad)
img = as_gpuarray_variable(img, ctx_name)
topgrad = as_gpuarray_variable(topgrad, ctx_name)
img = gpu_contiguous(img)
topgrad = gpu_contiguous(topgrad)
kerns_shp = theano.tensor.as_tensor_variable(kerns_shp)
precision = get_precision(precision, [img, topgrad])
desc = GpuDnnConvDesc(border_mode=border_mode, subsample=subsample, dilation=dilation,
conv_mode=conv_mode, precision=precision)(kerns_shp)
if beta == 0:
real_out = GpuAllocEmpty(dtype=img.dtype, context_name=ctx_name)(*kerns_shp)
else:
assert out is not None
out = as_gpuarray_variable(out, ctx_name)
out = gpu_contiguous(out)
check = Assert('GpuDnnConvGradW: qiven output (for beta not null) does not have expected shape')
real_out = check(out, theano.tensor.all(theano.tensor.eq(out.shape, kerns_shp)))
return GpuDnnConvGradW(algo=algo)(img, topgrad, real_out, desc, alpha, beta)
def dnn_gradinput(kerns, topgrad, img_shp, alpha=1, beta=0, out=None, border_mode='valid', subsample=(1, 1),
dilation=(1, 1), conv_mode='conv', algo=None, precision=None):
ctx_name = infer_context_name(kerns, topgrad)
kerns = as_gpuarray_variable(kerns, ctx_name)
topgrad = as_gpuarray_variable(topgrad, ctx_name)
class CuDNNV51ConvCaseGenerator(object):
"""
Helper class to generate specific test cases for every algorithm supported by cuDNN V5.1.
Same class exists for cuDNN V6.0 (see below).
This should help avoid test cases that are intended to fail according to cuDNN documentations.
"""
NONE = 'none'
FFT = 'fft'
FFT_TILING = 'fft_tiling'
WINOGRAD = 'winograd'
WINOGRAD_NON_FUSED = 'winograd_non_fused'
# Protected interface.
def _dilations(self, ndim):
return [(1,) * ndim]
def _fwd_fft(self, ndim):
inputs_sizes = [(10,) * ndim,
(248, 5) + (2,) * (ndim - 2)]
filters_sizes = [tuple(range(9, 9 - ndim, -1))]
subsamples = [(1,) * ndim]
return ConvCaseGenerator(ndim=ndim,
inputs_sizes=inputs_sizes,
filters_sizes=filters_sizes,
subsamples=subsamples,
dilations=self._dilations(ndim))
def _fwd_fft_tiling(self, ndim):
if ndim == 2:
filters_sizes = [(32, 5)]
if ndim == 3:
filters_sizes = [(16, 5, 5)]
subsamples = [(1,) * ndim]
return ConvCaseGenerator(ndim=ndim,
filters_sizes=filters_sizes,
subsamples=subsamples,
dilations=self._dilations(ndim))
def _fwd_winograd(self, ndim):
filters_sizes = [(3,) * ndim]
subsamples = [(1,) * ndim]
return ConvCaseGenerator(ndim=ndim,
filters_sizes=filters_sizes,
subsamples=subsamples,
dilations=self._dilations(ndim))
def _fwd_winograd_non_fused(self, ndim):
filters_sizes = [(3,) * ndim]
if not check_dtype_config_support('float16', 'float16'):
filters_sizes += [(5,) * ndim]
subsamples = [(1,) * ndim]
return ConvCaseGenerator(ndim=ndim,
filters_sizes=filters_sizes,
subsamples=subsamples,
dilations=self._dilations(ndim))
def _gw_fft(self, ndim):
return self._fwd_fft(ndim)
def _gw_winograd_non_fused(self, ndim):
return self._fwd_winograd_non_fused(ndim)
def _gi_fft(self, ndim):
return self._fwd_fft(ndim)
def _gi_fft_tiling(self, ndim):
return self._fwd_fft_tiling(ndim)
def _gi_winograd(self, ndim):
return self._fwd_winograd(ndim)
def _gi_winograd_non_fused(self, ndim):
return self._fwd_winograd_non_fused(ndim)
# Public interface.
def fwd(self, algo, ndim):
if algo == self.FFT:
return self._fwd_fft(ndim)
if algo == self.FFT_TILING:
return self._fwd_fft_tiling(ndim)
if algo == self.WINOGRAD:
return self._fwd_winograd(ndim)
if algo == self.WINOGRAD_NON_FUSED:
return self._fwd_winograd_non_fused(ndim)
return ConvCaseGenerator(ndim=ndim, dilations=self._dilations(ndim))
def gw(self, algo, ndim):
if algo == self.FFT:
return self._gw_fft(ndim)
if algo == self.WINOGRAD_NON_FUSED:
return self._gw_winograd_non_fused(ndim)
return ConvCaseGenerator(ndim=ndim, dilations=self._dilations(ndim))
def gi(self, algo, ndim):
if algo == self.FFT:
return self._gi_fft(ndim)
if algo == self.FFT_TILING:
return self._gi_fft_tiling(ndim)
if algo == self.WINOGRAD:
return self._gi_winograd(ndim)
if algo == self.WINOGRAD_NON_FUSED:
return self._gi_winograd_non_fused(ndim)
return ConvCaseGenerator(ndim=ndim, dilations=self._dilations(ndim))
class CuDNNV6ConvCaseGenerator(CuDNNV51ConvCaseGenerator):
def _fwd_none(self, ndim):
# All dilations allowed.
return ConvCaseGenerator(ndim=ndim)
def _fwd_fft_tiling(self, ndim):
if ndim == 2:
filters_sizes = [(32, 5), (256, 1), (10, 10), (5, 1)]
subsamples = [(1, 1)]
borders = [(1, 1), (2, 1)]
return ConvCaseGenerator(ndim=ndim,
filters_sizes=filters_sizes,
subsamples=subsamples,
borders=borders,
dilations=self._dilations(ndim))
if ndim == 3:
return super(CuDNNV6ConvCaseGenerator, self)._fwd_fft_tiling(ndim)
kerns = gpu_contiguous(kerns)
topgrad = gpu_contiguous(topgrad)
def _gw_none(self, ndim):
return self._fwd_none(ndim)
img_shp = theano.tensor.as_tensor_variable(img_shp)
precision = get_precision(precision, [kerns, topgrad])
def _gw_fft_tiling(self, ndim):
inputs_sizes = [(256, 1), (20, 1)]
filters_sizes = [(3, 1), (10, 1)]
subsamples = [(1,) * ndim]
borders = [(1, 1), (2, 1)]
return ConvCaseGenerator(ndim=ndim,
inputs_sizes=inputs_sizes,
filters_sizes=filters_sizes,
subsamples=subsamples,
borders=borders,
dilations=self._dilations(ndim))
desc = GpuDnnConvDesc(border_mode=border_mode, subsample=subsample, dilation=dilation,
conv_mode=conv_mode, precision=precision)(kerns.shape)
if beta == 0:
real_out = GpuAllocEmpty(dtype=kerns.dtype, context_name=ctx_name)(*img_shp)
else:
assert out is not None
out = as_gpuarray_variable(out, ctx_name)
out = gpu_contiguous(out)
check = Assert('GpuDnnConvGradI: qiven output (for beta not null) does not have expected shape')
real_out = check(out, theano.tensor.all(theano.tensor.eq(out.shape, img_shp)))
def _gi_none(self, ndim):
return self._fwd_none(ndim)
return GpuDnnConvGradI(algo=algo)(kerns, topgrad, real_out, desc, alpha, beta)
def fwd(self, algo, ndim):
if algo == self.NONE:
return self._fwd_none(ndim)
return super(CuDNNV6ConvCaseGenerator, self).fwd(algo, ndim)
def gw(self, algo, ndim):
if algo == self.NONE:
return self._gw_none(ndim)
return super(CuDNNV6ConvCaseGenerator, self).gw(algo, ndim)
def check_fwd_dtype_config_support(dtype, precision):
inputs_shape = (1, 1, 3, 3)
filters_shape = (1, 1, 2, 2)
inputs = np.zeros(inputs_shape, dtype=dtype)
filters = np.zeros(filters_shape, dtype=dtype)
inputs = theano.shared(inputs)
filters = theano.shared(filters)
conv = dnn_conv(inputs, filters, precision=precision)
f = theano.function([], conv, mode=mode_with_gpu)
try:
f()
except RuntimeError as e:
assert 'CUDNN_STATUS_ARCH_MISMATCH' in e.message
return False
return True
def gi(self, algo, ndim):
if algo == self.NONE:
return self._gi_none(ndim)
return super(CuDNNV6ConvCaseGenerator, self).gi(algo, ndim)
def test_fwd_true_half_config_support():
# For cuDNN V5.1 and V6.0:
# "TRUE_HALF_CONFIG is only supported on architectures with true fp16 support (compute capability 5.3 and 6.0)"
if not check_fwd_dtype_config_support('float16', 'float16'):
raise SkipTest('FWD: TRUE_HALF_CONFIG not supported on this GPU.')
cudnn_conv_case_generator = CuDNNV51ConvCaseGenerator() if cudnn.version < 6 else CuDNNV6ConvCaseGenerator()
class BaseTestDnnConv(object):
......@@ -334,18 +496,21 @@ class BaseTestDnnConv(object):
cpu_gradinput_class = None
cpu_gradweight_class = None
special_cases = [] # List of DnnCases.
special_cases = [] # List of special ConvCases.
# Utility methods.
def get_cases(self):
def __init__(self):
utt.seed_rng(1234)
self.dtype_configs = cudnn.get_supported_dtype_configs(check_dtype_config_support)
def get_cases(self, filter=None):
# Return an iterable of test cases. Each test case is a tuple (or list) with following syntax:
# (input shape, filter shape, subsample, dilation, border mode, convolution mode, alpha, beta)
generator = DnnCaseGenerator(ndim=self.ndim)
return generator.get_cases()
return ConvCaseGenerator(ndim=self.ndim).get_cases(filter)
def array_like_conv_output(self, inputs_shape, filters_shape, border_mode, subsample, dilation, dtype):
# Return an random array with inferred convolution output shape.
# Return a random array with inferred convolution output shape.
out_shp = get_conv_output_shape(inputs_shape, filters_shape, border_mode, subsample, dilation)
out_shp = assert_conv_shape(out_shp)
return np.random.random(out_shp).astype(dtype)
......@@ -375,7 +540,7 @@ class BaseTestDnnConv(object):
f = theano.function([], conv, mode=mode_with_gpu)
# If conv_mode is 'conv' the reference implementation should use
# filters filpped according to the width, height and time axis
# filters flipped according to the width, height and time axis
if conv_mode == 'conv':
if inputs.ndim == 5:
flipped_filters = filters[:, :, ::-1, ::-1, ::-1]
......@@ -392,10 +557,9 @@ class BaseTestDnnConv(object):
# Compare the results of the two implementations
res_ref = f_ref()
res = f()
res = np.asarray(f())
if algo in cudnn.deterministic_fwd_algorithms:
res2 = f()
utt.assert_allclose(res, res2)
utt.assert_allclose(res, np.asarray(f()))
# Raise tolerance for float16
rtol = 6e-2 if dtype == 'float16' else None
......@@ -430,7 +594,7 @@ class BaseTestDnnConv(object):
f = theano.function([], grad_i, mode=mode_with_gpu)
# If conv_mode is 'conv' the reference implementation should use
# filters filpped according to the width, height and time axis
# filters flipped according to the width, height and time axis
if conv_mode == 'conv':
if filters.ndim == 5:
flipped_filters = filters[:, :, ::-1, ::-1, ::-1]
......@@ -448,10 +612,9 @@ class BaseTestDnnConv(object):
# Compare the results of the two implementations
res_ref = f_ref()
res = f()
res = np.asarray(f())
if algo in cudnn.deterministic_bwd_data_algorithms:
res2 = f()
utt.assert_allclose(res, res2)
utt.assert_allclose(res, np.asarray(f()))
# Raise tolerance for float16
rtol = 5e-2 if dtype == 'float16' else None
......@@ -499,10 +662,9 @@ class BaseTestDnnConv(object):
# Compare the results of the two implementations
res_ref = f_ref()
res = f()
res = np.asarray(f())
if algo in cudnn.deterministic_bwd_filter_algorithms:
res2 = f()
utt.assert_allclose(res, res2)
utt.assert_allclose(res, np.asarray(f()))
# Raise tolerance for float16
rtol = 5e-2 if dtype == 'float16' else None
......@@ -511,27 +673,6 @@ class BaseTestDnnConv(object):
else:
utt.assert_allclose(alpha * res_ref + beta * filters_val, res, rtol=rtol)
def get_expected_tcount(self):
"""
Utility function to get expected test count
without actually run nosetests.
"""
len_cases = sum(1 for case in self.get_cases())
count_contexts = 0
for dtype, precision in cudnn.get_fwd_dtype_configs(check_runtime=check_fwd_dtype_config_support):
algos = (algo for algo in self.fwd_algorithms
if cudnn.fwd_algo_supports_dtype_config(algo, dtype, precision, self.ndim))
count_contexts += sum(1 for algo in algos) + len(SUPPORTED_DNN_CONV_ALGO_RUNTIME)
for dtype, precision in cudnn.get_bwd_data_dtype_configs():
algos = (algo for algo in self.bwd_data_algorithms
if cudnn.bwd_data_algo_supports_dtype_config(algo, dtype, precision, self.ndim))
count_contexts += sum(1 for algo in algos) + len(SUPPORTED_DNN_CONV_ALGO_RUNTIME)
for dtype, precision in cudnn.get_bwd_filter_dtype_configs():
algos = (algo for algo in self.bwd_filter_algorithms
if cudnn.bwd_filter_algo_supports_dtype_config(algo, dtype, precision, self.ndim))
count_contexts += sum(1 for algo in algos) + len(SUPPORTED_DNN_CONV_ALGO_RUNTIME)
return len(self.special_cases) + len_cases * count_contexts
def should_fail(self, callable, *args):
try:
print('(should fail)', file=sys.stderr, end=' ')
......@@ -541,13 +682,25 @@ class BaseTestDnnConv(object):
else:
raise AssertionError('Should fail', callable.__name__, *args)
def get_expected_tcount(self):
"""
Utility function to get expected test count
without actually run nosetests.
"""
return (sum(1 for t in self.test_fwd()) +
sum(1 for t in self.test_gradweight()) +
sum(1 for t in self.test_gradinput()))
# Iterable test methods.
def test_fwd(self):
for dtype, precision in cudnn.get_fwd_dtype_configs(check_runtime=check_fwd_dtype_config_support):
for dtype, precision in self.dtype_configs:
algos = (algo for algo in self.fwd_algorithms
if cudnn.fwd_algo_supports_dtype_config(algo, dtype, precision, self.ndim))
for algo in chain(algos, SUPPORTED_DNN_CONV_ALGO_RUNTIME):
for algo in algos:
for parameters in cudnn_conv_case_generator.fwd(algo, self.ndim).get_cases():
yield (self.run_conv_fwd, algo, dtype, precision, parameters)
for algo in SUPPORTED_DNN_CONV_ALGO_RUNTIME:
for parameters in self.get_cases():
yield (self.run_conv_fwd, algo, dtype, precision, parameters)
for dnn_case in self.special_cases:
......@@ -558,10 +711,13 @@ class BaseTestDnnConv(object):
yield (self.run_conv_fwd,) + dnn_case.get_case()
def test_gradinput(self):
for dtype, precision in cudnn.get_bwd_data_dtype_configs():
for dtype, precision in self.dtype_configs:
algos = (algo for algo in self.bwd_data_algorithms
if cudnn.bwd_data_algo_supports_dtype_config(algo, dtype, precision, self.ndim))
for algo in chain(algos, SUPPORTED_DNN_CONV_ALGO_RUNTIME):
for algo in algos:
for parameters in cudnn_conv_case_generator.gi(algo, self.ndim).get_cases():
yield (self.run_conv_gradinput, algo, dtype, precision, parameters)
for algo in SUPPORTED_DNN_CONV_ALGO_RUNTIME:
for parameters in self.get_cases():
yield (self.run_conv_gradinput, algo, dtype, precision, parameters)
for dnn_case in self.special_cases:
......@@ -572,10 +728,13 @@ class BaseTestDnnConv(object):
yield (self.run_conv_gradinput,) + dnn_case.get_case()
def test_gradweight(self):
for dtype, precision in cudnn.get_bwd_filter_dtype_configs():
for dtype, precision in self.dtype_configs:
algos = (algo for algo in self.bwd_filter_algorithms
if cudnn.bwd_filter_algo_supports_dtype_config(algo, dtype, precision, self.ndim))
for algo in chain(algos, SUPPORTED_DNN_CONV_ALGO_RUNTIME):
for algo in algos:
for parameters in cudnn_conv_case_generator.gw(algo, self.ndim).get_cases():
yield (self.run_conv_gradweight, algo, dtype, precision, parameters)
for algo in SUPPORTED_DNN_CONV_ALGO_RUNTIME:
for parameters in self.get_cases():
yield (self.run_conv_gradweight, algo, dtype, precision, parameters)
for dnn_case in self.special_cases:
......@@ -597,14 +756,14 @@ class TestDnnConv2D(BaseTestDnnConv):
cpu_gradinput_class = theano.tensor.nnet.corr.CorrMM_gradInputs
cpu_gradweight_class = theano.tensor.nnet.corr.CorrMM_gradWeights
special_cases = [DnnCase.bwd_filter(algo='deterministic', dtype='float32', precision='float32',
inputs_shape=(1, 1, 541211, 10), filters_shape=(50, 1, 3, 10),
border_mode=(1, 0), should_fail=True),
DnnCase.fwd(algo='small', dtype='float32', precision='float32',
inputs_shape=(65536, 2, 2, 2), filters_shape=(1, 2, 2, 2)),
DnnCase.fwd(algo='small', dtype='float32', precision='float32',
inputs_shape=(65537, 2, 2, 2), filters_shape=(1, 2, 2, 2),
should_fail=(version(raises=False) <= 6020))]
special_cases = [ConvCase.bwd_filter(algo='deterministic', dtype='float32', precision='float32',
inputs_shape=(1, 1, 541211, 10), filters_shape=(50, 1, 3, 10),
border_mode=(1, 0), should_fail=True),
ConvCase.fwd(algo='small', dtype='float32', precision='float32',
inputs_shape=(65536, 2, 2, 2), filters_shape=(1, 2, 2, 2)),
ConvCase.fwd(algo='small', dtype='float32', precision='float32',
inputs_shape=(65537, 2, 2, 2), filters_shape=(1, 2, 2, 2),
should_fail=(version(raises=False) <= 6020))]
class TestDnnConv3D(BaseTestDnnConv):
......@@ -618,14 +777,21 @@ class TestDnnConv3D(BaseTestDnnConv):
cpu_gradinput_class = theano.tensor.nnet.corr3d.Corr3dMM_gradInputs
cpu_gradweight_class = theano.tensor.nnet.corr3d.Corr3dMM_gradWeights
special_cases = [DnnCase.fwd(algo='small', dtype='float32', precision='float32',
inputs_shape=(65536, 2, 2, 2, 2), filters_shape=(1, 2, 2, 2, 2)),
DnnCase.fwd(algo='small', dtype='float32', precision='float32',
inputs_shape=(65537, 2, 2, 2, 2), filters_shape=(1, 2, 2, 2, 2),
should_fail=(version(raises=False) <= 6020))]
special_cases = [ConvCase.fwd(algo='small', dtype='float32', precision='float32',
inputs_shape=(65536, 2, 2, 2, 2), filters_shape=(1, 2, 2, 2, 2)),
ConvCase.fwd(algo='small', dtype='float32', precision='float32',
inputs_shape=(65537, 2, 2, 2, 2), filters_shape=(1, 2, 2, 2, 2),
should_fail=(version(raises=False) <= 6020))]
class CheckDnn():
def test_true_half_config_support():
# For cuDNN V5.1 and V6.0:
# "TRUE_HALF_CONFIG is only supported on architectures with true fp16 support (compute capability 5.3 and 6.0)"
if not check_dtype_config_support('float16', 'float16'):
raise SkipTest('FWD: TRUE_HALF_CONFIG not supported on this GPU.')
class CheckDnn:
"""
Utility functions for scripting and infos printing.
"""
......@@ -641,16 +807,17 @@ class CheckDnn():
return 'FLOAT_CONFIG'
if dtype == precision == 'float64':
return 'DOUBLE_CONFIG'
raise ValueError
raise ValueError('unknown data type configuration', dtype_config)
@staticmethod
def print_infos():
def print_infos(count_tests=True):
# Print infos about tests and cuDNN supported algorithms and configurations.
test_2d = TestDnnConv2D()
test_3d = TestDnnConv3D()
print()
print('Available data type configurations:',
', '.join(CheckDnn.dtype_config_to_str(d) for d in cudnn.get_supported_dtype_configs()))
', '.join(CheckDnn.dtype_config_to_str(d)
for d in cudnn.get_supported_dtype_configs(check_dtype_config_support)))
print()
print('2D algorithms:')
print('FWD :', ', '.join(test_2d.fwd_algorithms))
......@@ -662,34 +829,36 @@ class CheckDnn():
print('BWD FILTER :', ', '.join(test_3d.bwd_filter_algorithms))
print('BWD DATA :', ', '.join(test_3d.bwd_data_algorithms))
print()
count_tests_2d = test_2d.get_expected_tcount()
count_tests_3d = test_3d.get_expected_tcount()
print(count_tests_2d, 'conv2D test cases.')
print(count_tests_3d, 'conv3D test cases.')
print(count_tests_2d + count_tests_3d, 'total conv test cases.')
print()
if count_tests:
count_tests_2d = test_2d.get_expected_tcount()
count_tests_3d = test_3d.get_expected_tcount()
print(count_tests_2d, 'conv2D test cases.')
print(count_tests_3d, 'conv3D test cases.')
print('1 supplementary test.')
print(count_tests_2d + count_tests_3d + 1, 'total conv tests.')
print()
class TupleAction(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
values = tuple(int(v) for v in values.split(','))
setattr(namespace, self.dest, values)
class BorderAction(TupleAction):
def __call__(self, parser, namespace, values, option_string=None):
if values not in ('valid', 'full', 'half'):
super(CheckDnn.BorderAction, self).__call__(parser, namespace, values, option_string)
else:
setattr(namespace, self.dest, values)
@staticmethod
def print_tests():
# Print test cases without running them.
for test in (TestDnnConv2D(), TestDnnConv3D()):
for tcase in test.test_fwd():
print(*(x.__name__ if callable(x) else x for x in tcase))
for tcase in test.test_gradinput():
print(*(x.__name__ if callable(x) else x for x in tcase))
for tcase in test.test_gradweight():
print(*(x.__name__ if callable(x) else x for x in tcase))
if __name__ == '__main__':
computations = FWD, BWD_FILTER, BWD_DATA = ('fwd', 'bwd-filter', 'bwd-data')
# We remove programe name from args.
args = sys.argv[1:]
if len(args) == 0 or args[0] not in computations + ('help', 'infos'):
if len(args) == 1 and args[0] in ('infos', 'list'):
if args[0] == 'infos':
CheckDnn.print_infos()
if args[0] == 'list':
CheckDnn.print_tests()
else:
# We run all tests with nosetests.
module_name = sys.modules[__name__].__file__
if len(args) == 0:
......@@ -700,105 +869,3 @@ if __name__ == '__main__':
CheckDnn.print_infos()
nose.main(argv=argv)
elif len(args) == 1 and args[0] == 'infos':
CheckDnn.print_infos()
else:
# User wants to run a specific test.
dimensions = ('2D', '2d', '3D', '3d')
algorithms = (tuple(sorted(list(set(cudnn.cudnnConvolutionFwdAlgo_t.get_aliases() +
cudnn.cudnnConvolutionBwdFilterAlgo_t.get_aliases() +
cudnn.cudnnConvolutionBwdDataAlgo_t.get_aliases())))) +
SUPPORTED_DNN_CONV_ALGO_RUNTIME)
types = ('float16', 'float32', 'float64')
parser = argparse.ArgumentParser()
parser.add_argument('computation', choices=computations,
help='Computation to run.')
parser.add_argument('ndim', choices=dimensions,
help='Number od dimensions ("2D" or "3D", case ignored).')
parser.add_argument('-a', '--algo', choices=algorithms, required=True,
help='Algorithm to use for computation.')
parser.add_argument('-i', '--input-shape', action=CheckDnn.TupleAction, required=True,
help='Input shape. Comma-separated list of integers (no spaces).')
parser.add_argument('-f', '--filter-shape', action=CheckDnn.TupleAction, required=True,
help='Filter shape. Comma-separated list of integers (no spaces).')
parser.add_argument('-t', '--dtype', choices=types, default=theano.config.floatX,
help='Data type (default theano floatX).')
parser.add_argument('-p', '--precision', choices=types, default=theano.config.floatX,
help='Precision (default theano floatX).')
parser.add_argument('-s', '--subsample', action=CheckDnn.TupleAction,
help='Subsample. Comma-separated list of integers (no spaces). '
'Default: 1 per dimension.')
parser.add_argument('-d', '--dilation', action=CheckDnn.TupleAction,
help='Dilation. Comma-separated list of integers (no spaces). '
'Default: 1 per dimension.')
parser.add_argument('-b', '--border-mode', default='valid', action=CheckDnn.BorderAction,
help='Border mode. "valid" (default), "full", "half" '
'or a comma-separated list of integers (no spaces).')
parser.add_argument('-c', '--conv-mode', choices=('conv', 'cross'), default='conv',
help='Conv mode (default: conv).')
parser.add_argument('-A', '--alpha', type=float, default=1,
help="alpha (floating), must not be zero. Default 1.")
parser.add_argument('-B', '--beta', type=float, default=0,
help='beta (floating). Default 0.')
parser.add_argument('--print-infos', action='store_true', default=False,
help='Print some infos before testing.')
if len(args) == 1 and args[0] == 'help':
parser.parse_args(['-h'])
exit(0)
args = parser.parse_args(args)
test = args.computation
ndim = int(args.ndim[0])
if ndim == 2:
tests = TestDnnConv2D()
if ndim == 3:
tests = TestDnnConv3D()
if args.subsample is None:
args.subsample = (1,) * ndim
if args.dilation is None:
args.dilation = (1,) * ndim
if not (ndim == len(args.input_shape[2:]) == len(args.filter_shape[2:]) == len(args.subsample) == len(
args.dilation)):
raise ValueError('Expected parameters sized for %d dimensions.' % ndim)
if isinstance(args.border_mode, tuple) and ndim != len(args.border_mode):
raise ValueError('Expected borders sized for %d dimensions.' % ndim)
if args.alpha == 0:
raise ValueError('Nothing could be computed if alpha is 0.')
if (args.dtype, args.precision) not in cudnn.get_supported_dtype_configs():
raise ValueError('Unsupported data type configuration %s %s.' % (args.dtype, args.precision))
if args.algo not in SUPPORTED_DNN_CONV_ALGO_RUNTIME:
check_config = False
if test == FWD:
check_config = cudnn.fwd_algo_supports_dtype_config(args.algo, args.dtype, args.precision, ndim)
if test == BWD_FILTER:
check_config = cudnn.bwd_filter_algo_supports_dtype_config(args.algo, args.dtype, args.precision, ndim)
if test == BWD_DATA:
check_config = cudnn.bwd_data_algo_supports_dtype_config(args.algo, args.dtype, args.precision, ndim)
if not check_config:
raise ValueError('%s computation does not support configuration (%s, %s) for algo %s.' % (
test, args.dtype, args.precision, args.algo))
algo = args.algo
dtype = args.dtype
precision = args.precision
parameters = (
args.input_shape, args.filter_shape, args.subsample, args.dilation, args.border_mode, args.conv_mode,
args.alpha, args.beta)
if args.print_infos:
CheckDnn.print_infos()
print('======================')
print('Running %s %s %s %s %s' % (test, algo, dtype, precision, str(parameters)))
if test == FWD:
tests.run_conv_fwd(algo, dtype, precision, parameters)
if test == BWD_FILTER:
tests.run_conv_gradweight(algo, dtype, precision, parameters)
if test == BWD_DATA:
tests.run_conv_gradinput(algo, dtype, precision, parameters)
print('... OK')
# This script allows to run one specific cuDNN convolution test case.
# python run_dnn_conv.py --help # Print help.
# python run_dnn_conv.py {fwd|bwd-filter|bwd-data} {2d|3d} -a <algo> -i <inputShape> -f <filterShape> ...
from __future__ import absolute_import, print_function, division
import argparse
import sys
import theano
from theano.configdefaults import SUPPORTED_DNN_CONV_ALGO_RUNTIME
from theano.gpuarray.cudnn_defs import (HALF, FLOAT, DOUBLE,
TRUE_HALF_CONFIG, PSEUDO_HALF_CONFIG, FLOAT_CONFIG, DOUBLE_CONFIG)
from theano.gpuarray.tests.check_dnn_conv import (cudnn, TestDnnConv2D, TestDnnConv3D, CheckDnn)
class TupleAction(argparse.Action):
# Tuple extractor for command line args parser.
def __call__(self, parser, namespace, values, option_string=None):
values = tuple(int(v) for v in values.split(','))
setattr(namespace, self.dest, values)
class BorderAction(TupleAction):
# Border extractor for command line args parser.
def __call__(self, parser, namespace, values, option_string=None):
if values not in ('valid', 'full', 'half'):
super(BorderAction, self).__call__(parser, namespace, values, option_string)
else:
setattr(namespace, self.dest, values)
if __name__ != '__main__':
raise ImportError('This script cannot be imported.')
args = sys.argv[1:]
computations = FWD, BWD_FILTER, BWD_DATA = ('fwd', 'gradweight', 'gradinput')
dimensions = ('2D', '2d', '3D', '3d')
algorithms = (tuple(sorted(list(set(cudnn.cudnnConvolutionFwdAlgo_t.get_aliases() +
cudnn.cudnnConvolutionBwdFilterAlgo_t.get_aliases() +
cudnn.cudnnConvolutionBwdDataAlgo_t.get_aliases())))) +
SUPPORTED_DNN_CONV_ALGO_RUNTIME)
types = (HALF, FLOAT, DOUBLE)
data_type_configurations = dict(TRUE_HALF_CONFIG=TRUE_HALF_CONFIG, PSEUDO_HALF_CONFIG=PSEUDO_HALF_CONFIG,
FLOAT_CONFIG=FLOAT_CONFIG, DOUBLE_CONFIG=DOUBLE_CONFIG)
parser = argparse.ArgumentParser()
parser.add_argument('computation', choices=computations,
help='Computation to run.')
parser.add_argument('ndim', choices=dimensions,
help='Number of dimensions ("2D" or "3D", case insensitive).')
parser.add_argument('-a', '--algo', choices=algorithms, required=True,
help='Algorithm to use for computation.')
parser.add_argument('-i', '--input-shape', action=TupleAction, required=True,
help='Input shape. Comma-separated list of integers (no spaces).')
parser.add_argument('-f', '--filter-shape', action=TupleAction, required=True,
help='Filter shape. Comma-separated list of integers (no spaces).')
parser.add_argument('-D', '--dtype-config', choices=list(sorted(data_type_configurations.keys())), default=None,
help='Data type configuration for (data type; precision). Default (theano floatX; theano floatX). '
'To specify data type configuration, you can either use this option or set data type and '
'precision separately with "-t" and "-p" options.')
parser.add_argument('-t', '--dtype', choices=types, default=None,
help='Data type (default theano floatX).')
parser.add_argument('-p', '--precision', choices=types, default=None,
help='Precision (default theano floatX).')
parser.add_argument('-s', '--subsample', action=TupleAction,
help='Subsample. Comma-separated list of integers (no spaces). '
'Default: 1 per dimension.')
parser.add_argument('-d', '--dilation', action=TupleAction,
help='Dilation. Comma-separated list of integers (no spaces). '
'Default: 1 per dimension.')
parser.add_argument('-b', '--border-mode', default='valid', action=BorderAction,
help='Border mode. "valid" (default), "full", "half" '
'or a comma-separated list of integers (no spaces).')
parser.add_argument('-c', '--conv-mode', choices=('conv', 'cross'), default='conv',
help='Conv mode (default: conv).')
parser.add_argument('-A', '--alpha', type=float, default=1,
help="alpha (floating), must not be zero. Default 1.")
parser.add_argument('-B', '--beta', type=float, default=0,
help='beta (floating). Default 0.')
parser.add_argument('-I', '--print-infos', action='store_true', default=False,
help='Print some infos before testing.')
args = parser.parse_args(args)
test = args.computation
ndim = int(args.ndim[0])
if ndim == 2:
tests = TestDnnConv2D()
if ndim == 3:
tests = TestDnnConv3D()
if args.subsample is None:
args.subsample = (1,) * ndim
if args.dilation is None:
args.dilation = (1,) * ndim
if not (ndim == len(args.input_shape[2:]) == len(args.filter_shape[2:]) == len(args.subsample) == len(
args.dilation)):
raise ValueError('Expected parameters sized for %d dimensions.' % ndim)
if isinstance(args.border_mode, tuple) and ndim != len(args.border_mode):
raise ValueError('Expected borders sized for %d dimensions.' % ndim)
if args.alpha == 0:
raise ValueError('Nothing could be computed if alpha is 0.')
if args.dtype_config is None:
if args.dtype is None:
args.dtype = theano.config.floatX
if args.precision is None:
args.precision = theano.config.floatX
else:
if args.dtype is not None or args.precision is not None:
raise ValueError('You must specify either -D <data-type-configuration> '
'or (-t <data-type> -p <precision>), not both.')
args.dtype, args.precision = data_type_configurations[args.dtype_config]
if (args.dtype, args.precision) not in cudnn.get_supported_dtype_configs():
raise ValueError('Unsupported data type configuration %s %s.' % (args.dtype, args.precision))
if args.algo not in SUPPORTED_DNN_CONV_ALGO_RUNTIME:
check_config = False
if test == FWD:
check_config = cudnn.fwd_algo_supports_dtype_config(args.algo, args.dtype, args.precision, ndim)
if test == BWD_FILTER:
check_config = cudnn.bwd_filter_algo_supports_dtype_config(args.algo, args.dtype, args.precision, ndim)
if test == BWD_DATA:
check_config = cudnn.bwd_data_algo_supports_dtype_config(args.algo, args.dtype, args.precision, ndim)
if not check_config:
raise ValueError('%s computation does not support configuration (%s, %s) for algo %s.' % (
test, args.dtype, args.precision, args.algo))
algo = args.algo
dtype = args.dtype
precision = args.precision
parameters = (
args.input_shape, args.filter_shape, args.subsample, args.dilation, args.border_mode, args.conv_mode,
args.alpha, args.beta)
if args.print_infos:
CheckDnn.print_infos(count_tests=False)
print('======================')
print('Running', test, algo, dtype, precision, *parameters)
if test == FWD:
tests.run_conv_fwd(algo, dtype, precision, parameters)
if test == BWD_FILTER:
tests.run_conv_gradweight(algo, dtype, precision, parameters)
if test == BWD_DATA:
tests.run_conv_gradinput(algo, dtype, precision, parameters)
print('... OK')
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论