├── .gitignore ├── Dockerfile ├── Makefile ├── README.md ├── captcha ├── 3KC6YY.png ├── MG7M6P.png ├── RUKMSH.png ├── UWAGDJ.png ├── VL5NTR.png └── src │ └── main.py ├── solution ├── detailed-solution │ └── detailed-solution.go └── solution.go ├── template.go └── tensorflow_savedmodel_captcha └── saved_model.pb /.gitignore: -------------------------------------------------------------------------------- 1 | main 2 | run.log 3 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1-stretch 2 | 3 | # install tensorflow 4 | RUN curl -L "https://storage.googleapis.com/tensorflow/libtensorflow/libtensorflow-cpu-linux-x86_64-1.12.0.tar.gz" | tar -C /usr/local -xz 5 | RUN ldconfig 6 | 7 | # go get tensorflow lib 8 | RUN go get -d github.com/tensorflow/tensorflow/tensorflow/go 9 | 10 | # python lib and tools like `saved_model_cli` 11 | RUN curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py 12 | RUN python get-pip.py 13 | RUN pip install tensorflow -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | WDIR := /go/src/github.com/Pisush/tensorflow-and-go 3 | DIR := ${CURDIR}:${WDIR} 4 | 5 | DOCKER_IMAGE := dahernan/tensorflow-and-go 6 | 7 | login: 8 | docker run -i -v $(DIR) -w $(WDIR) --entrypoint=/bin/bash -t $(DOCKER_IMAGE) 9 | 10 | dockerbuild: 11 | docker build -f Dockerfile -t $(DOCKER_IMAGE) . 12 | 13 | dockerpush: 14 | docker push $(DOCKER_IMAGE):latest 15 | 16 | PHONY: dockerbuild login dockerpush -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # tensorflow-and-go 2 | This is an example of using the Go API to read CAPTCHAs with TensorFlow. 3 | 4 | Log is generated for each run in the file run.log. 5 | For printing the logs, run with flag -printlog=true 6 | 7 | ### Structure 8 | - `template.go` is the template with instructions in the comments 9 | - The `tensorflow_savedmodel_captcha` folder contains the model in a protobuf format. 10 | - The `captcha` folder has several CAPTCHAs that can be used for serving, alongside the Python script used to generate them. 11 | - `Dockerfile` is a docker container template will all the tooling installed (Go compiler and Tensorflow dependencies) and ready to use 12 | - `Makefile` targets to easy built and run the docker container 13 | - And, well, the solutions are in the `solution` folder. There is a standard one and the detailed one, if you want to read through the full solution with the detailed instructions. 14 | 15 | 16 | ## Develop From Docker 17 | 18 | If you don't have Go or Tensorflow installed on your system you can use the Docker image that is ready to use with: 19 | 20 | ``` 21 | # Download and login into the docker container 22 | $ make login 23 | 24 | # you can run go or tools like 'saved_model_cli' 25 | root@c7223ab43fbf:/go/src/github.com/Pisush/tensorflow-and-go# go --version 26 | 27 | ``` 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /captcha/3KC6YY.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pisush/tensorflow-and-go/c9702ad5573c9c86305d7cbb7fd8962d39c0c924/captcha/3KC6YY.png -------------------------------------------------------------------------------- /captcha/MG7M6P.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pisush/tensorflow-and-go/c9702ad5573c9c86305d7cbb7fd8962d39c0c924/captcha/MG7M6P.png -------------------------------------------------------------------------------- /captcha/RUKMSH.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pisush/tensorflow-and-go/c9702ad5573c9c86305d7cbb7fd8962d39c0c924/captcha/RUKMSH.png -------------------------------------------------------------------------------- /captcha/UWAGDJ.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pisush/tensorflow-and-go/c9702ad5573c9c86305d7cbb7fd8962d39c0c924/captcha/UWAGDJ.png -------------------------------------------------------------------------------- /captcha/VL5NTR.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pisush/tensorflow-and-go/c9702ad5573c9c86305d7cbb7fd8962d39c0c924/captcha/VL5NTR.png -------------------------------------------------------------------------------- /captcha/src/main.py: -------------------------------------------------------------------------------- 1 | import random 2 | from captcha.image import ImageCaptcha 3 | def random_string(length): 4 | return ''.join(random.choice("ABCDEFGHJKLMNPQRSTUVWXYZ23456789") for _ in range(length)) 5 | captcha_gen = ImageCaptcha(width=160, height=60, font_sizes=[42]) 6 | for i in xrange(5): 7 | captcha_string = random_string(6) 8 | captcha_gen.write(captcha_string, captcha_string+'.png') 9 | -------------------------------------------------------------------------------- /solution/detailed-solution/detailed-solution.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "io/ioutil" 7 | "log" 8 | "os" 9 | 10 | tf "github.com/tensorflow/tensorflow/tensorflow/go" 11 | ) 12 | 13 | const ( 14 | inputImage = "./captcha/3KC6YY.png" 15 | ) 16 | 17 | func captchaToText(path string, savedModel *tf.SavedModel, printLogs bool) string { 18 | // Read captcha 19 | captchaImage, err := ioutil.ReadFile(inputImage) 20 | if err != nil { 21 | log.Fatal(err) 22 | } 23 | 24 | // This is where the action happens: run captcha through tensorflow model! 25 | 26 | // Define the Output struct that will be fed in the model: 27 | // the operation here is providing the input image as bytes of the prediction node, the index is 0 28 | feedsOutput := tf.Output{ 29 | Op: savedModel.Graph.Operation("CAPTCHA/input_image_as_bytes"), 30 | Index: 0, 31 | } 32 | 33 | // Define the input Tensor: the string versino of the CAPTCHA 34 | feedsTensor, err := tf.NewTensor(string(captchaImage)) 35 | if err != nil { 36 | log.Fatal(err) 37 | } 38 | 39 | // Set a map from the operation we will apply to the input it will be applied on 40 | feeds := map[tf.Output]*tf.Tensor{feedsOutput: feedsTensor} 41 | 42 | // Define the Output struct that will be fetched as the model's result: 43 | // the operation here is the output of the prediction node, the index is 0 44 | fetches := []tf.Output{ 45 | { 46 | Op: savedModel.Graph.Operation("CAPTCHA/prediction"), 47 | Index: 0, 48 | }, 49 | } 50 | 51 | // Run the data through the graph and receive the output: the captcha prediction 52 | captchaText, err := savedModel.Session.Run(feeds, fetches, nil) 53 | if err != nil { 54 | log.Fatal(err) 55 | } 56 | 57 | // We only need the first element of the tensor 58 | var text string 59 | text = captchaText[0].Value().(string) 60 | 61 | if printLogs { 62 | log.Println("for file" + path + "the text is" + text) 63 | } 64 | 65 | return text 66 | } 67 | 68 | func main() { 69 | printLogs := flag.Bool("printlog", false, "set to true for printing all log lines on the screen") 70 | flag.Parse() 71 | 72 | // Always make the log file run.log 73 | logfile, err := os.OpenFile("run.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) 74 | if err != nil { 75 | log.Fatalf("error opening a log file: %v", err) 76 | } 77 | defer logfile.Close() 78 | log.SetOutput(logfile) 79 | 80 | // Creates a new SavedModel by loading a model previously exported to a directory on disk 81 | // the tag is "serve", no special options 82 | savedModel, err := tf.LoadSavedModel("./tensorflow_savedmodel_captcha", []string{"serve"}, nil) 83 | if err != nil { 84 | log.Println("failed to load model", err) 85 | return 86 | } 87 | 88 | captchaText := captchaToText(inputImage, savedModel, *printLogs) 89 | fmt.Println(captchaText) 90 | } 91 | -------------------------------------------------------------------------------- /solution/solution.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "io/ioutil" 7 | "log" 8 | "os" 9 | 10 | tf "github.com/tensorflow/tensorflow/tensorflow/go" 11 | ) 12 | 13 | const ( 14 | inputImage = "./captcha/3KC6YY.png" 15 | ) 16 | 17 | func captchaToText(path string, savedModel *tf.SavedModel, printLogs bool) string { 18 | // Read captcha 19 | captchaImage, err := ioutil.ReadFile(inputImage) 20 | if err != nil { 21 | log.Fatal(err) 22 | } 23 | 24 | // Run captcha through the TensorFlow model 25 | feedsOutput := tf.Output{ 26 | Op: savedModel.Graph.Operation("CAPTCHA/input_image_as_bytes"), 27 | Index: 0, 28 | } 29 | feedsTensor, err := tf.NewTensor(string(captchaImage)) 30 | if err != nil { 31 | log.Fatal(err) 32 | } 33 | feeds := map[tf.Output]*tf.Tensor{feedsOutput: feedsTensor} 34 | 35 | fetches := []tf.Output{ 36 | { 37 | Op: savedModel.Graph.Operation("CAPTCHA/prediction"), 38 | Index: 0, 39 | }, 40 | } 41 | 42 | captchaText, err := savedModel.Session.Run(feeds, fetches, nil) 43 | if err != nil { 44 | log.Fatal(err) 45 | } 46 | 47 | text := captchaText[0].Value().(string) 48 | if printLogs { 49 | log.Println("for file" + path + "the text is" + text) 50 | } 51 | 52 | return text 53 | } 54 | 55 | func main() { 56 | printLogs := flag.Bool("printlog", false, "set to true for printing all log lines on the screen") 57 | flag.Parse() 58 | 59 | // Always make a log file 60 | logfile, err := os.OpenFile("run.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) 61 | if err != nil { 62 | log.Fatalf("error opening a log file: %v", err) 63 | } 64 | defer logfile.Close() 65 | log.SetOutput(logfile) 66 | 67 | // Load TensorFlow model 68 | savedModel, err := tf.LoadSavedModel("./tensorflow_savedmodel_captcha", []string{"serve"}, nil) 69 | if err != nil { 70 | log.Println("failed to load model", err) 71 | return 72 | } 73 | 74 | captchaText := captchaToText(inputImage, savedModel, *printLogs) 75 | fmt.Println(captchaText) 76 | } 77 | -------------------------------------------------------------------------------- /template.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "io/ioutil" 7 | "log" 8 | 9 | tf "github.com/tensorflow/tensorflow/tensorflow/go" 10 | ) 11 | 12 | const ( 13 | inputImage = "./captcha/3KC6YY.png" 14 | ) 15 | 16 | func captchaToText(path string, savedModel *tf.SavedModel, printLogs bool) string { 17 | // Read captcha 18 | captchaImage, err := ioutil.ReadFile(inputImage) 19 | if err != nil { 20 | log.Fatal(err) 21 | } 22 | 23 | // This is where the action happens: run captcha through tensorflow model! 24 | 25 | // Define the Output struct that will be fed in the model: 26 | // the operation here is providing the input image as bytes of the prediction node, the index is 0 27 | 28 | feedsOutput := tf.Output{ 29 | //... 30 | } 31 | 32 | // here just for the template to run - delete me 33 | nilOutput := tf.Output{} 34 | if feedsOutput != nilOutput { 35 | lof.Fatal(err) 36 | } 37 | 38 | // Define the input Tensor: the string version of the CAPTCHA 39 | //... 40 | 41 | // Set a map from the operation we will apply to the input it will be applied on 42 | // feeds := map[tf.Output]*tf.Tensor{feedsOutput: feedsTensor} 43 | 44 | // Define the Output struct that will be fetched as the model's result: 45 | // the operation here is the output of the prediction node, the index is 0 46 | //... 47 | 48 | // Run the data through the graph using the two Output structs 49 | // and receive the output: the captcha prediction 50 | //... 51 | 52 | // We only need the first element of the tensor 53 | var text string 54 | //... 55 | 56 | if printLogs { 57 | log.Println("for file" + path + "the text is" + text) 58 | } 59 | 60 | return text 61 | } 62 | 63 | func main() { 64 | printLogs := flag.Bool("printlog", false, "set to true for printing all log lines on the screen") 65 | flag.Parse() 66 | 67 | // Always make the log file run.log 68 | //... 69 | 70 | // Creates a new SavedModel by loading a model previously exported to a directory on disk 71 | // the tag is "serve", no special options 72 | 73 | var captchaText string 74 | // captchaText = captchaToText(inputImage, savedModel, *printLogs) 75 | fmt.Println(captchaText) 76 | } 77 | -------------------------------------------------------------------------------- /tensorflow_savedmodel_captcha/saved_model.pb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pisush/tensorflow-and-go/c9702ad5573c9c86305d7cbb7fd8962d39c0c924/tensorflow_savedmodel_captcha/saved_model.pb --------------------------------------------------------------------------------