When you hear "Machine Learning," Python is likely the first language that comes to mind. But what if you want to deploy a model with a tiny memory footprint, massive concurrency, and a single statically compiled binary? Enter Go.
While Go isn't replacing Python for deep research or massive neural networks just yet, it is an incredibly powerful tool for implementing, serving, and deploying classical ML algorithms in production. Today, we'll build a simple Linear Regression model and serve it via a REST API.
1. The Architecture
Our pipeline is straightforward. We will train a model on some simple data (like predicting a house price based on square footage), and then wrap that model in a standard Go HTTP server.
2. Setting Up the Project
First, initialize your Go module and pull in a lightweight regression library. We will use github.com/sajari/regression for its simplicity.
go mod init go-ml-api
go get github.com/sajari/regression
3. Writing the Training and Serving Code
Create a file named main.go. We will do two things in our main function: train the model with hardcoded mock data, and start an HTTP server to listen for prediction requests.
package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
"strconv"
"github.com/sajari/regression"
)
var r new(regression.Regression)
func initModel() {
r = new(regression.Regression)
r.SetObserved("Price")
r.SetVar(0, "SquareFeet")
// Mock Data: Price based on Square Footage
r.Train(regression.DataPoint(300000, []float64{1500}))
r.Train(regression.DataPoint(400000, []float64{2000}))
r.Train(regression.DataPoint(500000, []float64{2500}))
r.Train(regression.DataPoint(600000, []float64{3000}))
r.Run()
fmt.Printf("Model trained. Formula: %v\n", r.Formula)
}
func predictHandler(w http.ResponseWriter, req *http.Request) {
sqftStr := req.URL.Query().Get("sqft")
if sqftStr == "" {
http.Error(w, "Please provide a 'sqft' query parameter", http.StatusBadRequest)
return
}
sqft, err := strconv.ParseFloat(sqftStr, 64)
if err != nil {
http.Error(w, "Invalid square footage", http.StatusBadRequest)
return
}
prediction, err := r.Predict([]float64{sqft})
if err != nil {
http.Error(w, "Prediction failed", http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]float64{"predicted_price": prediction})
}
func main() {
initModel()
http.HandleFunc("/predict", predictHandler)
fmt.Println("Server starting on port 8080...")
log.Fatal(http.ListenAndServe(":8080", nil))
}
4. Running and Testing the API
With your code saved, you can run the application. Go's compilation is incredibly fast, and your server will be up in milliseconds.
go run main.go
Now, test your deployment. Open a new terminal window or use your browser to make a GET request to your API:
curl "http://localhost:8080/predict?sqft=2200"
You should receive a JSON response with the predicted price based on the linear regression model you just trained in memory:
{
"predicted_price": 440000
}
5. Why This Matters
What you just built is a single, compiled binary that contains both your ML model and a high-performance web server. You can drop this binary into a scratch Docker container that weighs only a few megabytes, and it will handle thousands of concurrent requests without breaking a sweat.