Skip to content

[FEAT] 온디바이스 감정 분석 기능 추가 (KoELECTRA + TFLite) - #7

Merged
cchanmi merged 16 commits into
developfrom
feature/on-device-emotion-analysis
Jul 28, 2026
Merged

[FEAT] 온디바이스 감정 분석 기능 추가 (KoELECTRA + TFLite)#7
cchanmi merged 16 commits into
developfrom
feature/on-device-emotion-analysis

Conversation

@cchanmi

@cchanmi cchanmi commented Jul 26, 2026

Copy link
Copy Markdown
Collaborator

Describe

온디바이스 감정 분석 추론 엔진을 Core ML에서 TFLite(TensorFlowLiteSwift) 기반으로 구현합니다. Android와 동일 모델로 두 플랫폼이 같은 입력에 대해 같은 감정 라벨을 내도록 하는 것이 목적입니다.

Works made

모델: KoELECTRA 모델 사용

  • 결과적으로 모델 리소스 용량이 430MB → 109MB로 줄었고, 두 플랫폼이 동일한 가중치로 추론하게 되어 예측 결과의 크로스플랫폼 일관성이 높아졌습니다.
  • TensorFlowLiteSwift 라이브러리로 .tflite 경로를 열어 Interpreter를 생성합니다.
  • 텍스트 → 토큰화(swift-transformers) → 모델 호출하여 추론 →출력 로직으로 감정 라벨을 결정합니다.

의존성: CocoaPods로 마이그레이션 필요

  • TensorFlowLiteSwift가 iOS용 SPM 패키지를 공식 지원하지 않아서(CocoaPods/Bazel만 공식 지원 — Google 공식 문서, google-ai-edge/LiteRT#125 확인) Podfile을 신규 추가했습니다.
  • 기존 SPM을 CocoaPods로 마이그레이션 필요합니다.
  • 추가된 라이브러리: TensorFlowLiteSwift, swift-transformers
  • 빌드는 이제 .xcodeproj가 아니라 GAMSS.xcworkspace로 진행해야 합니다(pod install 필요).

테스트

  • Android 테스트 문장으로 동일하게 진행하였습니다.

Changes Made

As-Is

기존 로직

  • Jinuuuu/KoELECTRA_fine_tunning_emotion을 Core ML(FP32)로 변환해 온디바이스 추론
  • 의존성 관리는 SPM만 사용
  • 모델 리소스 430MB

To-Be

변경 로직

  • KoELECTRA + TFLite(INT8)로 온디바이스 추론
  • CocoaPods 신규 도입
  • 모델 리소스 109MB (약 74% 감소)

How to Test

  1. pod install 실행 후 GAMSS.xcworkspace로 열기
  2. xcodebuild test -workspace GAMSS.xcworkspace -scheme GAMSS -destination '<시뮬레이터>' — 전체 유닛 테스트 통과 확인 (9/9)
  3. 감정 분석 동작을 직접 보려면 GAMSSApp.swiftWindowGroup 내용을 EmotionTestView로 임시 교체해 시뮬레이터에서 문장을 입력해본다
  4. 실행 중 메모리 확인: footprint <PID> — physical footprint 약 50MB 확인됨

Issues Resolved

  • 연결된 이슈 없음

Additional context

  • CI(.github/workflows/ci.yml)에 pod install 단계가 추가되어, 이후 -workspace GAMSS.xcworkspace 기준으로 빌드/테스트합니다.
  • .tflite 모델은 Git LFS로 관리됩니다 (.gitattributes에 패턴 추가, 기존 .mlpackage LFS 설정 대체).

References

cchanmi and others added 15 commits July 24, 2026 19:03
토크나이저 설정 파일(tokenizer_config.json)이 리소스 번들에 빠져 있어서 함께 추가함.
- 토큰 수가 128을 초과할 때 토큰이 잘려나가 이슈 수정
- CI의 Test 환경 고정된 iPhone 16 시뮬레이터 실행 조건 제거하고, 실행 시점에 사용 가능한 iOS 18.1+ 시뮬레이터 UDID를 동적으로 찾아 사용하도록 변경
@cchanmi cchanmi changed the title [FEAT] 온디바이스 감정 분석 기능 추가 (TFLite, Android 모델 공유) [FEAT] 온디바이스 감정 분석 기능 추가 (KoELECTRA + TFLite) Jul 26, 2026
@cchanmi cchanmi linked an issue Jul 26, 2026 that may be closed by this pull request
@cchanmi cchanmi self-assigned this Jul 26, 2026

@dlrjswns dlrjswns left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cchanmi 온디바이스 작업하느라 고생많았습니다 !! CocoaPods쪽만 develop에 병합하기이전에 오류발생하는지 확인만 해주시고 리뷰 한번 확인부탁드려요 😀😀

Comment on lines +113 to +115
guard (try? writeInputs(inputIds: inputIds, attentionMask: attentionMask, tokenTypeIds: tokenTypeIds)) != nil else {
throw EmotionAnalysisError.inferenceFailed
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 코드에서 try?가 원래 발생한 에러는 nil로 바꿔버려서 do-catch문으로 바꾸는게 읽기 쉬울꺼같은데 어떻게 생각하시나요 ?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do-catch로 바꾸고 에러를 nil로 흘려보내지 않고 catch 구문에서 세팅해 주신 Log로 에러 원인을 출력하도록 수정했습니다.

Comment on lines +90 to +98
if tensor.name.contains("input_ids") {
roles.append(.ids)
} else if tensor.name.contains("attention_mask") {
roles.append(.mask)
} else if tensor.name.contains("token_type") {
roles.append(.tokenType)
} else {
throw EmotionAnalysisError.modelLoadFailed
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 분기문에서 모델이 하나뿐이라면 상관없겠지만 만약에 "my_input_ids"일 경우 통과되는 로직이라서 차라리 switch문으로 분기처리하는건 어떻게 생각하실까요 ?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

현재로서는 다르게 전달될 일이 없기는 한데, 다른 모델이 추가될 경우에는 또 어떤 형식으로 값이 전달될지 알 수 없어서 switch문으로 정확한 값을 바인딩하는 것도 애매한 것 같다고 판단했어요.
이부분은 다른 모델이 추가될 경우에 수정해 볼게요.

}

var options = Interpreter.Options()
options.threadCount = 4

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기서 모든 기종 전부 다 4로 고정인 이유가 궁금해요 !!

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

적절한 기준값을 4로 고정한 것이었는데...

iOS 18.1 버전의 저사양 기기도 고려해야 해야 하고, 과도한 스레드 생성을 방지해야 해서 ProcessInfo.processInfo.activeProcessorCount API를 추가로 사용했고, 사용 가능한 코어 수가 동적으로 반영되도록 변경했습니다.

@cchanmi
cchanmi merged commit 73ea820 into develop Jul 28, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] onDeviceLLM 연동

2 participants