Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/developeracademy-postech/2024-nc2-a21-machinelearning
https://github.com/developeracademy-postech/2024-nc2-a21-machinelearning
Last synced: about 8 hours ago
JSON representation
- Host: GitHub
- URL: https://github.com/developeracademy-postech/2024-nc2-a21-machinelearning
- Owner: DeveloperAcademy-POSTECH
- Created: 2024-06-15T16:22:33.000Z (5 months ago)
- Default Branch: main
- Last Pushed: 2024-06-29T06:15:47.000Z (5 months ago)
- Last Synced: 2024-06-29T07:27:54.075Z (5 months ago)
- Language: Swift
- Size: 74.9 MB
- Stars: 0
- Watchers: 2
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# 2024-NC2-A21-MachineLearning
## ๐ฅ Youtube Link
(์ถํ ๋ง๋ค์ด์ง ์ ํ๋ธ ๋งํฌ ์ถ๊ฐ)## ๐ก About Augmented Reality
(ํด๋น ๊ธฐ์ ์ ๋ํ ์กฐ์ฌ ๋ด์ฉ ์ ๋ฆฌ)
![image](https://github.com/DeveloperAcademy-POSTECH/2024-NC2-A21-MachineLearning/assets/163488928/cb333f8c-e7af-4486-84f3-ea26c2cdd66d)- ์ด๋ฏธ์ง๋ ํ ์คํธ, ์ฌ์ด๋๋ฑ์ ํ์ตํ์ฌ ์ํฉ์ ๋ํ ๋์์ ์ผ์ผ์ด ์ง์ ํ๋ ๋์ ,
์ค์ค๋ก ํ์ตํ์ฌ ๋์ํ๋๋ก ํ๋ ๋ฐฉ๋ฒ๋ก ์ด๋ค
- ๋ฌผ์ฒด๋ ์๋ฆฌ๋ฅผ ์ธ์ํ๊ฑฐ๋ ๋ถ์ํ ์ ์๊ณ ์ฌ์ฉ์์ ํจํด์ ํ์ ํด
์ด๋ ํ ๊ฒฐ๊ณผ๋ฅผ ์ถ์ฒํด์ฃผ๊ฑฐ๋ ์์ธกํ ์๋ ์๋ค.
![image](https://github.com/DeveloperAcademy-POSTECH/2024-NC2-A21-MachineLearning/assets/163488928/7f14c4f7-e06c-4218-8b9b-a3cc2e25814c)## ๐ฏ What we focus on?
![image](https://github.com/DeveloperAcademy-POSTECH/2024-NC2-A21-MachineLearning/assets/163488928/26617508-30c9-4fca-8696-645574bcfd23)
### SoundClassification- ์๋ง์ ์์ด๋์ด์ค ์ค๋ธ์ ํธ ๋ถ๋ฅ์ ์๋ฆฌ๋ฅผ ๋ถ์ํด์ฃผ๋๊ฒ์ ํฅ๋ฏธ๋ฅผ ๋๊ผ๊ณ
๊ทธ์ค ์๋ฆฌ์ ์ง์คํด๋ณด๊ณ ์ถ์ ์๊ฐ์ด ๋ค์์ต๋๋ค
- ์๋ฆฌ๋ฅผ ๊ณผ์ฐ ์ด๋ป๊ฒ ๋ถ์ํ๋์ง ์๋ฆฌ๋ฅผ ์์ง ๋ชปํด์ ์ด๋ฒ ๊ธฐํ์ ๋ฐฐ์๋ณด๊ณ ์ถ์์ต๋๋ค### AVFoundation
- input ๊ฐ์ผ๋ก ์ค๋์ค๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด, ๋ น์ ํ ์ ์๋ ๊ธฐ๋ฅ์ด ํ์ํ๋ค๊ณ ์๊ฐํ์ต๋๋ค
### Idation
![image](https://github.com/DeveloperAcademy-POSTECH/2024-NC2-A21-MachineLearning/assets/163488928/2a0bd799-4930-4fe6-bccf-d770e219ab90)
![image](https://github.com/DeveloperAcademy-POSTECH/2024-NC2-A21-MachineLearning/assets/163488928/e4e96c3f-96f7-4c53-b633-08f6e2cbd0cf)## ๐ผ Use Case
![image](https://github.com/DeveloperAcademy-POSTECH/2024-NC2-A21-MachineLearning/assets/163488928/85c75bce-7cd2-4e2e-93a6-ce96ce9a992a)## ๐ผ๏ธ Prototype
### 1. ๋ฉ์ธํ๋ฉด
![image](https://github.com/DeveloperAcademy-POSTECH/2024-NC2-A21-MachineLearning/assets/163488928/1e0f130f-e4da-4b25-a506-c6e99168bb8b)
- Start ๋ฒํผ์ ๋๋ฅด๋ฉด recordView (์์ฑ๋ น์ํ๋ฉด)์ผ๋ก ์ง์ ํฉ๋๋ค### 2. ์์ฑ ๋ น์ํ๋ฉด
![image](https://github.com/DeveloperAcademy-POSTECH/2024-NC2-A21-MachineLearning/assets/163488928/017cbbb4-c866-415f-a843-b24b6057e10d)
- ์ฌ์ฉ์๊ฐ ๋ณด๊ณ ์ฝ์ ์ ์๋ ์ง๋ฌธ์ ๋๋ค์ผ๋ก ์ ์ํด ์ค๋๋ค
- ์์ฑ ๋ น์ ๋ฒํผ์ ๋๋ฅด๋ฉด ์์ฑ์ด ๋ น์๋ฉ๋๋ค
- ๋ น์ ์ ์ง ๋ฒํผ์ ๋๋ฅด๋ฉด ๋ฐ๋ก ๋ถ์ ๊ฒฐ๊ณผ ํ๋ฉด์ผ๋ก ์ด๋ํฉ๋๋ค### 3. ์์ฑ ๋ถ์ ๊ฒฐ๊ณผ ํ๋ฉด
![image](https://github.com/DeveloperAcademy-POSTECH/2024-NC2-A21-MachineLearning/assets/163488928/e7134af6-243c-43c1-91fd-63c0459cbd8a)
- ๋ น์๋ ์์ฑ๊ณผ ํ์ตํ ๋ชจ๋ธ์ ์ ์ฉํ์ฌ ๋ชฉ์๋ฆฌ ํ์ ์ ๋ฐ๋ฅธ ๊ฒฐ๊ณผ ํ๋ฉด์ ์ ๊ณตํฉ๋๋ค์ด 8๊ฐ์ ๋ชฉ์๋ฆฌ ํ์ ์ด ์์ต๋๋ค!
![image](https://github.com/DeveloperAcademy-POSTECH/2024-NC2-A21-MachineLearning/assets/163488928/d9d7ecad-ce1c-49eb-b749-010d32e2e88a)## ๐ ๏ธ About Code
[(ํต์ฌ ์ฝ๋์ ๋ํ ์ค๋ช ์ถ๊ฐ)](https://www.notion.so/image/https%3A%2F%2Fprod-files-secure.s3.us-west-2.amazonaws.com%2F2e999faf-43aa-426e-ba81-0a9f876c0c58%2F70245514-95c4-422a-ba7f-fc3c048ff64b%2F5864d500-a1dc-4f84-9066-c71623dfe3a3.png?table=block&id=9c80ce15-cd83-4743-9fe2-cfcafd1adda9&spaceId=2e999faf-43aa-426e-ba81-0a9f876c0c58&width=1420&userId=e7637d63-e92f-4d98-a02f-63f160a8b78e&cache=v2)
- ๋ค์์ ํ๋กํ ํ์ ์ ์ ์ฉ๋ ๋ชจ๋ธ ๋ฐ์ดํฐ๋ฅผ ์์งํ๊ณ ๋ถ๋ฅํ๋ ๊ณผ์ ์ ๋ด์ ๋ด์ฉ์ ๋๋ค.๋จผ์ ๋ชฉ์๋ฆฌ ๋ฐ์ดํฐ๋ฅผ ์์งํ์๋๋ฐ, ์ ํฌ๋ ์ต๋ํ ๋น์ทํ ๋ถ๋ฅ ๊ธฐ์ค์ผ๋ก, ๋ง์ ๋ชฉ์๋ฆฌ ๋ฐ์ดํฐ๋ฅผ ์์งํ๊ธฐ ์ํด ๋ฌ๋๋ค ๋ชฉ์๋ฆฌ๋ฟ๋ง ์๋๋ผ, ๋ค์ด๋ฒ ํด๋ก๋ฐ ๋๋น์์ AI ๋ชฉ์๋ฆฌ๋ฅผ ์ถ์ถํ์๊ณ ,
๋ฐฑ๊ทธ๋ผ์ด๋ ์๋ฆฌ๋ ํจ๊ป ์ถ๊ฐํ์์ต๋๋ค.
*์ฌ๊ธฐ์ ๋ฐฑ๊ทธ๋ผ์ด๋ ์๋ฆฌ๋ ๊ตฌ๋ณํ ์ฌ์ด๋๊ฐ ์์ ๋ ์ฒ๋ฆฌํ๊ธฐ ์ํ ์ฉ๋์ ๋๋ค.
- ์ด๋ ๊ฒ ์์งํ ๋ฐ์ดํฐ๋ ์ด 340๊ฐ์ง๋ก, ์ด๋ฅผ gender์ voiceType์ผ๋ก ๋๋์ด ๋ถ๋ฅํ์์ต๋๋ค
Gender๋ ๋ง ๊ทธ๋๋ก ๋จ์์ ์ฌ์ ๋ชฉ์๋ฆฌ๋ฅผ ๋ถ๋ฅํ์ฌ ๋ด์๊ณ , voiceType์ ๋ชฉ์๋ฆฌ์ ํค์ด๋ ์ต์, ๋ถ์๊ธฐ์ ๋ฐ๋ผ ๋จ์ 4๊ฐ์ง, ์ฌ์ 4๊ฐ์ง์ ๋ชฉ์๋ฆฌ ์ ํ์ผ๋ก ๋ถ๋ฅํ์ฌ ์ด 8๊ฐ์ง์ ์ ํ์ผ๋ก ๊ตฌ๋ถํ์์ต๋๋ค.![image](https://github.com/DeveloperAcademy-POSTECH/2024-NC2-A21-MachineLearning/assets/163488928/32f2d601-042a-46a8-80ca-ad08b15ffcb4)
์ดํ ๋ชจ๋ธ์ ์ฑ์ ์ ์ฉํ ๋, ์ฒ์์๋ gender ๋ชจ๋ธ ์์ด ๋จ,์ฌ๊ฐ ๋ชจ๋ ํฉ์ณ์ ธ ์๋ voiceType ๋ชจ๋ธ๋ก ์ค๋์ค ๋ฐ์ดํฐ๋ฅผ ๋ถ์ํ์๋๋ฐ ์ ํ๋๊ฐ ๋ง์ด ๋จ์ด์ง๋ ๊ฒ์ ํ์ธํ์์ต๋๋ค..
์๋ฅผ ๋ค์ด ์ฌ์๋ชฉ์๋ฆฌ์ฌ๋, ์ต์์ด ๋ฎ์์ง๋ ๋ถ๋ถ์์๋ ๋จ์ ๋ชฉ์๋ฆฌ๋ก ์ธ์ ํ๋ ๋ฌธ์ ๊ฐ ์์์ด์.
๋ฐ๋ผ์ gender๋ฅผ ๊ตฌ๋ณํ๋ ๋ชจ๋ธ๋ก ์ค๋์ค ๋ฐ์ดํฐ๋ฅผ male๊ณผ female๋ก ๊ตฌ๋ณํ ํ์,
๊ฐ๊ฐ์ ์ฑ๋ณ์ ๋ง๋ voiceType์ ๊ตฌ๋ณํด์ฃผ๋ ๋ชจ๋ธ์ ์ ์ฉํ์ฌ ๋ถ์ํ๋๋ก ํ์์ต๋๋ค.### Code snippet
**์ค๋์ค๋ฅผ ๋ถ์ํด์ ์ป๋ ๊ฒฐ๊ณผ๊ฐ์ ๋ฐ์ ์ ์๋ ResultsObserver ๊ตฌํโฌ๏ธ**
import Foundation
import SwiftUI
import AVFoundation
import SoundAnalysis
//์ค๋์ค ๋ถ์์ผ๋ก ๋ถํฐ ๊ฒฐ๊ณผ ๋ฐ๋ ํ์ ๊ตฌํ
/// An observer that receives results from a classify sound request.
class ResultsObserver: NSObject, SNResultsObserving {
@Binding var classificationResult: String
//๊ฐ ์๊ฐ ๋ฒ์์ classification ๊ฒฐ๊ณผ๋ฅผ ์ ์ฅํ ๋์ ๋๋ฆฌ
private var classifications: [String: Double] = [:]
//๊ฐ์ฅ ๋ง์ด ๋์ถ๋ ์ค๋์คํ์ ๊ฐ ๋ฐ๊ธฐ
var mostClassificationIdentifier: String
//์ด๊ธฐํ
init(result: Binding){
_classificationResult = result
mostClassificationIdentifier = "" // Provide an initial value
super.init() // Call super.init() after initializing all properties
}
/// Notifies the observer when a request generates a prediction.
func request(_ request: SNRequest, didProduce result: SNResult) {
// ๊ฒฐ๊ณผ๋ฅผ SNClassificationResult๋ก๋ถํฐ ๋ฐ์์ด
// SNClassificationResul์ ์๊ฐ ๋ฒ์์ ๋ํด ๊ฐ์ฅ ๋์ ์์์ ์์ธก ๊ฒฐ๊ณผ๋ฅผ ๊ฐ์ ธ์จ๋ค๊ณ ํจ
guard let result = result as? SNClassificationResult else { return }
//classifications๋ [SNClassification]์
//์ด๋ ์์ ๋ถ๋ฅ ํ๋ณด๋ฅผ ๋์ดํ ๋ฐฐ์ด์ ๋ํ๋
//classification.first๋๊น ์ ค ๋์ ์์์ ํ๋ณด๋ฅผ ๋ฐ๋ ค์ด
guard let classification = result.classifications.first else { return }
classifications[classification.identifier, default: 0.0]
+= classification.confidence
//๊ฐ์ฅ ๋ง์ด ๋์ถ๋ classification ๊ฒฐ๊ณผ๊ฐ์ ๊ตฌํ๋ ๋ก์ง
//BG๋ ๋์ ๋๋ฆฌ์์ ์ญ์
classifications["BG"] = nil
//๋์ ๋๋ฆฌ ์์์ ๊ฐ์ฅ ๋ง์ด ๋์จ ๊ฐ ๊ตฌํ๊ธฐ
let mostFrequentClassification = classifications.max(by:
{ $0.value < $1.value })
// ๊ฐ์ฅ ๋ง์ด ๋์ถ๋ identifier
mostClassificationIdentifier = mostFrequentClassification!.key
}
}๋ชจ๋ธ์ ์ฐ๊ฒฐํด ์ค๋์ค๋ฅผ ๋ถ์ํ๋ ๋ฉ์๋โฌ๏ธ
func classifyAudio(){
let genderAnalyzer = try! SNAudioFileAnalyzer
(url: audioRecorder.recordedFile!)
let userTypeAnalyzer = try! SNAudioFileAnalyzer
(url: audioRecorder.recordedFile!)
let request = try! SNClassifySoundRequest
(mlModel: genderClassifier().model)
do{
try? genderAnalyzer.add(request, withObserver: genderObserver)
try genderAnalyzer.analyze()
}
gender = genderObserver.mostClassificationIdentifier
print(gender)
if gender == "male" {
let request = try! SNClassifySoundRequest
(mlModel: maleVoiceClassifier().model)
do{
try? userTypeAnalyzer.add(request,
withObserver: userTypeObserver)
try userTypeAnalyzer.analyze()
}
}
else if gender == "female" {
let request = try! SNClassifySoundRequest
(mlModel: femaleVoiceClassifier().model)
do{
try? userTypeAnalyzer.add(request,
withObserver: userTypeObserver)
try userTypeAnalyzer.analyze()
}
}
userType = userTypeObserver.mostClassificationIdentifier
}AVFoundation์ ์ฌ์ฉํด ์ค๋์ค๋ฅผ ๋ น์ํ๋ ๊ธฐ๋ฅ โฌ๏ธ
import Foundation
import AVFoundation
class AudioRecorder: NSObject, ObservableObject, AVAudioPlayerDelegate {
// ๋ น์
var audioRecorder: AVAudioRecorder?
@Published var isRecording = false
@Published var isNext = false
// ์ฌ์
var audioPlayer: AVAudioPlayer?
@Published var isPlaying = false
@Published var isPaused = false
// ์์ฑ ๋ฉ๋ชจ๋ ๋ฐ์ดํฐ
var recordedFile: URL?
// Singleton instance
static let shared = AudioRecorder()
override init() {
super.init()
configureAudioSession()
checkAudioRecordingPermission()
}
func configureAudioSession() {
let audioSession = AVAudioSession.sharedInstance()
do {
try audioSession.setCategory(.playAndRecord, mode: .default)
try audioSession.setActive(true)
} catch {
print("Failed to configure audio session:
\(error.localizedDescription)")
}
}
// ์์ฑ ๋ฉ๋ชจ ๋ น์ ๊ด๋ จ ๋ฉ์๋
// ๋ฐ์์ฌ ๋ ํ์๊ณผ ํ์ฅ์๋ฅผ
func startRecording() {
let fileURL = getDocumentsDirectory()
.appendingPathComponent("recording-\(Date().timeIntervalSince1970).wav")
let settings: [String: Any] = [
AVFormatIDKey: Int(kAudioFormatLinearPCM),
AVSampleRateKey: 16000.0,
AVNumberOfChannelsKey: 1, // mono
AVEncoderAudioQualityKey: AVAudioQuality.high.rawValue,
AVLinearPCMBitDepthKey: 16,
AVLinearPCMIsBigEndianKey: false,
AVLinearPCMIsFloatKey: false
]
do {
audioRecorder = try AVAudioRecorder
(url: fileURL, settings: settings)
audioRecorder?.record()
isRecording = true
isNext = false
print("Recording started")
} catch {
print("Failed to start recording: \(error.localizedDescription)")
}
}
func stopRecording() {
guard let recorder = audioRecorder else {
print("Audio recorder is not initialized.")
return
}
recorder.stop()
recordedFile = recorder.url
isRecording = false
isNext = true
print("Recording stopped: \(String(describing: recordedFile))")
}
func getDocumentsDirectory() -> URL {
let paths = FileManager.default.urls(for: .documentDirectory,
in: .userDomainMask)
return paths[0]
}
}