Я работаю над нейронной сетью с очень большими матрицами разреженного веса. Нулевые значения в весах должны оставаться нулевыми и не должны изменяться. Градиенты должны рассчитываться и распространяться только для ненулевых значений, так как в противном случае запуск будет слишком дорогим. Это означает, что я использую Theano и его матричное умножение sparse.structured_dot. Это мой код:
#!/usr/bin/env python3
import math
import numpy as np
import theano as th
import theano.tensor as T
from theano import sparse as sp
import scipy.sparse as spsp
def sparse_matrix(matrix, name):
"""Convert an array to a shared sparse theano matrix."""
matrix = np.asarray(matrix)
if matrix.shape[0] > matrix.shape[1]: matrix = spsp.csc_matrix(matrix)
else: matrix = spsp.csr_matrix(matrix)
return th.shared(matrix, name)
def mul(weight, matrix):
"""Sparse matrix multiplication.
:param weight: sparse weight m x n matrix, where m is number of features of output and n is number of features for
input.
:param matrix: input n x p matrix, where n is number of features for input and p is number of input vectors.
"""
return T.transpose(sp.structured_dot(weight, T.transpose(matrix)))
x = T.fmatrix('x')
target = T.fmatrix('target')
W = sparse_matrix([[0, 0.5], [0.5, 0]], 'W')
y = mul(W, x)
cost = T.mean((y - target) ** 2) / 2
gradient = T.grad(cost=cost, wrt=W)
W_updated = W - (gradient * 0.01)
updates = [(W, W_updated)]
f = th.function(inputs=[x, target], outputs=[y, cost, gradient], updates=updates, allow_input_downcast=True)
print("start weight:\n", W.get_value().todense())
for i in range(10):
pred, c, g = f([[4.0, 2.0]], [[2.0, 4.0]])
print("pred:", pred)
print("cost:", c)
print("grad:\n", g)
print("end weight:\n", W.get_value().todense())
Пример, который я тестирую, прост: предполагается, что значения матрицы будут от 0,5 до 1,0, где стоимость станет нулевой. Однако он расходится, оба значения уменьшаются, а градиенты всегда составляют около 1,0 и 2,0. Кажется, градиенты рассчитываются неправильно. Если я запускаю код, я получаю следующий вывод:
start weight:
[[ 0. 0.5]
[ 0.5 0. ]]
pred: [[ 1. 2.]]
cost: 1.25
grad:
(0, 1) 1.00000071339
(1, 0) 2.00000143424
pred: [[ 0.97999999 1.91999994]]
cost: 1.3417000669408599
grad:
(0, 1) 1.00000071343
(1, 0) 2.00000143439
pred: [[ 0.95999997 1.83999989]]
cost: 1.4368001387634612
grad:
(0, 1) 1.00000071347
(1, 0) 2.00000143453
pred: [[ 0.93999996 1.75999983]]
cost: 1.5353002154685411
grad:
(0, 1) 1.0000007135
(1, 0) 2.00000143468
pred: [[ 0.91999994 1.67999977]]
cost: 1.637200297056838
grad:
(0, 1) 1.00000071354
(1, 0) 2.00000143483
pred: [[ 0.89999993 1.59999971]]
cost: 1.7425003835290889
grad:
(0, 1) 1.00000071358
(1, 0) 2.00000143498
pred: [[ 0.87999991 1.51999966]]
cost: 1.8512004748860316
grad:
(0, 1) 1.00000071362
(1, 0) 2.00000143513
pred: [[ 0.8599999 1.4399996]]
cost: 1.9633005711284035
grad:
(0, 1) 1.00000071365
(1, 0) 2.00000143528
pred: [[ 0.83999989 1.35999954]]
cost: 2.0788006722569428
grad:
(0, 1) 1.00000071369
(1, 0) 2.00000143543
pred: [[ 0.81999987 1.27999948]]
cost: 2.197700778272387
grad:
(0, 1) 1.00000071373
(1, 0) 2.00000143558
end weight:
[[ 0. 0.39999993]
[ 0.29999986 0. ]]