Почему функция sympy lambdify не может определить функцию суммы numy и функцию умножения - PullRequest
0 голосов
/ 19 октября 2019

Я хочу использовать sympy и numpy для обучения машинному обучению. Потому что симой обеспечивает очень удобный расчет частной производной. Но в процессе использования я обнаружил, что функция sympy lambdify и не может идентифицировать функцию numy sum и функцию умножения.


Возьмем следующий пример

y_ = np.sum(np.dot(w,x)+b)
print(y_)
y_f = lambdify((w,x,b),y_,"numpy")
w_l = np.mat([1,1,1,1,1])
x_l= np.mat([1,1,1,1,1]).T
b_l = np.mat([0,0,0,0,0]).T
y_l = np.mat([6,6,6,6,6]).T
print(y_f(w_l,x_l,b_l))
b + w*x
[[5]
 [5]
 [5]
 [5]
 [5]]

Process finished with exit code 0
y_ = np.multiply(w,x)+b
print(y_)
y_f = lambdify((w,x,b),y_,"numpy")
w_l = np.mat([1,1,1,1,1]).T
x_l= np.mat([1,1,1,1,1]).T
b_l = np.mat([0,0,0,0,0]).T
y_l = np.mat([6,6,6,6,6]).T
print(y_f(w_l,x_l,b_l))
b + w*x
Traceback (most recent call last):
  File "G:/lijie/PycharmProjects/hw3/test.py", line 24, in <module>
    print(y_f(w_l,x_l,b_l))
  File "<lambdifygenerated-1>", line 2, in _lambdifygenerated
  File "C:\Users\lijie\AppData\Local\Programs\Python\Python36\lib\site-packages\numpy\matrixlib\defmatrix.py", line 220, in __mul__
    return N.dot(self, asmatrix(other))
ValueError: shapes (5,1) and (5,1) not aligned: 1 (dim 1) != 5 (dim 0)
b + w*x
Traceback (most recent call last):
  File "G:/lijie/PycharmProjects/hw3/test.py", line 24, in <module>
    print(y_f(w_l,x_l,b_l))
  File "<lambdifygenerated-1>", line 2, in _lambdifygenerated
  File "C:\Users\lijie\AppData\Local\Programs\Python\Python36\lib\site-packages\numpy\matrixlib\defmatrix.py", line 220, in __mul__
    return N.dot(self, asmatrix(other))
ValueError: shapes (5,1) and (5,1) not aligned: 1 (dim 1) != 5 (dim 0)

Как видите, lambdify просто принимает выражения lamda без проверки записи операции. Как решить эту проблему. Спасибо за вашу помощь

1 Ответ

1 голос
/ 19 октября 2019

Смешивание numpy и sympy может быть сложным;Добавьте к этому потенциальную путаницу, вызванную np.mat вместо базового типа массива, ndarray.

В сумме

y_ = np.sum(np.dot(w,x)+b)

вычисляет выражение python / numpy на объектах sympy. Результатом является симпатичное выражение w*x+b. Объекты sympy являются скалярами, так что это не кодирует никакого умножения матрицы или суммирования массива. Выражение multiply вычисляется таким же образом.

Затем выражения lambdify переводят один и тот же y_ в одну и ту же функцию Python. И эта оценка зависит от размеров и класса np.mat аргументов.

детали

На данный момент игнорируется sympy часть:

In [310]: w = np.mat([1,1,1,1,1]) 
     ...: x= np.mat([1,1,1,1,1]).T 
     ...: b = np.mat([0,0,0,0,0]).T 
     ...: y = np.mat([6,6,6,6,6]).T                                             
In [311]: np.sum(np.dot(w,x)+b)                                                 
Out[311]: 25
In [312]: np.multiply(w,x)+b                                                    
Out[312]: 
matrix([[1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1]])

Потому что ониnp.mat, оба w и x являются 2d:

In [316]: w.shape                                                               
Out[316]: (1, 5)
In [317]: x.shape                                                               
Out[317]: (5, 1)

np.dot из (1,5) с (5,1) является результатом (1,1):

In [313]: np.dot(w,x)                                                           
Out[313]: matrix([[5]])

и для np.matrix, * определяется как dot:

In [314]: w*x                                                                   
Out[314]: matrix([[5]])

По элементам:

In [315]: np.multiply(w,x)         # elementwise produces (5,5)                                   
Out[315]: 
matrix([[1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1]])

np.sum(np.dot(w,x)+b) делает dot, затем добавляет b и заканчивается sum над всеми элементами.

np.multiply(w,x)+b делает это умножение, добавляет b. Нет sum.

исправления

Использование w.T, которое я пропустил в первый раз:

