크리에이티브 커먼즈 라이선스
Creative Commons License
역전파망 backpropagation network 혹은
다층퍼셉트론인지 multi-layer perceptron 으로 불리는 신경망의 구현 
↑ 다층퍼셉으론이라구 검색을 마니 길래.....수정

별 내용은 업ㅂ구 코드만 나옵니다. 구현은 더럽지만 어째든 작동함 >_<

require 'matrix'

def generate_random(min = 0.0, max = 1.0)
    rand * (max - min) + min
end

class BackPropagationNet
    attr_reader :output_pattern, :error
    attr_reader :weights
    
    def initialize(number_of_neurons, a = 0.1, polarity = :bipolar )
        @number_of_neurons = number_of_neurons
        @a = a
        
        if polarity == :bipolar
            @af = Proc.new { |x| (1.0 - Math.exp(-x)) / (1.0 + Math.exp(-x)) }
            @diff_af = Proc.new { |x| 0.5 * (1 - x*x) }
        elsif polarity == :unipolar
            @af = Proc.new { |x| 1.0 / (1 + Math.exp(-x)) }
            @diff_af = Proc.new { |x| x * (1 - x) }
        end
        
        # initialize weights
        @weights = []
        for i in 1..@number_of_neurons.size-1
           @weights << Matrix[ *[].fill(0..@number_of_neurons[i]-1) { 
            [].fill(0..@number_of_neurons[i-1]) { generate_random(-0.5, 0.5) } } ]
        end
    end
    
    def recall(input_pattern)
        @net_weights = []
        @outputs = [input_pattern]
        
        # compute net_weight and output for each layer
        @weights.each do |w|
            net_weight = (Matrix[ [1, *@outputs[-1]] ] * w.t).to_a.flatten
            
            @net_weights << net_weight
            @outputs << net_weight.collect { |y| af(y) }
        end
        
        @output_pattern = @outputs[-1]
    end
    
    def learn(input_pattern, desired_pattern)
        recall input_pattern                # comput output
        compute_error desired_pattern       # comput error
        
        deltas = []
        temp = []
        
        # compute delta of output layer
        desired_pattern.each_with_index do |d, i| 
            temp << (d - @output_pattern[i]) * diff_af(@output_pattern[i])
        end
        deltas << temp
        
        # compute delta for each hidden layer
        (@number_of_neurons.size-3).downto(0) do |i|    # number of hidden layer
            temp = []
            
            @number_of_neurons[i+1].times do |j|    # number of nuerons in current layer
                current_delta = 0
                
                @number_of_neurons[i+2].times do |k|   # number of nuerons in next layer
                    a = deltas[-1][k]
                    b = @weights[i+1][k, j+1]
                    current_delta += a * b
                end
                temp << diff_af(@outputs[i+1][j]) * current_delta
            end
            deltas << temp
        end
        deltas.reverse!
        
        # update weights        
        (@weights.size).times do |i|
            temp = @weights[i].to_a
            temp.size.times do |j|
                temp[j].size.times do |k|
                    delta = deltas[i][j]
                    output = 1
                    output = @outputs[i][k-1] if k != 0
                    temp[j][k] += @a * delta * output
                end
            end
            
            @weights[i] = Matrix[*temp]
        end
        
        @error
    end
    
    private
    def af(net)
        @af.call(net)
    end
    
    def diff_af(net)
        @diff_af.call(net)
    end
    
    def compute_error(desired_pattern)
        @error = 0        
        desired_pattern.each_with_index do |d, i| 
            @error += (d - @output_pattern[i])**2
        end
        
        @error = 0.5 * @error
    end
end

net = BackPropagationNet.new [2, 10, 20, 2, 1], 1
x = [ [-1.0, -1.0], [-1.0, 1.0], [1.0, -1.0], [1.0, 1.0] ] y = [ [-1.0], [1.0], [1.0], [-1.0] ] print "BackPropagation Network(bipolar) simulation\n\n" puts "Before training" x.each do |inp| puts "[#{inp.join(", ")}] : #{net.recall(inp).join(", ")}" end print "\n\n" print "Training.....\n" 20000.times do |t| errors = [] total_error = 0 x.each_with_index do |inp, i| error = net.learn(inp, y[i]) total_error += error errors << error end #puts "#{t} : total error : #{total_error}" if errors[0] <= 0.0005 and errors[1] <= 0.0005 and errors[2] <= 0.0005 and errors[3] <= 0.0005 puts "#{t} - training complete" break end end print "\n\n" puts "After training" x.each do |inp| puts "[#{inp.join(", ")}] : #{net.recall(inp).join(", ")}" end puts "\n\nd>_<b"


실행결과
BackPropagation Network(bipolar) simulation

Before training
[-1.0, -1.0] : -0.0542964479707475
[-1.0, 1.0] : -0.0321681144483251
[1.0, -1.0] : -0.0630540475165143
[1.0, 1.0] : -0.0423248262571378


Training.....
0 : total error : 2.67503298609203
1 : total error : 2.61532655049581
2 : total error : 2.58326168229993
3 : total error : 2.56751261506715
4 : total error : 2.56008686383712
.
.
.
    대략 생략
.
.
.
907 : total error : 0.00179664781743692
908 : total error : 0.00177502154732301
909 : total error : 0.00175389506569839
910 : total error : 0.00173325145741755
911 : total error : 0.00171307455680966
911 - training complete


After training
[-1.0, -1.0] : -0.97101067663663
[-1.0, 1.0] : 0.97292656672447
[1.0, -1.0] : 0.968576984668481
[1.0, 1.0] : -0.971187181479301


d>_<b

저작자 표시 비영리 동일 조건 변경 허락

댓글을 달아 주세요