func (p *KernelPerceptron) RestoreFromFile(path string) error {
	if path == "" {
		return fmt.Errorf("ERROR: you just tried to restore your model from a file with no path! That's a no-no. Try it with a valid filepath")
	}
	bytes, err := ioutil.ReadFile(path)
	if err != nil {
		return err
	}
	err = json.Unmarshal(bytes, &p.SV)
	if err != nil {
		return err
	}
	return nil
}
RestoreFromFile takes in a path to a parameter vector theta
and assigns the model it's operating on's parameter vector
to that.

The path must ba an absolute path or a path from the current
directory

This would be useful in persisting data between running
a model on data, or for graphing a dataset with a fit in
another framework like Julia/Gadfly.
package perceptron
import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"github.com/cdipaolo/goml/base"
)
type KernelPerceptron struct {
	SV []base.Datapoint `json:"support_vectors,omitempty"`
	Kernel func([]float64, []float64) float64
	Output io.Writer
}
func NewKernelPerceptron(kernel func([]float64, []float64) float64) *KernelPerceptron {
	return &KernelPerceptron{
		Kernel: kernel,
		Output: os.Stdout,
	}
}
func (p *KernelPerceptron) Predict(x []float64, normalize ...bool) ([]float64, error) {
	if len(normalize) != 0 && normalize[0] {
		base.NormalizePoint(x)
	}
	var sum float64
	for i := range p.SV {
		sum += p.SV[i].Y[0] * p.Kernel(p.SV[i].X, x)
	}
	result := -1.0
	if sum > 0 {
		result = 1
	}
	return []float64{result}, nil
}
func (p *KernelPerceptron) OnlineLearn(errors chan error, dataset chan base.Datapoint, onUpdate func([][]float64), normalize ...bool) {
	if dataset == nil {
		errors <- fmt.Errorf("ERROR: Attempting to learn with a nil data stream!\n")
		close(errors)
		return
	}
	if errors == nil {
		errors = make(chan error)
	}
	fmt.Fprintf(p.Output, "Training:\n\tModel: Kernel Perceptron Classifier\n\tOptimization Method: Online Kernel Perceptron\n...\n\n")
	norm := len(normalize) != 0 && normalize[0]
	var point base.Datapoint
	var more bool
	for {
		point, more = <-dataset
		if more {
			if norm {
				base.NormalizePoint(point.X)
			}
			guess, err := p.Predict(point.X)
			if err != nil {
				errors <- err
				continue
			}
			if len(point.Y) != 1 {
				errors <- fmt.Errorf("The binary perceptron model requires that the data results (y) have length 1 - given %v", len(point.Y))
				continue
			}
			if guess[0] != point.Y[0] {
				p.SV = append(p.SV, point)
				go onUpdate([][]float64{append(point.X, point.Y...)})
			}
		} else {
			fmt.Fprintf(p.Output, "Training Completed.\n%v\n\n", p)
			close(errors)
			return
		}
	}
}
func (p *KernelPerceptron) String() string {
	return fmt.Sprintf("h(θ,x) = Σ y[i]*K(x[i], x`) > 0 ? 1 : 0\n\tTotal Support Vectors: %v\n", len(p.SV))
}
func (p *KernelPerceptron) PersistToFile(path string) error {
	if path == "" {
		return fmt.Errorf("ERROR: you just tried to persist your model to a file with no path!! That's a no-no. Try it with a valid filepath")
	}
	bytes, err := json.Marshal(p.SV)
	if err != nil {
		return err
	}
	err = ioutil.WriteFile(path, bytes, os.ModePerm)
	if err != nil {
		return err
	}
	return nil
}