es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

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 – t
2))))

¿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,)
Tags:  , ,

Answer

  1. Avatar for 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:

    # calcular z, s para todos los elementos S
    w = np.tanh(u_w[None, :, :] + Vt[:, 0, :])
    w_squared = w ** 2
    z = np.sum(v * w, axis=1)
    s = sigmoid(z)
    
    # calcular J para todos los elementos S
    J = -np.log(sigmoid(z))
    
    # calcular dv para todos los elementos S
    dv = np.sum((sigmoid(z) - 1)[:, None] * w, axis=0)
    
    # calcular du_w para todos los elementos S
    du_w = np.sum((s - 1)[:, None] * v[None, :, :] * (1 - w_squared), axis=(0, 1))
    
    # calcular dVt para todos los elementos S
    dVt_first = (sigmoid(z) - 1)[:, :, None] * v[None, :, None] * (1 - w_squared)[:, None, :]
    dVt_rest = -(sigmoid(np.sum(-v[None, :, :] * np.tanh(u_w[None, :, :] + Vt[:, 1:, :]), axis=-1)) - 1)[:, :, None] * v[None, :, None] * (1 - np.tanh(u_w[None, :, :] + Vt[:, 1:, :]) ** 2)[:, None, :]
    dVt = np.vstack((dVt_first[:, None, :, :], dVt_rest))
    
    # forma de las salidas:
    # J: (512,)
    # dv: (50,)
    # du_w: (50,)
    # dVt: (512, 5, 50)
    

    Explicación:

    • Primero usamos el operador None (o np.newaxis) para agregar ejes adicionales a u_w y v, para que sean broadcastables con los ejes correspondientes en w.
    • La característica de 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 de w con v para obtener z, sin necesidad de repetir explícitamente v a lo largo del primer eje de w.
    • De manera similar, también podemos hacer broadcasting de sigmoid(z) - 1 a lo largo del segundo eje de w para calcular dv.
    • Para du_w, hacemos broadcast de s-1 a lo largo del segundo eje de v y usamos el operador de multiplicación de matrices @ (o np.dot) entre el resultado y el producto de matrices (1-w_squared) v a lo largo del primer y segundo ejes, respectivamente.
    • Finalmente, para dVt, generamos dos matrices dVt_first y dVt_rest y las concatenamos usando np.vstack. dVt_first se calcula de manera similar a dv, excepto que hacemos broadcasting de v a lo largo del segundo eje de dVt_first. dVt_rest se calcula utilizando un bucle sobre el resto de Vt, excepto que primero eliminamos el primer Vt usando Vt[:, 1:, :].

Comments are closed.