Buscando la forma de inicializar los pesos de la matriz como ortogonales (es decir W*W^T = I
y todos los los valores propios son iguales a 1 o -1 ), (Me equivoqué) Encontré este post con un código de Lasagne:
https://stats.stackexchange.com/questions/228704
Sin embargo, este código no produce una matriz ortogonal, sino unitaria con valores propios complejos, que sigue satisfaciendo bastante bien la igualdad W*W^T = I:
import numpy as np
np.random.seed(1000)
def floatX(arr):
"""Converts data to a numpy array of dtype ``theano.config.floatX``.
Parameters
----------
arr : array_like
The data to be converted.
Returns
-------
numpy ndarray
The input array in the ``floatX`` dtype configured for Theano.
If `arr` is an ndarray of correct dtype, it is returned as is.
"""
return np.asarray(arr, dtype=np.float32)
def sample(shape,gain=1.0):
flat_shape = (shape[0], np.prod(shape[1:]))
a = np.random.normal(0, 1, flat_shape).astype(np.float32) #get_rng().normal(0.0, 1.0, flat_shape)
u, _, v = np.linalg.svd(a, full_matrices=False)
# pick the one with the correct shape
q = u if u.shape == flat_shape else v
q = q.reshape(shape)
res = floatX(gain * q)
#eigenvalues:
eigenvalues, _ = np.linalg.eig(u)
print(str(np.min(eigenvalues))+" "+ str(eigenvalues[1024])+ " "+ str(np.max(eigenvalues)) )
return res
W = sample([2048, 2048])
print(np.linalg.norm(W.dot(np.transpose(W))-np.eye(2048)))
La salida es
(-1+0j) (0.376566+0.92639j) (1+0j)
para algunos de los valores propios y
1.00117376019e-05
por la proximidad del W*W^T
y I
.
1) ¿Se trata de un error en Lasagne, como numpy.linalg.svd
produce efectivamente una matriz unitaria como se indica en su manual, y
2) ¿Cómo puedo inicializar una matriz ortogonal (no cuadrada) para mí en Python, excepto la unitaria?
Gracias.
EDIT: ¡Gracias a todos! A partir de todas las explicaciones he conseguido crear una solución sencilla en Python:
import numpy as np
## Using a subset of vectors
np.random.seed(1000)
p = 4096
A = np.random.normal(0,1,(p,p))
q, _ = np.linalg.qr(A) # q -orthonormal
print(q.shape) #(4096,4096)
q = q[:,::2] #cut q
print(q.shape) #(4096,2048) m>n ==> q^T * q = I_n
print(np.linalg.norm(np.transpose(q).dot(q)-np.eye(2048))) # 4.26e-14