如何使用 Theano 求解常微分方程?
How do I use Theano to solve an ordinary differential equation?
这是我的 Python 代码:
import numpy as np
def spread_points_in_cube(n, dimensions=3, rng=None):
from scipy.integrate import ode
if rng is None:
rng = np.random
size = n * dimensions
y0 = np.zeros((2 * size))
y0[:size] = rng.uniform(0, 0.1, size=size)
t0 = 0.0
mean = np.zeros(dimensions)
variance = np.eye(dimensions) * 0
def decode(y):
positions = np.remainder(y[:size].reshape((n, dimensions)), 1)
velocities = y[size:].reshape((n, dimensions))
return positions, velocities
def get_forces(positions, velocities):
delta_positions = positions[:, np.newaxis, :] - positions[np.newaxis, :, :]
delta_positions = np.remainder(delta_positions + 0.5, 1) - 0.5 # wrapping
distances = np.linalg.norm(delta_positions, axis=2, ord=2)
distances += 1e-5
pairwise_forces = delta_positions * (distances ** -3)[:, :, np.newaxis]
magnetic_forces = np.sum(pairwise_forces, axis=1) / (n ** 2)
velocity_mags = np.linalg.norm(velocities, axis=1, ord=2)
drag_forces = -velocities * velocity_mags[:, np.newaxis]
forces = magnetic_forces * 0.01 + drag_forces * 10.0
return forces
def f(t, y):
positions, velocities = decode(y)
forces = get_forces(positions, velocities)
retval = np.zeros((2 * size))
retval[:size] = velocities.reshape(size)
retval[size:] = forces.reshape(size)
return retval
r = ode(f).set_integrator('vode', method='bdf')
r.set_initial_value(y0, t0)
t_max = 20
dt = 1
while r.successful() and r.t < t_max:
positions, velocities = decode(r.y)
forces = get_forces(positions, velocities)
total_speed = np.sum(np.linalg.norm(velocities, axis=1, ord=2))
total_force = np.sum(np.linalg.norm(forces, axis=1, ord=2))
#print("\nt", r.t, "\np", positions, "\nv", velocities,
# "\nf", forces
print(total_speed, total_force)
if total_force < n * 1e-4:
print("breaking")
#break
r.integrate(r.t + dt)
print("converged after", r.t, total_speed, total_force)
return positions
spread_points_in_cube(1000, 3)
是否可以使用Theano求解ODE?
这是 theano 中一个非常简单的 ode 求解器:
import numpy
import theano
# the right-hand side
def f(x, t):
return x*(1-x)
x = theano.tensor.matrix() # why not a matrix
dt = theano.tensor.scalar()
t = theano.tensor.scalar()
x_next = x + f(x, t)*dt # implement your favourite RK method here!
# matrix of random initial values
# store it on the device
x_shared = theano.shared(numpy.random.rand(10, 10))
step = theano.function([t, dt], [],
givens=[(x, x_shared)],
updates=[(x_shared, x_next)],
on_unused_input='warn')
t = 0.0
dt = 0.01
while t < 10:
step(t, dt)
t += dt
# test halt condition here
print(x_shared.get_value()) # read back the result
希望对您有所帮助。
基本上你必须实现你的 Runge-Kutta 方法。
请注意,theano 的优势在于矢量化,因此我不会费心在 theano 中实现时间循环。这就是为什么我使用简单的 python while 循环,尽管我可以使用 theano scan。无论如何,根据您的目标,优化可能会很棘手。我不是 100% 相信 theano 是 ODE 求解器的不错选择。 Numpy 无论如何都会对力和位置矩阵进行矢量化,至少在 CPU 上是这样。通过 theano 实现,您可以利用 GPU,但这并不能保证加速。
这是我的 Python 代码:
import numpy as np
def spread_points_in_cube(n, dimensions=3, rng=None):
from scipy.integrate import ode
if rng is None:
rng = np.random
size = n * dimensions
y0 = np.zeros((2 * size))
y0[:size] = rng.uniform(0, 0.1, size=size)
t0 = 0.0
mean = np.zeros(dimensions)
variance = np.eye(dimensions) * 0
def decode(y):
positions = np.remainder(y[:size].reshape((n, dimensions)), 1)
velocities = y[size:].reshape((n, dimensions))
return positions, velocities
def get_forces(positions, velocities):
delta_positions = positions[:, np.newaxis, :] - positions[np.newaxis, :, :]
delta_positions = np.remainder(delta_positions + 0.5, 1) - 0.5 # wrapping
distances = np.linalg.norm(delta_positions, axis=2, ord=2)
distances += 1e-5
pairwise_forces = delta_positions * (distances ** -3)[:, :, np.newaxis]
magnetic_forces = np.sum(pairwise_forces, axis=1) / (n ** 2)
velocity_mags = np.linalg.norm(velocities, axis=1, ord=2)
drag_forces = -velocities * velocity_mags[:, np.newaxis]
forces = magnetic_forces * 0.01 + drag_forces * 10.0
return forces
def f(t, y):
positions, velocities = decode(y)
forces = get_forces(positions, velocities)
retval = np.zeros((2 * size))
retval[:size] = velocities.reshape(size)
retval[size:] = forces.reshape(size)
return retval
r = ode(f).set_integrator('vode', method='bdf')
r.set_initial_value(y0, t0)
t_max = 20
dt = 1
while r.successful() and r.t < t_max:
positions, velocities = decode(r.y)
forces = get_forces(positions, velocities)
total_speed = np.sum(np.linalg.norm(velocities, axis=1, ord=2))
total_force = np.sum(np.linalg.norm(forces, axis=1, ord=2))
#print("\nt", r.t, "\np", positions, "\nv", velocities,
# "\nf", forces
print(total_speed, total_force)
if total_force < n * 1e-4:
print("breaking")
#break
r.integrate(r.t + dt)
print("converged after", r.t, total_speed, total_force)
return positions
spread_points_in_cube(1000, 3)
是否可以使用Theano求解ODE?
这是 theano 中一个非常简单的 ode 求解器:
import numpy
import theano
# the right-hand side
def f(x, t):
return x*(1-x)
x = theano.tensor.matrix() # why not a matrix
dt = theano.tensor.scalar()
t = theano.tensor.scalar()
x_next = x + f(x, t)*dt # implement your favourite RK method here!
# matrix of random initial values
# store it on the device
x_shared = theano.shared(numpy.random.rand(10, 10))
step = theano.function([t, dt], [],
givens=[(x, x_shared)],
updates=[(x_shared, x_next)],
on_unused_input='warn')
t = 0.0
dt = 0.01
while t < 10:
step(t, dt)
t += dt
# test halt condition here
print(x_shared.get_value()) # read back the result
希望对您有所帮助。 基本上你必须实现你的 Runge-Kutta 方法。
请注意,theano 的优势在于矢量化,因此我不会费心在 theano 中实现时间循环。这就是为什么我使用简单的 python while 循环,尽管我可以使用 theano scan。无论如何,根据您的目标,优化可能会很棘手。我不是 100% 相信 theano 是 ODE 求解器的不错选择。 Numpy 无论如何都会对力和位置矩阵进行矢量化,至少在 CPU 上是这样。通过 theano 实现,您可以利用 GPU,但这并不能保证加速。