Permalink
Browse files

Basic MLP-NN webservice

  • Loading branch information...
larrytheliquid committed Jan 21, 2010
1 parent cc6d20b commit 79e6c8550b51c08e102a6dab079fe9235b4c3c1f
Showing with 85 additions and 13 deletions.
  1. +3 −0 Gemfile
  2. +14 −1 Perceptron.hs
  3. +5 −1 README.markdown
  4. +13 −4 Rakefile
  5. +17 −1 neurosis.rb
  6. +33 −6 neurosis_spec.rb
View
@@ -2,10 +2,13 @@ clear_sources
source "http://gemcutter.org"
gem "hubris"
+gem "sinatra"
+gem "json"
only :test do
gem "rake"
gem "rspec"
+ gem "rack-test"
end
disable_system_gems
View
@@ -1,10 +1,23 @@
module Perceptron where
+import qualified Data.Map as M
+import qualified Data.ByteString.Char8 as B
import Data.List (transpose, foldl')
learningRate = 1.0
bias = 1.0
epochsLimit = 4000
+hubris_learn :: M.Map B.ByteString [[Double]] -> Maybe [[Int]]
+hubris_learn m = result
+ (M.lookup (B.pack "input_patterns") m)
+ (M.lookup (B.pack "output_patterns") m)
+ (M.lookup (B.pack "hidden_weights_group") m)
+ (M.lookup (B.pack "output_weights_group") m)
+ where
+ result (Just a) (Just b) (Just c) (Just d) =
+ Just (learn a b c d)
+ result _ _ _ _ = Nothing
+
learn :: [[Double]] -> [[Double]] -> [[Double]] -> [[Double]] ->
[[Int]]
learn inputPatterns outputPatterns hiddenWeightsGroup outputWeightsGroup =
@@ -69,7 +82,7 @@ averageError inputPatterns outputPatterns hiddenWeightsGroup outputWeightsGroup
calculateError :: [Double] -> [Double] -> [[Double]] -> [[Double]] -> Double
calculateError inputNodes outputNodes hiddenWeightsGroup outputWeightsGroup =
(foldr (\ (x, y) result -> result + squaredError x y)
- 0.0 actualOutputsAndNodes) / 2
+ 0.0 actualOutputsAndNodes) / 2.0
where inputNodes' = calculateInputNodes inputNodes
hiddenNodes = calculateHiddenNodes inputNodes' hiddenWeightsGroup
outputNodes' = calculateOutputNodes hiddenNodes outputWeightsGroup
View
@@ -4,7 +4,11 @@
Neurosis is an example application to show off [Hubris](http://github.com/mwotton/Hubris) (a Haskell -> Ruby bridge) being used with non-trivial Haskell-code. See [this post](http://engineyard.com/blog/2010/a-hint-of-hubris/) for an intro to Hubris and for which Neurosis was written.
-Feel free to fork the code and send in pull requests if you would like to see this turn into a more sophisticated example webservice. I will be hacking on little improvements here and there as time goes on.
+Feel free to fork the code and send in pull requests if you would like to see this turn into a more sophisticated example webservice. I will be hacking on little improvements here and there as time goes on. Of course `learningRate` will need to be paramaterized as it is silly that it is a constant currently.
+
+## Up next
+
+This was written pretty quickly for the blog post so I just used the XOR problem as validation. Next up will be running it against the popular Idris dataset to make sure everything is really working.
## Installation
View
@@ -1,7 +1,16 @@
require "spec/rake/spectask"
-task :default => :spec
-Spec::Rake::SpecTask.new(:spec) do |t|
- t.spec_files = FileList["*_spec.rb"]
- t.spec_opts = ["-cfs"]
+namespace :test do
+ desc "Run all tests"
+ task :all => [:hunit, :spec]
+
+ desc "Run HUnit tests"
+ task :hunit do
+ `runghc PerceptronTest.hs`
+ end
+
+ Spec::Rake::SpecTask.new(:spec) do |t|
+ t.spec_files = FileList["*_spec.rb"]
+ t.spec_opts = ["-cfs"]
+ end
end
View
@@ -1,7 +1,23 @@
require 'hubris'
+require 'sinatra/base'
module Neurosis
class Perceptron
- hubris :source => 'Perceptron.hs'
+ hubris :source => 'Perceptron.hs', :no_strict => true
+ end
+
+ class Server < Sinatra::Base
+ def perceptron() Perceptron.new end
+
+ get '/' do
+ options = JSON.parse params[:input]
+ if output_nodes = perceptron.hubris_learn(options)
+ output_nodes.to_json
+ else
+ status 400
+ "Please specify all correct options for: " +
+ "input_patterns, output_patterns, hidden_weights_group, output_weights_group"
+ end
+ end
end
end
View
@@ -1,15 +1,42 @@
require File.dirname(__FILE__) + "/neurosis"
+require "rack/test"
+require "json"
Spec::Runner.configure do |config|
- system "rm /var/hubris/cache/Perceptron.so"
+ system "rm /var/hubris/cache/Perceptron.so" rescue nil
+ include Rack::Test::Methods
- def perceptron
- Neurosis::Perceptron.new
+ def app
+ Neurosis::Server
end
end
-describe "actualOutputDerivative given the actual-output" do
- it "returns its derivative" do
- perceptron.actualOutputDerivative(0.5250).should be_close(0.2494, 0.0001)
+describe Neurosis::Server, "GET /" do
+ it "responds with output nodes when given all options" do
+ get "/", :input => {
+ "input_patterns" =>
+ [[0.0, 0.0], [0.0, 1.0], [1.0, 0.0], [1.0, 1.0]],
+ "output_patterns" =>
+ [[0.0], [1.0], [1.0], [0.0]],
+ "hidden_weights_group" =>
+ [[0.0923, 0.1958, -0.4049], [0.2904, 0.1946, -0.1057]],
+ "output_weights_group" =>
+ [[0.0276, 0.1621, 0.2559]]
+ }.to_json
+
+ last_response.should be_successful
+ JSON.parse(last_response.body).should ==
+ [[0], [1], [1], [1]]
+ end
+
+ it "responds with error message when missing options" do
+ get "/", :input => {
+ "output_patterns" =>
+ [[0.0], [1.0], [1.0], [0.0]],
+ "output_weights_group" =>
+ [[0.0276, 0.1621, 0.2559]]
+ }.to_json
+
+ last_response.should be_client_error
end
end

0 comments on commit 79e6c85

Please sign in to comment.