Skip to content

Instantly share code, notes, and snippets.

def fn(x):
return x**2 + 0.2*(x-2)**5 + 2*x**3
# initialization
x = Variable(3.)
target = 42.
print('---- Initial Value ----')
print('fn(x): {}'.format(fn(x)))
print('Target: {}'.format(target))
print('intial guess for x: {}'.format(x))
def forward_fn(x):
for n in range(5):
if n % 2 == 0:
x = 3.*x
else:
x = x**(1./n) + 1./n
return x
x = Variable(2.)
for x in [-1., 0.5, 3.]:
print('Function Input: {}'.format(x))
print('Function Value: {}'.format(super_complicated_function(x)))
print('Function Symbolic Derivative: {}'.format(d_super_complicated_function(x)))
x_v = Variable(x)
L = super_complicated_function(x_v)
print('Variable Function Output Value: {}'.format(L))
L.backward()
print('Input value: {}'.format(x_v))
print('-'*32)
def __add__(self, other):
if isinstance(other, self.__class__):
return Variable(lambda a,b : a+b, (self, other))
else:
return Variable(lambda a,b : a+b, (self, Variable(other)))
def backward(self, output_gradient=1.):
# combine gradients from other paths and propagate to children
self.gradient += output_gradient
local_gradient = self.derivative_op(*self.calc_input_values())
for differential, input_variable in zip(local_gradient, self.input_variables):
input_variable.backward(differential * output_gradient)
def calc_input_values(self):
# calculate the real-valued input to operation
return [v.value for v in self.input_variables]
def forward(self):
# calculate the real-valued output of operation
return self.forward_op(*self.calc_input_values())
@property
def value(self):
class Variable:
def __init__(self, operation, input_variables=[]):
# note the setter for @property value below
self.value = operation
self.input_variables = input_variables
self.gradient = 0.
# compose a graph of nodes
x = Variable(10.01)
y = Variable(0.05)
z = x * y
m = 1.3
q = m+y
L = (q - (z**(m/2.) + z**2. - 1./z))**2
def create_diff_fn(fn):
def diff_fn(*argv):
jacobian = []
Dual_arguments = [Dual(x, 0.) for x in argv]
for input_arg in Dual_arguments:
input_arg.derivative = 1.
result = fn(*Dual_arguments)
jacobian.append(result.derivative)
input_arg.derivative = 0.
def super_complicated_function(x):
return x * sin(x+6.)**2. / 2. - 2. / 2.**x
# symbolic derivative by running the above in mathematica (wolfram alpha)
def d_super_complicated_function(x):
return 2**(1 - x) * math.log(2) + 0.5 * sin(x + 6)**2 + x * math.sin(x + 6) * math.cos(x + 6)
for x in [-1., 0.5, 3., 2.]:
print('Function Input: {}'.format(x))
print('Function Value: {}'.format(super_complicated_function(x)))