TensorFlow Lite Tutorial: Deploy ML on Mobile and Edge Devices

# Tutorial 18: TensorFlow Lite - Deploy ML di Perangkat Mobile ## Daftar Isi 1. [Pendahuluan](#pendahuluan) 2. [Prasyarat](#prasyarat) 3. [Memahami TensorFlow Lite](#memahami-tensorflow-lite) 4. [Ko...

By Ruby Abdullah · · tutorial
TensorFlow LiteMobile MLEdge AIQuantizationAndroidiOS

Tutorial 18: TensorFlow Lite - Deploy ML on Mobile

Table of Contents

  • Introduction
  • Prerequisites
  • Understanding TensorFlow Lite
  • Model Conversion from TensorFlow
  • Model Conversion from PyTorch
  • Post-Training Quantization
  • Quantization-Aware Training (QAT)
  • Model Optimization Techniques
  • Android Deployment
  • iOS Deployment with CoreML Bridge
  • Edge TPU Deployment
  • Benchmarking and Profiling
  • Best Practices
  • Conclusion
  • Introduction

    Deploying machine learning models on mobile and edge devices opens up possibilities that cloud-only inference cannot match: offline capability, reduced latency, improved privacy, and lower operational costs. TensorFlow Lite (TFLite) is Google's framework for running ML models on mobile phones, embedded devices, and edge hardware.

    This tutorial covers the complete workflow from converting trained models to the TFLite format, applying quantization to reduce model size and improve speed, deploying on Android and iOS, running on Edge TPUs, and benchmarking performance. Whether you are building a real-time image classifier, an on-device NLP model, or a sensor data pipeline, these techniques apply directly.

    Prerequisites

    • Python 3.9+ with TensorFlow 2.15+
    • Android Studio (for Android deployment)
    • Xcode 15+ (for iOS deployment)
    • Basic understanding of neural network architectures
    • A trained model (we will create one for demonstration)

    # Install required packages
    

    pip install tensorflow tflite-support onnx onnx-tf torch

    import tensorflow as tf

    import numpy as np

    print(f"TensorFlow version: {tf.version}")

    Understanding TensorFlow Lite

    TFLite uses a different model format (.tflite) from standard TensorFlow (.pb, SavedModel). The TFLite format is a FlatBuffer-based schema optimized for:

    • Small binary size - FlatBuffers are compact and zero-copy
    • Fast initialization - no parsing overhead, memory-mapped
    • Reduced memory footprint - designed for constrained devices
    • Hardware acceleration - supports GPU delegates, NNAPI, Edge TPU

    The conversion pipeline looks like this:

    TensorFlow Model / PyTorch Model
    

    |

    v

    TFLite Converter (with optional optimizations)

    |

    v

    .tflite file

    |

    v

    TFLite Interpreter (on device)

    Model Conversion from TensorFlow

    Converting a Keras Model

    import tensorflow as tf
    

    from tensorflow import keras

    Create and train a sample image classification model

    def buildmodel():

    model = keras.Sequential([

    keras.layers.Conv2D(32, (3, 3), activation='relu',

    inputshape=(224, 224, 3)),

    keras.layers.MaxPooling2D((2, 2)),

    keras.layers.Conv2D(64, (3, 3), activation='relu'),

    keras.layers.MaxPooling2D((2, 2)),

    keras.layers.Conv2D(128, (3, 3), activation='relu'),

    keras.layers.GlobalAveragePooling2D(),

    keras.layers.Dense(256, activation='relu'),

    keras.layers.Dropout(0.5),

    keras.layers.Dense(10, activation='softmax')

    ])

    model.compile(

    optimizer='adam',

    loss='sparsecategoricalcrossentropy',

    metrics=['accuracy']

    )

    return model

    model = buildmodel()

    Method 1: Convert from Keras model directly

    converter = tf.lite.TFLiteConverter.fromkerasmodel(model)

    tflitemodel = converter.convert()

    Save the model

    with open('model.tflite', 'wb') as f:

    f.write(tflitemodel)

    print(f"Model size: {len(tflitemodel) / 1024:.1f} KB")

    Converting from SavedModel

    # Save as SavedModel first
    

    model.save('savedmodeldir')

    Convert from SavedModel

    converter = tf.lite.TFLiteConverter.fromsavedmodel('savedmodeldir')

    tflitemodel = converter.convert()

    with open('modelfromsaved.tflite', 'wb') as f:

    f.write(tflitemodel)

    Setting Input/Output Details

    # Convert with explicit input shape and signature
    

    converter = tf.lite.TFLiteConverter.fromkerasmodel(model)

    Set input shape for dynamic batch size models

    converter.inputshape = {model.input.name: [1, 224, 224, 3]}

    tflitemodel = converter.convert()

    Verify input/output details

    interpreter = tf.lite.Interpreter(modelcontent=tflitemodel)

    interpreter.allocatetensors()

    inputdetails = interpreter.getinputdetails()

    outputdetails = interpreter.getoutputdetails()

    print("Input details:")

    for inp in inputdetails:

    print(f" Name: {inp['name']}, Shape: {inp['shape']}, "

    f"Type: {inp['dtype']}")

    print("Output details:")

    for out in outputdetails:

    print(f" Name: {out['name']}, Shape: {out['shape']}, "

    f"Type: {out['dtype']}")

    Model Conversion from PyTorch

    PyTorch models must go through ONNX as an intermediate format before converting to TFLite.

    import torch
    

    import torch.nn as nn

    Define a PyTorch model

    class PyTorchClassifier(nn.Module):

    def init(self, numclasses=10):

    super().init()

    self.features = nn.Sequential(

    nn.Conv2d(3, 32, 3, padding=1),

    nn.ReLU(),

    nn.MaxPool2d(2),

    nn.Conv2d(32, 64, 3, padding=1),

    nn.ReLU(),

    nn.AdaptiveAvgPool2d(1),

    )

    self.classifier = nn.Sequential(

    nn.Flatten(),

    nn.Linear(64, 128),

    nn.ReLU(),

    nn.Linear(128, numclasses),

    )

    def forward(self, x):

    x = self.features(x)

    x = self.classifier(x)

    return x

    Step 1: Export PyTorch to ONNX

    pytorchmodel = PyTorchClassifier()

    pytorchmodel.eval()

    dummyinput = torch.randn(1, 3, 224, 224)

    torch.onnx.export(

    pytorchmodel,

    dummyinput,

    "model.onnx",

    inputnames=['input'],

    outputnames=['output'],

    dynamicaxes={'input': {0: 'batchsize'},

    'output': {0: 'batchsize'}},

    opsetversion=13

    )

    Step 2: Convert ONNX to TensorFlow SavedModel

    import onnx

    from onnxtf.backend import prepare

    onnxmodel = onnx.load("model.onnx")

    tfrep = prepare(onnxmodel)

    tfrep.exportgraph("pytorchsavedmodel")

    Step 3: Convert SavedModel to TFLite

    converter = tf.lite.TFLiteConverter.fromsavedmodel("pytorchsavedmodel")

    tflitemodel = converter.convert()

    with open("pytorchmodel.tflite", "wb") as f:

    f.write(tflitemodel)

    print(f"PyTorch -> TFLite model size: {len(tflitemodel) / 1024:.1f} KB")

    Post-Training Quantization

    Quantization reduces model size and increases inference speed by converting 32-bit floating-point weights to lower-precision representations.

    Dynamic Range Quantization

    # Dynamic range quantization (simplest, good default)
    

    converter = tf.lite.TFLiteConverter.fromkerasmodel(model)

    converter.optimizations = [tf.lite.Optimize.DEFAULT]

    tflitequantmodel = converter.convert()

    with open('modeldynamicquant.tflite', 'wb') as f:

    f.write(tflitequantmodel)

    originalsize = len(tflitemodel)

    quantsize = len(tflitequantmodel)

    print(f"Original: {originalsize / 1024:.1f} KB")

    print(f"Quantized: {quantsize / 1024:.1f} KB")

    print(f"Reduction: {(1 - quantsize / originalsize) 100:.1f}%")

    Full Integer Quantization (INT8)

    # Full integer quantization requires a representative dataset
    

    def representativedataset():

    """Generate representative data for calibration."""

    for in range(100):

    data = np.random.rand(1, 224, 224, 3).astype(np.float32)

    yield [data]

    converter = tf.lite.TFLiteConverter.fromkerasmodel(model)

    converter.optimizations = [tf.lite.Optimize.DEFAULT]

    converter.representativedataset = representativedataset

    Force full integer quantization

    converter.targetspec.supportedops = [

    tf.lite.OpsSet.TFLITEBUILTINSINT8

    ]

    converter.inferenceinputtype = tf.uint8

    converter.inferenceoutputtype = tf.uint8

    tfliteint8model = converter.convert()

    with open('modelint8.tflite', 'wb') as f:

    f.write(tfliteint8model)

    print(f"INT8 model size: {len(tfliteint8model) / 1024:.1f} KB")

    Float16 Quantization

    # Float16 quantization - good balance of size and accuracy
    

    converter = tf.lite.TFLiteConverter.fromkerasmodel(model)

    converter.optimizations = [tf.lite.Optimize.DEFAULT]

    converter.targetspec.supportedtypes = [tf.float16]

    tflitefp16model = converter.convert()

    with open('modelfp16.tflite', 'wb') as f:

    f.write(tflitefp16model)

    print(f"FP16 model size: {len(tflitefp16model) / 1024:.1f} KB")

    Quantization-Aware Training (QAT)

    QAT simulates quantization during training, allowing the model to learn to compensate for quantization error. This typically produces better accuracy than post-training quantization.

    import tensorflowmodeloptimization as tfmot
    
    

    Start with a pre-trained model

    basemodel = buildmodel()

    basemodel.fit(traindata, trainlabels, epochs=10) # Pre-train first

    Apply quantization-aware training

    quantizemodel = tfmot.quantization.keras.quantizemodel

    qatmodel = quantizemodel(basemodel)

    qatmodel.compile(

    optimizer=keras.optimizers.Adam(learningrate=1e-4),

    loss='sparsecategoricalcrossentropy',

    metrics=['accuracy']

    )

    print("QAT Model Summary:")

    qatmodel.summary()

    Fine-tune with QAT (use lower learning rate, fewer epochs)

    qatmodel.fit(traindata, trainlabels, epochs=3, validationsplit=0.1)

    Convert QAT model to TFLite

    converter = tf.lite.TFLiteConverter.fromkerasmodel(qatmodel)

    converter.optimizations = [tf.lite.Optimize.DEFAULT]

    qattflitemodel = converter.convert()

    with open('modelqat.tflite', 'wb') as f:

    f.write(qattflitemodel)

    print(f"QAT model size: {len(qattflitemodel) / 1024:.1f} KB")

    Selective Quantization

    # Quantize only specific layers
    

    def applyquantizationtodense(layer):

    if isinstance(layer, keras.layers.Dense):

    return tfmot.quantization.keras.quantizeannotatelayer(layer)

    return layer

    annotatedmodel = keras.models.clonemodel(

    basemodel,

    clonefunction=applyquantizationtodense

    )

    selectiveqatmodel = tfmot.quantization.keras.quantizeapply(

    annotatedmodel

    )

    selectiveqatmodel.compile(

    optimizer='adam',

    loss='sparsecategoricalcrossentropy',

    metrics=['accuracy']

    )

    Model Optimization Techniques

    Pruning

    import tensorflowmodeloptimization as tfmot
    
    

    Apply pruning to reduce model complexity

    prunelowmagnitude = tfmot.sparsity.keras.prunelowmagnitude

    pruningparams = {

    'pruningschedule': tfmot.sparsity.keras.PolynomialDecay(

    initialsparsity=0.30,

    finalsparsity=0.80,

    beginstep=0,

    endstep=1000

    )

    }

    prunedmodel = prunelowmagnitude(basemodel, pruningparams)

    prunedmodel.compile(

    optimizer='adam',

    loss='sparsecategoricalcrossentropy',

    metrics=['accuracy']

    )

    Train with pruning callbacks

    callbacks = [tfmot.sparsity.keras.UpdatePruningStep()]

    prunedmodel.fit(traindata, trainlabels, epochs=5,

    callbacks=callbacks)

    Strip pruning wrappers and convert

    strippedmodel = tfmot.sparsity.keras.strippruning(prunedmodel)

    converter = tf.lite.TFLiteConverter.fromkerasmodel(strippedmodel)

    converter.optimizations = [tf.lite.Optimize.DEFAULT]

    prunedtflite = converter.convert()

    print(f"Pruned model size: {len(prunedtflite) / 1024:.1f} KB")

    Android Deployment

    Gradle Setup

    // app/build.gradle
    

    dependencies {

    implementation 'org.tensorflow:tensorflow-lite:2.15.0'

    implementation 'org.tensorflow:tensorflow-lite-support:0.4.4'

    implementation 'org.tensorflow:tensorflow-lite-gpu:2.15.0'

    }

    android {

    aaptOptions {

    noCompress "tflite"

    }

    }

    Android Inference Code (Kotlin)

    import org.tensorflow.lite.Interpreter
    

    import org.tensorflow.lite.gpu.GpuDelegate

    import java.io.FileInputStream

    import java.nio.MappedByteBuffer

    import java.nio.channels.FileChannel

    class ImageClassifier(private val context: Context) {

    private var interpreter: Interpreter? = null

    private val inputSize = 224

    private val numClasses = 10

    private val labels = listOf(

    "airplane", "automobile", "bird", "cat", "deer",

    "dog", "frog", "horse", "ship", "truck"

    )

    fun initialize(useGpu: Boolean = false) {

    val options = Interpreter.Options()

    if (useGpu) {

    val gpuDelegate = GpuDelegate()

    options.addDelegate(gpuDelegate)

    }

    options.setNumThreads(4)

    val model = loadModelFile("modelint8.tflite")

    interpreter = Interpreter(model, options)

    }

    private fun loadModelFile(filename: String): MappedByteBuffer {

    val assetFileDescriptor = context.assets.openFd(filename)

    val inputStream = FileInputStream(assetFileDescriptor.fileDescriptor)

    val fileChannel = inputStream.channel

    val startOffset = assetFileDescriptor.startOffset

    val declaredLength = assetFileDescriptor.declaredLength

    return fileChannel.map(

    FileChannel.MapMode.READONLY,

    startOffset,

    declaredLength

    )

    }

    fun classify(bitmap: Bitmap): List> {

    val resized = Bitmap.createScaledBitmap(

    bitmap, inputSize, inputSize, true

    )

    // Prepare input tensor

    val input = Array(1) {

    Array(inputSize) {

    Array(inputSize) {

    FloatArray(3)

    }

    }

    }

    for (y in 0 until inputSize) {

    for (x in 0 until inputSize) {

    val pixel = resized.getPixel(x, y)

    input[0][y][x][0] = ((pixel shr 16) and 0xFF) / 255.0f

    input[0][y][x][1] = ((pixel shr 8) and 0xFF) / 255.0f

    input[0][y][x][2] = (pixel and 0xFF) / 255.0f

    }

    }

    // Run inference

    val output = Array(1) { FloatArray(numClasses) }

    interpreter?.run(input, output)

    // Return sorted results

    return labels.zip(output[0].toList())

    .sortedByDescending { it.second }

    }

    fun close() {

    interpreter?.close()

    }

    }

    // Usage in Activity

    class MainActivity : AppCompatActivity() {

    private lateinit var classifier: ImageClassifier

    override fun onCreate(savedInstanceState: Bundle?) {

    super.onCreate(savedInstanceState)

    classifier = ImageClassifier(this)

    classifier.initialize(useGpu = true)

    }

    private fun classifyImage(bitmap: Bitmap) {

    val results = classifier.classify(bitmap)

    results.take(3).forEach { (label, confidence) ->

    Log.d("TFLite", "$label: ${confidence 100}%")

    }

    }

    override fun onDestroy() {

    super.onDestroy()

    classifier.close()

    }

    }

    iOS Deployment with CoreML Bridge

    Converting TFLite to CoreML

    # Convert TFLite model to CoreML for native iOS performance
    

    import coremltools as ct

    Option 1: Convert from TensorFlow directly to CoreML

    coremlmodel = ct.convert(

    model,

    inputs=[ct.ImageType(

    name="input",

    shape=(1, 224, 224, 3),

    scale=1/255.0

    )],

    classifierconfig=ct.ClassifierConfig(

    ["airplane", "automobile", "bird", "cat", "deer",

    "dog", "frog", "horse", "ship", "truck"]

    )

    )

    coremlmodel.save("ImageClassifier.mlmodel")

    Option 2: Use TFLite directly on iOS with TensorFlowLiteSwift

    iOS Swift Code with TFLite

    import TensorFlowLite
    
    

    class ImageClassifier {

    private var interpreter: Interpreter?

    private let inputSize = 224

    init() {

    guard let modelPath = Bundle.main.path(

    forResource: "modelint8",

    ofType: "tflite"

    ) else {

    fatalError("Model not found")

    }

    var options = Interpreter.Options()

    options.threadCount = 4

    // Enable GPU delegate

    var gpuOptions = MetalDelegate.Options()

    gpuOptions.isPrecisionLossAllowed = true

    let metalDelegate = MetalDelegate(options: gpuOptions)

    do {

    interpreter = try Interpreter(

    modelPath: modelPath,

    options: options,

    delegates: [metalDelegate]

    )

    try interpreter?.allocateTensors()

    } catch {

    print("Failed to initialize: \(error)")

    }

    }

    func classify(pixelBuffer: CVPixelBuffer) -> [(String, Float)]? {

    guard let interpreter = interpreter else { return nil }

    do {

    let inputTensor = try interpreter.input(at: 0)

    let inputData = preprocessImage(

    pixelBuffer,

    width: inputSize,

    height: inputSize

    )

    try interpreter.copy(inputData, toInputAt: 0)

    try interpreter.invoke()

    let outputTensor = try interpreter.output(at: 0)

    let results = parseOutput(outputTensor.data)

    return results

    } catch {

    print("Inference error: \(error)")

    return nil

    }

    }

    }

    Edge TPU Deployment

    The Google Coral Edge TPU provides hardware acceleration for INT8 TFLite models.

    # Compile model for Edge TPU
    

    First, ensure you have a fully INT8 quantized model

    Install Edge TPU compiler:

    curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -

    echo "deb https://packages.cloud.google.com/apt coral-edgetpu-stable main" |

    sudo tee /etc/apt/sources.list.d/coral-edgetpu.list

    sudo apt update && sudo apt install edgetpu-compiler

    Compile: edgetpucompiler modelint8.tflite

    Run inference on Edge TPU

    from pycoral.adapters import common

    from pycoral.adapters import classify

    from pycoral.utils.edgetpu import makeinterpreter

    def runedgetpuinference(modelpath, image):

    """Run inference on a Coral Edge TPU."""

    # Create interpreter with Edge TPU delegate

    interpreter = makeinterpreter(modelpath)

    interpreter.allocatetensors()

    # Get input details

    inputdetails = interpreter.getinputdetails()[0]

    inputshape = inputdetails['shape']

    # Preprocess image

    imageresized = image.resize(

    (inputshape[2], inputshape[1])

    )

    inputdata = np.expanddims(imageresized, axis=0)

    # Handle quantization

    if inputdetails['dtype'] == np.uint8:

    inputscale, inputzeropoint = inputdetails['quantization']

    inputdata = (inputdata / inputscale + inputzeropoint)

    inputdata = inputdata.astype(np.uint8)

    # Run inference

    common.setinput(interpreter, inputdata)

    interpreter.invoke()

    # Get results

    classes = classify.getclasses(interpreter, topk=5)

    return classes

    Benchmark Edge TPU vs CPU

    import time

    def benchmark(interpreter, inputdata, numruns=100):

    """Benchmark inference latency."""

    # Warmup

    for in range(10):

    interpreter.invoke()

    times = []

    for in range(numruns):

    start = time.perfcounter()

    common.setinput(interpreter, inputdata)

    interpreter.invoke()

    elapsed = (time.perfcounter() - start) 1000

    times.append(elapsed)

    return {

    'meanms': np.mean(times),

    'medianms': np.median(times),

    'p95ms': np.percentile(times, 95),

    'p99ms': np.percentile(times, 99),

    }

    Benchmarking and Profiling

    Python-Based Benchmarking

    import time
    

    import numpy as np

    def benchmarktflitemodel(modelpath, inputshape,

    numwarmup=10, numruns=100):

    """Comprehensive benchmark for a TFLite model."""

    import os

    modelsize = os.path.getsize(modelpath)

    interpreter = tf.lite.Interpreter(modelpath=modelpath)

    interpreter.allocatetensors()

    inputdetails = interpreter.getinputdetails()

    outputdetails = interpreter.getoutputdetails()

    # Generate random input

    inputdata = np.random.rand(inputshape).astype(

    inputdetails[0]['dtype']

    )

    # Warmup

    for in range(numwarmup):

    interpreter.settensor(inputdetails[0]['index'], inputdata)

    interpreter.invoke()

    # Benchmark

    latencies = []

    for in range(numruns):

    start = time.perfcounter()

    interpreter.settensor(inputdetails[0]['index'], inputdata)

    interpreter.invoke()

    end = time.perfcounter()

    latencies.append((end - start) 1000)

    results = {

    'modelsizekb': modelsize / 1024,

    'meanlatencyms': np.mean(latencies),

    'medianlatencyms': np.median(latencies),

    'p95latencyms': np.percentile(latencies, 95),

    'p99latencyms': np.percentile(latencies, 99),

    'minlatencyms': np.min(latencies),

    'maxlatencyms': np.max(latencies),

    'throughputfps': 1000.0 / np.mean(latencies),

    }

    return results

    Compare all model variants

    models = {

    'Original (FP32)': 'model.tflite',

    'Dynamic Quant': 'modeldynamicquant.tflite',

    'INT8': 'modelint8.tflite',

    'FP16': 'modelfp16.tflite',

    'QAT': 'modelqat.tflite',

    }

    print(f"{'Model':<20} {'Size (KB)':<12} {'Latency (ms)':<14} {'FPS':<8}")

    print("-" 54)

    for name, path in models.items():

    try:

    results = benchmarktflitemodel(

    path, inputshape=(1, 224, 224, 3)

    )

    print(f"{name:<20} {results['modelsizekb']:<12.1f} "

    f"{results['meanlatencyms']:<14.2f} "

    f"{results['throughputfps']:<8.1f}")

    except Exception as e:

    print(f"{name:<20} Error: {e}")

    Using TFLite Benchmark Tool

    # Download the benchmark tool
    

    Android:

    adb push benchmarkmodel /data/local/tmp/

    adb push model.tflite /data/local/tmp/

    Run benchmark on Android device

    adb shell /data/local/tmp/benchmarkmodel \

    --graph=/data/local/tmp/model.tflite \

    --numthreads=4 \

    --numruns=50 \

    --warmupruns=10 \

    --usegpu=true

    Best Practices

  • Always benchmark before and after quantization. Measure both accuracy and latency. A 0.5% accuracy drop with 4x speedup is usually worth it.
  • Use INT8 quantization for Edge TPU and NNAPI. These hardware accelerators require integer models for maximum performance.
  • Prefer QAT over post-training quantization when accuracy degradation is unacceptable. QAT adds 2-3 epochs of training but typically recovers most lost accuracy.
  • Test on actual target devices. Desktop benchmarks do not reflect mobile performance. ARM CPUs, mobile GPUs, and NPUs have very different characteristics.
  • Use the GPU delegate on Android (OpenGL/OpenCL) and the Metal delegate on iOS for GPU acceleration. Not all ops are supported, so test thoroughly.
  • Profile memory usage on mobile devices. Large models can cause OOM crashes. Keep total model + runtime memory under 200MB for broad device compatibility.
  • Consider model architecture from the start. MobileNet, EfficientNet-Lite, and similar architectures are designed for mobile deployment and convert cleanly to TFLite.
  • Use metadata in your TFLite models. The TFLite Support library uses metadata to automate pre/post-processing, reducing errors in deployment code.
  • Conclusion

    TensorFlow Lite bridges the gap between training powerful models and running them where they matter most: on user devices. The conversion pipeline from TensorFlow and PyTorch is well-established, quantization techniques can reduce model size by 75% with minimal accuracy loss, and deployment paths exist for Android, iOS, and edge hardware. By combining post-training quantization for quick wins with QAT for maximum accuracy retention, and by benchmarking rigorously on target devices, you can deliver ML-powered features that work offline, respond instantly, and respect user privacy.

    Related Articles

    OpenVINO: Running AI Models Fast on Intel CPUs, iGPUs, and NPUs

    OpenVINO: Menjalankan Model AI dengan Cepat di CPU, iGPU, dan NPU Intel Halo temen-temen, di tutorial kali ini aku mau n...

    TensorRT-LLM: Squeezing Maximum Throughput Out of NVIDIA GPUs for LLM Inference

    TensorRT-LLM: Memeras Throughput Maksimal dari GPU NVIDIA untuk Inference LLM Halo temen-temen, kali ini kita bahas sala...

    llama.cpp and GGUF Quantization: Local LLM Deployment

    llama.cpp dan GGUF Quantization: Deploy LLM Secara Lokal Pendahuluan Menjalankan Large Language Model (LLM) secara lokal...

    PaddleOCR: High Accuracy Text Extraction from Images and Documents

    PaddleOCR: Ekstraksi Teks dari Gambar dan Dokumen dengan Akurasi Tinggi Halo temen-temen, kali ini kita bahas salah satu...