Сумма Numpy () получила ошибку «keepdims»

Это абзац примера кода нейронной сети:

def forward_step(X, W, b, W2, b2):
    hidden_layer = np.maximum(0, np.dot(X, W) + b)
    scores = np.dot(hidden_layer, W2) + b2
    exp_scores = np.exp(scores)
    probs = exp_scores / np.sum(exp_scores, axis=1, keepdims=True)
    ...

Последняя строка кода, показанного выше, вызвала ошибку:

<ipython-input-49-d97cff51c360> in forward_step(X, W, b, W2, b2)
     14     scores = np.dot(hidden_layer, W2) + b2
     15     exp_scores = np.exp(scores)
---> 16     probs = exp_scores / np.sum(exp_scores, axis=1, keepdims=True)
     17     corect_logprobs = -np.log(probs[range(X.shape[0]), y])

/Users/###/anaconda/lib/python3.6/site-packages/numpy/core/fromnumeric.py in sum(a, axis, dtype, out, keepdims)
   1810             pass
   1811         else:
-> 1812             return sum(axis=axis, dtype=dtype, out=out, **kwargs)
   1813     return _methods._sum(a, axis=axis, dtype=dtype,
   1814                          out=out, **kwargs)

TypeError: sum() got an unexpected keyword argument 'keepdims'

Существует аналогичный вопрос ошибка Numpy sum keepdims, в котором говорится, что выпуск numpy должен быть больше, чем 1.7. Я проверил свою версию numpy:

import numpy
numpy.version.version
>> 1.12.1

Теперь я смущен тем, как эта ошибка произошла.


person Leo    schedule 26.09.2017    source источник
comment
Можете ли вы привести более явный пример, который люди могут запускать? т.е. приведите пример массива с этой проблемой, чтобы кто-то мог скопировать/вставить. Я не получаю ошибку, но я на numpy 1.13.1.   -  person alkasm    schedule 26.09.2017
comment
Чтобы немного расширить, я прошу пример, поскольку numpy docs специально указывает: если метод суммы подклассов не реализует keepdims, будут возбуждены любые исключения. поэтому мне интересно, является ли ваш exp_scores массивом подклассов, который не имеет реализации keepdims. Это работает, если exp_scores = np.ones((10, 10)) или что-то еще?   -  person alkasm    schedule 26.09.2017
comment
@AlexanderReynolds Спасибо за подробный ответ. Я боялся, что весь код ужасен, так что людям будет не терпиться. Я вставил контекст этой строки, но я все еще не уверен, является ли exp_scores здесь массивом подклассов, который не имеет реализации keepdims.   -  person Leo    schedule 26.09.2017
comment
@AlexRiley Я вставил больше трассировки. Но все же кажется коротковатым. Мне просто интересно, не потому ли это, что блокнот jupyter просто выдает ограниченную информацию о трассировке.   -  person Leo    schedule 26.09.2017
comment
@Лео - ах, спасибо. Я думаю, что вполне очевидно, что exp_scores не является массивом NumPy, как упоминает выше Александр Рейнольдс. Исходный код NumPy показывает, что строка 1812 может быть найдена только в том случае, если она не является обычным типом массива: github.com/numpy/numpy/blob/maintenance/1.12.x/numpy/core/   -  person Alex Riley    schedule 26.09.2017
comment
Что такое type(exp_scores)? Если exp_scores представляет собой пустую матрицу, а не массив, то есть type(exp_scores) = <class 'numpy.matrixlib.defmatrix.matrix'> или аналогичный, вы получите эту ошибку. Если это так, вам, вероятно, не нужно использовать матрицы numpy, и вам следует переключиться на массивы, если нет важной причины этого не делать. Но если вам не хочется переключать свои данные до этого, вы можете просто привести их к массиву в строке перед суммированием.   -  person alkasm    schedule 26.09.2017
comment
похоже, это старая проблема с keepdims   -  person Daniel F    schedule 26.09.2017
comment
@DanielF Я бы не назвал это проблемой, это ожидаемое поведение, отмеченное непосредственно в документах. Матрицы всегда двумерные, поэтому любая функция вроде sum не уменьшит размерность, поэтому keepdims — бесполезный параметр.   -  person alkasm    schedule 26.09.2017


