Instructions to use litert-community/GLiClass-Edge-v3.0-LiteRT with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- LiteRT
How to use litert-community/GLiClass-Edge-v3.0-LiteRT with LiteRT:
# No code snippets available yet for this library. # To use this model, check the repository files and the library's documentation. # Want to help? PRs adding snippets are welcome at: # https://github.com/huggingface/huggingface.js
- Notebooks
- Google Colab
- Kaggle
GLiClass-Edge v3.0 for LiteRT: S128 and S256 graphs (fp32 and fp16 weights), float16 token table, tokenizer, Python host, Android sample, conversion scripts, fixtures and card
88c9095 verified Download android/sample/app/src/test/java/com/gliclass/GliclassDecoderTest.kt from litert-community/GLiClass-Edge-v3.0-LiteRT: direct link, hf CLI and curl.
- Browser
- Download file 5.81 kB
-
https://huggingface.co/litert-community/GLiClass-Edge-v3.0-LiteRT/resolve/main/android/sample/app/src/test/java/com/gliclass/GliclassDecoderTest.kt
- Command line
-
hf download hf://litert-community/GLiClass-Edge-v3.0-LiteRT/android/sample/app/src/test/java/com/gliclass/GliclassDecoderTest.kt
-
curl -L -o GliclassDecoderTest.kt https://huggingface.co/litert-community/GLiClass-Edge-v3.0-LiteRT/resolve/main/android/sample/app/src/test/java/com/gliclass/GliclassDecoderTest.kt
5.81 kB
| package com.gliclass | |
| import kotlin.math.abs | |
| import kotlin.math.nextDown | |
| import kotlin.math.nextUp | |
| import org.json.JSONArray | |
| import org.json.JSONObject | |
| import org.junit.Assert.assertEquals | |
| import org.junit.Assert.assertTrue | |
| import org.junit.Test | |
| /** `_postprocess_logits` semantics on the oracle logits, plus the tie/threshold/repeat rules. */ | |
| class GliclassDecoderTest { | |
| fun oracleLogitsGiveTheOfficialResultsForEveryRequest() { | |
| val fixtures = OracleFixtures.load(ExternalTestData.resolve()) | |
| assertEquals(552, fixtures.size) | |
| val failures = JSONArray() | |
| var passed = 0 | |
| var maxScore = 0.0 | |
| var maxProbability = 0.0 | |
| for (fixture in fixtures) { | |
| // Slots past the labels hold scorer(0) in the graph; NaN proves they are never read. | |
| val slots = FloatArray(GliclassInputs.LABEL_SLOTS) { Float.NaN } | |
| fixture.logits.copyInto(slots) | |
| val single = GliclassDecoder.decide(slots, fixture.labels, GliclassDecoder.Mode.SINGLE_LABEL) | |
| val multi = | |
| GliclassDecoder.decide(slots, fixture.labels, GliclassDecoder.Mode.MULTI_LABEL, 0.5) | |
| val checks = | |
| mutableListOf( | |
| compare(single, fixture.single), | |
| compare(multi, fixture.multi), | |
| ) | |
| fixture.multiThresholdZero?.let { | |
| checks.add( | |
| compare( | |
| GliclassDecoder.decide(slots, fixture.labels, GliclassDecoder.Mode.MULTI_LABEL, 0.0), | |
| it, | |
| ) | |
| ) | |
| } | |
| val probability = | |
| maxOf( | |
| maxAbs(single.probabilities, fixture.softmax), | |
| maxAbs(multi.probabilities, fixture.sigmoid), | |
| ) | |
| maxProbability = maxOf(maxProbability, probability) | |
| maxScore = maxOf(maxScore, checks.maxOf { it.second }) | |
| if (checks.all { it.first } && checks.all { it.second <= SCORE_TOLERANCE }) { | |
| passed++ | |
| } else { | |
| failures.put( | |
| JSONObject() | |
| .put("id", fixture.id) | |
| .put("labels_equal", JSONArray(checks.map { it.first })) | |
| .put("max_abs_dscore", checks.maxOf { it.second }) | |
| .put("single", JSONArray(single.predictions.map { "${it.label}=${it.score}" })) | |
| .put("multi", JSONArray(multi.predictions.map { "${it.label}=${it.score}" })) | |
| ) | |
| } | |
| } | |
| ExternalTestData.reportFile("decoder_parity.json") | |
| .writeText( | |
| JSONObject() | |
| .put("test", "GliclassDecoderTest") | |
| .put("fixtures", fixtures.size) | |
| .put("passed", passed) | |
| .put("max_abs_dscore_vs_pipeline", maxScore) | |
| .put("max_abs_dprob_vs_oracle", maxProbability) | |
| .put("score_tolerance", SCORE_TOLERANCE) | |
| .put("input", "oracle logits (official fp32), slots past the labels = NaN") | |
| .put("failures", failures) | |
| .toString(1) + "\n" | |
| ) | |
| println( | |
| "GLICLASS_DECODER passed=$passed/${fixtures.size} max_dscore=$maxScore" + | |
| " max_dprob=$maxProbability" | |
| ) | |
| assertEquals("requests whose decisions match the pipeline: $failures", fixtures.size, passed) | |
| } | |
| fun thresholdComparesFloatProbabilityWithDoubleThreshold() { | |
| // 0.7f is the float just below 0.7: Python rejects it at threshold 0.7, a Float threshold | |
| // would accept it. | |
| val logit = findLogitWithSigmoid(0.7f) | |
| val decision = | |
| GliclassDecoder.decide( | |
| floatArrayOf(logit, 2f), | |
| listOf("a", "b"), | |
| GliclassDecoder.Mode.MULTI_LABEL, | |
| 0.7, | |
| ) | |
| assertEquals(0.7f, decision.probabilities[0]) | |
| assertTrue(0.7f.toDouble() < 0.7) | |
| assertEquals(listOf("b"), decision.predictions.map { it.label }) | |
| // Nothing reaches the threshold: the pipeline returns no label. | |
| val none = | |
| GliclassDecoder.decide( | |
| floatArrayOf(-5f, -6f), | |
| listOf("a", "b"), | |
| GliclassDecoder.Mode.MULTI_LABEL, | |
| ) | |
| assertTrue(none.predictions.isEmpty()) | |
| assertTrue(none.chosen.isEmpty()) | |
| } | |
| fun tiesKeepTheFirstLabelAndRepeatedLabelsFollowThePipelineDict() { | |
| val tie = | |
| GliclassDecoder.decide( | |
| floatArrayOf(1f, 1f, 0f), | |
| listOf("x", "y", "z"), | |
| GliclassDecoder.Mode.SINGLE_LABEL, | |
| ) | |
| assertEquals(listOf("x"), tie.predictions.map { it.label }) | |
| // {label: score}: "a" keeps its first position with the last score. | |
| val repeated = | |
| GliclassDecoder.decide( | |
| floatArrayOf(3f, 1f, -3f), | |
| listOf("a", "b", "a"), | |
| GliclassDecoder.Mode.MULTI_LABEL, | |
| 0.5, | |
| ) | |
| assertEquals(listOf("b"), repeated.predictions.map { it.label }) | |
| assertEquals(listOf(0, 1), repeated.chosen) | |
| val softmax = GliclassDecoder.softmax(floatArrayOf(0f, 0f)) | |
| assertTrue(softmax.all { it == 0.5f }) | |
| } | |
| private fun compare( | |
| decision: GliclassDecoder.Decision, | |
| expected: List<OracleFixtures.Prediction>, | |
| ): Pair<Boolean, Double> { | |
| val labelsEqual = decision.predictions.map { it.label } == expected.map { it.label } | |
| val score = | |
| if (labelsEqual) { | |
| decision.predictions.zip(expected).maxOfOrNull { (a, b) -> | |
| abs(a.score.toDouble() - b.score) | |
| } ?: 0.0 | |
| } else { | |
| Double.POSITIVE_INFINITY | |
| } | |
| return labelsEqual to score | |
| } | |
| private fun maxAbs(actual: FloatArray, expected: FloatArray): Double = | |
| expected.indices.maxOf { abs(actual[it].toDouble() - expected[it].toDouble()) } | |
| private fun findLogitWithSigmoid(target: Float): Float { | |
| var candidate = 0.8472978f | |
| repeat(4096) { | |
| val probability = GliclassDecoder.sigmoid(floatArrayOf(candidate))[0] | |
| if (probability == target) { | |
| return candidate | |
| } | |
| candidate = if (probability < target) candidate.nextUp() else candidate.nextDown() | |
| } | |
| error("No float logit maps to $target") | |
| } | |
| private companion object { | |
| const val SCORE_TOLERANCE = 1e-6 | |
| } | |
| } | |