In [322]: np.multiply(w.T,x)                                                    
Out[322]: 
matrix([[1],
        [1],
        [1],
        [1],
        [1]])
In [323]: w.T*x                                                                 
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-323-11ad839cfa88> in <module>
----> 1 w.T*x

/usr/local/lib/python3.6/dist-packages/numpy/matrixlib/defmatrix.py in __mul__(self, other)
    218         if isinstance(other, (N.ndarray, list, tuple)) :
    219             # This promotes 1-D vectors to row vectors
--> 220             return N.dot(self, asmatrix(other))
    221         if isscalar(other) or not hasattr(other, '__rmul__') :
    222             return N.dot(self, other)

<__array_function__ internals> in dot(*args, **kwargs)

ValueError: shapes (5,1) and (5,1) not aligned: 1 (dim 1) != 5 (dim 0)

np.multiply of (5,1) и(5,1) производит (5,1), поэлементное умножение

w.T*x - матричное умножение для np.mat, следовательно, ошибка np.dot.

Использование np.mat не рекомендуется (если формально не исключено). В numpy добавление matmul/@ устраняет его нотационные преимущества. Жизнь проще в numpy, если вы придерживаетесь базового класса массива, ndarray. Я понимаю, что sympy все еще использует концепцию 2d матрицы, с * в качестве умножения матрицы.

с sympy

В сеансе isympy я обнаружил, что мне нужно определить w,x,b как символы:

y_ = np.sum(np.dot(w,x)+b)

Если w,x,b - это просто символыэто скаляры, а не матрицы или массивы. Ваши np.sum(np.dot(1,2)+4), np.multiply(1,2)+4 и 1*2+4 все производят одно и то же. Только когда переменные являются массивами, или np.mat, или, может быть, sympy.Matrix, выражения отличаются.

Проблема не в lambdify. В обоих случаях ему присваивается один и тот же y_ (как проверено print(y_). Вы получаете ошибку, поскольку аргументы np.mat, а * - умножение матриц.

С x,y,zсимволы:

In [55]: f = lambdify((x,y,z),x*y+z, 'numpy')                                   

Использование isympy самоанализа:

In [56]: f??                                                                    
Signature: f(x, y, z)
Docstring:
Created with lambdify. Signature:

func(x, y, z)

Expression:

x*y + z

Source code:

def _lambdifygenerated(x, y, z):
    return (x*y + z)


Imported modules:
Source:   
def _lambdifygenerated(x, y, z):
    return (x*y + z)
File:      ~/mypy/<lambdifygenerated-4>
Type:      function

Ознакомьтесь с полной документацией по lambdify. Обратите внимание, что это в основном лексическая замена

https://docs.sympy.org/latest/modules/utilities/lambdify.html

Эта документация предупреждает:

Как правило, функции NumPy не знают, как работать с выражениями SymPy, а функции SymPy не знают, как работатьдля массивов NumPy. Вот почему существует lambdify: для обеспечения моста между SymPy и NumPy.

sympify

https://docs.sympy.org/latest/modules/core.html#module-sympy.core.sympify

говорит, что используетeval. С x,y,z, определенным как символы:

In [66]: eval('np.dot(x,y)+z')                                                  
Out[66]: x⋅y + z

In [67]: eval('np.sum(np.dot(x,y)+z)')                                          
Out[67]: x⋅y + z

In [68]: eval('np.multiply(x,y)+z')                                             
Out[68]: x⋅y + z

Другими словами, он просто передает символы в функции (и / или операторы),

In [69]: np.dot(x,y)                                                            
Out[69]: x⋅y

dot превращает свои входные данные в массивы:

In [70]: np.array(x)                                                            
Out[70]: array(x, dtype=object)

In [71]: np.dot(np.array(x), np.array(y))                                       
Out[71]: x⋅y

Это работает, потому что для символов определены '*' и '+'.

sympy документы предупреждают, что оценка numpy ничего не "знает" о объектах sympy. Он обрабатывает их как массивы объектов типа d, которые могут работать или не работать:

In [72]: sin(x)       # sympy sin                                                          
Out[72]: sin(x)

In [73]: np.sin(x)        # numpy sin                                                      
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
AttributeError: 'Symbol' object has no attribute 'sin'

The above exception was the direct cause of the following exception:

TypeError                                 Traceback (most recent call last)
<ipython-input-73-92f2c2d0df9d> in <module>
----> 1 np.sin(x)

TypeError: loop of ufunc does not support argument 0 of type Symbol which has no callable sin method

np.sin делает np.sin(np.array(x)), а затем делегирует действие методу sin x - который выполняетне существует.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...