Numpy: ¿Cómo vectorizar operaciones?
Tengo los siguientes vectores:
forma u_w: (50,)
forma Vt: (6, 50)
forma v: (50,)
y con ellos realizo los siguientes cálculos:
w = np.tanh(u_w + Vt[0])
w_squared = w ** 2
z = np.dot(v, w)
s = sigmoid(np.dot(v, w))
J = -np.log(sigmoid(z))
dv = np.dot(sigmoid(z) - 1, w)
du_w = np.dot(s - 1, v, (1 - w_squared))
dVt = np.dot(s - 1, v, (1 - w_squared))
para vt en Vt[1:]:
t = np.tanh(u_w + vt)
svt = sigmoid(np.dot(-v, t))
J -= np.log(svt)
dv -= np.dot((svt – 1), t)
du_w -= np.dot((svt – 1), v, (1 – t2))
dVt = np.vstack((dVt, -np.dot(svt – 1, v, (1 – t2))))
¿Cómo puedo vectorizar los cálculos para J, dv, du_w y dVt, para que funcionen para un lote de S elementos con las siguientes formas?
forma(u_w) => (512, 50)
forma(Vt) => (512, 6, 50)
forma(v) => (50,)
davy.ai
Para vectorizar los cálculos para un lote de S elementos con las formas dadas, podemos aprovechar el broadcasting en numpy. Aquí están las versiones modificadas de los cálculos:
Explicación:
None
(onp.newaxis
) para agregar ejes adicionales au_w
yv
, para que sean broadcastables con los ejes correspondientes enw
.broadcasting
en numpy nos permite operar en matrices con formas diferentes. Específicamente, numpy puede alinear automáticamente dimensiones de matrices con diferentes números de dimensiones. Esto nos permite hacer multiplicación elemento a elemento dew
conv
para obtenerz
, sin necesidad de repetir explícitamentev
a lo largo del primer eje dew
.sigmoid(z) - 1
a lo largo del segundo eje dew
para calculardv
.du_w
, hacemos broadcast des-1
a lo largo del segundo eje dev
y usamos el operador de multiplicación de matrices@
(onp.dot
) entre el resultado y el producto de matrices(1-w_squared)
v
a lo largo del primer y segundo ejes, respectivamente.dVt
, generamos dos matricesdVt_first
ydVt_rest
y las concatenamos usandonp.vstack
.dVt_first
se calcula de manera similar adv
, excepto que hacemos broadcasting dev
a lo largo del segundo eje dedVt_first
.dVt_rest
se calcula utilizando un bucle sobre el resto deVt
, excepto que primero eliminamos el primerVt
usandoVt[:, 1:, :]
.