Почему в модели MobileNet V2 (mobilenet_v2_1.4_224.tflite) вероятности всегда одинаковы?Android

Форум для тех, кто программирует под Android
Ответить Пред. темаСлед. тема
Anonymous
 Почему в модели MobileNet V2 (mobilenet_v2_1.4_224.tflite) вероятности всегда одинаковы?

Сообщение Anonymous »

Я реализую модель TensorFlow Lite в своем приложении для Android, используя модель mobilenet_v2_1.4_224.tflite, которую я скачал из репозитория TensorFlow GitHub:
MobileNet из TensorFlow Models
Приложение работает следующим образом:
  • Я делаю снимок с помощью камеры и сохраняю его как временный файл.
  • Затем размер изображения изменяется до 224x224 пикселей и нормализуется в соответствии с этапами предварительной обработки MobileNet (вычитание 127,5 и деление на 127,5).
  • Наконец, нормализованное изображение преобразуется в ByteBuffer и передается модели для вывода.
Пока модель работает без каких-либо исключений, вероятности возвращаемые значения всегда одинаковы для всех классов, независимо от входного изображения. Например, вероятность для каждого класса постоянно близка к нулю или равномерна, как будто модель не реагирует на входные данные.
Полная реализация кода:< /p>
MainActivity.kt

Код: Выделить всё

package com.example.myapplication

import android.Manifest
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.net.Uri
import android.os.Bundle
import android.util.Log
import android.widget.Button
import android.widget.FrameLayout
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.content.ContextCompat
import androidx.core.content.FileProvider
import java.io.File
import java.io.InputStream
import java.nio.ByteBuffer
import java.text.SimpleDateFormat
import java.util.*

class MainActivity : ComponentActivity() {
private lateinit var photoUri: Uri
private lateinit var mobileNetClassifier: MobileNetClassifier

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mobileNetClassifier = MobileNetClassifier(this)

// Layout programmatically
val layout = FrameLayout(this).apply {
id = FrameLayout.generateViewId()
}
setContentView(layout)

val button = Button(this).apply {
text = "Take a Photo"
setOnClickListener { checkPermissionsAndOpenCamera() }
}
layout.addView(button)

// Align button in the center
val params = FrameLayout.LayoutParams(
FrameLayout.LayoutParams.WRAP_CONTENT,
FrameLayout.LayoutParams.WRAP_CONTENT
).apply {
gravity = android.view.Gravity.CENTER
}
button.layoutParams = params
}

private fun analyzePhoto(photoUri: Uri) {
val inputStream: InputStream? = contentResolver.openInputStream(photoUri)
val bitmap = BitmapFactory.decodeStream(inputStream)
inputStream?.close()

// Convert the image to ByteBuffer
val byteBuffer = convertBitmapToByteBuffer(bitmap)

// Get the prediction
val result = mobileNetClassifier.classifyImage(byteBuffer)

// Display the result
Toast.makeText(this, "Result: $result", Toast.LENGTH_LONG).show()
}

private fun convertBitmapToByteBuffer(bitmap: Bitmap): ByteBuffer {
val IMAGE_MEAN = 127.5f
val IMAGE_STD = 127.5f
val IMAGE_SIZE_X = 224
val IMAGE_SIZE_Y = 224
val DIM_PIXEL_SIZE = 3
val NUM_BYTES_PER_CHANNEL = 4 // Float size

// Resize bitmap to match model input size
val resizedBitmap = Bitmap.createScaledBitmap(bitmap, IMAGE_SIZE_X, IMAGE_SIZE_Y, false)

val intValues = IntArray(IMAGE_SIZE_X * IMAGE_SIZE_Y)
resizedBitmap.getPixels(intValues, 0, resizedBitmap.width, 0, 0, resizedBitmap.width, resizedBitmap.height)

val byteBuffer = ByteBuffer.allocateDirect(
IMAGE_SIZE_X * IMAGE_SIZE_Y * DIM_PIXEL_SIZE * NUM_BYTES_PER_CHANNEL
)
byteBuffer.order(ByteOrder.nativeOrder())
byteBuffer.rewind()

// Normalize pixel values
for (pixel in intValues) {
byteBuffer.putFloat(((pixel shr 16 and 0xFF) - IMAGE_MEAN) / IMAGE_STD) // Red
byteBuffer.putFloat(((pixel shr 8 and 0xFF) - IMAGE_MEAN) / IMAGE_STD)  // Green
byteBuffer.putFloat(((pixel and 0xFF) - IMAGE_MEAN) / IMAGE_STD)       // Blue
}
return byteBuffer
}

