<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>haikoo_ai96.log</title>
        <link>https://velog.io/</link>
        <description>안뇽하세요</description>
        <lastBuildDate>Sat, 20 Apr 2024 12:30:38 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>haikoo_ai96.log</title>
            <url>https://velog.velcdn.com/images/haikoo_ai96/profile/856c1b95-9578-4f3e-9a17-22b050be5f77/social_profile.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. haikoo_ai96.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/haikoo_ai96" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[chp 4: 프로젝트를 마치며]]></title>
            <link>https://velog.io/@haikoo_ai96/chp-4-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EB%A5%BC-%EB%A7%88%EC%B9%98</link>
            <guid>https://velog.io/@haikoo_ai96/chp-4-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EB%A5%BC-%EB%A7%88%EC%B9%98</guid>
            <pubDate>Sat, 20 Apr 2024 12:30:38 GMT</pubDate>
            <description><![CDATA[<h3 id="회고-및-감사인사말">회고 및 감사인사말</h3>
<p>프로젝트를 마치면서 많은 걸 느꼈다. 그중에 가장 크게 와닿았던 건 기본에 충실해야 하는 것이었다. 전반적으로 VGG16 부터 AST 까지 기초적인 부분에서 문제가 많았기 때문에 좋은 실험 결과를 낳을 수 없었고 실수가 잦았던 것 같다. 그럼에도 불구하고 다 같이 데이터 정제부터 다시 시작하는 마음과 용기가 이 번 프로젝트에서 가장 인상 깊었고 기억에 남는다. 역시 필자는 다시 동료분들께 무한한 감사의 말을 전하고 싶다.</p>
<h3 id="데이터셋에-대한-아쉬움">데이터셋에 대한 아쉬움</h3>
<p>데이터 셋 수집 관련해서도 아쉬운 부분이 있다. 엡에서 녹음 테스트를 초반에 했었더라면 아마 원본 데이터셋을 핸드폰 녹음기를 한 번 더 거쳐서 오디오 데이터를 확보했을 수도 있을 것 같다는 생각이 들었다.</p>
<p>그리고 구글 번역기를 써가면서 유튜브에서 더 다양한 언어로 아기 울음소리를 수집해 볼 수 있지 않았을까라는 생각도 해본다. </p>
<p>물론 데이터 셋을 구하기 위해 논문 저자, 의사, 병원 등 메일로 컨택을 해봤지만 답변이 오질 않았고 병원 같은 경우 데이터 수집 과정이 까다롭다고 들었기 때문에 2달 치 프로젝트를 감안하면 크게 아쉬울 부분은 없었다.</p>
<p>필자의 지극히 개인적인 생각이지만 이 번 모델링 파트를 잘 포장해 보면 좋은 물이 많이 들어올 때 좋은 배를 만든 시간이었다고 본다. 여기서 물은 데이터이고 배는 모델을 뜻한다. </p>
<h3 id="그-외-아쉬움">그 외 아쉬움</h3>
<p>모델링도 모델링이지만 사실 이 외에도 앱 개발과 모델 배포(서버개발)에 상당한 노고가 들어가 있다. 하지만 필자는 디버깅에 조금 도움만 주고 end-to-end 개발은 동료 분들께서 마무리 지어주셨다. 그래서 앱 개발과 서버 개발 과정을 세세히 녹여내지 못해 아쉬움이 남아있다. </p>
<p>마무리로 특별히 김영진 님께 감사 인사말을 전하고 싶다. 영진님은 우리 프로젝트 중간에 들어오셨고 모델 배포와 서버 쪽을 맡아주셨다. 영진님이 들어오는 바람에 필자 포함해서 두 명이서 모델링을 진행할 수 있었다. 그래서 여러 실험을 할 수 있는 시간을 만들어준 셈이다. 그 덕에 프로젝트 평가 부분에서 실험 점수에서 가장 큰 점수를 받았다.</p>
<p>정말 2 달 동안 많은 걸 배울 수 있었기 때문에 필자에겐 굉장히 의미 있는 시간이었다. 앞으로 더 열심히 해서 더 성장할 모습을 기대하며 이 글에 마침표를 찍어본다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Chp 3-4: AST를 활용한 울음소리 분류(EDA 편)]]></title>
            <link>https://velog.io/@haikoo_ai96/Chp-3-4-AST%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-%EC%9A%B8%EC%9D%8C%EC%86%8C%EB%A6%AC-%EB%B6%84%EB%A5%98</link>
            <guid>https://velog.io/@haikoo_ai96/Chp-3-4-AST%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-%EC%9A%B8%EC%9D%8C%EC%86%8C%EB%A6%AC-%EB%B6%84%EB%A5%98</guid>
            <pubDate>Sat, 20 Apr 2024 12:00:59 GMT</pubDate>
            <description><![CDATA[<h1 id="ast-여정-후반부">AST 여정 후반부</h1>
<hr>
<h3 id="back-to-square-one다시-시작">Back to Square One(다시 시작)</h3>
<p>AST 전반부에서 훈련한 모델을 서버에 배포 후 앱에서 아기 울음소리를 직접 녹음해 테스트를 진행했다. 이때 앱 테스트 전 Test Accuracy는 70%를 살짝 넘기는 정도여서 나름 만족을 하고 있었다. 하지만 앱에서 테스트 결과 복통에만 치우치는 inference 결과를 확인했다. 전반부 모델링, 데이터 EDA, 전처리를 맡은 나로서 팀원들에게 굉장한 치명타를 안겨주었다. 이때 정말 프로젝트 전체적으로 어떤 Miss 가 있었는지 주마등처럼 스쳐 지나갔다. 그리고 더 최악인 건 프로젝트 끝나기 2주 남기고 이 사태가 벌어진 것이었다. 정말 쥐구멍이 없으면 손톱이 부러지더라도 구멍을 파서 없어지고 싶었다. 하지만 팀원들이 바로 다시 시작해 보자고 했다. 2주 남기고 이렇게 빨리 결단을 내려 대응한 용기가 정말 대단했다고 생각했다. 정말 전생에 어떤 일을 했길래 이렇게 좋은 팀원들을 만났는지 그저 감사할 따름이었다.</p>
<p>우선 팀원들 각각 맡은 울음소리를 하나씩 들으면서 소음이 많거나 울음소리가 잘 안 들리는 오디오를 정제해 나갔다. 이렇게 해서 아래 그래프처럼 다시 데이터 셋을 구축했다.</p>
<p><img src="https://velog.velcdn.com/images/haikoo_ai96/post/bda2d5d8-92f7-4dbd-bcda-b4edc52fa06c/image.png" alt=""></p>
<p>데이터 셋 사이즈가 더 작아졌지만 제대로 된 학습을 위해 양보단 질을 선택해 좋은 데이터를 선별하는 게 맞다고 생각했다. </p>
<p>그리고 이 번에는 EDA를 더 면밀히 진행했다. 진행한 EDA 항목은 다음과 같다.</p>
<hr>
<h3 id="eda">EDA</h3>
<ol>
<li>Sampling Rate 체크</li>
<li>오디오 길이 체크</li>
<li>클래스별 평균 증폭, 배음 갯수, 평균 주파수<ol>
<li>클래스 별 평균 Mel Spectrogram을 기반으로 주파수 산출</li>
</ol>
</li>
</ol>
<p><strong><code>Sampling Rate</code></strong></p>
<p>Sampling Rate가 중요한 이유는 오디오의 resolution을 나타내기 때문에 얼마나 정보를 담고 있는지 정해주는 요소이다. 그래서 Sampling Rate가 높을수록 음질이 올라간다.</p>
<p>아래 영상을 들어보면 Sampling Rate가 낮아질수록 음의 정보가 점점 없어지는 걸 느낄 수 있다.</p>
<p><a href="https://www.youtube.com/watch?v=hRhVb6iRArg">https://www.youtube.com/watch?v=hRhVb6iRArg</a></p>
<p>그래서 오디오 관련 모델링에선 Sampling Rate에 따라 학습되는 정보량이 달라지기 때문에 중요한 요소이다.  </p>
<p>또한 어떤 Sampling Rate으로 pretrained model 이 학습되어 있는지도 중요하기 때문에 전처리 부분에서 pretrained model에 설정된 sampling rate에 맞게 오디오를 불러오는 것도 중요하다.</p>
<p>다시 정리해서</p>
<ol>
<li>Sampling Rate는 오디오의 Resolution</li>
<li>Pretrained Model에 설정된 Sampling Rate에 맞게 오디오 load</li>
</ol>
<p>각 클래스마다 sampling rate을 분석한 결과 아래 같이 정리할 수 있었다. </p>
<table>
<thead>
<tr>
<th></th>
<th>Sampling Rate(Hz)</th>
</tr>
</thead>
<tbody><tr>
<td>복통</td>
<td>48000: 75.5%/ 44100: 6.1%/ 8000: 18.4%</td>
</tr>
<tr>
<td>불편함</td>
<td>44100: 36.2%/ 8000: 63.8%</td>
</tr>
<tr>
<td>배고픔</td>
<td>44100: 12.2%/ 8000: 87.8%</td>
</tr>
<tr>
<td>피곤함</td>
<td>48000: 44.0%/ 44100: 6.0%/ 16000: 16.0%/ 8000: 34.0%</td>
</tr>
</tbody></table>
<p>생각보다 40kHz 이상인 sampling rate가 상당히 많았다.</p>
<p><strong><code>오디오 길이</code></strong></p>
<p>좀 더 일정하게 데이터 input을 맞추기 위해 오디오 길이 체크도 진행했다. 각 클래스마다 오디오 길이는 아래와 같이 확인할 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/haikoo_ai96/post/dd0b1df3-28d7-46f6-955d-1275ea9383ad/image.png" alt=""></p>
<p>평균 오디오 길이는 약 6초가 나왔다.</p>
<p><strong><code>클래스별 증폭(Magnitude), 배음 갯 수, 가중평균 주파수</code></strong></p>
<table>
<thead>
<tr>
<th>클래스</th>
<th>평균 증폭량 (magnitude, peak 25 이상 기준)</th>
<th>평균 배음 갯 수 (peak 25 이상기준)</th>
<th>가중평균 주파수 (HZ, 평균 멜스펙트럼 기준)</th>
</tr>
</thead>
<tbody><tr>
<td>복통</td>
<td>61.5</td>
<td>9082</td>
<td>826.8</td>
</tr>
<tr>
<td>불편함</td>
<td>97.0</td>
<td>9906</td>
<td>1164.6</td>
</tr>
<tr>
<td>배고픔</td>
<td>98.8</td>
<td>10242</td>
<td>920.7</td>
</tr>
<tr>
<td>피곤함</td>
<td>76.4</td>
<td>9030</td>
<td>815.4</td>
</tr>
<tr>
<td>- 증폭은 음의 <strong>세기</strong>를 의미</td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>- 배음은 주(기본) 주파수외 다른 주파수들을 의미</td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>- 배음의 수가 많을수록 <strong>복합적인 소리(음색)를</strong> 낸다.</td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>- 주파수는 <strong>음의 높 낮이</strong>를 의미</td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody></table>
<p>위 세 개의 feature를 가지고 각 클래스를 간단히 3d scatter plot으로 분류를 진행해 보았다.</p>
<p><img src="https://velog.velcdn.com/images/haikoo_ai96/post/415479e1-2aa9-447b-9be4-833d328eeed6/image.png" alt=""></p>
<p><strong><code>클래스별 평균 Mel Spectrogram</code></strong></p>
<p>사실 어떻게 보면 평균 Mel Spectrogram이 우리 팀에게 가장 중요한 인사이트를 주었다. 왜냐하면 클래스별 평균적으로 어떤 주파수가 주요한지 볼 수 있었기 때문이다. </p>
<p>먼저 클래스별 평균 Mel Spectrogram을 살펴보면 아래와 같다. </p>
<blockquote>
<h3 id="복통">복통</h3>
<p><img src="https://velog.velcdn.com/images/haikoo_ai96/post/351c44fe-c820-4929-84f9-bfc2cf7bf0f3/image.png" alt=""></p>
</blockquote>
<blockquote>
<h3 id="불편함"><strong>불편함</strong></h3>
<p><img src="https://velog.velcdn.com/images/haikoo_ai96/post/7724d8bd-02d3-42e9-bac8-142d59aeed2a/image.png" alt=""></p>
</blockquote>
<blockquote>
<h3 id="배고픔"><strong>배고픔</strong></h3>
<p><img src="https://velog.velcdn.com/images/haikoo_ai96/post/e3c4611a-b1d7-444c-bd2c-b303a6a51db7/image.png" alt=""></p>
</blockquote>
<blockquote>
<h3 id="피곤함"><strong>피곤함</strong></h3>
<p><img src="https://velog.velcdn.com/images/haikoo_ai96/post/3b7e1b7f-c9d0-428f-89bb-db3d1a49ac38/image.png" alt=""></p>
</blockquote>
<p>Mel Spectrogram은 x 축에는 시간, y 축에는 주파수(Hz), 색은 Magnitude를 의미한다. 색이 밝을수록 소리의 세기가 크다고 볼 수 있다. </p>
<p>주파수와 Magnitude를 기준으로 파란색 Bounding Box 안에 클래스마다 주요한 주파수를 찾을 수 있었다.</p>
<p>위 표를 다시 가져오면 클래스 별 가중평균 주파수가 Bounding Box 안에 포함되는 걸 확인할 수 있다.</p>
<ul>
<li>산출 방법은 Lower Bound와 Upper Bound를 정하고 각 주파수의 증폭을 가중치로 두어 주파수들의 가중평균을 계산하였다.</li>
<li>방법 및 코드 출처: ChatGPT</li>
</ul>
<pre><code class="language-python"># find the average frequency in this range
# multiply the magnitude by the frequency to get a weighted sum
weighted_frequencies = np.sum(target_range * mel_frequencies[lower_bound_idx:upper_bound_idx+1, np.newaxis], axis=0)
total_magnitude = np.sum(target_range, axis=0)
average_frequency = np.sum(weighted_frequencies) / np.sum(total_magnitude)

average_frequency</code></pre>
<p>이 인사이트를 바탕으로 모델 학습 시 주요한 주파수에 집중할 수 있도록 BandPass Filter를 사용하기로 했다.</p>
<hr>
<p>👉👉 <a href="https://velog.io/@haikoo_ai96/Chp-3-5-AST%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-%EC%9A%B8%EC%9D%8C%EC%86%8C%EB%A6%AC-%EB%B6%84%EB%A5%98%EC%A0%84%EC%B2%98%EB%A6%AC%EC%A6%9D%EA%B0%95-%ED%8E%B8">다음 챕터 읽으러 가기</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Chp 3-5: AST를 활용한 울음소리 분류(전처리&증강 편)]]></title>
            <link>https://velog.io/@haikoo_ai96/Chp-3-5-AST%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-%EC%9A%B8%EC%9D%8C%EC%86%8C%EB%A6%AC-%EB%B6%84%EB%A5%98%EC%A0%84%EC%B2%98%EB%A6%AC%EC%A6%9D%EA%B0%95-%ED%8E%B8</link>
            <guid>https://velog.io/@haikoo_ai96/Chp-3-5-AST%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-%EC%9A%B8%EC%9D%8C%EC%86%8C%EB%A6%AC-%EB%B6%84%EB%A5%98%EC%A0%84%EC%B2%98%EB%A6%AC%EC%A6%9D%EA%B0%95-%ED%8E%B8</guid>
            <pubDate>Sat, 20 Apr 2024 12:00:33 GMT</pubDate>
            <description><![CDATA[<h3 id="전처리">전처리</h3>
<p>AST pretrained 모델 같은 경우 추구하는 input configuration 이 있다.</p>
<ul>
<li>window size: 25ms, hop length: 10ms 기준으로 10.24초의 Mel Spectrogram</li>
<li>Mel Filter Bank: 128 filters</li>
<li>16kHz Sampling rate</li>
</ul>
<p>다행히도 HuggingFace Transformers 라이브러리에서 AST 모델에 맞게 전처리 모듈을 쉽게 불러오게끔 만들어 놓았다.</p>
<p>자세한 코드는 아래 링크를 통해 확인해볼 수 있다.</p>
<blockquote>
<p><strong><em>AST Feature Extractor</em></strong>
<a href="https://github.com/huggingface/transformers/blob/v4.38.2/src/transformers/models/audio_spectrogram_transformer/feature_extraction_audio_spectrogram_transformer.py#L39">https://github.com/huggingface/transformers/blob/v4.38.2/src/transformers/models/audio_spectrogram_transformer/feature_extraction_audio_spectrogram_transformer.py#L39</a></p>
</blockquote>
<p>AST Feature Extractor 로 전처리 하기 전에 먼저 세 가지를 진행하였다.</p>
<ol>
<li>Sampling Rate 조절</li>
<li>오디오 길이 조절</li>
<li>Band Pass Filter</li>
</ol>
<p><strong><code>Sampling Rate 조절</code></strong></p>
<p>AST model 은 기본적으로 <strong>16kHz</strong> Sampling rate을 요구한다. 그러나 EDA에서 봤듯이 <strong>40kHz</strong> 이상의 sampling rate이 상당히 많았기 때문에 16kHz로 압축을 시키면 정보손실이 클 우려가 있었다.</p>
<p>그렇다고 해서 기본 configuration을 크게 벗어나면 성능 및 학습에 문제가 있을 수 있으므로 우리 팀은 타협점을 찾아야 했다. 그래서 모든 오디오 sampling rate를 <strong>20kHz</strong>로 불러오기로 결정했다.</p>
<p><strong><code>오디오 길이 조절</code></strong></p>
<p>사실 AST Feature Extractor가 자동으로 10.24초로 패딩을 해주어 길이를 맞춰주기 때문에 길이 조절을 할 필요는 없었다. 그때 당시는 이 부분을 생각을 못하고 EDA에서 확인한 평균 6초로 오디오 길이를 맞춰주었다.</p>
<ul>
<li>오디오 길이 조절 코드</li>
</ul>
<pre><code class="language-python"> def __getitem__(self, idx):
        audio_path = self.audio_paths[idx]
        label = self.audio_labels[idx]
        waveform, _ = librosa.load(audio_path, sr=self.sr, duration=6.0)
        if waveform.shape[0] &lt; 120000:
            waveform = librosa.util.fix_length(waveform, size=120000)</code></pre>
<p><strong><code>BandPass Filter</code></strong></p>
<p><img src="https://velog.velcdn.com/images/haikoo_ai96/post/916b52d3-c4ff-4b76-994b-25d93666a250/image.png" alt=""></p>
<p>Band Pass filter를 설명하면 center frequency를 기준으로 Bandwidth를 정해서 Bandwidth 밖에 있는 주파수의 증폭을 줄이는 방식이다. Bandwidth는 쉽게 말해 통과시킬 주파수 범위를 의미하고 center frequency는 Bandwidth의 중간값을 의미한다.</p>
<p>이렇게 했을 때 아래와 같이 원본과 Band Pass Filter 가 적용된 Mel Spectrogram을 비교해 볼 수 있다.
<img src="https://velog.velcdn.com/images/haikoo_ai96/post/78a69bb8-e0fc-40a4-bcec-f258d8d7c7ed/image.png" alt=""></p>
<p>덤으로 STFT(Short Term Fourier Transform)으로도 비교를 할 수 있었다.</p>
<p><img src="https://velog.velcdn.com/images/haikoo_ai96/post/137c28c4-9970-4b19-b2a4-e5e59805824c/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/haikoo_ai96/post/66841a23-9d05-4506-a709-1e9fbc1ad147/image.png" alt=""></p>
<hr>
<h3 id="데이터-증강">데이터 증강</h3>
<p>데이터 셋을 재구성 후 사이즈가 작은 걸 인지하였기에 증강을 하기로 했다.</p>
<p>방법은 tf.ImageDataGenerator 같은 방식을 택하였다. 그래서 에폭마다 데이터셋이 바뀌어 input으로 들어가게 해서 작은 데이터 셋 사이즈를 어느 정도 보완하였다.</p>
<p>처음에는 증강을 torchaudio를 활용할 생각이었으나 방법이 복잡하여 <a href="https://iver56.github.io/audiomentations/"><strong>Audiomentations</strong></a>을 쓰기로 했다.</p>
<p>증강은 아래 방법으로 진행하였다.</p>
<ol>
<li>생활소음 합성
 a. 아무래도 육아 환경이 집일 확률이 높기 때문에 생활소음을 섞어 증강에 적용하는 게 적절하다고 판단
 b. <a href="https://www.aihub.or.kr/aihubdata/data/view.do?currMenu=115&amp;topMenu=100&amp;aihubDataSe=data&amp;dataSetSn=71296"><strong>생활소음 데이터 셋 소스</strong></a></li>
<li>길이 확대 및 축소</li>
<li>음 높낮이 변경</li>
</ol>
<p>적용 코드는 아래와 같다.</p>
<pre><code class="language-python">augmentations = Compose([
    AddBackgroundNoise(sounds_path = noise_path,
                       min_snr_db=17,
                       max_snr_db=17,
                       p=0.3),
    TimeStretch(min_rate=0.9, max_rate=1.1, p=0.5),
    PitchShift(min_semitones=-1.1, max_semitones=1.1, p=0.5),
    BandPassFilter(min_center_freq=1500, max_center_freq=1500,
                   max_bandwidth_fraction=1.33, min_bandwidth_fraction=1.33,
                   max_rolloff=12, min_rolloff=12, p=1.0),
    Normalize(p=1.0)
])

train_dataset = AudioPipeline(audio_paths=train_paths, audio_labels=train_labels, sr=20000, transform=augmentations)
val_dataset = AudioPipeline(audio_paths=val_paths, audio_labels=val_labels, sr=20000)
test_dataset = AudioPipeline(audio_paths=test_paths, audio_labels=test_labels, sr=20000)

# dataloader에 담기
train_dataloader = DataLoader(train_dataset, batch_size=10, shuffle=True)
val_dataloader = DataLoader(val_dataset, batch_size=10, shuffle=True)
test_dataloader = DataLoader(test_dataset, batch_size=10, shuffle=True)</code></pre>
<hr>
<p>👉👉 <a href="https://velog.io/@haikoo_ai96/Chp-3-5-AST%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-%EC%9A%B8%EC%9D%8C%EC%86%8C%EB%A6%AC-%EB%B6%84%EB%A5%98%EB%AA%A8%EB%8D%B8%EB%A7%81">다음 챕터 읽으러 가기</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Chp 3-6: AST를 활용한 울음소리 분류(모델링 편)]]></title>
            <link>https://velog.io/@haikoo_ai96/Chp-3-5-AST%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-%EC%9A%B8%EC%9D%8C%EC%86%8C%EB%A6%AC-%EB%B6%84%EB%A5%98%EB%AA%A8%EB%8D%B8%EB%A7%81</link>
            <guid>https://velog.io/@haikoo_ai96/Chp-3-5-AST%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-%EC%9A%B8%EC%9D%8C%EC%86%8C%EB%A6%AC-%EB%B6%84%EB%A5%98%EB%AA%A8%EB%8D%B8%EB%A7%81</guid>
            <pubDate>Sat, 20 Apr 2024 11:59:54 GMT</pubDate>
            <description><![CDATA[<h3 id="모델링">모델링</h3>
<p>AST 후반부에서 가장 크게 달라진 점은 체계적인 <strong>실험지 기록</strong>과 <strong>Learning Rate 서치</strong> 였다.</p>
<p>AST 전반부 까지는 실험을 굉장히 중구난방식으로 진행하여 실험 결과 트래킹에 어려움을 겪었다. 그래서 모델링을 시작하기 전에 실험 기록지를 스프레드시트에 특정 format에 맞춰 만들었다. 정말 이 번에는 마지막이기도 하고 혹시 모를 대참사를 막기 위해 더 체계적으로 관리를 하였다. </p>
<p>그리고 Learning Rate Search를 통해 모델이 더 안정적으로 학습할 수 있었다. </p>
<blockquote>
<p><strong>실험 기록지 소개</strong>
    - AST Model configuration
    - 증강 parameters
    - 분류 모델 hyperparameter 설정 값
    - 이 에 따른 특정 epoch 의 test accuracy
    - Train Validation 그래프</p>
</blockquote>
<p>이렇게 크게 4가지로 구분 지어 실험 기록지를 만들었다. 더 자세히 보고 싶으면 아래 링크를 통해 확인할 수 있다.</p>
<p>👉 <a href="https://docs.google.com/spreadsheets/d/1VrBcxZ9iSM_e3_7EH3_9JRecfQMw1EZPscAJo_ZtN-k/edit#gid=1392562511">으아앙팀 AST 모델 실험 기록지</a> 👈</p>
<hr>
<p><strong><code>Learning Rate Search 소개</code></strong></p>
<p><img src="https://velog.velcdn.com/images/haikoo_ai96/post/c421f84e-1e68-4e71-88d4-5cf10d637948/image.png" alt=""></p>
<p>위 수식은 우리가 사용했던 Learning Rate Search 방식이다.</p>
<p>조금 더 부연설명을 하면 한 에폭에 batch가 input으로 들어올 때마다 LR init이 LR final까지 n_step 만큼 LR increment 이 증가하여 loss가 가장 적은 Learning Rate를 선택하는 것이다.</p>
<p>Learning Rate Search 코드는 아래와 같다. (방법 및 코드 출처: ChatGPT)</p>
<pre><code class="language-python">    def find_learning_rate(model, train_loader, loss_fn, device=&#39;cpu&#39;):
        optimizer = torch.optim.Adam(model.parameters(), lr=1e-4)

        lr_find_loss = []
        lr_find_lr = []

        lr_init = 1e-8 # &lt;&lt;&lt;&lt; 요기만 바꾸면됨
        lr_final = 1e-2
        n_steps = 100
        current_lr = lr_init
        lr_increment = (lr_final / lr_init) ** (1/n_steps)

        model.train()  # Set model to training mode

        for batch_idx, batch in enumerate(train_loader):
            inputs, targets = batch
            inputs, targets = inputs.to(device), targets.to(device)

            optimizer.param_groups[0][&#39;lr&#39;] = current_lr
            outputs = model(inputs)
            loss = loss_fn(outputs, targets.squeeze())

            optimizer.zero_grad()
            loss.backward()
            optimizer.step()

            lr_find_loss.append(loss.item())
            lr_find_lr.append(current_lr)

            current_lr *= lr_increment
            if current_lr &gt; lr_final:
                break

        return lr_find_lr, lr_find_loss</code></pre>
<hr>
<blockquote>
<p>📌 혹시 Classification 부분을 읽기 전에 AST 모델 구조가 궁금하시면 아래를 읽어주세요.</p>
</blockquote>
<h4 id="ast-모델-구조-및-forward-과정"><strong>AST 모델 구조 및 forward 과정</strong></h4>
<p><img src="https://velog.velcdn.com/images/haikoo_ai96/post/9760bbbc-7e53-48c9-babe-dec441cb1004/image.png" alt=""></p>
<p><strong>AST 모델 Forward 과정</strong></p>
<ol>
<li>(1024, 128)의 형태인 Mel Spectrogram이 input으로 들어간다.
 a. 1024는 Time Step(sequence), 128은 mel filter bank 갯 수</li>
<li>Mel Spectrogram은 16 x 16 patch로 쪼개진다. 위 그림에서 1번, 2번 같이 숫자로 지정된 것들이 patch들이다.</li>
<li>Linear Projection에서 Convolution 2d로 한 개의 patch를 768개의 값을 추출하여 1d array 형태인 임베딩 값으로 변환한다.
 a. out-channel: 768</li>
</ol>
<p><img src="https://velog.velcdn.com/images/haikoo_ai96/post/59e65821-99ff-4e53-93b0-55d822a469b1/image.png" alt=""></p>
<ol start="4">
<li>그리고 encoder에 forward 되기 전에 sequence 처음 구간에 CLS 토큰이 추가된다.</li>
<li>위치 정보를 담기 위해 Positional Embedding이 더해진다.</li>
<li>Encoder를 통과 후 최종적으로 Layer Normalization을 거치면 (1214, 768) 형태인 임베딩값이 나온다.
a. 1214: sequence/time step, 768: feature/hidden dimension</li>
</ol>
<hr>
<p>이 변화들을 가지고 우리 팀은 두 가지 방향으로 분류를 진행하였다.</p>
<p><strong>1. Dense Layer Classification</strong></p>
<p>처음에는 embedding을 그대로 flatten을 시켜 분류를 진행하였다. 하지만 첫 번째 Dense Layer에서 neuron 크기가 90만 이상이 되어 우려가 됐다. 그래서 Computational Power를 고려해 Pooler Output을 써서 분류해보기로 했다.</p>
<blockquote>
<p>flatten 후 분류 실험은 스프레드시트에서 확인 가능
    👉 <strong><a href="https://docs.google.com/spreadsheets/d/1VrBcxZ9iSM_e3_7EH3_9JRecfQMw1EZPscAJo_ZtN-k/edit#gid=1392562511">으아앙팀 AST 모델 실험 기록지</a></strong> 👈</p>
</blockquote>
<p>처음에는 Pooler Output이 뭔지 잘 몰라서 멘토님께 여쭤봤다.</p>
<p>멘토님께서 설명하길 Pooler Output은 전체 Hidden Attention Layer를 거친 후 압축한 embedding 값이라고 설명했다. 더 자세한 설명은 아래 HuggingFace에서 제공한 Documentation을 읽어보면 된다. </p>
<p><img src="https://velog.velcdn.com/images/haikoo_ai96/post/b50dc0a1-5f1d-4e48-a1d8-cf6ff8b12993/image.png" alt=""></p>
<p>사실 필자는 Documentation을 읽어봤지만 BERT에 대한 이해가 없어 이 부분은 넘겨버렸다. 그냥 압축된 임베딩이라고 머릿속에 담고 진행하였다. </p>
<p>물론 바로 분류 모델을 쌓아서 실험을 진행했지만 한 번 Pooler Output이 Classification에 적합한지 보기 위해 각 클래스마다 Pooler Output을 뽑아 T-SNE로 클러스터 여부를 보았다.</p>
<p><img src="https://velog.velcdn.com/images/haikoo_ai96/post/9ec40904-d5df-480f-a26e-9159b2bdb81e/image.png" alt=""></p>
<p><strong>Pooler Output Classification 결과</strong></p>
<ul>
<li>여러 개의 실험이 있었지만 여기서는 그나마 대표적인 것만 표시<ul>
<li>나머지 실험들은 스프레드시트에서 확인 바람</li>
</ul>
</li>
<li>Test Accuracy: 53.00%</li>
<li>Train, Validation 그래프</li>
</ul>
<p><img src="https://velog.velcdn.com/images/haikoo_ai96/post/d19d8be3-b1a7-4952-b040-8e72c06db28a/image.png" alt=""></p>
<p>그래프가 보여지는 것 처럼 오버피팅이 심했기 때문에 좋은 결과를 보지는 못했다. </p>
<p>결과적으로 T-SNE에서 클러스터 여부와 그래프, Test Accuracy를 고려했을 때 Pooler Output이 classification에 적합하지 않았다고 생각했다. 물론 그때 상황에서의 판단이었고 더 좋은 하이퍼파라미터나 데이터 셋의 사이즈와 다양성이 컸으면 또 다를 수도 있었기 때문에 Pooler Output에 대한 결론은 사실 조금 객관적이지 않을 수 있다. </p>
<p>아쉬운 실험 결과로 결국 우리 팀은 Convolution 1d에 희망을 걸게 되었다.</p>
<p><strong>2. Convolution 1D Classification(최종 모델 채택)</strong></p>
<p>CNN을 이미지 분류에서 다루어 받기 때문에 처음에는 Convolution 1D는 괜찮을 거라 생각했다. 하지만 우리가 익숙해 있었던 건 일반적인 convolution 2D, 3 채널 이미지에서 Pointwise Convolution 혹은 Depthwise Convolution 연산들이었고 Convolution 1D는 다른 각도로 접근했어야 했기 때문에 생각보다 생소하게 느껴졌다.</p>
<p>그래도 멘토님의 설명 덕분에 빠르게 이해하고 넘어갈 수 있었다.</p>
<p>아래 그림은 우리가 설계한 Conv1d 구조이다.</p>
<p><strong><code>그림 1</code></strong></p>
<p><img src="https://velog.velcdn.com/images/haikoo_ai96/post/ab1d112e-740f-4449-93fd-9d44a445d589/image.png" alt=""></p>
<p>우선 AST 모델을 통과하게 되면 (1214: sequence, 768: hidden dimension) 사이즈의 임베딩 값을 가지게 된다. 그 후 Transpose를 취하고 Convolution을 연산을 하여 1d array의 형식인 512개 channel의 Feature Map을 만든다. </p>
<p>여기서 자세히 볼 건 처음에 2D 임베딩이 어떻게 Convolution 연산을 거치는 것이다. Convolution 2D와 다른 점은 Convolution의 stride 가 횡 이동 없이 세로 방향으로만 이동이 된다. 그래서 Kernel Size 4는 열(Sequence) 기준으로 얼마큼 차지하는지의 의미로만 보면 된다. </p>
<p>더 쉽게 이해하기 위해 아래 그림을 참고하는 게 좋다.</p>
<p><strong><code>그림 2</code></strong>
<img src="https://velog.velcdn.com/images/haikoo_ai96/post/d5634b8a-51ec-414d-b69f-960f0aaf28fe/image.png" alt=""></p>
<p>먼저 <strong>그림 2</strong> 왼쪽 부분에서 (1214, 768) 인 임베딩을 보면 (1214, 1)인 array를 768 만큼 나열된 걸 볼 수 있다. 그리고 <strong>그림 2</strong> 오른쪽 Feature Map 처럼 다시 나열한다고 생각하면 된다. 그러면 768 channels 의 (1214, 1) array들로 구성된다. </p>
<p>그리고 Kernel Size 가 4인 경우 똑같은 Kernel이 768 번 Convolution 연산이 된다. 그래서 Convolution 2D 로 따져보면 <strong>그림 1</strong> 처럼 (768, 4)인 커널을 갖게 되는 셈이다.  <strong>그림1</strong> 의 빨간색 박스를 보면 (768, 4)의 형태인 Kernel를 볼 수 있다. <strong>그림2</strong> 에선 점선으로 이어진 Kernel들이 같이 세로로 움직인다고 보면 된다.</p>
<ul>
<li><p><code>conv1d 코드 예시</code></p>
<pre><code class="language-python">   # Conv1d starts
   self.conv1d1 = nn.Sequential(
       nn.Conv1d(in_channels=768,
                 out_channels = 512,
                 kernel_size = 4,
                 stride = 1),
       nn.BatchNorm1d(512),
       nn.ReLU())</code></pre>
</li>
</ul>
<p>Convolution 1D 이후 Global Average Pooling을 하여 flatten을 시켰고 Dense Layer 하나만 쌓아서 Classifier Layer 로 분류를 진행하였다.</p>
<ul>
<li><p><code>Dense Layer 코드</code></p>
<pre><code class="language-python">   self.adapted = nn.AdaptiveAvgPool1d(1)

   # Dense Layer
   self.layer_fc3 = nn.Sequential(
       nn.Linear(512,128),
       nn.BatchNorm1d(128),
       nn.GELU(),
       nn.Dropout(0.3))

   self.add_layer_01 = nn.Linear(128, num_labels)
   self.num_labels = num_labels</code></pre>
</li>
</ul>
<p>실험 결과는 다음과 같다.</p>
<ol>
<li>Epoch 50<br><img src="https://velog.velcdn.com/images/haikoo_ai96/post/98cca0f6-5f12-4d0f-83cb-76ca76de2e7d/image.png" alt=""></li>
</ol>
<p>Test Accuracy: 74.36%</p>
<ol start="2">
<li>Epoch 75
<img src="https://velog.velcdn.com/images/haikoo_ai96/post/c2411056-ffbe-4122-a554-be630f265652/image.png" alt=""></li>
</ol>
<p>Test Accuracy: 69.23%</p>
<p>그래서 전체 모델별 Test Accuracy 는 아래와 같이 정리해 볼 수 있다.</p>
<table>
<thead>
<tr>
<th></th>
<th>Test Accuracy</th>
</tr>
</thead>
<tbody><tr>
<td>VGG16</td>
<td>35.00%</td>
</tr>
<tr>
<td>Multi_input_DNN</td>
<td>58.21%</td>
</tr>
<tr>
<td>U-Net with Classifier</td>
<td>58.82%</td>
</tr>
<tr>
<td>AST</td>
<td>74.36%</td>
</tr>
</tbody></table>
<hr>
<p>👉👉 <a href="https://velog.io/@haikoo_ai96/chp-4-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EB%A5%BC-%EB%A7%88%EC%B9%98">마지막 챕터 읽으러 가기</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Chapter 3-3: Audio Spectrogram Transformer(AST)를 활용한 울음소리 분류]]></title>
            <link>https://velog.io/@haikoo_ai96/Chapter-3-3-Audio-Spectrogram-TransformerAST%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-%EC%9A%B8%EC%9D%8C%EC%86%8C%EB%A6%AC-%EB%B6%84</link>
            <guid>https://velog.io/@haikoo_ai96/Chapter-3-3-Audio-Spectrogram-TransformerAST%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-%EC%9A%B8%EC%9D%8C%EC%86%8C%EB%A6%AC-%EB%B6%84</guid>
            <pubDate>Sat, 20 Apr 2024 05:13:07 GMT</pubDate>
            <description><![CDATA[<h2 id="ast-여정-전반부">AST 여정 전반부</h2>
<p>멘토링을 통해 CLAP과 AST 모델을 추천받았지만 팀 내에서 AST 모델이 CLAP 모델보다 접근이 더 쉬어 AST 모델을 쓰기로 하였다. </p>
<p>AST 를 활용하는 데 있어서 U-Net 과 비슷한 흐름으로 진행되었다. 물론 HuggingFace, Pytorch를 다루는 법을 새로 배워야 하는 상황인 부분에서 조금 다르긴 했지만 U-Net에서 처럼 기본에 충실하지 않았던 부분이 AST 여정 후반부가 생긴 이유이기도 하다. 후반부가 메인 하이라이트이기 때문에 전반부는 간략하게 어떤 부분에서 문제가 있었는지 서술하고 후반부로 넘어갈 예정이다.</p>
<h3 id="구현과-성능에-집착에-따른-문제점">구현과 성능에 집착에 따른 문제점</h3>
<ol>
<li>잘못된 Embedding 값의 활용
 a. AST encoder를 통과한 임베딩을 그대로 사용하지 않고 평균을 내어 사용</li>
<li>Dense Layer 에서 이진분류가 아닌데 Sigmoid Activation을 사용</li>
<li>Data Imbalance</li>
</ol>
<p>위 문제를 충분히 고려하지 않은 탓에 아주 치명적인 문제가 생겼다. 그래서 우리 팀은 아주 큰 결단을 하게 되는데 이 부분은 후반부에서 다뤄지기 때문에 꼭 읽었으면 한다.</p>
<hr>
<p>👉👉 <a href="https://velog.io/@haikoo_ai96/Chp-3-4-AST%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-%EC%9A%B8%EC%9D%8C%EC%86%8C%EB%A6%AC-%EB%B6%84%EB%A5%98">다음 챕터 읽으러 가기</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Chapter 3-2: U-net을 활용한 울음소리 분류]]></title>
            <link>https://velog.io/@haikoo_ai96/Chapter-3-U-net%EC%9D%84-%ED%99%9C%EC%9A%A9%ED%95%9C-%EC%9A%B8%EC%9D%8C%EC%86%8C%EB%A6%AC-%EB%B6%84</link>
            <guid>https://velog.io/@haikoo_ai96/Chapter-3-U-net%EC%9D%84-%ED%99%9C%EC%9A%A9%ED%95%9C-%EC%9A%B8%EC%9D%8C%EC%86%8C%EB%A6%AC-%EB%B6%84</guid>
            <pubDate>Sat, 20 Apr 2024 05:10:18 GMT</pubDate>
            <description><![CDATA[<h2 id="u-net-encoder의-데뷔-무대">U-Net Encoder의 데뷔 무대</h2>
<p>비지도 학습이 끝이 난 후 드디어 우린 U-Net Encoder의 데뷔 무대를 볼 수 있었다. 뭐든 시작에는 설렘과 긴장이 반반 섞여있듯이 기대반 긴장반인 상태로 훈련에 들어갔다.</p>
<p>우선 Dense Layer는 아래 같이 쌓았다.</p>
<pre><code class="language-python"># Dense layers after the encoder 
inputs = layers.Input(shape= X_train_dim[0].shape)

input_layer = load_encoder(inputs)

full01 = layers.Flatten()(input_layer)
dense01 = layers.Dense(1024, activation=&#39;relu&#39;)(full01)
batch01 = layers.BatchNormalization()(dense01)
drop01 = layers.Dropout(0.25)(batch01)

dense02 = layers.Dense(512, activation=&#39;relu&#39;)(drop01)
batch02 = layers.BatchNormalization()(dense02)
drop02 = layers.Dropout(0.25)(dense02)

dense03 = layers.Dense(128, activation=&#39;relu&#39;)(drop02)
batch03 = layers.BatchNormalization()(dense03)
drop03 = layers.Dropout(0.25)(dense03)

# classifier
out_layer = layers.Dense(4, activation=&#39;softmax&#39;)(drop03)</code></pre>
<h3 id="실험-결과">실험 결과</h3>
<p><img src="https://velog.velcdn.com/images/haikoo_ai96/post/895c1820-ba2c-45f6-9ad3-c4fa6a347564/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/haikoo_ai96/post/98e4c517-5f08-4ff2-97bc-faa1b89868ed/image.png" alt=""></p>
<p>Test Accuracy: 58.82%</p>
<p>이 실험을 요약해 보면 Encoder의 데뷔전은 아쉬운 결과로 볼 수 있다. 그래프를 살펴보면 YAMnet에 비해 오버피팅이 확연하게 드러났고 Confusion Matrix를 통해 두 개의 클래스(불편함, 배고픔)를 주로 예측하는 모습을 볼 수 있다. Test Accuracy는 YAMNet 보다 소폭 증가하긴 했지만 그래프와 혼동행렬이 Robust하지 않음을 증명해주고 있다.</p>
<h3 id="회고">회고</h3>
<p>가장 큰 문제였던 건 데이터셋 구성이 아닐까 싶다. 사실 이 프로젝트가 끝난 후 가장 크게 깨달은 점이 기본을 먼저 지키는 것이었다. 모델링 전에 데이터 셋 Balance가 어떤지 그리고 Input 사이즈의 의미 등등 EDA 부터 전처리까지 제대로 이루어지지 않았기 때문에 모델링에서 좋은 결과를 바라기에는 무리가 있다. </p>
<p>아래 그래프는 U-Net Classification에 사용된 데이터 셋 구성을 나타낸 그래프이다. 살펴보면 불편함, 배고픔이 가장 많다.</p>
<p><img src="https://velog.velcdn.com/images/haikoo_ai96/post/48cc5b5c-a065-483d-be98-5c5ab061c817/image.png" alt=""></p>
<p>첫 번째로 Data Imbalance의 문제를 잡지 않고 모델링을 한 것이 치명타로 다가왔다.</p>
<p>두 번째로 Mel Spectrogram의 사이즈 의미에 대한 파악 없이 진행한 것이다. Data Imbalance 만큼 치명적이진 않지만 이 부분을 유심히 봤으면 좀 더 좋은 성능을 내지 않았을까 하는 아쉬움이 있다.</p>
<p>아래 코드가 우리가 사용한 Mel Spectrogram 추출 코드의 파라미터 들이다. 여기서 주목할 파라미터는 <code>n_fft</code>와 <code>hop_length</code> 이다. 이 두 개가 Mel Spectrogram의 사이즈에 영향을 주기 때문이다.</p>
<pre><code class="language-python">librosa.feature.melspectrogram(y=None,
                            # sr=22050,
                            # S=None,
                            n_fft=2048,
                            hop_length=512, 
                            # win_length=None, 
                            # window=&#39;hann&#39;,
                            # center=True,
                            # pad_mode=&#39;constant&#39;,
                            # power=2.0, **kwargs)</code></pre>
<p>좀 더 구체적으로 설명하면 n_fft는 window size인데 여기서 window size는 얼마만큼 전체 오디오를 잘라서 볼 것인지에 대한 파라미터다. 마치 CNN에서 <code>Kernel Filter</code>와 비슷한 역할을 한다. 단위는 millisecond(ms)이 기 때문에 위의 2048은 2.48초만큼 오디오를 들여다보는 것이다.</p>
<p>Hop Length 같은 경우 <code>stride</code>의 개념으로 보면 된다. Kernel Size에 맞춰 움직이듯이 Window Size 기준으로 얼큼 이동시키면서 오디오를 들여다볼 것인지에 대한 파라미터이다. </p>
<p>그래서 window size와 hop_length를 줄여 더 촘촘한 Mel Spectrogram을 뽑은 후에 학습을 돌려보면 좀 더 나은 결과 나오지 않을까 하는 추측을 해본다.</p>
<hr>
<p>👉👉 <a href="https://velog.io/@haikoo_ai96/Chapter-3-3-Audio-Spectrogram-TransformerAST%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-%EC%9A%B8%EC%9D%8C%EC%86%8C%EB%A6%AC-%EB%B6%84">다음 챕터 읽으러 가기</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Chapter 3: 프로젝트 후반부]]></title>
            <link>https://velog.io/@haikoo_ai96/Chapter-3-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9B%84%EB%B0%98</link>
            <guid>https://velog.io/@haikoo_ai96/Chapter-3-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9B%84%EB%B0%98</guid>
            <pubDate>Sat, 20 Apr 2024 05:03:10 GMT</pubDate>
            <description><![CDATA[<h1 id="a-u-net-autoencoder-학습">A. U-Net Autoencoder 학습</h1>
<hr>
<h2 id="u-net-을-활용한-비지도-학습">U-Net 을 활용한 비지도 학습</h2>
<p>지금까지 배워온 비지도학습은 Clustering 기법이나 PCA 같은 Dimension Reduction 기법이었다. 그래서 Encoder Decoder를 MSE로 학습시키는 방법은 생소하긴 했다. 하지만 나름 직관적으로 이해할 수 있었기 때문에 팀에서도 접근성이 좋은 방법 중에 하나였다.</p>
<h3 id="데이터-셋">데이터 셋</h3>
<p>데이터 셋 비율은 다음과 같다.</p>
<ol>
<li>AudioSet 60%</li>
<li>CryCeleb 30%</li>
<li>Kaggle Data 10%
 a. <a href="https://www.kaggle.com/datasets/raiyanjahangir1939/infant-cry-sounds">https://www.kaggle.com/datasets/raiyanjahangir1939/infant-cry-sounds</a></li>
</ol>
<p>CryCeleb 같은 경우 18000개의 오디오 데이터가 있지만 대부분 1초가량의 데이터가 많아 1초를 5번 루프를 돌려 재구성했다. 그래서 CryCeleb이 비율이 높았지만 루프에 대한 Feature 즉 음색 보단 Temporal Feature에 집중이 될 우려가 있어 비율을 낮춰서 데이터 셋을 구성했다.</p>
<h3 id="전처리">전처리</h3>
<p>우선 멘토님께서 말했듯이 Mel Spectrogram 을 input으로 써보기로 했다. </p>
<blockquote>
<p>Mel Spectrogram 에 대해 다시 설명을 보고 싶으시면 아래 링크를 클릭해주세요!
<a href="https://www.notion.so/Mel-spectrogram-acc75755d705487eb57f8030a1c021d6?pvs=21"><strong><em>Mel-spectrogram 이란?</em></strong></a></p>
</blockquote>
<p>아기 울음소리를 Mel Spectrogram으로 변환 후 (128, 128) 로 모든 데이터를 맞춰주었다. 여기서 첫 번째 128은 Mel Filter Bank의 Filter 개수이다. 두 번째 128은 Time Step 이다. 자세한 설명은 아래 링크에 들어가서 영상과 설명을 보는 걸 추천한다. 영어로 되어 있어 한글 자료를 찾아 이해하고 링크에 있는 영상을 꼭 보는 걸 추천한다.</p>
<p><a href="https://learn.flucoma.org/reference/melbands/">https://learn.flucoma.org/reference/melbands/</a></p>
<p><code>전처리 코드</code></p>
<pre><code class="language-python"># Mel Spectrogram 패딩 혹은 자르기
reshaped = []

for mspc in mel_spec_re:
    h, w = mspc.shape

    if w &lt; h:
        left_width = (h - w) // 2
        pad_remainder = (h - w) % 2
        padded = np.pad(mspc, pad_width = ((0, 0), (left_width, left_width + pad_remainder)), mode = &#39;constant&#39;, constant_values=0)
        reshaped.append(padded)
    else:
        trunc_mspc = mspc[:, :h]
        reshaped.append(trunc_mspc)</code></pre>
<h3 id="모델링">모델링</h3>
<p>이번에도 팀장님이 솔선수범하게 U-net을 직접 구현하였다.</p>
<p><code>U-net 코드</code></p>
<pre><code class="language-python">from tensorflow.keras.layers import LeakyReLU

def build_unet(input_shape):
    # Define the input layer
    inputs = tf.keras.Input(shape=input_shape)

    # Encoder Layer
    # [1]
    conv0 = layers.Conv2D(32, activation=&#39;relu&#39;, kernel_size = 3, padding=&#39;same&#39;)(inputs) # 104  52 26
    conv1 = layers.Conv2D(32, activation=&#39;relu&#39;, kernel_size = 3, padding=&#39;same&#39;)(conv0)  # Skip connection으로 Expanding path로 이어질 예정, 
    conv2 = layers.MaxPooling2D(pool_size=(2, 2), strides=(2, 2))(conv1) # 64

    # [2]
    conv3 = layers.Conv2D(64, activation=&#39;relu&#39;, kernel_size = 3, padding=&#39;same&#39;)(conv2) # 
    conv4 = layers.Conv2D(64, activation=&#39;relu&#39;, kernel_size = 3, padding=&#39;same&#39;)(conv3) # 
    conv5 = layers.MaxPooling2D(pool_size=(2, 2), strides=(2, 2))(conv4) # 32

    # [3]
    conv6 = layers.Conv2D(128, activation=&#39;relu&#39;, kernel_size=3, padding=&#39;same&#39;)(conv5) # 
    conv7 = layers.Conv2D(128, activation=&#39;relu&#39;, kernel_size=3, padding=&#39;same&#39;)(conv6) # 
    conv8 = layers.MaxPooling2D(pool_size=(2, 2), strides=(2, 2))(conv7) # 16

    # [4]
    conv9 = layers.Conv2D(256, activation=&#39;relu&#39;, kernel_size=3, padding=&#39;same&#39;)(conv8) # 
    conv10 = layers.Conv2D(256, activation=&#39;relu&#39;, kernel_size=3, padding=&#39;same&#39;)(conv9) # 
    conv11 = layers.MaxPooling2D(pool_size=(2, 2), strides=(2, 2))(conv10) # 8

    # [5]
    conv12 = layers.Conv2D(512, activation=&#39;relu&#39;, kernel_size=3, padding=&#39;same&#39;)(conv11) # 
    conv13 = layers.Conv2D(512, activation=&#39;relu&#39;, kernel_size=3, padding=&#39;same&#39;)(conv12) # 

    # Contracting path

    # The output of the last encoder layer
    encoder_output = conv10

    # Decoder Layer
    # [6]
    trans01 = layers.Conv2DTranspose(256, kernel_size=2, strides=(2, 2), activation=&#39;relu&#39;)(conv13) # 
    # crop01 = layers.Cropping2D(cropping=(4, 4))(conv4) 
    concat01 = layers.concatenate([trans01, conv10], axis=-1) # 

    # [7]
    conv14 = layers.Conv2D(256, activation=&#39;relu&#39;, kernel_size=3, padding=&#39;same&#39;)(concat01) # 
    conv15 = layers.Conv2D(256, activation=&#39;relu&#39;, kernel_size=3, padding=&#39;same&#39;)(conv14)  # 

    trans02 = layers.Conv2DTranspose(128, kernel_size=2, strides=(2, 2), activation=&#39;relu&#39;)(conv15)
    # crop02 = layers.Cropping2D(cropping=(16, 16))(conv1) # 
    concat02 = layers.concatenate([trans02, conv7], axis=-1)

    # [8]
    conv16 = layers.Conv2D(128, activation=&#39;relu&#39;, kernel_size=3, padding=&#39;same&#39;)(concat02) # 
    conv17 = layers.Conv2D(128, activation=&#39;relu&#39;, kernel_size=3, padding=&#39;same&#39;)(conv16)  # 

    trans03 = layers.Conv2DTranspose(64, kernel_size=2, strides=(2, 2), activation=&#39;relu&#39;)(conv17)
    # crop02 = layers.Cropping2D(cropping=(16, 16))(conv1) # 
    concat03 = layers.concatenate([trans03, conv4], axis=-1)

    # [9]
    conv18 = layers.Conv2D(64, activation=&#39;relu&#39;, kernel_size=3, padding=&#39;same&#39;)(concat03) # 
    conv19 = layers.Conv2D(64, activation=&#39;relu&#39;, kernel_size=3, padding=&#39;same&#39;)(conv18)

    trans04 = layers.Conv2DTranspose(32, kernel_size=2, strides=(2, 2), activation=&#39;relu&#39;)(conv19)
    # crop02 = layers.Cropping2D(cropping=(16, 16))(conv1) # 
    concat04 = layers.concatenate([trans04, conv1], axis=-1)

    # [10]
    conv20 = layers.Conv2D(32, activation=&#39;relu&#39;, kernel_size=3, padding=&#39;same&#39;)(concat04) # 
    conv21 = layers.Conv2D(32, activation=&#39;relu&#39;, kernel_size=3, padding=&#39;same&#39;)(conv20)

    # Expanding path

    # Define the output layer for the U-Net
    outputs = layers.Conv2D(1, kernel_size=1)(conv21)

    # Full U-Net model
    unet_model = tf.keras.Model(inputs=inputs, outputs=outputs)

    # Return the full model and the encoder part
    encoder_model = tf.keras.Model(inputs=inputs, outputs=encoder_output)
    return unet_model, encoder_model

# Define your input shape based on your mel-spectrogram dimensions
input_shape = (128, 128, 1)  # Example shape
unet, encoder = build_unet(input_shape)</code></pre>
<p><code>optimizer 설정</code></p>
<p><img src="https://velog.velcdn.com/images/haikoo_ai96/post/ed70817e-629c-4b2f-9968-3de400657b65/image.png" alt=""></p>
<p>손실함수는 <strong>MSE</strong>로 설정하여 훈련을 진행했다.</p>
<hr>
<p>👉👉 <a href="https://velog.io/@haikoo_ai96/Chapter-3-U-net%EC%9D%84-%ED%99%9C%EC%9A%A9%ED%95%9C-%EC%9A%B8%EC%9D%8C%EC%86%8C%EB%A6%AC-%EB%B6%84">다음 챕터 읽으러 가기</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Chapter 2-5: 멘토링]]></title>
            <link>https://velog.io/@haikoo_ai96/Chapter-2-5-%EB%A9%98%ED%86%A0%EB%A7%81</link>
            <guid>https://velog.io/@haikoo_ai96/Chapter-2-5-%EB%A9%98%ED%86%A0%EB%A7%81</guid>
            <pubDate>Sat, 20 Apr 2024 04:59:51 GMT</pubDate>
            <description><![CDATA[<h2 id="멘토님의-처방전">멘토님의 처방전</h2>
<p>YAMNet 이후 우리 팀은 뭔가 Turning Point가 필요했다. 뭔가 더 이상 진전할 수 있는 방법을 생각하기 어려운 나머지 멘토링을 받기로 했다.</p>
<p>멘토님을 간단히 소개하면 모두의 연구소에서 Rubato Lab 랩 장을 맡고 계시다. 루바토 랩은 생성형 AI를 통해 음원제작에 연구하는 팀이라고 보면 될 것 같다. </p>
<p><code>Rubato Lab</code></p>
<p><a href="https://modulabs.co.kr/product/lab-14146-2023-11-15-120437/">Rubato LAB</a></p>
<p>우선 오디오 분야에 전문가이시기 때문에 왠지 멘토링 이후 막혔던 부분이 뻥~ 뚫릴 것 같은 느낌이 들었다.</p>
<h3 id="여기-처방전이요">여기 처방전이요~</h3>
<p>아니다 다를까 멘토링은 나름 만족스러웠다. 우선 우리가 해온 과정에 대해 잘못된 점을 짚어주셨다. 특히, input type에 대해서 말이다.</p>
<p>우리는 줄곳 MFCC를 써왔지만 멘토님께서 MFCC 는 음색을 나타내는 Feature가 아니기 때문에 Mel Spectrogram의 Input으로 바꿔보라고 제안하셨다. </p>
<p>그리고 더 나아가 YAMnet은 SOTA 모델이 아니기 때문에 그래도 최신 모델인 Transformer 기반의 Encoder를 써서 classification task에 적용해 보라고 알려주셨다.</p>
<p>추천해 주신 모델은 다음과 같다.</p>
<ol>
<li>CLAP: <a href="https://huggingface.co/docs/transformers/model_doc/clap">https://huggingface.co/docs/transformers/model_doc/clap</a></li>
<li>AST(Audio Spectrogram Transformer): <a href="https://huggingface.co/docs/transformers/model_doc/audio-spectrogram-transformer">https://huggingface.co/docs/transformers/model_doc/audio-spectrogram-transformer</a></li>
</ol>
<p>솔직히 Transformer에 대해 이해가 잘 되어 있지는 않았지만 성능을 높여보기 위해 팀원들과 공부하고 적용하는 방향으로 결정을 하게 됐다.</p>
<p>마지막으로 멘토님께서 unlabeled data를 Autoencoder 에 Unsupervised 방식으로 학습시킨 후 Encoder를 떼와서 classification을 진행해 보는 방법도 제시해 주었다. 개인적으론 dataset 사이즈가 작은 상황을 고려하면 제시해 주신 Autoencoder 아이디어가 제일 흡족스러웠다.</p>
<hr>
<p>👉👉 <a href="https://velog.io/@haikoo_ai96/Chapter-3-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9B%84%EB%B0%98">다음 챕터 읽으러 가기</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Chapter 2-4: 모델링 Pt.2]]></title>
            <link>https://velog.io/@haikoo_ai96/Chapter-2-4-%EB%AA%A8%EB%8D%B8</link>
            <guid>https://velog.io/@haikoo_ai96/Chapter-2-4-%EB%AA%A8%EB%8D%B8</guid>
            <pubDate>Sat, 20 Apr 2024 04:57:42 GMT</pubDate>
            <description><![CDATA[<h2 id="데이터가-적을땐-pretrained-model-이-인지상정-그러나">데이터가 적을땐 Pretrained-model 이 인지상정! 그러나…</h2>
<p>VGG16 성능에서 기대에 못 미치는 결과를 본 이유는 MFCC에 맞게 Kernel size와 stride를 설정을 못해준 이유도 있지만 데이터셋 사이즈 영향이 있는 것도 확실하다. </p>
<p>하지만 데이터 수집 부분에서 말했듯이 우리 팀은 만족할 수 있는 데이터 수량을 맞추지 못했다. 그래서 차 선택으로 pretrained model 을 써보는 방향으로 논의가 진행됐다.</p>
<p>마침 Kaggle에서 구글에서 제공한 AudioSet으로 학습된 pretrained-model이 있었다. </p>
<blockquote>
<p><a href="https://research.google.com/audioset//dataset/baby_cry_infant_cry.html">AudioSet(Infant Cry)</a></p>
<ol>
<li>Google에서 공개한 YouTube 영상에 기반한 오디오 데이터셋
 a. 2,084,320 개의 영상을 오디오 셋으로 묶은 데이터셋
 b. 이 중 아기 울음소리 영상은 무려 2390개나 포함</li>
</ol>
</blockquote>
<p>Pretrained-model 이름은 <strong><a href="https://www.kaggle.com/models/google/yamnet">YAMNet</a></strong>이고 Mobilenet_v1 구조를 갖고 있다. </p>
<h2 id="yamnet-과의-여정">YAMNet 과의 여정</h2>
<p>YAMNet을 찾은 후 왠지 안도감이 들었다. 따로 모델을 구축해서 분류할 필요 없이 바로 분류가 될 거라는 희망으로 김칫국 한 사발을 들이켰다. 역시 설레발 드링킹이 주는 안도감은 금방 꺼지기 마련이다. </p>
<p>그렇게 희망에 가득 찬 눈빛으로 분류를 시작하려 하는데… 
<img src="https://velog.velcdn.com/images/haikoo_ai96/post/499665bd-7b02-4204-b7c6-6d2a48e237cc/image.png" alt=""></p>
<blockquote>
<p>또잉하는 맛은 역시 Documentation을 읽을 때 재 맛인  것 같다. 하하하하….. 😂😂</p>
</blockquote>
<p>Documentation을 읽은 결과 YAMnet 의 output은 Scores, Embeddings, Mel-spectrogram이었다. Embedding은 YAMNet 을 거쳐서 Global Average 된 값이고 Score는 521 클래스에 해당하는 점수이다. Mel Spectrogram은 아래 설명을 참고 바람.</p>
<blockquote>
<p><strong><em>Mel-spectrogram 이란?</em></strong></p>
<p><img src="https://velog.velcdn.com/images/haikoo_ai96/post/7c67a872-6267-45c6-8cd3-bf51b07ddbfb/image.png" alt=""></p>
<p>쉽게 설명해서 시간축과 증폭축에서 시간축과 주파수축으로 변환된 상태라 보면 된다. 위 사진은 변환과정을 나타낸 것이다. 더 정확하게 이해하려면 Fourier Transform을 봐야 한다. 그래서 Fourier Transform이 어떻게 Frequency Domain으로 변환하는지 알면 더 깊게 이해할 수 있다. 하지만 나도 여기까지 자세히 이해하는데 어려움을 겪어 아쉽게 Pass 하였다.</p>
</blockquote>
<p>분류기는 따로 없는 걸 확인 한 순간 나의 안도감은 저 세상으로 가버렸다. 어떻게 보면 멍청한 실수를 한 것일지도 모른다. 모든 Pretrained-Model에서는 Embedding이나 Feature Map을 뽑아주는 역할이 주인데 분류기까지 바라는 어리섞은 희망이 나에게 가시로 돌아왔다. 더 군다나 VGG16으로 팀원들과 분류까지 했었는데 Convolution 이후 Dense Layer를 쌓는 과정 자체를 잠시 까먹은 나에게 참 어떤 말을 해줘야 할지 난감했다. </p>
<p>나의 일시적 수난시대는 잠시 뒤로 하고 팀원들과 어떻게 YAMNet을 활용 방안에 대해 얘기를 나눠본 결과 Multi-Input Deep Neural Network로 해보기로 결정했다.</p>
<p>이렇게 결정한 이유는 하나의 input 보다 3 가지 input(<code>scores</code>, <code>embeddings</code>, <code>Mel Spectrogram</code>)을 동시에 입력받아 Forward 시키면 좋은 성능을 기대할 수 있지 않을까 하는 이유로 시도해 보기로 했다.</p>
<h3 id="multi-input-dense-layer-architecture"><strong>Multi-Input Dense Layer Architecture</strong></h3>
<p>분류 모델 구조는 아래 그림과 같다.</p>
<p><img src="https://velog.velcdn.com/images/haikoo_ai96/post/5eec7516-c6f6-4602-a665-0844241a4c16/image.png" alt=""></p>
<blockquote>
<p>자세한 코드를 보시려면 아래 링크를 클릭 해주세요.
<em><a href="https://github.com/Haikoo96/aiffelton_babycry_classification/blob/main/modeling/Multi_input_YAMnet_classification.ipynb">Multi-Input-DNN Notebook</a></em></p>
</blockquote>
<h3 id="실험결과"><code>실험결과</code></h3>
<p><img src="https://velog.velcdn.com/images/haikoo_ai96/post/1ab118ca-7139-42d3-be78-dd5e8ed30726/image.png" alt=""></p>
<p>Test Accuracy: 34.15%</p>
<p>실험결과 좋은 성능을 내지 못하였다. 그래서 다시 논의 후 Mel Spectrogram을 입력받는 대신 MFCC로 진행해 보기로 하였다.</p>
<h3 id="mfcc-실험결과">MFCC 실험결과</h3>
<p><img src="https://velog.velcdn.com/images/haikoo_ai96/post/b69c547e-ec21-40c0-9c8f-d18643b3b4be/image.png" alt=""></p>
<p>Test Accuracy: 58.21%</p>
<p>이전 실험보단 좋은 성능을 보였고 그래프도 전 보다 overfitting 덜한 걸 확인할 수 있었다. 그래서 우선 이걸로 추론 모델로 지정하였다. 하지만 여전히 낮은 성능을 개선하기 위해 우리 팀은 멘토링을 받기로 했다.</p>
<p>다만 Training Accuraccy가 아직 1.0을 못 찍었기 때문에 에폭을 더 늘려봤으면 하는 아쉬움이 남아 있다. </p>
<p>그리고 어차피 flatten 시켜서 입력을 받기 때문에 Score 대신 MFCC를 flatten 해서 입력을 주는 방식도 괜찮았을 것 같다.</p>
<h3 id="감사-인사-to-우리-팀장님">감사 인사 to 우리 팀장님</h3>
<p>이번 전반부 모델링은 팀원이자 팀장님인 임구 님께서 맡아 주셨는데 VGG16과 Multi Input DNN을 직접 다 구현해 주신 덕에 좋은 인사이트를 얻을 수 있었다. 모델 구현을 직접 하는 게 힘드셨을 텐데 감사 인사말로 마무리 지어 봅니다. 수고하셨어요 임구 님!!! 👍</p>
<blockquote>
<p>강임구(팀장님스): <a href="https://github.com/knggu">깃헙링크</a></p>
</blockquote>
<hr>
<p>👉👉 <a href="https://velog.io/@haikoo_ai96/Chapter-2-5-%EB%A9%98%ED%86%A0%EB%A7%81">다음 챕터 읽으러 가기</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Chapter 2-3: 모델링 Pt.1]]></title>
            <link>https://velog.io/@haikoo_ai96/Chapter-2-3-%EB%AA%A8%EB%8D%B8%EB%A7%81</link>
            <guid>https://velog.io/@haikoo_ai96/Chapter-2-3-%EB%AA%A8%EB%8D%B8%EB%A7%81</guid>
            <pubDate>Sat, 20 Apr 2024 04:48:09 GMT</pubDate>
            <description><![CDATA[<h2 id="vgg16-과-mfcc의-만남과-헤어짐">VGG16 과 MFCC의 만남과 헤어짐</h2>
<p>데이터 수집 부분에서 MFCC를 잠깐 소개한 적이 있다.</p>
<blockquote>
<p>데이터 수집 챕터를 못 보셨거나 다시 일고 싶으시다면 아래 링크 클릭! 
👉 <a href="https://velog.io/@haikoo_ai96/Chapter-2-2-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%A0%84%EB%B0%98%EB%B6%80">데이터 수집(MFCC 설명 포함)</a></p>
</blockquote>
<p>다시 간략하게 짚고 넘어가면 MFCC는 2d 형태인 데이터인데 Time Step마다 소리의 에너지(혹은 증폭)가 어떻게 변하는지 보여주는 오디오 Feature중에 하나이다. </p>
<p>우선 MFCC에 대해 처음 논의 됐을 때 2d 형태인 feature 였기 때문에 CNN으로 분류 task를 진행해 볼 수 있지 않을까 하는 의견들이 있었다. 그래서 이 가설로 VGG16으로 해보자고 합심하여 진행을 해보았다.</p>
<h3 id="sub-chapter-1-만남">Sub-Chapter 1: 만남</h3>
<p>처음에는 VGG16을 한 번 ‘image-net’ 으로 pretrained된 모델을 불러와서 진행해 보았다. 하지만 벌써 여기서부터 문제가 일어날 것을 이미 짐작이 될 것이라고 본다(하….). </p>
<p>첫 번째로 MFCC는 1 channel 데이터이기 때문에 3 channel 데이터를 입력 받는 ‘image-net’ pretrained VGG16 모델은 이미 첫 관문인 input에서 부터 MFCC와 헤어질 조짐이 보였다. 이렇게 짧은 시간 안에 헤어짐은 아쉬울 수 있기 때문에 우리 MFCC 친구를 위해 동료분께서 VGG16을 직접 구현하여 1 channel 데이터 input으로 맞춰주었다.</p>
<p><code>1 channel input VGG16 코드</code></p>
<pre><code class="language-python">train_X_mfcc[0].shape
&gt;&gt;&gt; (20, 334, 1)

# 1 channel input VGG16
input_layer = tf.keras.layers.Input(shape=train_X_mfcc[0].shape)
x = tf.keras.layers.Conv2D(64,(3,3), strides=1, padding=&#39;same&#39;, activation=&#39;relu&#39;)(input_layer)
x=tf.keras.layers.Conv2D(64, (3, 3), strides=1, activation=&#39;relu&#39;, padding=&#39;same&#39;)(x)
x=tf.keras.layers.BatchNormalization()(x)
x=tf.keras.layers.MaxPool2D((2, 2))(x)
x=tf.keras.layers.Dropout(0.5)(x)

x=tf.keras.layers.Conv2D(128, (3, 3), strides=1, activation=&#39;relu&#39;, padding=&#39;same&#39;)(x)
x=tf.keras.layers.Conv2D(128, (3, 3), strides=1, activation=&#39;relu&#39;, padding=&#39;same&#39;)(x)
x=tf.keras.layers.BatchNormalization()(x)
x=tf.keras.layers.MaxPool2D((2, 2))(x)

x=tf.keras.layers.Conv2D(256, (3, 3), strides=1, activation=&#39;relu&#39;, padding=&#39;same&#39;)(x)
x=tf.keras.layers.Conv2D(256, (3, 3), strides=1, activation=&#39;relu&#39;, padding=&#39;same&#39;)(x)
x=tf.keras.layers.BatchNormalization()(x)
x=tf.keras.layers.MaxPool2D((2, 2))(x)

x=tf.keras.layers.Conv2D(512, (3, 3), strides=1, activation=&#39;relu&#39;, padding=&#39;same&#39;)(x)
x=tf.keras.layers.Conv2D(512, (3, 3), strides=1, activation=&#39;relu&#39;, padding=&#39;same&#39;)(x)
x=tf.keras.layers.BatchNormalization()(x)
x=tf.keras.layers.MaxPool2D((2, 2))(x)
x=tf.keras.layers.Dropout(0.5)(x)

x=tf.keras.layers.Flatten()(x)
x=tf.keras.layers.Dense(1024, activation=&#39;relu&#39;)(x)
x=tf.keras.layers.Dense(512, activation=&#39;relu&#39;)(x)
out_layer=tf.keras.layers.Dense(4, activation=&#39;softmax&#39;)(x)

model = tf.keras.Model(inputs=[input_layer], outputs=[out_layer])</code></pre>
<p>이러하여 결국 MFCC와 VGG16의 만남이 성사되길 기대하며 에폭을 돌려보는데…..</p>
<h3 id="sub-chapter-2-헤어짐">Sub-Chapter 2: 헤.어.짐</h3>
<p>만약 모든 만물이 처음에 바로 완벽해진 다면 이거야 말로 우주 대사기극이 아닐까 싶다.</p>
<p>아니다 다를까 MFCC와 VGG16은 Train and Validation Loss 그리고 Accuracy 그래프에서 헤어질 조짐이 보였다.</p>
<p><img src="https://velog.velcdn.com/images/haikoo_ai96/post/913ff04d-5d98-4b2b-b1a2-96c87c637711/image.png" alt=""></p>
<p>그리고 역시 확실한 종지부를 찍은 Test Accuracy 는 예상되었던 조짐과 크게 벗어나질 않았다.</p>
<p><img src="https://velog.velcdn.com/images/haikoo_ai96/post/720c3ea5-fe79-4cf7-9867-29517bb19311/image.png" alt=""></p>
<p>미안하다 나의 벗 MFCC여…</p>
<h3 id="개선-방안">개선 방안</h3>
<p>우선 MFCC는 아래 그림처럼 특정한 모양을 띄진 않는다. 그저 바코드 같은 모양을 띄기 때문에 오른쪽에 있는 파형의 이미지처럼 특정 모양 패턴을 육안으로 확인하기는 힘들다. 그저 색이 어떻게 바뀌는지만 볼 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/haikoo_ai96/post/c431662f-5539-406f-81f0-2a085b277bab/image.png" alt=""></p>
<p>그래서 VGG16 처럼 색뿐만 아닌 모양도 Feature Map에 녹여내는 CNN모델들은 MFCC와 적합하지 않았나 생각이 들었다. 만약 CNN을 쓰더라도 kernel sized와 stride를 time step에 맞게 지정해서 Convolution 연산을 해보는 게 더 적합해 보인다. 가령 아래 그림처럼 말이다.</p>
<p><img src="https://velog.velcdn.com/images/haikoo_ai96/post/118de0ed-be10-4895-9b62-bc0edf17393c/image.png" alt=""></p>
<p>물론 MFCC 에 맞게 CNN을 맞춰서 classification task를 진행해 보는 것 도 좋으나 기본 중의 기본인 데이터셋가 사이즈가 받쳐줘야 의미가 있지 않나 싶다.</p>
<hr>
<p>👉👉 <a href="https://velog.io/@haikoo_ai96/Chapter-2-4-%EB%AA%A8%EB%8D%B8">다음 챕터 읽으러 가기</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Chapter 2-2: Unlabeled data 활용]]></title>
            <link>https://velog.io/@haikoo_ai96/Chapter-2-2-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%A0%84%EB%B0%98%EB%B6%80</link>
            <guid>https://velog.io/@haikoo_ai96/Chapter-2-2-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%A0%84%EB%B0%98%EB%B6%80</guid>
            <pubDate>Tue, 16 Apr 2024 12:07:43 GMT</pubDate>
            <description><![CDATA[<h1 id="unlabeled-data-너는-대체-누구길래-🤔"><strong>Unlabeled Data 너는 대체 누구길래</strong> 🤔</h1>
<hr>
<p>이게 비운이면 비운이고 행운이면 행운 같은 복불복 게임 테마인 데이터 수집 수난시대를 겪고 있었다. 라벨링 데이터는 없지만 이상하게도 라벨링 되어있지 않은 데이터는 수두룩 깔려있었다.</p>
<p>우선 팀에서 찾은 unlabeled data 리스트는 다음과 같았다.</p>
<ol>
<li><a href="https://huggingface.co/datasets/Ubenwa/CryCeleb2023">Ubenwa Cry Celeb 2023</a>
 a. HuggingFace 에서 공개한 아기 울음소리 데이터셋
 b. 데이터 수를 체크해보니 자그마치 아니 18000개의 오디오 노다지 밭이었다.</li>
<li><a href="https://research.google.com/audioset//dataset/baby_cry_infant_cry.html">AudioSet(Infant Cry)</a>
 a. Google에서 공개한 YouTube 영상에 기반한 오디오 데이터셋<ul>
<li>2,084,320 개의 영상을 오디오 셋으로 묶은 데이터셋</li>
<li>이 중 아기 울음소리 영상은 무려 2390개나 포함이 되어 있었다.<h3 id="cry-celeb-2023-활용-방안에-대하여">Cry Celeb 2023 활용 방안에 대하여</h3>
</li>
</ul>
</li>
</ol>
<aside>
💡 우선 프로젝트 초반이어서 뭔가 무리해 보여도 라벨링 되지 않은 데이터를 뭔가 라벨링 데이터에 편입할 수 있는 방법을 시도해 보았다.(뭐 결국 철퇴됐지만…)

</aside>

<p>프로젝트 초반에 팀에서 MFCC 라는 오디오 특징 벡터를 활용해 보자는 얘기가 나왔다. 물론 모델링 input 관점에서 나온 얘기였지만 라벨링 데이터와 <strong>유사도가</strong> 높으면 편입해 볼 수 있지 않을까 하는 괜한 가설을 한 번 시도해보고 싶었다. </p>
<p>그래서 다음과 같은 방법으로 유사도를 측정해 보았다.</p>
<ol>
<li>코사인 유사도</li>
<li>벡터 간의 거리(Euclidean Distance)</li>
</ol>
<blockquote>
<p><strong><em>MFCC 란?</em></strong>
오디오의 Power Spectrum 즉 오디오의 세기를 Time Step마다 특정 계수의 수만큼 나타낸 것이다. 더 쉽게 직관적으로 살펴보면 아래 사진을 볼 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/haikoo_ai96/post/d2f1a175-58c4-4d0b-871a-806bdc9d8911/image.png" alt=""></p>
<p>위 사진을 보면 Spectral Envelope은 특정 Time Frame에서의 주파수마다 증폭을 나타낸 것이다. 이를 산과 비교해 보면 증폭은 산 높이와 연결 지어 이해해 볼 수 있다. 그리고 MFCC는 산의 전체적인 Contour Map으로 연결 지어 보면 조금 더 직관적으로 이해할 수 있다.</p>
<p>하지만 위 사진은 정확한 묘사는 아니다. 더 자세하고 정확하게 이해하기 위해 Fourier Transform과 Discrete Cosine Transform을 이해해야 하는데 프로젝트 진행을 위해 여기까지 이해하기엔 난이도가 있어서 이 정도로만 이해하고 넘겼다. </p>
</blockquote>
<h3 id="코사인-유사도"><strong>코사인 유사도</strong></h3>
<ol>
<li><p>각 클래스마다 MFCC를 구한 후 flatten 시켜 평균 벡터를 구하였다.</p>
<ul>
<li><p>라벨링 되지 않은 데이터를 1대 1로 라벨링 데이터와 하나씩 비교하는 건 어렵기 때문에 평균 벡터를 구함</p>
<ul>
<li><p>아래 코드 참조</p>
<pre><code class="language-python"># hungry audio to MFCCs
# MFCC 추출 예
spectro_hungry = []

for path in hungry_path:
  y, sr = librosa.load(path, sr = 44100)
  mfccs = librosa.feature.mfcc(y=y, sr=sr)
  spectro_hungry.append(mfccs)

# labeled 와 unlabeled 리사이징 및 백터화
spectro_belly_resized = [np.array(mfcc).flatten()[:160] for mfcc in spectro_belly]
spectro_burp_resized = [np.array(mfcc).flatten()[:160] for mfcc in spectro_burp]
spectro_discomfort_resized = [np.array(mfcc).flatten()[:160] for mfcc in spectro_discomfort]
spectro_hungry_resized = [np.array(mfcc).flatten()[:160] for mfcc in spectro_hungry]
spectro_tired_resized = [np.array(mfcc).flatten()[:160] for mfcc in spectro_tired]
spectro_unlabeled_resized = [np.array(mfcc).flatten()[:160] for mfcc in spectro_unlabeled]

# 평균벡터 추출
def mean_vector(vectors):
  return np.mean(vectors, axis=0)

mean_bellypain = mean_vector(spectro_belly_resized)
mean_burp = mean_vector(spectro_burp_resized)
mean_discomfort = mean_vector(spectro_discomfort_resized)
mean_hungry = mean_vector(spectro_hungry_resized)
mean_tired = mean_vector(spectro_tired_resized)</code></pre>
</li>
</ul>
</li>
</ul>
</li>
</ol>
<ol start="2">
<li><p>이후 18000 가량의 unlabeled data를 각 클래스의 평균 mfcc 벡터와 코사인 유사도로 비교하였다. </p>
<ul>
<li><p>아래 코드 참조</p>
<pre><code class="language-python"># 코사인 유사도 계산
def cosine_similarity(vecA, vecB):
 return 1 - cosine(vecA, vecB)

similarity_result = []

for idx, unlabeled_vector in enumerate(spectro_unlabeled_resized):
 similarity_bellypain = cosine_similarity(unlabeled_vector, mean_bellypain)
 similarity_burp = cosine_similarity(unlabeled_vector, mean_burp)
 similarity_discomfort = cosine_similarity(unlabeled_vector, mean_discomfort)
 similarity_hungry = cosine_similarity(unlabeled_vector, mean_hungry)
 similarity_tired = cosine_similarity(unlabeled_vector, mean_tired)

 # 결과 값을 딕셔너리로 저장
 similarity_result.append({
     &#39;Index&#39;: f&#39;unlabeled_audio{idx}&#39;,
     &#39;Bellypain&#39;: similarity_bellypain,
     &#39;Burp&#39;: similarity_burp,
     &#39;Discomfort&#39;: similarity_discomfort,
     &#39;Hungry&#39;: similarity_hungry,
     &#39;Tired&#39;: similarity_tired
 })</code></pre>
</li>
</ul>
</li>
</ol>
<ol start="3">
<li><p>코사인 유사도 결과</p>
<ul>
<li><p>코사인 유사도 0.90 이상 기준</p>
<pre><code>Max_Column
Bellypain     647개
Tired         382개
Hungry        145개
Discomfort     96개
Burp           26개</code></pre></li>
<li><p>복통과 피곤함이 가장 유사도가 높게 나온 걸 확인할 수 있었다.</p>
</li>
</ul>
</li>
</ol>
<h3 id="벡터간-거리"><strong>벡터간 거리</strong></h3>
<ol>
<li><p>평균 MFCC 벡터와 unlabeled data의 MFCC를 벡터 간 거리를 계산해 보았다.</p>
<ul>
<li><p>아래 코드 참조</p>
<pre><code class="language-python"># 벡터간 거리 측정
def euclidean_distance(vec1, vec2):
  return np.linalg.norm(np.array(vec1) - np.array(vec2))

distance_result = []

for idx, unlabeled_vector in enumerate(spectro_unlabeled_resized):
  distance_bellypain = euclidean_distance(unlabeled_vector, mean_bellypain)
  distance_burp = euclidean_distance(unlabeled_vector, mean_burp)
  distance_discomfort = euclidean_distance(unlabeled_vector, mean_discomfort)
  distance_hungry = euclidean_distance(unlabeled_vector, mean_hungry)
  distance_tired = euclidean_distance(unlabeled_vector, mean_tired)

  # 결과 값을 딕셔너리로 저장
  distance_result.append({
      &#39;Index&#39;: f&#39;unlabeled_audio{idx}&#39;,
      &#39;Bellypain&#39;: distance_bellypain,
      &#39;Burp&#39;: distance_burp,
      &#39;Discomfort&#39;: distance_discomfort,
      &#39;Hungry&#39;: distance_hungry,
      &#39;Tired&#39;: distance_tired
  })</code></pre>
</li>
</ul>
</li>
<li><p>코사인 유사도와 동일한 스케일(0과 1사이)로 보기 위해 Inverse Scaling을 진행하였다.</p>
<ul>
<li><p>Min Max scaling을 조금 변형해서 inverse scaling으로 변환 (코드 출처: ChatGPT)</p>
<pre><code class="language-python"># 최솟값 최댓값 지정
min_val = 262
max_val = 6253

# Inverse Scaling 함수 정의
def inverse_scaling(x, min_val, max_val):
  x = np.clip(x, min_val, max_val)
  return (max_val - x) / (max_val - min_val)</code></pre>
</li>
</ul>
</li>
</ol>
<ol start="3">
<li><p>코사인 유사도와 벡터 간 거리를 DataFrame으로 합친 후 가중 합을 내어 점수를 내어 보았다.
 a. 벡터 간 거리가 코사인 유사도보다 분산이 높은 이유로 가중치를 0.9로 주어 점수에 반영
 b. 합산 결과</p>
<pre><code> Max_Column
 Bellypain_score     508
 Tired_score         164
 Discomfort_score     62
 Hungry_score         28
 Burp_score           19</code></pre></li>
</ol>
<p>결과를 보면 복통과 피곤함이 유사도가 높은 걸 확인할 수 있었다. 합산 후 차이는 있었지만 코사인 유사도와 비슷한 양상을 볼 수 있었다. </p>
<h3 id="회고">회고</h3>
<ul>
<li><p>우선 팀원들과 회의 후 이 방법은 쓰지 않기로 했다. 그 이유는 다음과 같았다.</p>
<ol>
<li><p>객관적이지 않았다.
 a. 육아 관련 전문가가 확인하지 않았고 순전히 우리만의 가설로 진행했다는 점에서 객관적이지 못했다.
 b. 하지만 이 가설을 전문가들에게 실험은 해볼 수 있지 않을까 하는 호기심은 들었다. 이러한 방법으로 혹은 보다 더 좋은 방법으로 유사도를 측정해 정말 필요한 데이터만 추려내서 라벨링을 할 수 있다면 데이터 라벨러도 더 확실히 라벨을 할 수  있을뿐더러 라벨링 양이 줄기 때문에 수고가 덜어지지 않을까 하는 생각을 해보게 되었다.</p>
</li>
<li><p>MFCC 만으로 유사도를 판단하기엔 부족해 보인다.
 a. 오디오 데이터는 MFCC 뿐만 아니라 다른 특징들도 있기 때문에 더 다양한 feature 시각에서 유사도를 측정해야 더 robust 한 유사도 값이 나오지 않을까 생각이 된다.</p>
</li>
<li><p>Unlabeled data와 labeled data의 오디오 길이 차이가 컸다.
 a. Unlabeled data는 1초에서 2초가량의 오디오가 대부분이었고 labeled data는 5초 이상의 데이터였다. labeled data를 truncate 해 비교하는 건 정보의 손실이 컸기 때문에 사실 유사도 측정이 이상적이라고 보기는 어려웠다.</p>
</li>
</ol>
</li>
<li><p>unlabeled data를 루프를 돌려 5초로 맞추고 평균 벡터대신 K-means clustering을 통해 Centroid로 비교해 봤으면 더 좋은 측정이 됐을 것 같다. 하지만 여전히 이건 가설일 뿐이다.</p>
</li>
<li><p>AudioSet 활용 방안을 팀과 더 회의를 해봤으면 하는 아쉬움이 있었다.</p>
</li>
</ul>
<hr>
<p>👉👉 <a href="https://velog.io/@haikoo_ai96/Chapter-2-3-%EB%AA%A8%EB%8D%B8%EB%A7%81">다음 챕터 읽으러 가기</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Chapter 2-1: 데이터 수집]]></title>
            <link>https://velog.io/@haikoo_ai96/Chapter-2-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%A0%84%EB%B0%98%EB%B6%80</link>
            <guid>https://velog.io/@haikoo_ai96/Chapter-2-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%A0%84%EB%B0%98%EB%B6%80</guid>
            <pubDate>Tue, 16 Apr 2024 11:56:37 GMT</pubDate>
            <description><![CDATA[<h2 id="데이터-수집-시작"><strong>데이터 수집 시작!</strong></h2>
<p>우선 우리 팀은 Dunstan Baby Language라는 이론을 바탕으로 데이터 수집을 시작했다.</p>
<blockquote>
<p><strong>Dunstan Baby Language 란?</strong>
아기 울음소리에는 5가지 패턴이 있다고 주장하는 이론이다. 배고픔, 트림, 복통, 불편함, 피곤함이 5가지 패턴에 속하는 이론이다.</p>
</blockquote>
<p>Dunstan Baby Language 를 바탕으로 제일 처음에 찾은 데이터 셋은 Donate-a-Cry-Corpus 데이터셋이었다. Donate-a-Cry-Corpus 데이터셋을 간단히 소개하면 2015년에 아기울음 분석 앱을 출시하기 위해 Lullabond 라는 단체(혹은 회사)에서 Donate-a-cry 캠페인을 열어 유저들에게 아기울음소리를 기부받는 형식으로 진행하였다. 지금은 Lullabond 와 관련된 모든 사이트가 접근이 되지 않아 추후 진척상황은 알 수가 없었다.</p>
<blockquote>
<p><strong>Donate-a-Cry-Campaign 소개 영상</strong>
<a href="https://www.youtube.com/watch?v=81gcaQdgd7s">https://www.youtube.com/watch?v=81gcaQdgd7s</a></p>
</blockquote>
<h3 id="donate-a-cry-corpus의-문제점">Donate-a-Cry-Corpus의 문제점</h3>
<ul>
<li>Dunstan Baby Language 와 같은 클래스로 수집이 되어 유의미했지만 Dataset 자체에 Imbalance가 심했다. 특히, 배고픔에 많은 데이터가 치중되었다.</li>
</ul>
<table>
<thead>
<tr>
<th>Symptom</th>
<th>데이터 수</th>
</tr>
</thead>
<tbody><tr>
<td>복통</td>
<td>16</td>
</tr>
<tr>
<td>트림</td>
<td>8</td>
</tr>
<tr>
<td>불편함</td>
<td>27</td>
</tr>
<tr>
<td>배고픔</td>
<td>382</td>
</tr>
<tr>
<td>피곤함</td>
<td>24</td>
</tr>
</tbody></table>
<h3 id="mendeley-data로-보완-하지만">Mendeley Data로 보완 하지만…</h3>
<ul>
<li>Google Dataset Search로 Mendeley Data를 찾았지만 다른 클래스(트림, 복통)는 없어서 다소 아쉬웠다.</li>
<li>그리고 Donate-a-Cry Corpus의 imbalance를 해결할 만큼 불편함이나 피곤함 데이터수가 많지는 않았다.</li>
</ul>
<table>
<thead>
<tr>
<th></th>
<th>데이터 수</th>
</tr>
</thead>
<tbody><tr>
<td>배고픔</td>
<td>31</td>
</tr>
<tr>
<td>불편함</td>
<td>31</td>
</tr>
<tr>
<td>피곤함</td>
<td>1</td>
</tr>
</tbody></table>
<h3 id="다른-방법-모색">다른 방법 모색</h3>
<ul>
<li>우선 팀원들과 최대한 YouTube에 라벨링 된 울음소리를 찾아 크롤 해서 wav 파일로 써보자고 했다.</li>
</ul>
<p>전반적으로 뭔가 라벨링이 되어있는 데이터는 찾기는 어려운 분위기였다. 그렇게 해서 우리 팀은 더욱더 고민하게 되는데…</p>
<hr>
<p>👉👉 <a href="https://velog.io/@haikoo_ai96/Chapter-2-2-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%A0%84%EB%B0%98%EB%B6%80">다음 챕터 읽으러 가기</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[아기 울음소리 분류 프로젝트 (으아앙)]]></title>
            <link>https://velog.io/@haikoo_ai96/%EC%95%84%EA%B8%B0-%EC%9A%B8%EC%9D%8C%EC%86%8C%EB%A6%AC-%EB%B6%84%EB%A5%98-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%9C%BC%EC%95%84%EC%95%99%E3%85%8E%E3%85%8E</link>
            <guid>https://velog.io/@haikoo_ai96/%EC%95%84%EA%B8%B0-%EC%9A%B8%EC%9D%8C%EC%86%8C%EB%A6%AC-%EB%B6%84%EB%A5%98-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%9C%BC%EC%95%84%EC%95%99%E3%85%8E%E3%85%8E</guid>
            <pubDate>Thu, 07 Mar 2024 12:11:13 GMT</pubDate>
            <description><![CDATA[<h2 id="acknowledgement"><strong>Acknowledgement</strong></h2>
<p>이 프로젝트를 같이 진행해 주신 동료 분들게 감사인사말을 전합니다. 그리고 이 프로젝트 기회를 마련해 주신 모두의 연구소, 아이펠 퍼실님들, 운영진, 아이펠톤 매니저님게 감사드립니다.</p>
<h2 id="머리말"><strong>머리말</strong></h2>
<p>우선 내용이 긴 관계로 벨로그에 챕터별로 정리를 해두었습니다. 매 챕터마다 맨 하단에 다음글을 읽을 수 있도록 링크를 배치해 두었으니 차례로 읽으시면 됩니다. 만약 읽기가 불편하거나 가독성이 조금 떨어지신다면 노션 링크를 통해서 보셔도 됩니다.</p>
<p>본 프로젝트 블로그는 앱 및 서버 개발 보단 데이터 수집부터 모델링까지의 과정을 더 세세히 담았기 때문에 앱 구동 프로세스가 궁금하신 분은 노션에서 &quot;개인화 깃헙&quot; 링크를 통해 시연영상을 확인해 주시면 됩니다.</p>
<h2 id="프로젝트-개요"><strong>프로젝트 개요</strong></h2>
<p>으아앙 프로젝트는 딥러닝을 활용하여 4개의 아기 울음소리를 분류하는 앱 제작 프로젝트 입니다.</p>
<h2 id="목차"><strong>목차</strong></h2>
<ol>
<li>프로젝트 소개
a. chp1: 프로젝트 시작 동기</li>
<li>프로젝트 전반부
a. <a href="https://velog.io/@haikoo_ai96/Chapter-2-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%A0%84%EB%B0%98%EB%B6%80">chp 2-1: 데이터 수집</a>
b. <a href="https://velog.io/@haikoo_ai96/Chapter-2-2-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%A0%84%EB%B0%98%EB%B6%80">chp 2-2: Unlabeled Data 활용</a>
c. <a href="https://velog.io/@haikoo_ai96/Chapter-2-3-%EB%AA%A8%EB%8D%B8%EB%A7%81">chp 2-3: 모델링 pt.1</a>
d. <a href="https://velog.io/@haikoo_ai96/Chapter-2-4-%EB%AA%A8%EB%8D%B8">chp 2-4: 모델링 pt.2</a>
e. <a href="https://velog.io/@haikoo_ai96/Chapter-2-5-%EB%A9%98%ED%86%A0%EB%A7%81">chp 2-5: 멘토링</a></li>
<li>프로젝트 후반부
a. <a href="https://velog.io/@haikoo_ai96/Chapter-3-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9B%84%EB%B0%98">chp 3-1: U-net 비지도 학습</a>
b. <a href="https://velog.io/@haikoo_ai96/Chapter-3-U-net%EC%9D%84-%ED%99%9C%EC%9A%A9%ED%95%9C-%EC%9A%B8%EC%9D%8C%EC%86%8C%EB%A6%AC-%EB%B6%84">chp 3-2: U-net을 활용한 울음소리 분류</a>
c. <a href="https://velog.io/@haikoo_ai96/Chapter-3-3-Audio-Spectrogram-TransformerAST%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-%EC%9A%B8%EC%9D%8C%EC%86%8C%EB%A6%AC-%EB%B6%84">chp 3-3: Audio Spectrogram Transformer(AST)를 활용한 울음소리 분류</a>
d. <a href="https://velog.io/@haikoo_ai96/Chp-3-4-AST%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-%EC%9A%B8%EC%9D%8C%EC%86%8C%EB%A6%AC-%EB%B6%84%EB%A5%98">chp 3-4: AST를 활용한 울음소리 분류(EDA편)</a>
e. <a href="https://velog.io/@haikoo_ai96/Chp-3-5-AST%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-%EC%9A%B8%EC%9D%8C%EC%86%8C%EB%A6%AC-%EB%B6%84%EB%A5%98%EC%A0%84%EC%B2%98%EB%A6%AC%EC%A6%9D%EA%B0%95-%ED%8E%B8">chp 3-5: AST를 활용한 울음소리 분류(전처리&amp;증강 편)</a>
f. <a href="https://velog.io/@haikoo_ai96/Chp-3-5-AST%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-%EC%9A%B8%EC%9D%8C%EC%86%8C%EB%A6%AC-%EB%B6%84%EB%A5%98%EB%AA%A8%EB%8D%B8%EB%A7%81">Chp 3-6: AST를 활용한 울음소리 분류(모델링 편)</a></li>
</ol>
<hr>
<h2 id="chapter-1-프로젝트-시작-동기">Chapter 1: 프로젝트 시작 동기</h2>
<p>아이펠 AI 코어 과정 막바지에 접어들면서 졸업 프로젝트를 어떤 걸 해야 할지 고민이 많이 됐다. CV, NLP 등등 여러 분야에 관심이 있었지만 오디오에 딥러닝이 어떻게 접목될지 취미로 디제잉을 하던 나로서 늘 마음 한 곳에 호기심으로 남아있었다. 때마침 동료 분 한 분이 아기 울음소리 분류 아이디어로 기획서를 공유했는데 그저 오디오라는 공통분모로 마음이 이끌려 팀원으로 신청하게 되었다. </p>
<p>뒤에 어떤 후폭풍이 있을지 모르고 신청한 나에게 칭찬을…. 😅</p>
<hr>
<p>👉👉 <a href="https://velog.io/@haikoo_ai96/Chapter-2-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%A0%84%EB%B0%98%EB%B6%80">다음 챕터 읽으로 가기</a></p>
<p>👉👉 <a href="https://haekeukpark.notion.site/721e196b3bbc44d1b44bd0c1869b153c">프로젝트 노션에서 읽기</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[openCV 이미지 불러오기 오류]]></title>
            <link>https://velog.io/@haikoo_ai96/openCV-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EB%B6%88%EB%9F%AC%EC%98%A4%EA%B8%B0-%EC%98%A4%EB%A5%98</link>
            <guid>https://velog.io/@haikoo_ai96/openCV-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EB%B6%88%EB%9F%AC%EC%98%A4%EA%B8%B0-%EC%98%A4%EB%A5%98</guid>
            <pubDate>Mon, 27 Nov 2023 14:46:56 GMT</pubDate>
            <description><![CDATA[<h1 id="overview"><strong>Overview</strong></h1>
<blockquote>
<ul>
<li>opencv 를 쓰고 싶은데 이미지 read 에서 오류가 있으신분들을 위한 tip</li>
</ul>
</blockquote>
<ul>
<li>이미지 로드 할때만 PIL로 사용하여 우회</li>
<li>그 후 opencv를 자유롭게 사용</li>
</ul>
<h4 id="1-우선-필요한-라이브러리와-모듈을-불러오겠습니다">1. 우선 필요한 라이브러리와 모듈을 불러오겠습니다.</h4>
<pre><code class="language-python">import cv2
import PIL
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
import os</code></pre>
<h4 id="2-경로가-존재하는지-확인">2. 경로가 존재하는지 확인</h4>
<pre><code class="language-python"># 경로 존재 확인
cwd = os.getcwd()
filename = &#39;example.jpg&#39;
filepath = os.path.join(cwd, filename)
os.path.exists(filepath)</code></pre>
<h4 id="3-cv2imread-테스트">3. cv2.imread() 테스트</h4>
<pre><code class="language-python">im_read = cv2.imread(filepath)
type(im_read)</code></pre>
<blockquote>
<p>만약 경로가 존재하는데도 <strong>numpy array</strong> 가 아닌 <strong>NoneType</strong>이 출력이 되면 아래 방법으로 시도해보세요.</p>
</blockquote>
<h4 id="4-pil-라이브러리를-사용하여-이미지-로드-부분만-우회">4. PIL 라이브러리를 사용하여 이미지 로드 부분만 우회</h4>
<pre><code class="language-python">img_read = Image.open(filepath)
img_arr = np.array(img_read)
resized_img = cv2.resize(img_arr, (300, 300))

plt.imshow(resized_img)
plt.show()</code></pre>
<blockquote>
<p>이미지 불러올때만 <strong>PIL</strong> 라이브러리를 사용하시고 그 후 openCV 를 자유롭게 사용해보세요!!! 🙌🙌</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[텐서플로우 gpu 설정]]></title>
            <link>https://velog.io/@haikoo_ai96/%ED%85%90%EC%84%9C%ED%94%8C%EB%A1%9C%EC%9A%B0-gpu-%EC%84%A4%EC%A0%95-reeqenho</link>
            <guid>https://velog.io/@haikoo_ai96/%ED%85%90%EC%84%9C%ED%94%8C%EB%A1%9C%EC%9A%B0-gpu-%EC%84%A4%EC%A0%95-reeqenho</guid>
            <pubDate>Thu, 16 Nov 2023 14:47:01 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><strong>참고사항 및 DISCLAIMER</strong>
본 가이드라인은 window 유저와 NVIDIA 그래픽카드를 가지고 계신분들을 위해 작성되었습니다. 아쉽지만 맥 유저나 AMD 그래픽카드를 가지고 계신 분들은 다른 방법을 권장드립니다. 😊</p>
</blockquote>
<h1 id="설정-프로세스-overview">설정 프로세스 Overview</h1>
<ol>
<li>그래픽카드 모델 확인(skip 가능)<ul>
<li>만약 그래픽카드 모델을 아신다면 스킵하셔도 좋습니다!</li>
</ul>
</li>
<li>사양에 맞는 CUDA 버전 확인</li>
<li>그래픽카드 사향에 맞는 tensorflow-gpu 버전 및 cudnn 버전 확인</li>
<li>그래픽카드 드라이버 설치</li>
<li>CUDA와 cuDNN 다운로드</li>
<li>환경변수 설정</li>
<li>gpu 연결 확인</li>
</ol>
<h1 id="1-그래픽카드-모델-확인">1. 그래픽카드 모델 확인</h1>
<ul>
<li>먼저 그래픽카드 모델을 확인하기 위해 장치관리자를 열어 봅시다!</li>
<li>아래 사진과 같이 윈도우 검색창에 <code>장치 관리자</code>를 찾아봅시다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/haikoo_ai96/post/5f5a39b8-7e80-4307-9ed7-c36df7625280/image.png" alt=""></p>
<ul>
<li>장치 관리자가 열리고 아래와 같이 여러 토글들이 있는데요. 그 중에서 디스플레이 어댑터 토글을 눌러주세요. 그럼 모델이름을 확인 하실 수 있습니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/haikoo_ai96/post/e5e94b6f-8ec9-44cd-ac05-18eef1feaa32/image.png" alt=""></p>
<blockquote>
<p>제 그래픽카드는 모델은 NVIDIA GeForce GTX 1050TI 인걸 확인할 수 있습니다.</p>
</blockquote>
<h1 id="2-사양에-맞는-cuda-버전확인">2. 사양에 맞는 CUDA 버전확인</h1>
<blockquote>
<p>혹시 CUDA 와 cuDNN이 뭔지 궁금하면 링크를 눌러주세요. 저는 귀찮아서 걍 무시하고 바로 설치하러 갔습니다 😅 
<a href="https://namu.wiki/w/CUDA">CUDA 링크</a> 👈
<a href="https://velog.io/@jk01019/nvidia-driver-CUDA-CuDNN-%EC%9D%B4%EB%9E%80">cuDNN 링크</a> 👈
귀찮으시면 바로 설치하러 꼬우~~</p>
</blockquote>
<ul>
<li><p>먼저 그래픽 카드 모델마다 <a href="https://developer.nvidia.com/cuda-gpus">compute capability</a> ( 👈링크 클릭해주세요)가 다 다른데요. 이 <code>compute capability</code> 에 따라 어떤 CUDA 버전과 어떤 cuDNN 버전이 설치되야 되는지 결정됩니다. 그러니 꼭 주의하시고 살펴주세요!!!!</p>
</li>
<li><p>링크 따라 들어오면 아래와 같은 페이지가 뜨는데요. 그래픽카드 모델에 따라 맞게 버튼을 클릭해주세요.
<img src="https://velog.velcdn.com/images/haikoo_ai96/post/b6c36281-6fba-4773-9a29-fa541adb6a3b/image.png" alt=""></p>
</li>
<li><p>GeForce 그래픽카드를 가지고 계시면 <code>CUDA-Enabled GeForce and TITAN Products</code> 를 눌러주세요. 그럼 아래와 같이 촤라락~~ 펼처지는데요. 저는 모델이 1050Ti니 한 번 확인해보겠습니다.
<img src="https://velog.velcdn.com/images/haikoo_ai96/post/bd4c135b-2793-48ea-ae2b-3086ce91d8ae/image.png" alt=""></p>
<blockquote>
<p>모든 10 시리즈들은 compute capability가 6.1인걸 확인할 수 있습니다. </p>
</blockquote>
</li>
<li><p>자 이제 compute capability를 확인 했으니 아래 차트를 확인해봅시다. 저 같은 경우 6.1이기 때문에 pascal 해당하고 CUDA 버전을 8.0부터 12.3 버전까지 사용이 가능합니다. 그래픽모델에 맞게 차트를 확인해보세요. 화살표와 곡선은 제 모델을 가지고 차트를 어떻게 보는냐를 보여주는 도구입니다.
<img src="https://velog.velcdn.com/images/haikoo_ai96/post/69f2ad29-2eb3-414b-a662-ba5977e4e737/image.png" alt=""></p>
</li>
</ul>
<h1 id="3-tensorflow-gpu-버전-및-호환가능한-버전-확인">3. tensorflow-gpu 버전 및 호환가능한 버전 확인</h1>
<ul>
<li><p>이제 대망의 tensorflow-gpu 버전과 cudnn 버전을 확인할 시간 😍</p>
</li>
<li><p>먼저 이 <a href="https://www.tensorflow.org/install/source_windows?hl=ko">링크</a>( 👈)를 클릭해주세요. 클릭 후 아래 사진처럼 GPU 섹션을 찾을 때까지 스크롤 해봅시다.
<img src="https://velog.velcdn.com/images/haikoo_ai96/post/4be3ab54-fba6-44ce-92ca-8dfcebff1ae2/image.png" alt=""></p>
<blockquote>
<p>저 같은 경우 compute capability 가 6.1이고 쿠다 12.3 까지 쓸 수 있지만 아쉽게도 tensorflow-gpu 에 호환되는 가장 최근 쿠다버전은 11.2 입니다. 그래서 저는 아쉽지만 쿠다 12.3 설치했다가 다시 지우고 쿠다 11.2 버전을 설치했습니다. 여러분은 이런 번거로움을 겪지 않기를 🙏 </p>
</blockquote>
</li>
<li><p>위 사진을 보면 tensorflow-gpu와 호환되는 <code>파이썬 버전, cuDNN 버전, 쿠다버전</code>을 확인 하실 수 있습니다. 컴파일러나 빌드도구는 아마 tensorflow-gpu에 맞게 이미 설치가 되어 있을 겁니다.</p>
<ul>
<li>윈도우용 tensorflow-gpu는 2.10.0 까지 지원하니 2.10.0 버전 설치를 권장드립니다. 하지만 compute capability 확인 후 그래픽카드가 쿠다 11.2 버전과 호환이 안되면 맞춰서 tensorflow-gpu 버전을 맞춰서 설치 부탁드립니다.</li>
</ul>
</li>
<li><p>그럼 파이썬 버전을 한 번 확인해봅시다!! 아래 코드를 복사 후 shell이나 cmd에 넣어봅시다.</p>
<pre><code>python --version
# 만약 3.7-3.10 버전보다 낮거나 높으면 다시 지우고 버전에 맞게 다시 설치해주세요.</code></pre></li>
</ul>
<h1 id="4-그래픽-드라이버-설치">4. 그래픽 드라이버 설치</h1>
<ul>
<li>그래픽 드라이버 설치 링크: <a href="https://www.nvidia.com/download/index.aspx">https://www.nvidia.com/download/index.aspx</a></li>
<li>링크에 들어가서 gpu 모델에 맞게 설치해주세요.</li>
</ul>
<h1 id="5-cuda-및-cudnn-설치">5. CUDA 및 cuDNN 설치</h1>
<ul>
<li><p>자 이제 compute capability와 호환되는 tensorflow-gpu, cudnn, cuda 버전을 확인했으니 설치를 해봅시다.</p>
<ul>
<li>tensorflow-gpu 2.10.0 기준으로 설치를 해보겠습니다.</li>
</ul>
</li>
<li><p>cuda 11.2 다운로드 링크:<a href="https://developer.nvidia.com/cuda-11.2.0-download-archive">https://developer.nvidia.com/cuda-11.2.0-download-archive</a></p>
</li>
<li><p>cuDNN 8.1 다운로드 링크:<a href="https://developer.nvidia.com/rdp/cudnn-archive">https://developer.nvidia.com/rdp/cudnn-archive</a></p>
<p>   링크 같은 경우 모든 cuDNN 버전을 archiving 한 페이지이기 때문에 버전에 맞게 잘 찾아주세요. 
<img src="https://velog.velcdn.com/images/haikoo_ai96/post/aa374ce1-fad4-4af4-8bb2-fb3c3656473d/image.png" alt=""></p>
<blockquote>
<p>8.1.1이나 8.1.0 둘 중에 아무거나 설치하셔도 좋습니다. </p>
</blockquote>
</li>
<li><p>cuDNN 을 설치 후 압축해제를 합니다. 그리고 cudnn-11.2-????? 폴더를 누른 후 cuda 폴더로 들어가주세요. 그럼 아래와 같이 보이는데요.
<img src="https://velog.velcdn.com/images/haikoo_ai96/post/909a6210-0554-42bf-81f2-add53124f2d6/image.png" alt=""></p>
</li>
<li><p>여기서 제가 highlight 했듯이 모든 파일을 복사해주세요.</p>
</li>
<li><p>그리고 이제 아래 제시된 순서로 경로를 따라가주세요 (CUDA 11.2가 이미 설치 되어있어야 합니다).</p>
<blockquote>
<p>C 드라이브 ➡️ Program Files ➡️ NVIDIA GPU Computing Toolkit ➡️ CUDA ➡️ v11.2</p>
</blockquote>
</li>
<li><p>그럼 이제 아까 복사했던 파일과 폴더를 덮어씌워 주면 됩니다.</p>
</li>
</ul>
<h1 id="6-환경변수-설정">6. 환경변수 설정</h1>
<ul>
<li><p>이제 cuDNN 파일들을 붙혀두었으니 환경변수를 설정해야 합니다.</p>
</li>
<li><p>아래와 같이 윈도우 검색 창에 <strong>환경변수</strong>를 검색 후 <strong>시스템 환경 변수 편집</strong>을 눌러주세요.
<img src="https://velog.velcdn.com/images/haikoo_ai96/post/d64ff4b5-2b19-42db-aab4-2dfeacddf2d9/image.png" alt=""></p>
</li>
<li><p>그럼 아래와 같이 <strong>시스템 속성</strong> 창이 뜨는데요. 여기서 환경 변수를 클릭해줍니다.
<img src="https://velog.velcdn.com/images/haikoo_ai96/post/59d543fe-e3a1-419e-b563-42c836331784/image.png" alt=""></p>
</li>
<li><p>그럼 아래와 같이 환경 변수창이 뜨는데요. 여기서 시스템 변수에 보이는 <strong>CUDA_PATH</strong>(빨간 박스)를 더블 클릭 해줍니다.
<img src="https://velog.velcdn.com/images/haikoo_ai96/post/b5fa5c41-0b18-4800-ac31-f4e6212e7dee/image.png" alt=""></p>
</li>
<li><p>클릭 후 <strong>변수 값</strong>을 복사해줍니다.
<img src="https://velog.velcdn.com/images/haikoo_ai96/post/f9d7c2d5-a1c7-4e8c-9022-3757a7810fbb/image.png" alt=""></p>
</li>
<li><p>그리고 <strong>Path</strong>를 highlight 한 상태에서 편집을 누르거나 더블클릭을 해줍니다.
<img src="https://velog.velcdn.com/images/haikoo_ai96/post/b858de36-eb5b-4dae-9abb-a5117dd751cf/image.png" alt=""></p>
</li>
<li><p>환경 변수 편집창에서 <strong>새로 만들기</strong>를 누르고 아까 복사했던 변수 값을 붙혀넣기를 합니다. 그리고 2번 더 반복해주세요. 그럼 아래와 같이 3개의 환경 변수가 추가된걸 확인 하실 수 있습니다. 
<img src="https://velog.velcdn.com/images/haikoo_ai96/post/0b15e677-e7a1-40af-b196-7aade7d8537e/image.png" alt=""></p>
</li>
<li><p>하지만 여기서 끝난게 아니죠ㅎㅎ 추가된 변수에 bin 폴더, include 폴더, lib 폴더를 추가해주셔야 됩니다. 아래와 같이 각 환경편수 마다 더블클릭 혹은 편집을 누른 후 bin, include, lib을 추가해주세요</p>
<blockquote>
<p>~\NVIDIA GPU Computing Toolkit\CUDA\v11.2\bin
~\NVIDIA GPU Computing Toolkit\CUDA\v11.2\include
~\NVIDIA GPU Computing Toolkit\CUDA\v11.2\lib</p>
</blockquote>
</li>
<li><p>이제 환경변수 설정이 완료되었습니다!!! 👍</p>
</li>
</ul>
<h1 id="7-gpu-연결확인">7. GPU 연결확인</h1>
<ul>
<li><p>자 이제 vscode 같은 text editor, python terminal, 혹은 jupytor notebook 를 열어봅시다! 기호에 맞게 해주시면 됩니다.</p>
</li>
<li><p>아래와 같이 코드를 실행해봅시다.</p>
<pre><code>import tensorflow as tf
from tensorflow.python.client import device_lib
print(tf.__version__)
device_lib.list_local_devices()</code></pre></li>
<li><p>코드 실행 후 아래와 같이 CPU만이 아닌 GPU란 말이 뜨고 GPU 모델이름이 뜨면 세팅이 완료된겁니다!!!! 유후<del>~</del>
<img src="https://velog.velcdn.com/images/haikoo_ai96/post/3b48d085-2d76-4e56-9b5f-2ff78d87c830/image.png" alt=""></p>
</li>
</ul>
<h1 id="기타-참고사항">기타 참고사항</h1>
<ul>
<li>저 같은 경우 GPU 설정은 잘 됐지만 여러 Tensorflow 라이브러리와 호환성에 문제가 좀 있어서 이 섹션은 덤으로 Tensorflow-gpu 2.10.0 과 호환되는 tensorflow 라이브러리를 소개해 드리려고 합니다.<pre><code># 우선 shell, cmd, 혹은 conda 에서 pip list 를 찍어봅시다.
</code></pre></li>
</ul>
<p>protobuf                     3.19.6
tensorboard                  2.10.1
tensorboard-data-server      0.6.1
tensorboard-plugin-wit       1.8.1
tensorflow-datasets          4.8.0
tensorflow-estimator         2.10.0
tensorflow-gpu               2.10.0
tensorflow-hub               0.15.0
tensorflow-io-gcs-filesystem 0.31.0
tensorflow-metadata          1.13.0</p>
<h1 id="특히-tensorflow-datasets-를-설치했을때-문제가-많이-있었는데요">특히 tensorflow-datasets 를 설치했을때 문제가 많이 있었는데요</h1>
<h1 id="위-와-같이-버전들을-맞춰주시면-tensorflow-datasets-호환-문제가-해결이-됩니다">위 와 같이 버전들을 맞춰주시면 tensorflow-datasets 호환 문제가 해결이 됩니다.</h1>
<h1 id="삭제-및-설치-코드-탬플릿">삭제 및 설치 코드 탬플릿</h1>
<p>pip uninstall &quot;name-of-library_or_module&quot;
pip install &quot;name-of-library_or_module==version&quot;</p>
<h1 id="ex">ex)</h1>
<p>pip install protobuf==3.19.6</p>
<pre><code>
&gt; 프로세스 따라오시느라 수고 하셨습니당. 앞으로 이제 맴껏 모델 훈련 돌려보세용~~
감사합니다🙏🙏








</code></pre>]]></description>
        </item>
    </channel>
</rss>