Ответы (1)


Обратите внимание, что под аргументом keepdims в документах для numpy.sum() в нем говорится:

keepdims : bool, необязательный
Если установлено значение True, уменьшаемые оси остаются в результате как измерения с размером один. С этой опцией результат будет корректно транслироваться относительно входного массива.
Если передано значение по умолчанию, то keepdims не будет передаваться методу sum подклассов ndarray, однако будет любое значение, отличное от значения по умолчанию. Если метод подклассов sum не реализует keepdims, будут вызваны любые исключения.

Итак, здесь говорится, что если вы используете подкласс numpy.ndarray, вы получите эту ошибку, если соответствующая функция sum для подкласса не была определена с ним.

Обратите внимание, что в вашей ошибке он ссылается на строку 1812 в numpy/core/fromnumeric.py. Взгляните на это в контексте фактического numpy Исходный код 1.12.x:

kwargs = {}
if keepdims is not np._NoValue:
    kwargs['keepdims'] = keepdims
if isinstance(a, _gentype):
    res = _sum_(a)
    if out is not None:
        out[...] = res
        return out
    return res
if type(a) is not mu.ndarray:
    try:
        sum = a.sum
    except AttributeError:
        pass
    else:
        return sum(axis=axis, dtype=dtype, out=out, **kwargs)
return _methods._sum(a, axis=axis, dtype=dtype,
                     out=out, **kwargs)

Здесь важно отметить две вещи: функция sum делала разбор вашей переменной keepdims, поскольку она вытащила ее выше строки 1812 и попыталась поместить ее в другую функцию, так что вы знаете, что ошибка была не той. вы использовали переменную. Другая важная вещь заключается в том, что строка 1812, в которой вы ошибаетесь, выполняется только if type(a) is not mu.ndarray, т. е. если вы используете класс, отличный от ndarray. И это именно то, на что ссылается документация. Если у вас другой класс, им нужно реализовать эту sum функцию с аргументом keepdims, и если они этого не сделают, это вызовет ошибку.

Другие классы, такие как np.matrix, например, будут иметь другую функцию суммирования, и кажется, что даже в numpy 1.13.x, sum для типов np.matrix не поддерживает аргумент keepdim (поскольку в numpy матрицы всегда двумерные). Например, он отлично работает с np.array:

>>> import numpy as np
>>> A = np.eye(4)
>>> A
array([[ 1.,  0.,  0.,  0.],
       [ 0.,  1.,  0.,  0.],
       [ 0.,  0.,  1.,  0.],
       [ 0.,  0.,  0.,  1.]])
>>> np.sum(A, axis=1, keepdims=True)
array([[ 1.],
       [ 1.],
       [ 1.],
       [ 1.]])

Но с np.matrix это не так:

>>> import numpy.matlib
>>> B = np.matlib.eye(4)
>>> np.sum(B, axis=1, keepdims=True)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File ".../numpy/core/fromnumeric.py", line 1832, in sum
    return sum(axis=axis, dtype=dtype, out=out, **kwargs)
TypeError: sum() got an unexpected keyword argument 'keepdims'

Но большинство объектов типа массива/матрицы можно легко привести к массиву в numpy с помощью np.array(<object>), и это должно решить проблему для большинства подклассов объектов в numpy и, вероятно, вашу проблему. Вы также можете просто обернуть результат обратно в np.matrix, если вам нужно.

>>> B = np.matlib.eye(4)
>>> B = np.array(B)
>>> np.sum(B, axis=1, keepdims=True)
array([[ 1.],
       [ 1.],
       [ 1.],
       [ 1.]])

Однако, если ваш класс объектов является типом np.matrix, то аргумент keepdims не имеет смысла. Матрицы всегда двумерные, поэтому функция sum не будет уменьшать размерность, и поэтому аргумент ничего не сделает. Вот почему он не реализован для матриц.

person alkasm    schedule 26.09.2017