private fun checkPermissionsAndOpenCamera() {
when {
ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED -> {
openCamera()
}
else ->  {
requestPermissionLauncher.launch(Manifest.permission.CAMERA)
}
}
}

private val requestPermissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted: Boolean ->
if (isGranted) {
openCamera()
}
}

private val takePictureLauncher = registerForActivityResult(
ActivityResultContracts.TakePicture()
) { isSaved: Boolean ->
if (isSaved) {
analyzePhoto(photoUri)
}
}

private fun openCamera() {
val photoFile = createImageFile()
photoUri = FileProvider.getUriForFile(
this,
"${packageName}.provider",
photoFile
)
takePictureLauncher.launch(photoUri)
}

private fun createImageFile(): File {
val timestamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(Date())
val storageDir = getExternalFilesDir(null)
return File.createTempFile(
"JPEG_${timestamp}_",
".jpg",
storageDir
)
}
}
MobileNetClassifier.kt

Код: Выделить всё

package com.example.myapplication

import android.content.Context
import android.graphics.Bitmap
import android.util.Log
import org.tensorflow.lite.Interpreter
import org.tensorflow.lite.support.common.FileUtil
import java.io.InputStream
import java.nio.ByteBuffer
import java.nio.ByteOrder

class MobileNetClassifier(context: Context) {

private val interpreter: Interpreter
private val labels: List

init {
interpreter = loadModel(context, "mobilenet_v2_1.4_224.tflite")
labels = loadLabels(context)
Log.d("MobileNetClassifier", "Model and labels successfully loaded")
}

private fun loadModel(context: Context, modelFileName: String): Interpreter {
return try {
val model = FileUtil.loadMappedFile(context, modelFileName)
Interpreter(model)
} catch (e: Exception) {
Log.e("MobileNetClassifier", "Error loading model file: $modelFileName", e)
throw RuntimeException("Failed to load model", e)
}
}

private fun loadLabels(context: Context): List {
val labelsList = mutableListOf()
try {
val inputStream: InputStream = context.assets.open("labels.txt")
inputStream.bufferedReader().useLines { lines ->
lines.forEach { line ->
if (line.isNotBlank()) labelsList.add(line.trim())
}
}
} catch (e: Exception) {
Log.e("MobileNetClassifier", "Error loading labels", e)
throw RuntimeException("Failed to load labels", e)
}
return labelsList
}

fun classifyImage(byteBuffer: ByteBuffer): String {
val output = Array(1) { FloatArray(1001) }
interpreter.run(byteBuffer, output)
val probabilities = output[0]
val maxIndex = probabilities.indices.maxByOrNull { probabilities[it] }
return labels.getOrNull(maxIndex ?: -1) ?: "Unknown"
}
}
Сведения о проблеме:
Несмотря на соблюдение рекомендуемой предварительной обработки и использование допустимой модели .tflite, вероятности вывода идентичны. для всех входов. Может ли это быть проблема с предварительной обработкой или самим файлом модели?
Что я пробовал?
Проверено с помощью несколько изображений:
Я сделал разные фотографии с разным содержанием (например, объекты, пейзажи и т. д.), но вероятности классификации каждый раз остаются одинаковыми.
Проверил загрузку модели процесс:
Я убедился, что Модель mobilenet_v2_1.4_224.tflite была правильно загружена с использованием метода FileUtil.loadMappedFile TensorFlow Lite.
Проверенная обработка ввода:
Я проверил функцию ConvertBitmapToByteBuffer, чтобы убедиться, что нормализация пикселей (вычитание среднего значения) и деление по стандартному отклонению) реализовано правильно.
Записаны значения ByteBuffer:
Я зарегистрировал первые 10 значений входных данных ByteBuffer, отправленных в модель, чтобы убедиться, что они меняются между изображениями. Журналы показывают, что входной буфер действительно различен для каждого изображения.
Проверил выходные вероятности:
Я проверил выходные вероятности модели после вывода, и они всегда являются одинаково, независимо от входного изображения.
Чего я ожидал?
Я ожидал, что вероятности будут различаться в зависимости от содержание изображения. Поскольку MobileNet представляет собой предварительно обученную модель классификации изображений, она должна выдавать разные выходные данные для разных входных данных, особенно для таких разных фотографий.

Подробнее здесь: https://stackoverflow.com/questions/792 ... bilenet-v2
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «Android»