mosmetro-android / module-captcha-recognition

Модуль автоматического распознавания капчи для приложения "Wi-Fi в метро"
GNU General Public License v3.0
7 stars 1 forks source link

Распознавание каптчи #4

Open Luonic opened 7 years ago

Luonic commented 7 years ago

С чего все начиналось: прошлый тред Репозиторий с кодом для распознавания: tf-cnn-lstm-ocr-captcha

Я смог уменьшить размер графа с 7.4мб до 283кб! Теперь на вход подается такая картинка, которая приходит от WiFi AP. То есть, не транспонированная, в uint8, в RGB, все преобразования включены в граф frozen_graph.pb.zip При этом, текущее среднее расстояние левенштейна на тестовом датасете составляет всего 0.0074 (99.26%)

Я попробовал квантизировать веса и операции в графе, но его размер только увеличился (356кб), видимо, описание самого графа уже занимает больше места, чем веса, а квантизация привносит множество дополнительных операций. Но в теории, этот граф должен работать несколько быстрее на телефонах, но с небольшой потерей точности (обычно 1.1%) quantized_graph.pb.zip

Работаю над тем, чтобы скомпилировать граф в отдельную библиотеку UPD: граф в библиотеку лучше собирать самостоятельно @TheDrHax Потому что надо собирать под разные архитектуры и писать свой код вызова Тут есть инструкция, надо собрать TF из сорцов и обязательно с поддержкой XLA (это указывается при вызове ./configure): инструкция

Думаю, можно смело выкатывать этот граф в приложение, убирая старый код с преобразованиями изображений

TheDrHax commented 7 years ago

frozen_graph.pb

Кажется, отсутствуют нужные вычислительные ядра в этой нативной библиотеке. Возможно, придётся собрать свою с параметром -DANDROID_TYPES=ANDROID_TYPES_FULL.

java.lang.IllegalArgumentException: No OpKernel was registered to support Op 'Transpose' with these attrs.  Registered devices: [CPU], Registered kernels:
device='CPU'; T in [DT_BFLOAT16]; Tperm in [DT_INT32]
device='CPU'; T in [DT_FLOAT]; Tperm in [DT_INT32]
device='CPU'; T in [DT_INT32]; Tperm in [DT_INT32]

[[Node: transpose = Transpose[T=DT_UINT8, Tperm=DT_INT32](Placeholder, transpose/perm)]]
at org.tensorflow.Session.run(Native Method)
at org.tensorflow.Session.access$100(Session.java:48)
at org.tensorflow.Session$Runner.runHelper(Session.java:295)
at org.tensorflow.Session$Runner.run(Session.java:245)
at org.tensorflow.contrib.android.TensorFlowInferenceInterface.run(TensorFlowInferenceInterface.java:144)
at org.tensorflow.contrib.android.TensorFlowInferenceInterface.run(TensorFlowInferenceInterface.java:113)
at pw.thedrhax.captcharecognition.CaptchaRecognition.recognize(CaptchaRecognition.java:52)
at pw.thedrhax.captcharecognition.CaptchaRecognitionTest.recognize(CaptchaRecognitionTest.java:48)
at java.lang.reflect.Method.invoke(Native Method)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runners.Suite.runChild(Suite.java:128)
at org.junit.runners.Suite.runChild(Suite.java:27)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at android.support.test.internal.runner.TestExecutor.execute(TestExecutor.java:59)
at android.support.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:262)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1932)

quantized_graph.pb

Отказывается загружаться с ошибкой Not a valid TensorFlow Graph serialization.

java.lang.RuntimeException: Failed to load model from 'file:///android_asset/quantized_graph.pb'
at org.tensorflow.contrib.android.TensorFlowInferenceInterface.<init>(TensorFlowInferenceInterface.java:102)
at pw.thedrhax.captcharecognition.CaptchaRecognition.<init>(CaptchaRecognition.java:40)
at pw.thedrhax.captcharecognition.CaptchaRecognitionTest.recognize(CaptchaRecognitionTest.java:40)
at java.lang.reflect.Method.invoke(Native Method)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runners.Suite.runChild(Suite.java:128)
at org.junit.runners.Suite.runChild(Suite.java:27)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at android.support.test.internal.runner.TestExecutor.execute(TestExecutor.java:59)
at android.support.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:262)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1932)
Caused by: java.io.IOException: Not a valid TensorFlow Graph serialization: NodeDef expected inputs '' do not match 1 inputs specified; Op<name=Const; signature= -> output:dtype; attr=value:tensor; attr=dtype:type>; NodeDef: RNN/StackRNN/Layer0/bidirectional_rnn/bw/bw/while/bw/gru_cell/candidate/candidate/concat/axis = Const[dtype=DT_INT32, value=Tensor<type: int32 shape: [] values: 1>](RNN/StackRNN/Layer0/bidirectional_rnn/bw/bw/while/Switch:1)
at org.tensorflow.contrib.android.TensorFlowInferenceInterface.loadGraph(TensorFlowInferenceInterface.java:439)
at org.tensorflow.contrib.android.TensorFlowInferenceInterface.<init>(TensorFlowInferenceInterface.java:98)
... 29 more
TheDrHax commented 7 years ago

Сейчас пойду компилировать TensorFlow. Если сборка удастся, то можно будет сразу и AOT опробовать.

Luonic commented 7 years ago

@TheDrHax если не получится собрать библиотеку из графа, то я могу убрать транспонирование, пускай оно будет в java коде, и сделаю новый граф И еще, в этом проекте, в версии, которая сейчас в Google Play почему-то библиотеки для разных архитектур все в одном apk. Я думал, что они уже разбиты на разные файлы

TheDrHax commented 7 years ago

собрать библиотеку из графа

Возникла ещё одна проблема. Выполнил всё по инструкциям и примерам, но tfcompiler, похоже, очень не любит двунаправленные сети.

INVALID ARGUMENTS: Missing Exit successor to RNN/StackRNN/Layer0/bidirectional_rnn/fw/fw/while/Switch

В одном из тикетов находится патч, который обходит именно это исключение, но дальше встречается только ужасный каскад ошибок О_о

Я немного разобрался в том, как вообще происходит сборка, так что попробую собрать новую версию нативной библиотеки. Возможно, что транспонирование убирать не придётся.

И еще, в этом проекте, в версии, которая сейчас в Google Play почему-то библиотеки для разных архитектур все в одном apk. Я думал, что они уже разбиты на разные файлы

Выбор "вводить капчу или поставить тяжелый модуль" всё-таки лучше, чем "ставить приложение или не ставить приложение" :)