Module: TensorStream::RandomOps

Included in:
Evaluator::RubyEvaluator
Defined in:
lib/tensor_stream/evaluator/ruby/random_ops.rb

Overview

Collection of machine learning related ops

Class Method Summary collapse

Class Method Details

.included(klass) ⇒ Object



4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/tensor_stream/evaluator/ruby/random_ops.rb', line 4

def self.included(klass)
  klass.class_eval do
    register_op :glorot_uniform, no_eval: true do |_context, tensor, _inputs|
      seed = tensor.options[:seed]
      random = _get_randomizer(tensor, seed)

      shape = tensor.options[:shape] || tensor.shape.shape
      fan_in, fan_out = if shape.size.zero?
                          [1, 1]
                        elsif shape.size == 1
                          [1, shape[0]]
                        else
                          [shape[0], shape.last]
                        end

      limit = Math.sqrt(6.0 / (fan_in + fan_out))

      minval = -limit
      maxval = limit

      generator = -> { random.rand * (maxval - minval) + minval }
      generate_vector(shape, generator: generator)
    end

    register_op :random_uniform, no_eval: true do |_context, tensor, inputs|
      maxval = tensor.options.fetch(:maxval, 1)
      minval = tensor.options.fetch(:minval, 0)
      seed = tensor.options[:seed]

      random = _get_randomizer(tensor, seed)
      generator = -> { random.rand * (maxval - minval) + minval }
      shape = inputs[0] || tensor.shape.shape
      generate_vector(shape, generator: generator)
    end

    register_op :random_standard_normal, no_eval: true do |_context, tensor, inputs|
      seed = tensor.options[:seed]
      random = _get_randomizer(tensor, seed)
      r = RandomGaussian.new(tensor.options.fetch(:mean), tensor.options.fetch(:stddev), -> { random.rand })
      random = _get_randomizer(tensor, seed)
      generator = -> { r.rand }
      shape = inputs[0] || tensor.shape.shape
      generate_vector(shape, generator: generator)
    end

    register_op :truncated_normal, no_eval: true do |_context, tensor, inputs|
      seed = tensor.options[:seed]
      random = _get_randomizer(tensor, seed)
      r = RandomGaussian.new(tensor.options.fetch(:mean), tensor.options.fetch(:stddev), -> { random.rand })

      generator = -> { r.rand }
      shape = inputs[0] || tensor.shape.shape
      random_values = Array.new(shape.reduce(:*) || 1) {
        generator.call
      }
      mean = random_values.reduce(:+) / random_values.size

      # standard deviation

      stddev = Math.sqrt(random_values.map { |v| (v - mean)**2 }.reduce(:+) / (random_values.size - 1))
      minval = random_values.min
      maxval = random_values.max
      max_iterations = 100

      if (minval.infinite? && minval < 0.0) || (maxval < mean)
        # Reverse all calculations. normMin and normMax will be flipped.
        a = minval
        minval = maxval
        maxval = a
        stddev = -stddev
      end

      norm_min = (minval - mean) / stddev
      norm_max = (maxval - mean) / stddev

      val = random_values.map { |v|
        iterations = 0
        pick = v
        while (pick > norm_max) || (pick < norm_min)
          pick = generator.call
          iterations += 1
          if iterations > max_iterations
            pick = v
            break
          end
        end

        pick
      }
      TensorShape.reshape(val, shape)
    end
  end
end