몇 주 전에 저는 Google의 Gemma 개발자 데이에 참석했습니다. Google이 Gemma라는 최신 LLM 모델의 기능, 이동성 및 개방성을 소개하는 날입니다.
이러한 모델은 Generative AI의 흥미롭고 새로운 단계를 제시합니다. 로컬 장치에 배포할 수 있을 만큼 작은 모델이면서 여전히 매력적이고 유용한 경험을 제공할 수 있습니다.
오랜만에 모바일 AI를 보다가 감동을 받으며 하루를 떠났습니다. 나는 Android 앱에서 이러한 모델을 시험해 보면 어떤 일이 일어나는지 확인하기로 결정했습니다.
젬마에게 쉽고도 참신한 도전을 주고 싶었습니다. Simon Says 게임을 플레이하고 있습니다.
규칙은 간단합니다. 한 명의 플레이어가 Simon이 됩니다. 그들의 역할은 다른 플레이어에게 수행할 작업을 제공하는 것입니다. Simon으로 플레이하는 플레이어는 작업을 주기 전에 "Simon이 말합니다"라고 말해야 합니다.
3개의 화면이 있는 앱을 만들었습니다. 젬마가 소통하고 임무를 줄 수 있는 진입 화면, 안내 화면, 채팅 화면입니다.
채팅 화면 구축 속도를 높이기 위해 Meyta Taliti 의 이 블로그 게시물이 매우 유용하다는 것을 알았습니다.
화면이 생성된 후 다음 작업은 Gemma를 통합하는 것이었습니다. 이를 위해 저는 MediaPipe라는 제가 배운 도구 세트에 의존했습니다.
MediaPipe 는 AI 모델을 Android, iOS 및 웹의 앱에 단순화하는 것을 목표로 하는 도구 모음입니다. MediaPipe를 사용하면 필요에 따라 다양한 선택이 가능합니다.
빠르게 시작하고 싶다면 MediaPipe는 AI 모델을 호출할 수 있는 작업 이라는 API를 제공합니다. 이러한 API는 비전, 텍스트 및 오디오와 같은 다양한 영역으로 구분됩니다.
MediaPipe는 또한 앱에 삽입할 수 있는 사전 학습된 모델 컬렉션을 제공합니다. 다시 말하지만 빠르게 시작하는 데 유용합니다.
좀 더 맞춤화된 것이 필요하고 처음부터 모델을 생성하고 싶지 않은 경우 MediaPipe는 Model Maker 라는 도구를 제공합니다. Model Maker는 전이 학습 이라는 프로세스를 사용하여 기존 기계 학습 모델을 재교육하고 새 데이터를 제공합니다. 이 접근 방식의 이점은 시간을 절약하고 새 모델을 생성하는 데 필요한 교육 데이터가 더 적다는 것입니다.
Model Maker도 이 과정을 통해 생성된 모델의 크기를 줄일 수 있습니다. 이 프로세스로 인해 모델이 기존 지식 중 일부를 "잊게" 된다는 점에 유의하세요.
MediaPipe의 마지막 도구는 사용자 정의 모델을 평가하고 조정하는 웹 애플리케이션인 MediaPipe Studio 입니다. 모델을 벤치마킹하고 배포 전에 모델이 얼마나 잘 작동하는지 이해하려는 경우 유용합니다.
필요에 따라 MediaPipe용 새로운 API인 LLM Interfence API를 활용하겠습니다. 이를 통해 우리는 Gemma와 통신하고 응답을 받을 수 있습니다.
MediaPipe를 사용하려면 먼저 이를 앱에 Gradle 종속성으로 추가해야 합니다.
implementation ("com.google.mediapipe:tasks-genai:0.10.11")
다음으로 LlmInference
의 인스턴스를 만듭니다. 이것은 Gemma와 통신하는 데 사용하는 개체입니다.
val llmInference = LlmInference.createFromOptions( context, LlmInference.LlmInferenceOptions.builder() .setModelPath("/data/local/tmp/llm/gemma-2b-it-cpu-int8.bin") .build() )
.setModelPath
사용하여 설정된 경로를 기록해 두는 것이 중요합니다. 이것은 Gemma 모델이 장치에 있는 위치입니다. 사용된 Gemma 모델이 gemma-2b
버전이라는 것도 중요합니다. 7b
버전은 아직 MediaPipe에서 지원되지 않습니다. 이것이 의미하는 바는 나중에 자세히 설명하겠습니다. 지금은 모델을 다운로드해 보겠습니다.
Kaggle 에서 Gemma를 다운로드할 수 있습니다. 데이터 과학자 및 기계 학습 전용 웹사이트입니다. 모델을 다운로드하려면 먼저 계정을 만들고 이용 약관에 동의해야 합니다. 여기에서 Gemma 페이지를 찾을 수 있습니다.
이 게시물을 따르고 있다면 TensorFlow Lite
탭에서 gemma-2b-it-cpu
버전의 모델만 다운로드하는 것을 기억하세요. gemma-2b-it-gpu
버전을 사용해보시면 스스로 해결하실 수 있습니다.
일단 모델을 다운로드 받습니다. Android Studio의 Device Explorer를 사용하여 .setModelPath
에 설정된 경로로 모델을 가져옵니다. 경로나 모델 이름을 변경한 경우 경로 이름을 업데이트해야 합니다.
모델을 가져온 후에는 .generateResponse
메소드를 사용하여 Gemma에 프롬프트를 전달할 수 있습니다. 다음은 Simon Says를 플레이하기 위해 Gemma에게 전달하는 프롬프트의 예입니다.
private const val SimonSaysPrompt = """ You are a Simon in a game of Simon Says. Your objective is to ask the player to perform tasks. For every task you give, you must prefix it with the words "Simon says". You must not ask the player to do anything that is dangerous, unethical or unlawful. Do not try to communicate with the player. Only ask the player to perform tasks. """ val gemmaResponse = llmInference.generateResponse(SimonSaysPrompt)
이전에 LLM을 사용해 본 적이 있고 프롬프트 엔지니어링에 대한 기본적인 이해가 있다면 이것이 익숙해 보일 것입니다. 실수를 범하지 않도록 프롬프트에 예방 지침을 포함시켰습니다. 우리는 Simon이 사용자에게 의심스러운 행동을 요구하는 것을 원하지 않습니다!
이것을 장치에서 실행하려고 하면 다음과 같은 일이 발생할 수 있습니다.
앱이 응답하고 결국 응답을 제공하는 데 시간이 조금 걸릴 수 있습니다.
앱이 충돌할 수 있습니다. Logcat을 보면 MediaPipe가 모델을 찾을 수 없다는 메시지가 표시됩니다. 올바른 모델 경로를 설정했습니까?
앱이 충돌할 수 있습니다. Logcat을 보면 많은 네이티브 코드 로깅과 메모리 재활용에 대한 정보를 볼 수 있습니다.
내 경험은 두 번째와 세 번째 범주에 속했습니다. 모든 것을 올바르게 설정하고 높은 사양의 물리적 장치를 사용했다면 여러분의 경험은 달라질 수 있습니다.
이런 에테르가 없다면. 에뮬레이터를 통해 사용 가능한 RAM의 양을 늘리는 또 다른 옵션이 있습니다.
사용 가능한 RAM 양을 늘리면 일반적으로 메모리 집약적 환경에 도움이 되는데, 메모리가 부족한 LLM이 왜 다를까요? 이를 위해 Android 에뮬레이터에서 사용하는 RAM의 양을 맞춤설정했습니다.
기존 에뮬레이터가 있는 경우 RAM 필드가 비활성화된 것을 볼 수 있습니다. 장치 관리자에서 오른쪽에 있는 세 개의 점을 클릭하여 사용 가능한 RAM 용량을 업데이트할 수 있습니다.
디스크에 표시를 클릭한 다음 텍스트 편집기에서 config.ini 및 hardware-qemu.ini 파일을 엽니다. 각 파일의 hw.ramSize
값을 변경합니다. 수행 방법에 대한 답변을 주신 이 스택 오버플로 질문에 감사드립니다.
또는 Android Studio의 Device Manager 로 이동하여 Create Virtual Device를 클릭한 다음 New Hardware Profile을 클릭하여 맞춤 에뮬레이터를 생성할 수 있습니다. 사용자 정의 옵션의 일부로 RAM 용량을 선택할 수 있습니다.
8GB RAM이 비교적 잘 작동하는 것으로 나타났습니다. 또한 22GB RAM으로 행운을 시험해 보았습니다. 기대한 만큼은 아니지만 속도 측면에서는 약간 더 나은 성능을 발휘합니다.
에뮬레이터의 나머지 부분이 유동적으로 실행되기 때문에 Gemma가 메모리에 로드될 때 어딘가에 병목 현상이 있는 것으로 생각됩니다. 아마도 어딘가에서 개선이 이루어질 수 있을 것입니다.
MediaPipe와 호환되는 Gemma 모델은 gemma-2b
버전입니다. 2b
20억 개의 매개변수를 나타냅니다. 모델이 작동하도록 함께 작동하는 매개변수의 양입니다.
이는 Gemma에게 질문할 때 서로 간의 연결과 추론을 제공하기 위해 훈련 중에 모델 내에 설정되는 값입니다.
70억 개의 매개변수를 사용하는 gemma-7b
컬렉션도 있습니다. 그러나 MediaPipe에서는 지원되지 않습니다. 어쩌면 언젠가!
LLM과 관련된 매개변수에 대해 더 자세히 이해하고 싶다면 이 페이지를 추천합니다.
20억 개의 매개변수 모델을 모바일 장치에 로드하고 실행한다는 것은 인상적인 성과입니다. 그래도 얼마나 잘 작동합니까? 알아 보자.
gemma-2b-it-cpu-int4
4비트 LLM입니다. 이는 모델에서 사용되는 각 매개변수의 메모리 크기가 4비트임을 의미합니다. 여기서의 이점은 모델의 전체 크기가 더 작다는 것입니다. 그러나 각 매개변수의 메모리 크기가 줄어들면 모델의 정확도와 품질도 영향을 받습니다.
그렇다면 gemma-2b-it-cpu-int4
어떻게 작동합니까? 솔직히 말하면 별로 좋지 않습니다. 다음은 위의 프롬프트를 사용하여 Simon Says를 플레이하고 일반적인 질문을 묻는 몇 가지 스크린샷입니다.
반응은 예상치 못했고 모델이 Simon Says 게임과 유사한 작업을 수행하도록 하는 것은 실망스러웠습니다. 그것은 다른 주제로 방향을 틀고 부정확한 정보에 환각을 일으킬 것입니다.
환각은 LLM이 거짓과 진실이 아닌 것을 마치 사실인 것처럼 말하는 현상입니다. 위의 예를 들어보면 시속 60마일로 60분 안에 화성까지 운전할 수 있다는 것은 사실이 아닙니다. 어쨌든 아직은 아닙니다. 😃
맥락 인식도 부족했다. 이는 내가 앞서 대화에서 언급한 내용을 기억하지 못한다는 의미입니다. 이는 모델의 크기가 제한되어 있기 때문일 수 있습니다.
얼마 후 나는 이 모델을 포기하고 더 큰 8비트 크기의 모델을 사용해 보기로 결정했습니다.
gemma-2b-it-cpu-int8
8비트 LLM입니다. 4비트 형제보다 크기가 더 큽니다. 이는 더 정확하고 더 나은 품질의 답변을 제공할 수 있음을 의미합니다. 그래서 여기서 결과는 어땠나요?
이 모델은 Simon Says의 아이디어를 파악하여 즉시 Simon의 역할을 맡을 수 있었습니다. 불행히도 상황 인식 부족으로 인해 어려움을 겪었습니다.
이에 대응하기 위해 저는 Simon Says의 규칙에 따라 모델을 다시 요청하고 이를 다른 프롬프트와 결합하여 작업을 제공하도록 요청해야 했습니다.
작업 프롬프트는 목록에서 무작위로 선택되어 Gemma에 전달되므로 요청되는 작업에 다양성이 부여됩니다.
다음은 무슨 일이 일어나고 있는지에 대한 예입니다.
private const val SimonSaysPrompt = """ You are a Simon in a game of Simon Says. Your objective is to ask the player to perform tasks. For every task you give, you must prefix it with the words "Simon says". You must not ask the player to do anything that is dangerous, unethical or unlawful. Do not try to communicate with the player. Only ask the player to perform tasks. """ private const val MovePrompt = SimonSaysPrompt + """ Give the player a task related to moving to a different position. """ private const val SingASongPrompt = SimonSaysPrompt + """ Ask the player to sing a song of their choice. """ private const val TakePhotoPrompt = SimonSaysPrompt + """ Give the player a task to take a photo of an object. """ private val prompts = listOf( MovePrompt, SingASongPrompt, TakePhotoPrompt ) val prompt = prompts.random() val response = llmInference.generateResponse(prompt)
때때로 성격에 맞지 않는 커브 볼 응답을 던집니다. 모델사이즈에 맞춰서 올려드립니다. 이것이 단지 v1이라는 점을 고려해 볼 가치가 있습니다.
프롬프트가 확정되면 프롬프트에만 의존하고 사용자 입력을 고려하지 않는 것이 유용하다는 것을 알았습니다. 모델에 상황 인식이 부족하기 때문에 사용자 입력으로 인해 Simon Says 재생이 중단되고 대신 입력에 응답하게 됩니다.
이런 약간의 속임수를 추가하는 것은 만족스러운 결과가 아니었지만 Gemma가 Simon Says를 계속 플레이해야 했습니다.
그러면 Gemma가 Android 기기에서 Simon Says를 플레이할 수 있나요? 나는 "일종의, 도움을 받아"라고 말할 것입니다.
나는 Gemma 2b의 4비트 버전이 좀 더 직관적으로 반응하는 것을 보고 싶습니다. 모든 요청에 대해 재요청할 필요가 없도록 Gemma 2b의 컨텍스트를 인식하고 사용자 입력에 주의를 기울이는 것도 도움이 될 것입니다.
단일 프롬프트만 필요한 간단한 요청의 경우. Gemma 2b가 이러한 작업을 편안하게 처리할 수 있다는 것을 알 수 있습니다.
또한 이 모델은 v1이라는 점을 명심할 가치가 있습니다. 모바일 운영 체제에서 실행하고 작업한다는 사실은 인상적인 성과입니다!
모바일 장치에서 LLM의 미래는 어떻습니까? 제가 보기에는 두 가지 장벽이 있습니다. 하드웨어 제한 사항 및 실제 사용 사례.
내 생각에 우리는 고급 장치만이 이러한 모델을 효과적으로 실행할 수 있는 시점에 와 있다고 생각합니다. 떠오르는 장치는 Tensor G 칩이 탑재된 Pixel 7 또는 Pixel 8 시리즈 휴대폰과 Neural Engine 칩이 탑재된 Apple iPhone입니다.
이런 종류의 사양이 중저가폰까지 필터링되는지 확인해야 합니다.
검색 증강 생성을 활용하는 장치 LLM에서 흥미로운 아이디어가 나올 수 있습니다. 답변을 제공할 때 LLM이 외부 데이터 소스와 통신하여 추가 컨텍스트를 검색하는 기술입니다. 이는 성능을 향상시키는 효과적인 방법이 될 수 있습니다.
두 번째 장벽은 실제 사용 사례를 찾는 것입니다. 장치가 인터넷을 통해 더 강력한 LLM과 통신할 수 있는 동안에는 이것이 제한적이라고 생각합니다. 예를 들어 OpenAI의 GPT-4는 1조 개가 넘는 매개변수를 지원한다는 소문이 있습니다!
하지만 이러한 모델을 모바일 장치에 배포하는 비용이 클라우드에서 호스팅하는 것보다 저렴해지는 때가 올 수 있습니다. 요즘 비용 절감이 대세이기 때문에 이것이 실행 가능한 사용 사례라고 볼 수 있습니다.
정보가 장치의 범위를 벗어나지 않고 자신만의 개인 LLM을 갖는 데 따른 개인 정보 보호 혜택도 있습니다. 개인 정보 보호를 중시하는 앱 사용자의 관심을 끌 수 있는 유용한 이점입니다.
내 생각에는 LLM이 장치에 정기적으로 배포되려면 아직 몇 년이 걸릴 것입니다.
모바일 장치에서 Gemma를 직접 사용해 보고 싶다면 다음 리소스를 참조하세요.
Gemma : 공식 Gemma 웹사이트에는 벤치마크, 빠른 시작 가이드, 책임감 있는 Generative AI 개발에 대한 Google의 접근 방식에 대한 정보 등 풍부한 정보가 포함되어 있습니다.
MediaPipe : MediaPipe에는 이에 대한 자세한 내용과 사용 방법을 알아볼 수 있는 자체 Google 개발자 섹션이 있습니다. 독서를 적극 권장합니다.
Google 개발자 그룹 Discord : Google 개발자 그룹 Discord 에는 Generative AI 전용 채널이 있습니다. #gemma, #gemini 및 #ml 채널을 확인하여 같은 생각을 가진 사람들과 채팅하세요.
Simons는 앱에 대해 다음과 같이 말합니다. 이 블로그 게시물의 샘플 코드를 복제하고 실행하여 실제로 작동하는 모습을 확인하세요. 또한 MediaPipe의 이미지 분류 작업 사용도 포함됩니다. 설정 지침은 README에 있습니다.
IO 스레드에서 LLM 추론 호출을 언급하기 위해 24/03/23에 업데이트되었습니다.
이 게시물을 쓴 후 gemma를 호출하는 것은 파일에 대한 읽기/쓰기 작업이라는 생각이 들었습니다. .generateResponse()
메서드를 IO 스레드로 이동하면 gemma가 메모리에 로드될 때 엄청난 버벅거림을 피할 수 있습니다.
suspend fun sendMessage(): String { return withContext(Dispatchers.IO) { val prompt = prompts.random() llmInference.generateResponse(prompt) } }
여기에도 나타납니다.