hedgefund

pycodon_autograd_01

Nov 28th, 2024
312
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 4.29 KB | Software | 0 0
  1. import math
  2. import time
  3. from typing import List, Optional
  4.  
  5. class OpType:
  6.     OP_SUM = 0
  7.     OP_PROD = 1
  8.     OP_SOFTMAX = 2
  9.     OP_SOFTPLUS = 3
  10.  
  11. class NaiveVar:
  12.     val: float
  13.     grad: float
  14.  
  15.     def __init__(self, val: float) -> None:
  16.         self.val = val
  17.         self.grad = 0.0
  18.  
  19. class MyOperation:
  20.     op_type: int
  21.     n_inputs: int
  22.     inputs: List[NaiveVar]
  23.     outputs: List[NaiveVar]
  24.  
  25.     def __init__(self, op_type: int, n_inputs: int, inputs: List[NaiveVar], outputs: List[NaiveVar]) -> None:
  26.         self.op_type = op_type
  27.         self.n_inputs = n_inputs
  28.         self.inputs = inputs
  29.         self.outputs = outputs
  30.  
  31. class NaiveTape:
  32.     n_ops: int
  33.     max_ops: int
  34.     ops: List[Optional[MyOperation]]
  35.  
  36.     def __init__(self, max_ops: int) -> None:
  37.         self.n_ops = 0
  38.         self.max_ops = max_ops
  39.         self.ops = [None] * max_ops
  40.  
  41.     def add_op(self, op: MyOperation) -> None:
  42.         if self.n_ops >= self.max_ops:
  43.             self.max_ops *= 2
  44.             self.ops.extend([None] * (self.max_ops - len(self.ops)))
  45.         self.ops[self.n_ops] = op
  46.         self.n_ops += 1
  47.  
  48. def naive_var(val: float) -> NaiveVar:
  49.     return NaiveVar(val)
  50.  
  51. def naive_tape_create(max_ops: int) -> NaiveTape:
  52.     return NaiveTape(max_ops)
  53.  
  54. def naive_tape_sum(tape: NaiveTape, vars: List[NaiveVar]) -> NaiveVar:
  55.     sum_val = sum(var.val for var in vars)
  56.     res = naive_var(sum_val)
  57.     op = MyOperation(OpType.OP_SUM, len(vars), vars, [res])
  58.     tape.add_op(op)
  59.     return res
  60.  
  61. def naive_tape_prod(tape: NaiveTape, var1: NaiveVar, var2: NaiveVar) -> NaiveVar:
  62.     prod_val = var1.val * var2.val
  63.     res = naive_var(prod_val)
  64.     op = MyOperation(OpType.OP_PROD, 2, [var1, var2], [res])
  65.     tape.add_op(op)
  66.     return res
  67.  
  68. def naive_tape_softmax(tape: NaiveTape, vars: List[NaiveVar]) -> List[NaiveVar]:
  69.     vals = [var.val for var in vars]
  70.     maxval = max(vals)
  71.     vals = [val - maxval for val in vals]
  72.     denom = sum(math.exp(val) for val in vals)
  73.     res = [naive_var(math.exp(val) / denom) for val in vals]
  74.     op = MyOperation(OpType.OP_SOFTMAX, len(vars), vars, res)
  75.     tape.add_op(op)
  76.     return res
  77.  
  78. def naive_tape_softplus(tape: NaiveTape, var: NaiveVar) -> NaiveVar:
  79.     softplus_val = math.log1p(math.exp(var.val))
  80.     res = naive_var(softplus_val)
  81.     op = MyOperation(OpType.OP_SOFTPLUS, 1, [var], [res])
  82.     tape.add_op(op)
  83.     return res
  84.  
  85. def naive_tape_backward(tape: NaiveTape, var: NaiveVar) -> None:
  86.     var.grad = 1.0  # Set gradient of the output variable
  87.     for i in range(tape.n_ops - 1, -1, -1):
  88.         op = tape.ops[i]
  89.         if op is None:
  90.             continue
  91.         if op.op_type == OpType.OP_SUM:
  92.             for j in range(op.n_inputs):
  93.                 op.inputs[j].grad += op.outputs[0].grad
  94.         elif op.op_type == OpType.OP_PROD:
  95.             in1 = op.inputs[0]
  96.             in2 = op.inputs[1]
  97.             in1.grad += in2.val * op.outputs[0].grad
  98.             in2.grad += in1.val * op.outputs[0].grad
  99.         elif op.op_type == OpType.OP_SOFTPLUS:
  100.             op.inputs[0].grad += op.outputs[0].grad / (1.0 + math.exp(-op.inputs[0].val))
  101.         elif op.op_type == OpType.OP_SOFTMAX:
  102.             # Softmax backward not implemented for now
  103.             pass
  104.         else:
  105.             # Handle unknown operations
  106.             pass
  107.  
  108. def main() -> None:
  109.     start_time = time.time()
  110.     iterations = 1000000
  111.  
  112.     for i in range(iterations):
  113.         # Create variables
  114.         x = naive_var(1.0)
  115.         y = naive_var(2.0)
  116.  
  117.         # Create tape
  118.         tape = naive_tape_create(10)
  119.  
  120.         # Perform operations
  121.         sum_xy = naive_tape_sum(tape, [x, y])
  122.         prod_sum_xy = naive_tape_prod(tape, sum_xy, sum_xy)
  123.         softplus_prod = naive_tape_softplus(tape, prod_sum_xy)
  124.  
  125.         # Backward pass
  126.         naive_tape_backward(tape, softplus_prod)
  127.  
  128.         if i == iterations - 1:
  129.             print(f"sum_xy.val: {sum_xy.val}")
  130.             print(f"prod_sum_xy.val: {prod_sum_xy.val}")
  131.             print(f"softplus_prod.val: {softplus_prod.val}")
  132.             print(f"sum_xy.grad: {sum_xy.grad}")
  133.             print(f"x.grad: {x.grad}")
  134.             print(f"y.grad: {y.grad}")
  135.  
  136.     end_time = time.time()
  137.     elapsed_time = (end_time - start_time) * 1000
  138.     print(f"\nElapsed time: {elapsed_time} ms\n")
  139.  
  140.  
  141. main()
  142.  
Advertisement
Add Comment
Please, Sign In to add comment