AI을_통한_라벨링 - boostcampwm-2024/and04-Nature-Album GitHub Wiki
우선 기존 팀원과의 회의에서 AI 사용과 관련해서 2가지 방법이 제시되었다.
첫번재는 Tensorflow Lite를 사용하는 것이고, 두번째는 Gemini AI를 사용하는 것이었다.
우선 Tensorflow Lite를 통해 구현해보기로 결정했다.
위 공식문서에서 코코 데이터셋을 사용하여 객체인식을 구현했다.
class ObjectDetectorHelper(context: Context, modelPath: String) {
private val detector: ObjectDetector
init {
val modelFile = copyAssetToInternalStorage(context, "EfficientDet.tflite", "EfficientDet.tflite")
val options = ObjectDetector.ObjectDetectorOptions.builder()
.setMaxResults(5) // 최대 5개의 결과만 반환
.setScoreThreshold(0.5f) // 50% 이상의 신뢰도만 반환
.build()
detector = ObjectDetector.createFromFileAndOptions(modelFile, options)
}
fun detectObjects(bitmap: Bitmap): List<Detection> {
val tensorImage = TensorImage.fromBitmap(bitmap)
return detector.detect(tensorImage)
}
}
fun copyAssetToInternalStorage(context: Context, assetFileName: String, outputFileName: String): File {
val outputFile = File(context.filesDir, outputFileName)
if (!outputFile.exists()) {
context.assets.open(assetFileName).use { inputStream ->
outputFile.outputStream().use { outputStream ->
inputStream.copyTo(outputStream)
}
}
}
return outputFile
}
코드는 정말 간단했고, bitmap을 통해 detector.detect
메서드를 호출하면 끝이다.


처음에는 고양이, 강아지, 새 같은 간단한 이미지를 통해 테스트 했을 땐 70~ 80%의 정확도를 보여주었다.
하지만 위의 이미지 같이 사자, 나비, 장수풍뎅이 처럼 조금만 복잡해져도 정확도가 매우 떨어졌다.
위 이미지의 사자를 여러번 돌렸을 때, 꼬끼리, 말 같은 탐지만 되는 것을 보아하니 코코 데이터에는 사자가 없는 듯 했다.
그렇기에 이렇게 정확도가 떨어지는 것을 사용할 수 없다고 생각하여 두 번째 방법인 Gemini AI를 사용하기로 했다.
Google AI for Developers Gemini API | Google AI for Developers
Google AI for Developers Gemini API 빠른 시작 | Google AI for Developers
Gemini API를 사용하기 위해 REST API를 사용하는 방법과 REST API없이 Google AI SDK 를 통해 사용하는 두개의 방법이 존재했다.
복잡한 REST API 보다는, 클라이언트에서 바로 사용 가능한 Google AI SDK를 사용하자는 회의를 통해 후자의방식으로 진행하고자 했다.
Android Developers Google AI 클라이언트 SDK | Android Developers


사용하려 공식문서를 확인했을 때 아래와 같은 주의사항이 있었고, 안드로이드에서 Gemini API를 직접 호출하려면 Google SDK가 아닌 Android용 Vertex AI 사용하라는 안내하고 있었다.
Firebase Google AI SDK 대신 Vertex AI SDK를 사용하도록 마이그레이션
어떤 이유로 Vertex AI를 사용하라고 권장했던 걸까?
이는 위 공식문서에서 확인할 수 있었다.
우선 가장 큰 특징은 API KEY 노출 여부인 것 같았다.
// Google AI
val generativeModel = GenerativeModel(modelName = "MODEL_NAME",
// Access your API key as a Build Configuration variable
apiKey = BuildConfig.apiKey
)
//Vertext AI in Firebase
val generativeModel = Firebase.vertexAI.generativeModel("MODEL_NAME")
위와 같이 키를 사용하지 않고도 Gemini AI를 사용할 수 있다.

공식문서에도 나와있듯이 API 키를 앱에 직접 삽입하는 거는 악위적인 행위자에게 노출될 수 있기에 적극 권장하고 있다. Vertex AI Gemini API는 Google AI Gemini API와 같은 API 키가 아닌 Google Cloud IAM에 의해 승인되기에 더 안전하게 호출할 수 있다고 한다.
이 외에도 아래와 같은 장점이 있다고 한다.

Gemini API에게 이미지를 넘겨주기 위하여 첫 시도로는 Bitmap을 Base64로 변환하는 것이었다.

하지만 위와 같은 답변을 받았다…
그럼 다른 방법으로는 uri를 보내는 것인데, Uri를 보내기 위해서는 서버에 저장 후 그 URI를 가져오는 방법을 선택해야 한다. 하지만 우리 앱은 RoomDB의 이미지를 uri로 가져오는 것이기에 이 uri를 사용할 수 없었다.
또한, uri를 통해 Gemini AI를 사용해봤는데 아래와 같은 답변을 받았다.

즉, 다른 방법을 선택해야 했는데 찾을 수 없었다.
시간을 지체할 수 없어 내 상황을 팀원에게 공유했고, 팀원들과 함께 서칭한 결과 답을 찾을 수 있었다.
처음에는 문자열 형태로만 보내야 한다고 생각했는데 bitmap 자체를 보낼 수 있었던 것이다…
image
메서드 안에 비트맵을 넣고 실행한 결과 정확한 결과를 얻을 수 있었다.
error.mov
사진 찍고 Gemini AI를 통해 이미지 식별하는 과정이 여러번 일어나는 버그가 발생했다.
위 영상 뒤쪽에 보이다 시피 Label이 계속 바뀌고 있는 것을 볼 수 있었고, Log와 Inspector를 통해 여러번 리컴포지션되고 있는 버그라는 것을 확인했다.
우선 UiState
와 UiState.Sucess
됐을 때 저장하는 상태를 합치는 작업을 진행했다.
그 후 UiState.Idle
인 상태에만 Gemini AI 를 호출하도록 변경하였고, UiState.Loading
상태일 땐, 로딩 애니메이션을 UiState.Sucess
일때는 Success 상태의 데이터를 하위 컴포저블에게 넘겨주는 방식으로 해결했다.