jiebi/CodeConvo huggingface dataset:
def batch_norm(input, running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-5): <ins> size = list(input.size()) if reduce(mul, size[2:], size[0]) == 1: raise ValueError('Expected more than 1 value per channel, got input size {}'.format(size)) </ins> f = torch._C._functions.BatchNorm(running_mean, running_var, training, momentum, eps, torch.backends.cudnn.enabled) return f(input, weight, bias)
| :attr:`stride` controls the stride for the cross-correlation. | If :attr:`padding` is non-zero, then the input is implicitly zero-padded on both sides <del> for :attr:`padding` number of points | :attr:`dilation` controls the spacing between the kernel points. It is harder to describe, but this `link`_ has a nice visualization of what :attr:`dilation` does. | :attr:`groups` controls the connections between inputs and outputs. </del> <ins> for :attr:`padding` number of points. | :attr:`dilation` controls the spacing between the kernel points; also known as the à trous algorithm. It is harder to describe, but this `link`_ has a nice visualization of what :attr:`dilation` does. | :attr:`groups` controls the connections between inputs and outputs. `in_channels` and `out_channels` must both be divisible by `groups`. </ins> |       At groups=1, all inputs are convolved to all outputs. |       At groups=2, the operation becomes equivalent to having two conv layers side by side, each seeing half the input channels, and producing half the output channels, and both subsequently concatenated. <ins> At groups=`in_channels`, each input channel is convolved with its own set of filters (of size `out_channels // in_channels`). </ins> .. note::
| :attr:`stride` controls the stride for the cross-correlation. | If :attr:`padding` is non-zero, then the input is implicitly zero-padded on both sides <del> for :attr:`padding` number of points | :attr:`dilation` controls the spacing between the kernel points. It is harder to describe, but this `link`_ has a nice visualization of what :attr:`dilation` does. | :attr:`groups` controls the connections between inputs and outputs. </del> <ins> for :attr:`padding` number of points. | :attr:`dilation` controls the spacing between the kernel points; also known as the à trous algorithm. It is harder to describe, but this `link`_ has a nice visualization of what :attr:`dilation` does. | :attr:`groups` controls the connections between inputs and outputs. `in_channels` and `out_channels` must both be divisible by `groups`. </ins> |       At groups=1, all inputs are convolved to all outputs. |       At groups=2, the operation becomes equivalent to having two conv layers side by side, each seeing half the input channels, and producing half the output channels, and both subsequently concatenated. <ins> At groups=`in_channels`, each input channel is convolved with its own set of filters (of size `out_channels // in_channels`). </ins> The parameters :attr:`kernel_size`, :attr:`stride`, :attr:`padding`, :attr:`dilation` can either be:
composed of several input planes. This module can be seen as the gradient of Conv1d with respect to its input. <del> It is sometimes (but incorrectly) refered to as a deconvolutional operation. </del> <ins> It is also known as a fractionally-strided convolution or a deconvolution (although it is not an actual deconvolution operation). | :attr:`stride` controls the stride for the cross-correlation. | If :attr:`padding` is non-zero, then the input is implicitly zero-padded on both sides for :attr:`padding` number of points. | If :attr:`output_padding` is non-zero, then the output is implicitly zero-padded on one side for :attr:`output_padding` number of points. | :attr:`dilation` controls the spacing between the kernel points; also known as the à trous algorithm. It is harder to describe, but this `link`_ has a nice visualization of what :attr:`dilation` does. | :attr:`groups` controls the connections between inputs and outputs. `in_channels` and `out_channels` must both be divisible by `groups`. |       At groups=1, all inputs are convolved to all outputs. |       At groups=2, the operation becomes equivalent to having two conv layers side by side, each seeing half the input channels, and producing half the output channels, and both subsequently concatenated. At groups=`in_channels`, each input channel is convolved with its own set of filters (of size `out_channels // in_channels`). </ins> .. note::
composed of several input planes. This module can be seen as the gradient of Conv2d with respect to its input. <del> It is sometimes (but incorrectly) refered to as a deconvolutional operation. </del> <ins> It is also known as a fractionally-strided convolution or a deconvolution (although it is not an actual deconvolution operation). </ins> | :attr:`stride` controls the stride for the cross-correlation. | If :attr:`padding` is non-zero, then the input is implicitly zero-padded on both sides <del> for :attr:`padding` number of points </del> <ins> for :attr:`padding` number of points. </ins> | If :attr:`output_padding` is non-zero, then the output is implicitly zero-padded on one side <del> for :attr:`output_padding` number of points | :attr:`dilation` controls the spacing between the kernel points. It is harder to describe, but this `link`_ has a nice visualization of what :attr:`dilation` does. | :attr:`groups` controls the connections between inputs and outputs. </del> <ins> for :attr:`output_padding` number of points. | :attr:`dilation` controls the spacing between the kernel points; also known as the à trous algorithm. It is harder to describe, but this `link`_ has a nice visualization of what :attr:`dilation` does. | :attr:`groups` controls the connections between inputs and outputs. `in_channels` and `out_channels` must both be divisible by `groups`. </ins> |       At groups=1, all inputs are convolved to all outputs. |       At groups=2, the operation becomes equivalent to having two conv layers side by side, each seeing half the input channels, and producing half the output channels, and both subsequently concatenated. <ins> At groups=`in_channels`, each input channel is convolved with its own set of filters (of size `out_channels // in_channels`). </ins> The parameters :attr:`kernel_size`, :attr:`stride`, :attr:`padding`, :attr:`output_padding` can either be: <del> - a single ``int`` -- in which case the same value is used for the height and width dimension </del> <ins> - a single ``int`` -- in which case the same value is used for the height and width dimensions </ins> - a ``tuple`` of two ints -- in which case, the first `int` is used for the height dimension, and the second `int` for the width dimension
The transposed convolution operator multiplies each input value element-wise by a learnable kernel, and sums over the outputs from all input feature planes. <del> **This module can be seen as the exact reverse of Conv3d**. It is sometimes (but incorrectly) refered to as a deconvolutional operation. </del> <ins> This module can be seen as the gradient of Conv3d with respect to its input. It is also known as a fractionally-strided convolution or a deconvolution (although it is not an actual deconvolution operation). </ins> | :attr:`stride` controls the stride for the cross-correlation. | If :attr:`padding` is non-zero, then the input is implicitly zero-padded on both sides <del> for :attr:`padding` number of points </del> <ins> for :attr:`padding` number of points. </ins> | If :attr:`output_padding` is non-zero, then the output is implicitly zero-padded on one side <del> for :attr:`output_padding` number of points | :attr:`groups` controls the connections between inputs and outputs. </del> <ins> for :attr:`output_padding` number of points. | :attr:`dilation` controls the spacing between the kernel points; also known as the à trous algorithm. It is harder to describe, but this `link`_ has a nice visualization of what :attr:`dilation` does. | :attr:`groups` controls the connections between inputs and outputs. `in_channels` and `out_channels` must both be divisible by `groups`. </ins> |       At groups=1, all inputs are convolved to all outputs. |       At groups=2, the operation becomes equivalent to having two conv layers side by side, each seeing half the input channels, and producing half the output channels, and both subsequently concatenated. <ins> At groups=`in_channels`, each input channel is convolved with its own set of filters (of size `out_channels // in_channels`). </ins> The parameters :attr:`kernel_size`, :attr:`stride`, :attr:`padding`, :attr:`output_padding` can either be: <del> - a single ``int`` -- in which case the same value is used for the height and width dimension </del> <ins> - a single ``int`` -- in which case the same value is used for the depth, height and width dimensions </ins> - a ``tuple`` of three ints -- in which case, the first `int` is used for the depth dimension, the second `int` for the width dimension and the third `int` for the width dimension
template<typename FnType, FnType fn, typename ...Args> static PyObject* wrap_tuple_fn(Args ... args) { <del> PyObject *result = (*fn)(std::forward<Args>(args)...); </del> <ins> THPObjectPtr result((*fn)(std::forward<Args>(args)...)); </ins> if (!result) return NULL; <del> if (PyTuple_Check(result)) { return PyObject_CallFunctionObjArgs((PyObject*)&THPSizeType, result, NULL); </del> <ins> if (PyTuple_Check(result.get())) { return PyObject_CallFunctionObjArgs((PyObject*)&THPSizeType, result.get(), NULL); </ins> } <del> Py_INCREF(result); return result; </del> <ins> return result.release(); </ins> } static auto sq_concat = PyTuple_Type.tp_as_sequence->sq_concat;
<del> FROM nvidia/cuda:8.0-devel-ubuntu16.04 </del> <ins> FROM nvidia/cuda:8.0-cudnn6-devel-ubuntu16.04 </ins> RUN echo "deb http://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1604/x86_64 /" > /etc/apt/sources.list.d/nvidia-ml.list <del> ENV CUDNN_VERSION 6.0.20 </del> RUN apt-get update && apt-get install -y --no-install-recommends  build-essential  cmake  git  curl  <ins> vim  </ins> ca-certificates  libjpeg-dev  <del> libpng-dev  libcudnn6=$CUDNN_VERSION-1+cuda8.0  libcudnn6-dev=$CUDNN_VERSION-1+cuda8.0 &&  </del> <ins> libpng-dev && </ins> rm -rf /var/lib/apt/lists/* RUN curl -o ~/miniconda.sh -O  https://repo.continuum.io/miniconda/Miniconda3-4.2.12-Linux-x86_64.sh  &&
# This will segfault if things have been erroneously released out.backward(torch.randn(out.size())) <ins> def test_norm_subgradient(self): def run_test(input_size, norm_deg): input = Variable(torch.zeros(*input_size), requires_grad=True) out = input.norm(norm_deg) out.backward() self.assertEqual(input.grad.data.abs().sum(), 0) run_test((10,), 2) run_test((10, 10), 2) run_test((10,), 3) </ins> def index_variable(shape, max_indices): if not isinstance(shape, tuple):
ctx.keepdim = False if keepdim is None else keepdim if dim is None: <del> ctx.norm = input.norm(p) ctx.save_for_backward(input) return input.new((ctx.norm,)) </del> <ins> norm = input.norm(p) output = input.new((norm,)) </ins> else: if keepdim is not None: output = input.norm(p, dim, keepdim=keepdim) else: output = input.norm(p, dim) <del> ctx.save_for_backward(input, output) return output </del> <ins> ctx.save_for_backward(input, output) return output </ins> @staticmethod def backward(ctx, grad_output): <del> if ctx.dim is None: input, = ctx.saved_variables if ctx.p == 2: scale_v = (grad_output / ctx.norm).expand_as(input) return input.mul(scale_v), None, None, None else: pow = input.abs().pow(ctx.p - 2) scale_v = (grad_output / ctx.norm ** (ctx.p - 1)).expand_as(input) return input.mul(pow).mul(scale_v), None, None, None </del> <ins> input, output = ctx.saved_variables if ctx.dim is not None and ctx.keepdim is False and input.dim() != 1: grad_output = grad_output.unsqueeze(ctx.dim) output = output.unsqueeze(ctx.dim) if ctx.p == 2: grad_input = input.mul(grad_output).div(output) </ins> else: <del> input, output = ctx.saved_variables </del> <ins> input_pow = input.abs().pow(ctx.p - 2) output_pow = output.pow(ctx.p - 1) grad_input = input.mul(input_pow).mul(grad_output).div(output_pow) </ins> <del> if ctx.keepdim is False and input.dim() != 1: grad_output = grad_output.unsqueeze(ctx.dim) output = output.unsqueeze(ctx.dim) </del> <ins> # Special case at 0 where we return a subgradient containing 0 grad_input.masked_fill_(output == 0, 0) </ins> <del> big_grad_output = grad_output.expand_as(input) if ctx.p == 2: big_output = output.expand_as(input) return input.mul(big_grad_output).div(big_output), None, None, None else: pow = input.abs().pow(ctx.p - 2) big_output = output.pow(ctx.p - 1).expand_as(input) return input.mul(pow).mul(big_grad_output).div(big_output), None, None, None </del> <ins> return grad_input, None, None, None </ins> # TODO: renorm
self.assertEqual(torch.mm(flattened_tensor, flattened_tensor.t()), torch.eye(rows) * gain ** 2, prec=1e-6) <ins> # Generates rand tensor with non-equal values. This ensures that duplicate # values won't be causing test failure for modules like MaxPooling. # size should be small, otherwise randperm fails / long overflows. def _rand_tensor_non_equal(*size): total = reduce(mul, size, 1) return torch.randperm(total).view(*size).double() </ins> def add_test(test): test_name = test.get_name()
dict( module_name='AdaptiveMaxPool1d', constructor_args=(3,), <del> input=torch.rand(1, 3, 5), </del> <ins> input=_rand_tensor_non_equal(1, 3, 5), </ins> ), dict( module_name='AdaptiveMaxPool2d', constructor_args=(3,), <del> input=torch.rand(1, 3, 5, 6), </del> <ins> input=_rand_tensor_non_equal(1, 3, 5, 6), </ins> desc='single', ), dict( module_name='AdaptiveMaxPool2d', constructor_args=((3, 4),), <del> input=torch.rand(1, 3, 5, 6), </del> <ins> input=_rand_tensor_non_equal(1, 3, 5, 6), </ins> desc='tuple', ), dict( module_name='AdaptiveMaxPool3d', constructor_args=(3,), <del> input=torch.rand(2, 3, 5, 6, 7), </del> <ins> input=_rand_tensor_non_equal(2, 3, 5, 6, 7), </ins> desc='single', ), dict( module_name='AdaptiveMaxPool3d', constructor_args=((3, 4, 5),), <del> input=torch.rand(2, 3, 5, 6, 7), </del> <ins> input=_rand_tensor_non_equal(2, 3, 5, 6, 7), </ins> desc='tuple', ), dict( module_name='AdaptiveMaxPool3d', constructor_args=(3,), <del> input=torch.rand(2, 3, 12, 9, 3), </del> <ins> input=_rand_tensor_non_equal(2, 3, 12, 9, 3), </ins> desc='single_nonatomic', ), dict( module_name='AdaptiveMaxPool3d', constructor_args=((3, 4, 5),), <del> input=torch.rand(2, 3, 6, 4, 10), </del> <ins> input=_rand_tensor_non_equal(2, 3, 6, 4, 10), </ins> desc='tuple_nonatomic', ), dict(
if momentum != 0: param_state = self.state[p] if 'momentum_buffer' not in param_state: <del> buf = param_state['momentum_buffer'] = d_p.clone() </del> <ins> buf = param_state['momentum_buffer'] = p.data.new().resize_as_(p.data).zero_() buf.mul_(momentum).add_(d_p) </ins> else: buf = param_state['momentum_buffer'] buf.mul_(momentum).add_(1 - dampening, d_p)
{ /* Get normalized cumulative distribution from prob distribution */ double sum = 0; <ins> double val; </ins> for (j=0; j<n_categories; j++) { <del> sum += THStorage_(get)(  </del> <ins> val = THStorage_(get)(  </ins> prob_dist->storage,  prob_dist->storageOffset+i*prob_dist->stride[0]+j*prob_dist->stride[1]  ); <ins> THArgCheckWithCleanup((val >= 0), THCleanup(THDoubleTensor_free(cum_dist); if (start_dim == 1) THTensor_(resize1d)(prob_dist, n_categories);), 2, "invalid multinomial distribution (encountering probability entry < 0)"); sum += val; </ins> THDoubleStorage_set( cum_dist->storage,  cum_dist->storageOffset+j*cum_dist->stride[0],
__global__ void renormRowsL1(T* dist, long rows, long cols) { extern __shared__  unsigned char my_smem[]; T *smem = reinterpret_cast<T *>(my_smem); <ins> T zero = ScalarConvert<int, T>::to(0); T val; </ins> for (int64_t row = blockIdx.x; row < rows; row += gridDim.x) { T sum = ScalarConvert<int, T>::to(0); for (int64_t col = threadIdx.x; col < cols; col += blockDim.x) { <del> sum = THCNumerics<T>::add(sum, dist[row * cols + col]); </del> <ins> val = dist[row * cols + col]; assert(THCNumerics<T>::ge(val, zero)); sum = THCNumerics<T>::add(sum, val); </ins> } <del> sum = reduceBlock(smem, blockDim.x, sum, ReduceAdd<T, T>(), ScalarConvert<int, T>::to(0)); </del> <ins> sum = reduceBlock(smem, blockDim.x, sum, ReduceAdd<T, T>(), zero); </ins> if (threadIdx.x == 0) { <ins> assert(THCNumerics<T>::gt(sum, zero)); </ins> smem[0] = sum; } __syncthreads();
// Each block handles one distribution // First pass, find the total sum of the distribution AccT sum = accZero; <ins> T val; </ins> for (int cat = threadIdx.x; cat < categories; cat += blockDim.x) { <del> sum = THCNumerics<AccT>::add( sum, ScalarConvert<T, AccT>::to(dist[curDist * categories + cat])); </del> <ins> val = dist[curDist * categories + cat]; assert(THCNumerics<T>::ge(val, zero)); sum = THCNumerics<AccT>::add(sum, ScalarConvert<T, AccT>::to(val)); </ins> } // threadIdx.x == 0 has the sum value from this
begin{array}{ll} i_t = sigma(W_{ii} x_t + b_{ii} + W_{hi} h_{(t-1)} + b_{hi})  f_t = sigma(W_{if} x_t + b_{if} + W_{hf} h_{(t-1)} + b_{hf})  <del> g_t = tanh(W_{ig} x_t + b_{ig} + W_{hc} h_{(t-1)} + b_{hg})  </del> <ins> g_t = tanh(W_{ig} x_t + b_{ig} + W_{hg} h_{(t-1)} + b_{hg})  </ins> o_t = sigma(W_{io} x_t + b_{io} + W_{ho} h_{(t-1)} + b_{ho})  c_t = f_t c_{(t-1)} + i_t g_t  h_t = o_t tanh(c_t)
<ins> From PyTorch: Copyright (c) 2016-     Facebook, Inc            (Adam Paszke) Copyright (c) 2014-     Facebook, Inc            (Soumith Chintala) Copyright (c) 2011-2014 Idiap Research Institute (Ronan Collobert) Copyright (c) 2012-2014 Deepmind Technologies    (Koray Kavukcuoglu) Copyright (c) 2011-2012 NEC Laboratories America (Koray Kavukcuoglu) Copyright (c) 2011-2013 NYU                      (Clement Farabet) Copyright (c) 2006-2010 NEC Laboratories America (Ronan Collobert, Leon Bottou, Iain Melvin, Jason Weston) Copyright (c) 2006      Idiap Research Institute (Samy Bengio) Copyright (c) 2001-2004 Idiap Research Institute (Ronan Collobert, Samy Bengio, Johnny Mariethoz) From Caffe2: Copyright (c) 2016-present, Facebook Inc. All rights reserved. All contributions by Facebook: Copyright (c) 2016 Facebook Inc. All contributions by Google: Copyright (c) 2015 Google Inc. All rights reserved. All contributions by Yangqing Jia: Copyright (c) 2015 Yangqing Jia All rights reserved. All contributions from Caffe: Copyright(c) 2013, 2014, 2015, the respective contributors All rights reserved. All other contributions: Copyright(c) 2015, 2016 the respective contributors All rights reserved. Caffe2 uses a copyright model similar to Caffe: each contributor holds copyright over their contributions to Caffe2. The project versioning records all such contribution and copyright details. If a contributor wants to further mark their specific copyright on a particular contribution, they should indicate their copyright solely in the commit message of the change when it is committed. </ins> All rights reserved. Redistribution and use in source and binary forms, with or without
<del> From PyTorch: Copyright (c) 2016-     Facebook, Inc            (Adam Paszke) Copyright (c) 2014-     Facebook, Inc            (Soumith Chintala) Copyright (c) 2011-2014 Idiap Research Institute (Ronan Collobert) Copyright (c) 2012-2014 Deepmind Technologies    (Koray Kavukcuoglu) Copyright (c) 2011-2012 NEC Laboratories America (Koray Kavukcuoglu) Copyright (c) 2011-2013 NYU                      (Clement Farabet) Copyright (c) 2006-2010 NEC Laboratories America (Ronan Collobert, Leon Bottou, Iain Melvin, Jason Weston) Copyright (c) 2006      Idiap Research Institute (Samy Bengio) Copyright (c) 2001-2004 Idiap Research Institute (Ronan Collobert, Samy Bengio, Johnny Mariethoz) From Caffe2: Copyright (c) 2016-present, Facebook Inc. All rights reserved. All contributions by Facebook: Copyright (c) 2016 Facebook Inc. All contributions by Google: Copyright (c) 2015 Google Inc. All rights reserved. All contributions by Yangqing Jia: Copyright (c) 2015 Yangqing Jia All rights reserved. All contributions from Caffe: Copyright(c) 2013, 2014, 2015, the respective contributors All rights reserved. All other contributions: Copyright(c) 2015, 2016 the respective contributors All rights reserved. Caffe2 uses a copyright model similar to Caffe: each contributor holds copyright over their contributions to Caffe2. The project versioning records all such contribution and copyright details. If a contributor wants to further mark their specific copyright on a particular contribution, they should indicate their copyright solely in the commit message of the change when it is committed. </del> ======================================================================= Software under third_party =======================================================================
def grid_sampler(input, grid, padding_mode): <del> if cudnn.is_acceptable(input.data) and padding_mode == 'zeros' and input.dim() == 4: </del> <ins> if (cudnn.is_acceptable(input.data) and padding_mode == 'zeros' and input.dim() == 4 and input.size(1) <= 1024):  # as of cudnn 7102, will not work for larger than 1024 </ins> return torch.cudnn_grid_sampler(input, grid) else: return GridSampler.apply(input, grid, padding_mode)
upstream="$1" pr="$2" git diff --name-only "$upstream" "$pr" <del> git diff --name-only "$upstream" "$pr" | grep -Eq '^(CMakeLists.txt|Makefile|.gitmodules|.jenkins/caffe2|binaries|caffe|caffe2|cmake|conda|docker|docs/caffe2|modules|scripts|third_party)' </del> <ins> # For safety, unconditionally trigger for any changes. #git diff --name-only "$upstream" "$pr" | grep -Eq '^(CMakeLists.txt|Makefile|.gitmodules|.jenkins/caffe2|binaries|caffe|caffe2|cmake|conda|docker|docs/caffe2|modules|scripts|third_party)' </ins>
upstream="$1" pr="$2" git diff --name-only "$upstream" "$pr" <del> git diff --name-only "$upstream" "$pr" | grep -Eq '^(aten/|caffe2/|.jenkins/pytorch|docs/(make.bat|Makefile|requirements.txt|source)|mypy|requirements.txt|setup.py|test/|third_party/|tools/|.gitmodules|torch/)' </del> <ins> # Now that PyTorch build depends on Caffe2, unconditionally trigger # for any changes. # TODO: Replace this with a NEGATIVE regex that allows us to blacklist # files (letting us skip builds when they are unnecessary) #git diff --name-only "$upstream" "$pr" | grep -Eq '^(aten/|caffe2/|.jenkins/pytorch|docs/(make.bat|Makefile|requirements.txt|source)|mypy|requirements.txt|setup.py|test/|third_party/|tools/|.gitmodules|torch/)' </ins>
unset(CUDA_ARCH_PTX CACHE) endif() <del> if(DEFINED ENV{TORCH_CUDA_ARCH_LIST}) </del> <ins> if($ENV{TORCH_CUDA_ARCH_LIST}) </ins> # Pass CUDA architecture directly set(__cuda_arch_bin $ENV{TORCH_CUDA_ARCH_LIST}) message(STATUS "Set CUDA arch from TORCH_CUDA_ARCH_LIST: ${__cuda_arch_bin}")
BASE_DIR=$(pwd) cd torch/lib INSTALL_DIR="$(pwd)/tmp_install" <del> BASIC_C_FLAGS=" -DTH_INDEX_BASE=0 -I$INSTALL_DIR/include -I$INSTALL_DIR/include/TH -I$INSTALL_DIR/include/THC " </del> <ins> BASIC_C_FLAGS=" -DTH_INDEX_BASE=0 -DTH_GENERIC_USE_HALF=1 -DCUDA_HAS_FP16=1 -I$INSTALL_DIR/include -I$INSTALL_DIR/include/TH -I$INSTALL_DIR/include/THC " </ins> LDFLAGS="-L$INSTALL_DIR/lib " if [[ $(uname) == 'Darwin' ]]; then LDFLAGS="$LDFLAGS -Wl,-rpath,@loader_path"
} std::string FunctionSignature::toString() const { <ins> // TODO: consider printing more proper schema strings with defaults, optionals, etc. </ins> std::ostringstream ss; <ins> bool keyword_already = false; </ins> ss << "("; int i = 0; for (auto& param : params) { if (i != 0) { ss << ", "; } <ins> if (param.keyword_only && !keyword_already) { ss << "*, "; keyword_already = true; } </ins> ss << param.type_name() << " " << param.name; i++; }