<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>jh_one.log</title>
        <link>https://velog.io/</link>
        <description>노력하는 개발자</description>
        <lastBuildDate>Tue, 29 Apr 2025 06:44:14 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>jh_one.log</title>
            <url>https://velog.velcdn.com/images/jh_one/profile/ad5417a0-2490-45ef-ab85-e25245e138b8/social_profile.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. jh_one.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/jh_one" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[스타트업 면접 후기]]></title>
            <link>https://velog.io/@jh_one/%EC%8A%A4%ED%83%80%ED%8A%B8%EC%97%85-%EB%A9%B4%EC%A0%91-%ED%9B%84%EA%B8%B0</link>
            <guid>https://velog.io/@jh_one/%EC%8A%A4%ED%83%80%ED%8A%B8%EC%97%85-%EB%A9%B4%EC%A0%91-%ED%9B%84%EA%B8%B0</guid>
            <pubDate>Tue, 29 Apr 2025 06:44:14 GMT</pubDate>
            <description><![CDATA[<h3 id="회사">회사</h3>
<p>경기도권의 자율주행 관련 스타트업 회사였다. 잡코리아로 채용 진행을 하였고, </p>
<p><em>서류전형 -&gt; 코딩테스트 -&gt; 1차면접 -&gt; 2차면접</em></p>
<p>의 전형으로 진행되었다. </p>
<h3 id="서류전형">서류전형</h3>
<p>잡코리아의 무지성 서류 지원 중 한 곳이였다. 다만 인상깊었던 점은 설립된지 4~5년된 스타트업이였지만 돈을 상당히 많이 준다는..
그래서 이력서와 포트폴리오 2가지의 서류를 첨부하여 지원을 했다.</p>
<p><img src="https://velog.velcdn.com/images/jh_one/post/af0f8602-5feb-4f03-91ec-0d04bbfd8353/image.png" alt=""></p>
<h3 id="코딩테스트">코딩테스트</h3>
<p>스타트업이였지만, <strong>프로그래머스</strong> 환경에서 시험을 치뤘다. 총 3문제였고, 다른 기업의 시험과는 다르게 문제마다 점수를 바로 확인할 수 있었다.</p>
<p><img src="https://velog.velcdn.com/images/jh_one/post/6bccde96-650f-4ea2-9de7-87b87ed7d4fb/image.png" alt=""></p>
<h3 id="1차-면접">1차 면접</h3>
<p>면접관 3, 지원자 4의 대면 면접으로 1시간 30분동안 이루어졌다. 사실 이 면접은 준비 기간이 너무 짧았기 때문에 <strong>자기소개, 지원동기, 직무역량강점</strong> 이 3개만 준비해갔던 것 같다.</p>
<ol>
<li>자기소개</li>
<li>프로젝트 가장 인상깊은 프로젝트와, 그것을 하면서 무엇이 힘들었는지</li>
<li>tdd가 무엇인지, 그리고 프로젝트 하면서 적용해본 적이 있는지.</li>
<li>실력향상을 위해, 어떻게 학습을 하는지.</li>
<li>학부수업들으면서 가장 흥미로웠던 수업, 가장 재미없었던 수업, 그리고 가장 도움이 됐던 수업</li>
<li>만약 코드 컨벤션 맞출때, 팀원과 스타일이 다르다면 어떻게 하는지?</li>
<li>유닛테스트가 뭔지 설명. </li>
<li>통합테스트와 유닛테스트의 차이를 설명.</li>
<li>서비스(MVC)가 무엇인가? </li>
<li>궁금한점 + 마지막으로 할말</li>
</ol>
<p>질문은 이렇게 물어봤다. 모두 공통 질문이였고, 답변에 대한 꼬리질문이 굉장히 디테일하게 들어왔다.</p>
<p>기억나는 것 중 하나는 어떤 분이 캐시얘기를 했는데 캐시 히트와 캐시 미스일때 각각 어떻게 처리했는지를 굉장히 자세하게 물어보셨다. 원하는 답변이 나오지않자 계속해서 집요하게 파고드셨다. </p>
<p>아마 해당 질문에서 가장 중요했던 것은 총 2개라 생각한다.</p>
<blockquote>
<ol>
<li>개발에 있어 기본 지식이 있는가 하는가.</li>
<li><del>관상</del></li>
</ol>
</blockquote>
<p>지금까지 봐왔던 면접과는 너무 다른 스타일로 진행이 되었던 것 같다. 이력서와 포트폴리오를 하나도 참고를 안했던 것 같고 그냥 이 회사에서 원하는 인재상이 있던 것 같은데 그게 무엇이였는지 도저히 감을 못잡겠단 것이였다. </p>
<p>나의 프로젝트에서 이 기술을 왜 썼는지, 어려운 점을 어떻게 타개했는지를 물어봐주었으면 좋았었을텐데 단순히 <strong>인성쪽?</strong> 으로만 물어봤던 것 같아 매우 아쉬웠다. 내 역량을 절반도 못보여준 것 같아 굉장히 아쉽고, 사실 준비도 안했고, 면접 분위기가 좋지 않아서 별 기대도 안했지만 1차 면접 합격 연락이 왔다.</p>
<p><del>엥 진짜 관상보고 뽑나</del></p>
<h3 id="2차면접">2차면접</h3>
<p>1차 면접때는 정말 준비를 안해가서, 이번에는 직무와 인성 분야 두 개다 준비를 정말 열심히 해갔다. <del>단지 내가 예상한 질문들이 단 하나도 나오지 않아 하나도 사용을 못했다는</del></p>
<p>1차면접과 달리 2차면접은 <strong>다대일 면접</strong>으로 진행이 되었다. 진짜 이번 2차면접은 정말 뭘 대체 물어보고싶은건지, 어떤 것을 원하는지 감이 1도 안잡혔다..</p>
<ol>
<li><p>OO대학교 왜 가셨나요? 
답 못함.. 한번도 이거에 대해 생각을 해본 적이 없다. 아마 이것은 서울대학교 학생들도 답을 하지 못할 것이라 생각한다. <del>성적 맞춰서 가는 사람들이 99%일텐데</del></p>
</li>
<li><p>OO대학교만의 장점을 알려주세요
<del>진짜 대체 왜물어보냐고</del> 학교가 평지다.. 국립대학법인이라 연구비가 짱짱하다.. 이런 것만 말했다. </p>
</li>
<li><p>대학교 다니면서 4년간 기숙사 살았다고 말씀하셨는데 몇인실이였나요??
<em>아! 룸메이트와 잘 지냈냐고 물어보려 하는구나! 트러블이 없었는지 물어보는구나!</em></p>
<blockquote>
<p>나: 2년간 4인실, 2년간 2인실 살았습니다~
면접관: OO대학교엔 모집요강에는 4인실이 없는데요?
나: 아 7년전이라 아마 지금은 없어졌나 보네요~
면접관: 여기서 끝나고 다른 질문함.</p>
</blockquote>
</li>
</ol>
<p><img src="https://velog.velcdn.com/images/jh_one/post/1fd549f0-f7c3-449a-9a56-238de303b629/image.png" alt=""></p>
<ol start="4">
<li><p>팀원과 협력을 통해 문제를 해결한 경험을 말씀해주세요. 
<em>드디어 질문다운 질문..!!</em>
이것은 어찌어찌 잘 말햇다.</p>
</li>
<li><p>개발자에게 가장 필요한 역량이 무엇이라 생각하나요?
<em>내가 준비한 질문이 드디어 나왔구나.</em></p>
<blockquote>
<p>개발자에게 가장 필요한 역량은 <strong>문제해결역량</strong>이라 생각합니다. 왜냐하면 개발 과정에서 수많은 에러 혹은 문제가 발생할텐데, 이 문제를 해결하기에 급급한 것이 아닌, 근본적인 원인을 분석하고 이에 맞는 해결책을 통해 ~ 하는 게 중요합니다. 실제로 저도 ~ 문제를 겪고 <del>~</del> .</p>
</blockquote>
</li>
</ol>
<p>??: 그게 중요한 역량이라고 한다면 신입사원보단 경력사원만 뽑는게 맞지 않겠어요??
<img src="https://velog.velcdn.com/images/jh_one/post/4332a18c-8d61-46db-8b59-96422cb95ab5/image.png" alt=""></p>
<p>당황해하니깐, 그래도 좀 힌트를 주셨다. </p>
<p>면접관: 저희 입장에서 경력보단 신입 개발자를 뽑는 이유가 있을거에요. 신입 개발자를 뽑는 이유가 뭐라고 생각하세요?
나: <del>연봉이 저렴하니깐.</del> 잠재력이라 생각합니다! 저같은 경우엔, 다양한 개발환경에서 빠르게 적응해 실질적인 성과를 이끈 경험이 있습니다. 이처럼, 저희 신입개발자는 백지이므로, 회사에 빠르게 적응하여 성과를 내는 &quot;잠재력&quot;이 있다 생각합니다. <del>지금 쓰면서 보니깐 이상하네..</del></p>
<blockquote>
<p>결국 면접관이 원하는 답변을 하지 못했다. 나중에 여쭤봤을때, 기본적인 CS지식, 그리고 이를 활용하는 능력이 중요하다 생각해요.</p>
</blockquote>
<p><img src="blob:https://velog.io/e4403d38-64cf-4196-b886-1d1e6eaecfb4" alt="업로드중..">
<del>이것도 신입개발자보단 경력개발자 역량 아닌가..</del></p>
<ol start="6">
<li>삼성청년SW아카데미를 수료하셨는데, 여기서 배운 것, 얻은 것이 있을까요??</li>
</ol>
<blockquote>
<p>답변: 우선, 다양한 직무의 사람들과 함께 하는 &quot;협업 능력&quot;에 대해 키울 수 있었습니다! 저는 ~ </p>
</blockquote>
<p>여기에서 면접관님이 답변을 끊으셨다.</p>
<blockquote>
<p>면접관: 아시다시피, 실무에서의 협업과 교육 목적의 싸피에서의 협업 능력은 상당히 다르다 생각해요. 사실 Jira와 Git 등 이 회사에서 사용하지 않는다면 도루묵 아닌가요?</p>
</blockquote>
<p>말고도 질문들은 이랬다.</p>
<ul>
<li>스트레스를 해소하는 취미가 있는지.</li>
<li>당신이 싸피에서 배운 기술스택들은 우리 회사에서 전혀 사용하지 않는다. 어떻게 생각하는지?</li>
<li>일을 할 때, 도전하여 일을 벌이는 스타일인지 혹은 계획적으로 접근하는 스타일인지.</li>
<li>회사에 대해 궁금한 점.</li>
</ul>
<blockquote>
<p>그냥 전체적으로 분위기가 좋지 않았던 것 같다.열심히 준비했지만, 준비한 질문에 대해서는 하나도 나오지 않았고 나름 회사 자체에서 원하는 인재상이 있는 것 같고, 질문에도 의도가 있던 것 같지만 그 자리에서 의도를 파악하지 못했던 것이 패착이였던 것 같다.
<del>사실 아직도 이런 질문들의 의도를 모르겠음.</del></p>
</blockquote>
<ol>
<li>회사의 성향을 파악하여 질문의 의도를 파악하자.</li>
<li>말할 때, 좀 두서있게 정리해서 말하자.</li>
<li><del>면접은 운빨 + 관상</del></li>
</ol>
<p>아직 결과는 나오지 않았다. 가고싶은 회사라 하늘에 기도해야겠다.</p>
<p><img src="blob:https://velog.io/a1e8b414-747d-41ed-a865-0a483d45e6b5" alt="업로드중.."></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[운영체제2(컴퓨터의 요소)]]></title>
            <link>https://velog.io/@jh_one/%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C2%EC%BB%B4%ED%93%A8%ED%84%B0%EC%9D%98-%EC%9A%94%EC%86%8C</link>
            <guid>https://velog.io/@jh_one/%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C2%EC%BB%B4%ED%93%A8%ED%84%B0%EC%9D%98-%EC%9A%94%EC%86%8C</guid>
            <pubDate>Wed, 15 Jan 2025 09:36:11 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/jh_one/post/fd7c7dec-2f23-4f9d-8390-2c87b54f2266/image.png" alt=""></p>
<h3 id="cpu">CPU</h3>
<p>CPU(Central Processing Unit)은 <strong>인터럽트</strong>에 의해 단순히 메모리에 존재하는 명령어를 해석하여 실시하는 일꾼이다. CPU의 구성은 다음과 같다.</p>
<blockquote>
<ul>
<li><strong>제어장치(Control Unit)</strong>
프로세스 조작을 지시하는 장치로, I/O장치 간 통신을 제어하고 명령어들을 읽고 해석하며 데이터 처리를 위한 순서를 결정한다.</li>
</ul>
</blockquote>
<ul>
<li><strong>레지스터(Register)</strong>
레지스터는 CPU안에 있는 매우 빠른 <strong>임시기억장치</strong>이다. CPU는 자체적으로 데이터를 저장할 방법이 없어, 레지스터를 거쳐 데이터를 전달한다. CPU와 직접 연결되어있어, 속도가 매우 빠르다. </li>
<li><strong>산술논리연산장치(Arithmetic Logic Unit)</strong>
덧셈, 뺄셈 같은 두 숫자의 산술 연산과 배타적 논리합, 논리 곱과 같은 <strong>논리 연산을 계산하는 디지털 회로</strong>이다.</li>
</ul>
<h3 id="cpu의-연산-처리-과정">CPU의 연산 처리 과정</h3>
<p><img src="https://velog.velcdn.com/images/jh_one/post/ec5542b7-fef2-474c-b1b4-1a1a23dafe43/image.png" alt=""></p>
<ol>
<li>제어장치가 계산할 값을 <strong>메모리에 로드한다</strong> 그리고 <strong>레지스터</strong>에도 로드한다</li>
<li>제어장치가 레지스터에 있는 값을 계산하라고 산술논리연산장치에 명령한다.</li>
<li>제어장치가 계산된 값을 다시 <strong>레지스터</strong>에 저장하고, 레지스터에서 해당 값을 다시 <strong>메모리</strong>에 저장한다.</li>
</ol>
<h3 id="인터럽트interrupt">인터럽트(Interrupt)</h3>
<p>인터럽트는 CPU를 잠깐 정지시키는 것이다. 키보드, 마우스 등 I/O 디바이스로 인한 인터럽트, 0을 숫자로 나누는 산술연산에서의 인터럽트, 프로세스 오류 등으로 발생한다. </p>
<p>컴퓨터에 문제가 발생하거나, 중요한 일이 생기면 즉시 처리해야한다. 이 때 인터럽트는 컴퓨터가 현재 하고 있는 일을 잠시 멈추고 해당 일을 해결하는데 도움을 주는 역할을 한다.</p>
<p>인터럽트가 발생되면 <strong>인터럽트 핸들러 함수</strong>가 모여있는 <strong>인터럽트 벡터</strong>로 가서 <strong>인터럽트 핸들러 함수</strong>를 실행시킨다. 인터럽트는 총 2가지로 나뉜다.</p>
<blockquote>
<ul>
<li>하드웨어 인터럽트
하드웨어 인터럽트는 키보드를 연결하거나, 마우스를 연결할 때 I/O 디바이스에서 발생하는 인터럽트를 의미한다.</li>
</ul>
</blockquote>
<ul>
<li>소프트웨어 인터럽트
소프트웨어 인터럽트는 <code>트랩</code>이라고도 한다. 프로세스 오류 등으로 프로세스가 시스템콜을 호출할 때 발생한다.</li>
</ul>
<h3 id="dma-컨트롤러">DMA 컨트롤러</h3>
<p><code>DMA(Direct Memory Access) 컨트롤러</code>는 I/O 디바이스가 메모리에 직접 접근할 수 있도록 도와주는 장치를 의미한다.</p>
<p>CPU에만 너무 많은 <strong>인터럽트 요청</strong>이 들어오기 때문에 CPU 부하를 막아주며, CPU의 일을 부담하는 보조 일꾼이라 생각하면 된다.</p>
<h3 id="메모리">메모리</h3>
<p>메모리(Memory)는 데이터나 상태, 명령어 등을 기록하는 장치를 말하며 보통 <code>RAM(Random Access Memory)</code>를 일컬어 메모리라고도 한다. </p>
<p>CPU는 계산을 담당하고, 메모리는 기억을 담당한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[운영체제1 (운영체제 기본과 시스템콜)]]></title>
            <link>https://velog.io/@jh_one/%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C1</link>
            <guid>https://velog.io/@jh_one/%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C1</guid>
            <pubDate>Wed, 15 Jan 2025 09:09:00 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>운영체제 (OS, Opreating System)은 사용자가 컴퓨터를 쉽게 다루게 해주는 <strong>인터페이스</strong>입니다.</p>
</blockquote>
<p>즉, 운영체제(OS)에서의 <strong>인터페이스</strong>는 컴퓨터 사용자와 컴퓨터 하드웨어 사이의 매개체 역할을 합니다. 즉, 사용자가 복잡한 컴퓨터 명령어를 직접 입력하지 않고도 마우스 클릭, 키보드 입력 등 직관적인 방식으로 컴퓨터를 조작할 수 있도록 연결해 주는 <strong>중간다리</strong>라고 할 수 있습니다.</p>
<h3 id="운영체제의-구조">운영체제의 구조</h3>
<img src="https://velog.velcdn.com/images/jh_one/post/1f9511e0-f605-45e5-87e6-3e10da1de0ff/image.png" width="50%">

<p>GUI, 시스템콜, 커널, 드라이버 부분이 바로 운영체제를 지칭합니다.
참고로 GUI가 없고, CUI만 있는 <strong>리눅스 서버</strong>도 있습니다.</p>
<blockquote>
<ul>
<li><strong>GUI</strong>
사용자가 장치와 상호작용할 수 있도록 하는 사용자 인터페이스의 한 형태. 단순 명령어가 아닌 아이콘을 마우스로 클릭하는 단순한 동작으로 컴퓨터와 상호작용할 수 있도록 해준다.</li>
<li>*<em>드라이버 (Driver) *</em>
컴퓨터와 하드웨어를 연결하는 다리: 컴퓨터와 키보드, 마우스, 프린터 같은 하드웨어 기기들은 서로 다른 언어를 사용하는데. 드라이버는 이 두 가지 언어를 번역해 주는 역할을 하여 컴퓨터가 하드웨어를 제대로 인식하고 사용할 수 있도록 해주는 소프트웨어입니다.
예시: 새 프린터를 구매하면 드라이버를 설치해야 프린터를 사용할 수 있는 것처럼, 대부분의 하드웨어는 드라이버가 필요합니다.</li>
<li><strong>CUI (Character User Interface)</strong>
명령어를 입력해서 사용하는 방식: GUI와는 반대로, 텍스트로 된 명령어를 직접 입력하여 컴퓨터에게 명령을 내리는 방식입니다.
예시: DOS 창이나 리눅스 터미널에서 명령어를 입력하여 파일을 복사하거나 프로그램을 실행하는 것이 CUI의 예입니다.</li>
<li><strong>커널(Kernel)</strong>
커널은 운영체제 중 항상 메모리에 올라가 있는 <strong>운영체제의 핵심 부분</strong>으로 컴퓨터의 <strong>모든 자원들(소프트웨어 + 하드웨어)을 관리하는 소프트웨어</strong>이다.</li>
</ul>
</blockquote>
<h3 id="시스템콜system-call">시스템콜(System Call)</h3>
<p>시스템콜이란 운영 체제의 <strong>커널(Kernel)</strong>이 제공하는 서비스에 대해 유저의 프로그램이 운영체제의 서비스를 받기 위한 인터페이스입니다.</p>
<blockquote>
<p>응용 프로그램이 무엇인가를 하고 싶을 때, 직접 하드웨어를 건드리지 못한다.그렇기 때문에 <strong>시스템 콜</strong>을 통해 커널에 접근해 작업을 한다.</p>
</blockquote>
<p>ex) 유저 프로그램이 I/O 요청을 통해 파일을 읽기 위해 <strong>fs.readFile()</strong>이라는 함수가 실행되었을 때?</p>
<ol>
<li>파일을 읽기 위해 운영체제에 <strong>open()</strong>이라는 <strong>시스템콜(System Call)</strong>을 호출한다. </li>
<li>운영체제는 시스템콜 요청을 받으면, <strong>커널 모드</strong>로 전환된다. </li>
<li>커널은 전달받은 파일 경로를 이용해, 파일 시스템에 접근하여 해당 파일을 찾는다.</li>
<li>커널은 읽어온 파일을 <strong>유저 프로그램</strong>이 접근할 수 있는 버퍼로 복사한다.</li>
<li>유저 프로그램은 커널로부터 받은 파일을 읽어올 수 있다.</li>
</ol>
<p><img src="https://velog.velcdn.com/images/jh_one/post/b02edfa4-f048-4f06-9924-586dc14ade50/image.png" alt=""></p>
<h3 id="modebit">modebit</h3>
<p>시스템콜이 작동될 때, <strong>modebit</strong>을 통해 유저 모드와 커널 모드를 구분한다. modebit은 1 또는 0의 값을 가지는 Flag 변수이다.
만약 유저모드를 기반으로 카메라가 켜진다면, 사용자가 의도하지 않았음에도 공격자가 갑자기 카메라를 킬 수 있는 등의 위협때문에 <strong>카메라, 키보드 등 디바이스는 운영체제를 통해서만 제어할 수 있다.</strong></p>
<p><img src="https://velog.velcdn.com/images/jh_one/post/4cbe232e-a921-42be-8889-8e53d483f18e/image.png" alt=""></p>
<p><img src="blob:https://velog.io/e174b57c-dbac-4db0-a96b-2e645e89f4a6" alt="업로드중.."></p>
<ol>
<li>유저 프로그램이 카메라를 이용하려 할 때 =&gt; <strong>시스템콜 호출</strong></li>
<li><code>modebit</code>을 1에서 0으로 바꾸어, 커널모드로 변경 후 카메라 자원을 이용한 로직 수행</li>
<li><code>modebit</code>을 0에서 1로 바꾸어, 유저모드로 변경하고 이후 로직 실행</li>
</ol>
<blockquote>
<ul>
<li>유저 모드
유저가 접근할 수 있는 영역을 제한적으로 두어, 컴퓨터 자원에 함부로 침범하지 못하는 모드</li>
</ul>
</blockquote>
<ul>
<li>커널 모드
모든 컴퓨터 자원에 접근할 수 있는 모드</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[ResNet50 (1)]]></title>
            <link>https://velog.io/@jh_one/ResNet50-1</link>
            <guid>https://velog.io/@jh_one/ResNet50-1</guid>
            <pubDate>Sat, 19 Oct 2024 08:17:37 GMT</pubDate>
            <description><![CDATA[<h1 id="resnetresidual-network">ResNet(Residual Network)</h1>
<p>마이크로소프트에서 개발한 알고리즘으로, GoogleLeNet은 22개 층으로 구성됐지만, 7배 깊은 층, 152개를 사용하여 깊은 네트워크를 사용한 층을 갖는다.</p>
<blockquote>
<p><strong>단순히 네트워크 깊이만 깊어지면 성능이 좋아질까?</strong></p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/jh_one/post/1a003f11-d3f8-4d0a-a257-7e56b154aa2a/image.png" alt=""></p>
<p><strong>ResNet의 논문에는</strong> 56층의 네트워크가 20층의 네트워크보다 성능이 안좋은 것을 볼 수 있다. </p>
<p>Training 에서도, Test 에서도 성능이 좋지 않았기 때문에 우리는 이것이 Overfitting 때문이 아님을 알 수 있습니다.</p>
<p><strong>무조건 네트워크가 깊다해서 성능이 좋아지는 것은 아니다. 그렇다면 어떻게 깊은 층을 구성하여 성능을 높였을까?</strong></p>
<h3 id="residual-block">Residual block</h3>
<p><img src="https://velog.velcdn.com/images/jh_one/post/e8fc5555-64c6-427a-896a-4e40258d2e42/image.png" alt=""></p>
<p>위의 그림에서도 볼 수 있듯이, <strong>Plain Network</strong>가 단순히 Convolution 연산을 쌓는다면, <strong>ResNet</strong>은 Block이 쌓인 구조를 가지고 있고, Block 단위로(Residual Block이라고 부름) Parameter를 전달하기 전에 이전의 값을 더하는 방식을 취한다. </p>
<p><img src="https://velog.velcdn.com/images/jh_one/post/8b6f0afe-5d15-4e36-898c-35b6a7a8cefa/image.png" alt=""></p>
<p>ResNet을 구성하는 <strong>Residual Block</strong>의 구조는 위와 같다. weight layer를 통과한 f(x)와 weight layer를 통과하지 않은 x의 합을 논문에서는 <strong>Residual Mapping</strong>이라고 한다. </p>
<p><img src="https://velog.velcdn.com/images/jh_one/post/f02b6c64-a517-40f7-9910-bbc3b46da252/image.png" alt=""></p>
<p>Residual Block을 plain layer과 비교하여 설명하자면, plain layer는 동일한 연산 f(x)를 수행하고 난 뒤 Input x를 더해주지 않지만, residual block에서는 동일한 연산 f(x)를 수행하고 난 뒤 Input x를 더해준다. </p>
<p>즉, plain layer와는 다르게 residual block에는 <strong>skip connection</strong>이 존재한다. (그림의 곡선 화살표 부분 Skip connection은 하나의 layer의 output을 몇 개의 layer를 건너띄고 다음 layer의 input에 추가되는 것을 의미한다.) </p>
<blockquote>
<p>skip connection을 사용하게 되면 각각의 layer가 작은 정보들을 추가적으로 학습하도록 한다.(= 각각의 layer가 배워야 하는 정보량을 축소시킴)</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[SQL Fundamental7 ( Analytic SQL + 순위 함수)]]></title>
            <link>https://velog.io/@jh_one/SQL-Fundamental7-Analytic-SQL-%EC%88%9C%EC%9C%84-%ED%95%A8%EC%88%98</link>
            <guid>https://velog.io/@jh_one/SQL-Fundamental7-Analytic-SQL-%EC%88%9C%EC%9C%84-%ED%95%A8%EC%88%98</guid>
            <pubDate>Thu, 06 Jul 2023 12:56:32 GMT</pubDate>
            <description><![CDATA[<h2 id="analytic-sql이란">Analytic SQL이란?</h2>
<blockquote>
<p>RDBMS가 Analytic SQL을 사용하게 됨으로써 다시 데이터 분석의 중심이 될 수 있던 기능이다. 기존 Group by 함수는 원본 데이터 집합의 레벨을 변경하여 적용함에 비해, <strong>Analytic SQL은 원본 데이터 집합의 레벨을 그대로 유지하면서 집계 함수를 적용함</strong></p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/jh_one/post/aa60f1b9-1b76-4be5-a4f8-4ced2fb33f11/image.png" alt=""></p>
<ul>
<li>일반 Aggregation Function은 원본 데이터의 레벨을 변경하여 적용</li>
<li>Analytic SQL은 window를 사용하여 Row단위의 집합에 대한 연산이 가능하다.</li>
</ul>
<h3 id="analytic-sql의-유형">Analytic SQL의 유형</h3>
<p><img src="https://velog.velcdn.com/images/jh_one/post/c7ef6b3a-0179-4ff2-a66e-45621d3d3d3a/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/jh_one/post/25bcfb3c-1caa-44ac-ae97-c12f3d83895d/image.png" alt=""></p>
<p><strong>원본 데이터의 레벨을 그대로 유지하면서 그룹핑 레벨에서 자유롭게 Window의 이동과 크기를 조절하면서 Analytic 수행.</strong></p>
<h2 id="순위-analytic-sql">순위 Analytic SQL</h2>
<blockquote>
<ul>
<li>일반적인 순위: rank, dense_rank, row_number</li>
</ul>
</blockquote>
<ul>
<li>0~1 사이 정규화 순위: cume_dist, percent_rank</li>
<li>분위: ntile</li>
</ul>
<h4 id="일반적인-순위">일반적인 순위</h4>
<p><img src="https://velog.velcdn.com/images/jh_one/post/4f797d1c-eda6-4d9a-9878-22d0922f9efd/image.png" alt=""></p>
<pre><code>select a.empno, ename, job, sal 
    , rank() over(order by sal desc) as rank --rank
    , dense_rank() over(order by sal desc) as dense_rank --dense_rank
    , row_number() over (order by sal desc) as row_number from hr.emp a; --row_number
</code></pre><blockquote>
<p>위의 코드는 partition을 정하지 않았기 때문에 전체 데이터에서 순위를 매긴다. 결과는 다음과 같다.</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/jh_one/post/a19e2630-e5dd-400d-bf1b-736c40d282e6/image.png" alt=""></p>
<p>row_number는 모든 순위가 unique해야 하고, rank는 공통 부분을 제외한 갯수만큼 순위가 밀려나도록 계산. dense_rank는 공통 부분 바로 다음 순위로 계산한다.</p>
<pre><code>select a.empno, ename, job, deptno, sal 
, rank() over(partition by deptno order by sal desc) as rank 
, dense_rank() over(partition by deptno order by sal desc) as dense_rank
, row_number() over (partition by deptno order by sal desc) as row_number from hr.emp a;</code></pre><blockquote>
<p>위의 코드는 deptno로 partition을 지정하였다. 그러면 deptno가 같은 데이터끼리 순위를 매기게 된다. 결과는 다음과 같다.</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/jh_one/post/2626562e-4e3f-458d-af01-cab912e1f307/image.png" alt=""></p>
<hr>

<h4 id="부서-별-가장-급여가-높은-직원-정보">부서 별 가장 급여가 높은 직원 정보</h4>
<pre><code>--서브쿼리문 사용. row_number() 사용
select *
from ( 
select a.ename
        , a.deptno
        , b.dname
        , a.sal
        , row_number() over(partition by a.deptno order by a.sal desc) as sal_rank
from emp a 
    join dept b on a.deptno = b.deptno  ) as c 
    where sal_rank = 1</code></pre><p><img src="https://velog.velcdn.com/images/jh_one/post/888af1ba-3b91-48c8-8dee-680423904e86/image.png" alt=""></p>
<h4 id="회사-내-커미션-높은-순위-null-처리">회사 내 커미션 높은 순위. (null 처리)</h4>
<pre><code>select *
    , rank() over (order by comm desc) as comm_rank
    , row_number() over (order by comm desc) as comm_rank
from emp</code></pre><p><img src="https://velog.velcdn.com/images/jh_one/post/3e5ccd7e-7439-4deb-a8e2-d4f1ca536234/image.png" alt=""></p>
<p>null값이 존재하는 comm에 rank()와 row_number()를 적용하면 다음가 같이 null값에 대한 row들이 우선 순위로 계산된다. 왜냐하면 order by를 적용할 때 <strong>nulls first</strong> 라는 파라미터가 default이기 때문이다. null값이 우선이 된다는 뜻이다. 즉 위의 코드는 다음 코드와 같다.</p>
<pre><code>select *
    , rank() over (order by comm desc nulls first) as comm_rank
    , row_number() over (order by comm desc nulls first) as comm_rank
from emp</code></pre><p>이러한 null들을 후순위로 사용하고 싶다면 <strong>nulls first가 아닌 nulls last를 적용하면 된다.</strong> </p>
<ul>
<li>nulls first: null을 최우선 순위로</li>
<li>nulls last: null을 마지막 순위로</li>
</ul>
<p>위의 문제를 nulls last로 적용해서 실행한 결과는 다음과 같다.</p>
<pre><code>select *
    , rank() over (order by comm desc nulls last) as comm_rank
    , row_number() over (order by comm desc nulls last) as comm_rank
from emp</code></pre><p><img src="https://velog.velcdn.com/images/jh_one/post/3e169f24-8996-4d44-8011-50281223cc23/image.png" alt=""></p>
<p>또는 coalesce를 사용하여 null값을 다른 값으로 대체해도 된다.</p>
<p>다음은 comm값이 null값이면 0으로 대체 후 순위를 매기는 함수이다.</p>
<pre><code>select *
    , rank() over (order by coalesce(comm, 0) as comm_rank
    , row_number() over (order by coalesce(comm, 0) as comm_rank
from emp</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[SQL Fundamental6 (Group by, Rollup, Cube, With)]]></title>
            <link>https://velog.io/@jh_one/SQL-Fundamental6-Group-by-With</link>
            <guid>https://velog.io/@jh_one/SQL-Fundamental6-Group-by-With</guid>
            <pubDate>Wed, 05 Jul 2023 09:43:38 GMT</pubDate>
            <description><![CDATA[<h4 id="emp-테이블">emp 테이블</h4>
<p><img src="https://velog.velcdn.com/images/jh_one/post/ca979fdb-64bc-4e37-9729-c351a6e12522/image.png" alt=""></p>
<p>hiredate는 입사일의 데이터인 Date타입이다. 여기에서 입사년도. 즉 1981이란 년도만 추출하고 싶으면 다음과 같이 한다.</p>
<pre><code>select *, to_char(hiredate, &#39;yyyy&#39;) as hire_year from emp</code></pre><p>그렇다면 다음과 같이 문자열 형식으로 추출할 수 있다.
<img src="https://velog.velcdn.com/images/jh_one/post/ccb7235d-ee25-49ec-b6c0-5dfae59aecab/image.png" alt=""></p>
<h4 id="emp-테이블에서-입사년도-별-평균-급여-구하기">emp 테이블에서 입사년도 별 평균 급여 구하기.</h4>
<pre><code>select to_char(hiredate, &#39;yyyy&#39;) as hire_year, avg(sal), count(*) as cnt
from emp a
group by to_char(hiredate, &#39;yyyy&#39;)
order by 1</code></pre><p><img src="https://velog.velcdn.com/images/jh_one/post/52b2ed54-6fab-48a3-964d-ded3d771ba4d/image.png" alt=""></p>
<h2 id="case-when">Case When</h2>
<p><img src="https://velog.velcdn.com/images/jh_one/post/73b0ac87-986b-4817-a379-b7a78ef4af5d/image.png" alt=""></p>
<p><strong>Cases When은 조건에 따라서 값을 지정해 주는 문법이다.</strong></p>
<p>CASE 문의 형식은  </p>
<pre><code>CASE 컬럼  
WHEN 조건1 THEN 값1 

WHEN 조건2 THEN 값2 

ELSE 값3 

END </code></pre><h4 id="job이-salesman인-경우와-그렇지-않은-경우만-나누어서-평균최소최대-급여를-구하기">job이 SALESMAN인 경우와 그렇지 않은 경우만 나누어서 평균/최소/최대 급여를 구하기.</h4>
<pre><code>-- job이 SALESMAN인 경우와 그렇지 않은 경우만 나누어서 평균/최소/최대 급여를 구하기. 
select case job
when &#39;SALESMAN&#39; then &#39;SALESMAN&#39;
else &#39;OTHERS&#39;
end as job_category, min(sal), max(sal), round(avg(sal), 2)
from emp
group by job_category</code></pre><p><img src="https://velog.velcdn.com/images/jh_one/post/690da643-f058-47d3-84e7-06c2d6ffeb34/image.png" alt=""></p>
<hr>

<h2 id="group-by-rollup">Group by rollup</h2>
<p><strong>rollup은 group by로 나누어진 소그룹간의 계산을 하는 함수이다.</strong></p>
<p>다음 코드와 같이 deptno, job으로 group by를 해보자.</p>
<pre><code>select deptno, job, sum(sal)
from hr.emp
group by rollup(deptno, job)
order by 1, 2;</code></pre><p><img src="https://velog.velcdn.com/images/jh_one/post/0f72234e-7dfa-4663-8a71-f7af8d307770/image.png" alt=""></p>
<p>다음과 같이 deptno의 합계를 계산해준다. deptno가 10인 sum. deptno가 20인 sum, deptno가 30인 sum. 후에 전체 카테고리에 대한 Aggregation을 진행한다.</p>
<h2 id="group-by-cube">Group by Cube</h2>
<p>Group by 시 Rollup을 함께 사용하면 Rollup에 적용된 컬럼의 순서대로 계층적인 Group by 를 추가적으로 수행. </p>
<p><img src="https://velog.velcdn.com/images/jh_one/post/d98ec0f3-4e9e-4c1c-bf8f-9bf1e2afd60c/image.png" alt=""></p>
<p>위의 rollup과 달리 추가적으로 job 컬럼마다 Aggregation을 진행한다.</p>
<table>
<thead>
<tr>
<th><img src="https://velog.velcdn.com/images/jh_one/post/8cb71fc2-67a3-4550-b28c-dc3f129306ad/image.png" alt=""></th>
<th><img src="https://velog.velcdn.com/images/jh_one/post/50b22e3c-5161-498f-8b8b-4719c9003019/image.png" alt=""></th>
</tr>
</thead>
</table>
<blockquote>
<p><strong>Rollup은 계층적으로, Cube는 가능한 경우의 수에 대한 Aggregation을 진행한다.</strong></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[SQL Fundamental6 (Aggregation)]]></title>
            <link>https://velog.io/@jh_one/SQL-Fundamental6-Aggregation</link>
            <guid>https://velog.io/@jh_one/SQL-Fundamental6-Aggregation</guid>
            <pubDate>Sun, 02 Jul 2023 10:43:56 GMT</pubDate>
            <description><![CDATA[<h2 id="aggregation-function">Aggregation Function</h2>
<blockquote>
<p>대표적인 집계함수 종류</p>
</blockquote>
<ul>
<li><p>Count(): 정해진 집합 레벨에서 데이터 건수를 계산</p>
</li>
<li><p>Sum(컬럼): 정해진 집합 레벨에서 지정된 컬럼값의 총합을 계산</p>
</li>
<li><p>Min(컬럼): 정해진 집합 레벨에서 지정된 컬럼값의 최솟값을 계산</p>
</li>
<li><p>Max(컬럼): 정해진 집합 레벨에서 지정된 컬럼값의 최댓값을 계산</p>
</li>
<li><p>Avg(컬럼): 정해진 집합 레벨에서 지정된 컬럼값의 평균값을 계산</p>
</li>
<li><p><strong>집계 함수는 NULL을 계산하지 않는다.</strong></p>
</li>
<li><p>Min, Max 함수의 경우에는 문자열, 날짜, 시간에 적용이 가능하다.</p>
</li>
</ul>
<h2 id="group-by-countdistinct-케이스">Group by count(distinct) 케이스</h2>
<p>다음의 테이블이 있다.</p>
<p><img src="https://velog.velcdn.com/images/jh_one/post/90c3e3f1-5a44-431e-a5dd-8fc67bb2e410/image.png" alt=""></p>
<p>다음은 user_id로 group by된 테이블의 개수를 세는 코드이다.</p>
<pre><code>select user_id,  count(*) as cnt from orders group by user_id 
--결과: user_id: 1, cnt: 11</code></pre><p>여기에서 distinct product_id를 추가하자. 중복을 제거한 unique한 product_id의 개수를 세는 것이다.</p>
<pre><code>select user_id, count(distinct product_id) as cnt from orders group by user_id 
--결과: user_id: 1, cnt: 8</code></pre><blockquote>
<p><strong>Count 함수에서 distinct를 사용하면 컬럼에서 중복된 값을 제외한 행의 개수를 세는 함수이다.</strong></p>
</blockquote>
<hr>

<h4 id="emp_test-테이블">emp_test 테이블</h4>
<p><img src="https://velog.velcdn.com/images/jh_one/post/b0dcfe27-8e39-4654-80c8-11cf77379a60/image.png" alt=""></p>
<p>현재 해당 테이블에는 deptno가 10이면 comm은 전부 null값이다. 20에는 comm값이 하나, 30에는 4개가 할당이 되어있다.</p>
<p>다음은 deptno별 comm의 최솟값, 최댓값, 평균, count를 구하는 코드이다.</p>
<pre><code>select deptno, count(*) as cnt, sum(comm), min(comm), avg(comm)
from emp_test
group by deptno </code></pre><p><img src="https://velog.velcdn.com/images/jh_one/post/df9a94d4-eca3-4de8-92bc-4201a1372bd8/image.png" alt=""></p>
<blockquote>
<p>다음과 같이 deptno가 10인 행은 3개, 30은 6개, 20은 4개이다. 또한 deptno가 10인 경우에는 comm의 값이 전부 null값이므로, sum, min, avg는 다음과 같이 나온다</p>
</blockquote>
<h4 id="distinct를-사용하여-unique한-개수-계산">distinct를 사용하여 unique한 개수 계산</h4>
<p>전체 행 개수 출력</p>
<pre><code>select count(1) from hr.emp_test;
--출력: 13</code></pre><p>job 컬럼에 unique한 개수 계산</p>
<pre><code>select count(distinct job) from hr.emp_test;
--출력: 5</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[SQL Fundamental5 (Group by, With)]]></title>
            <link>https://velog.io/@jh_one/SQL-Fundamental5</link>
            <guid>https://velog.io/@jh_one/SQL-Fundamental5</guid>
            <pubDate>Sun, 02 Jul 2023 10:22:56 GMT</pubDate>
            <description><![CDATA[<h2 id="group-by">Group by</h2>
<p>만약 다음과 같은 테이블이 있다 한다.</p>
<p><img src="https://velog.velcdn.com/images/jh_one/post/f3522c7a-c585-45bd-86d9-14a8de3c3d9f/image.png" alt=""></p>
<p>직원들의 부서별 급여의 합을 구하려면 Group by 기능을 사용한다.</p>
<pre><code>select deptno, sum(sal) as sum_salary from hr.emp
group by deptno
</code></pre><p><img src="https://velog.velcdn.com/images/jh_one/post/b5bf62f9-be45-4447-941e-a2b54ef5aa4c/image.png" alt=""></p>
<blockquote>
<ul>
<li>Group by 절에 기술된 컬럼 값(또는 가공 컬럼값)으로 그룹화 한 뒤 집계(Aggregation) 함수와 함께 사용되어 그룹화된 집계 정보를 제공한다.</li>
</ul>
</blockquote>
<ul>
<li>Group by 절에 기술된 컬럼 값으로 반드시 1의 집합을 가지게 됨. (중복된 value가 없음)</li>
<li>Select 절에는 Group by 절에 기술된 컬럼(또는 가공 컬럼)과 집계 함수만 사용될 수 있음. </li>
</ul>
<p>만약 그룹화한 결과에 조건을 걸고 싶다면 <strong>having</strong>을 사용한다.</p>
<pre><code>SELECT job
     , SUM(sal) AS sum_sal
  FROM emp
 WHERE deptno IN (20, 30)
 GROUP BY job HAVING SUM(sal) &gt; 5000</code></pre><p><strong>having이랑 where 둘 다 조건에 따른 필터링 기능을 가지고 있다. 하지만 둘의 차이점은 where는 그룹화 하기 전이고, having은 그룹화 후에 조건입니다.</strong></p>
<h3 id="emp-테이블">emp 테이블</h3>
<p><img src="https://velog.velcdn.com/images/jh_one/post/61964f12-28bb-4ef1-9426-4e91c9321881/image.png" alt=""></p>
<h4 id="emp-테이블에서-부서별-최대-급여-최소-급여-평균-급여를-구할것">emp 테이블에서 부서별 최대 급여, 최소 급여, 평균 급여를 구할것.</h4>
<pre><code>select deptno, max(sal), min(sal), round(avg(sal), 2) as avg_sal 
from emp
group by deptno 
order by deptno asc</code></pre><p>결과
<img src="https://velog.velcdn.com/images/jh_one/post/1fcb9295-5c41-4e23-b47c-8694b2353cd8/image.png" alt=""></p>
<h4 id="emp-테이블에서-부서별-최대-급여-최소-급여-평균-급여를-구하되-평균-급여가-2000-이상인-경우만-추출">emp 테이블에서 부서별 최대 급여, 최소 급여, 평균 급여를 구하되 평균 급여가 2000 이상인 경우만 추출.</h4>
<pre><code>select deptno, max(sal), min(sal), round(avg(sal), 2)
from emp
group by deptno
having avg(sal) &gt;= 2000
order by deptno asc</code></pre><p><img src="https://velog.velcdn.com/images/jh_one/post/57955e82-1e22-44eb-a1e3-16f09aaf2f6c/image.png" alt=""></p>
<h4 id="부서명-sales와-research-소속-직원별로-과거부터-현재까지-모든-급여를-취합한-평균-급여">부서명 SALES와 RESEARCH 소속 직원별로 과거부터 현재까지 모든 급여를 취합한 평균 급여</h4>
<pre><code>-- 부서명 SALES와 RESEARCH 소속 직원별로 과거부터 현재까지 모든 급여를 취합한 평균 급여

select a.empno, max(a.ename ), max(c.dname), round(avg(b.sal), 2) 
from emp a
    join emp_salary_hist b on a.empno = b.empno 
    join dept c on a.deptno = c.deptno
where c.dname in (&#39;SALES&#39;, &#39;RESEARCH&#39;)
group by a.empno
</code></pre><h4 id="위의-코드를-with-절로-사용하기">위의 코드를 with 절로 사용하기.</h4>
<pre><code>with 
temp_01 as 
(
select a.empno, max(a.ename) ename, max(c.dname) dname, round(avg(b.sal), 2) avg_sal
from emp a
    join emp_salary_hist b on a.empno = b.empno 
    join dept c on a.deptno = c.deptno
where c.dname in (&#39;SALES&#39;, &#39;RESEARCH&#39;)
group by a.empno
)
select * from temp_01</code></pre><blockquote>
<p><strong>with 절은 서브 쿼리를 만드는 문법이다. 임시 테이블을 만들어 가독성을 더욱 높이는 기능이다.</strong></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[SQL Fundamental4 (Timestamp, Date, Interval)]]></title>
            <link>https://velog.io/@jh_one/SQL-Fundamental4</link>
            <guid>https://velog.io/@jh_one/SQL-Fundamental4</guid>
            <pubDate>Sat, 01 Jul 2023 12:14:58 GMT</pubDate>
            <description><![CDATA[<h3 id="시간에-대한-타입">시간에 대한 타입</h3>
<blockquote>
<ul>
<li>Date: 일자로서 년, 월, 일의 정보를 가짐. YYYY-MM-DD</li>
</ul>
</blockquote>
<ul>
<li>Timestamp: 일자를 시간 정보까지 같이 가짐. YYYY-MM-DD HH24:MI:SS</li>
<li>Time: 오직 시간 정보만 가짐. HH24:MI:SS</li>
<li>Interval: N days HH24:MI_SS =&gt; 시작부터 종료까지 며칠동안 혹은 몇달동안 걸렸느냐 표현하는 타입</li>
</ul>
<h3 id="문자열을-date-timestamp로-변환">문자열을 Date, Timestamp로 변환</h3>
<blockquote>
<ul>
<li>to_date(&#39;2022-01-01&#39;, &#39;yyyy-mm-dd&#39;) =&gt; 2022-01-01</li>
</ul>
</blockquote>
<ul>
<li>to_timestamp(&#39;2022-01=01 14:36:52&#39;, &#39;yyyy-mm-dd hh24:mi:ss&#39;) =&gt; 2022-01-01 14:36:52.000 +0900</li>
</ul>
<h3 id="date-timestamp를-문자열로-변환">Date, Timestamp를 문자열로 변환</h3>
<blockquote>
<ul>
<li>to_char(date_column, &#39;yyyy-mm-dd&#39;) =&gt; 1980-12-17 (문자열)</li>
</ul>
</blockquote>
<h3 id="시간에-대한-formatting">시간에 대한 Formatting</h3>
<p><img src="https://velog.velcdn.com/images/jh_one/post/88888366-9b0c-4bd8-b743-96a99dc77d6f/image.png" alt=""></p>
<h3 id="date-timestamp-text를-사용한-형-변환postgresql-문법">::date, ::timestamp, ::text를 사용한 형 변환(PostgreSQL 문법)</h3>
<blockquote>
<ul>
<li>Date를 Timestamp로 변환: <strong>select to_date(&#39;2022-01-01&#39;, &#39;yyyy-mm-dd&#39;)::timestamp;</strong></li>
</ul>
</blockquote>
<ul>
<li>Timestamp를 Text 변환: <strong>select to_date(&#39;2022-01-01&#39;, &#39;yyyy-mm-dd&#39;)::text;</strong></li>
<li>Timestamp를 Date로 변환: <strong>select to_date(&#39;2022-01-01&#39;, &#39;yyyy-mm-dd&#39;)::date;</strong></li>
</ul>
<h3 id="extract를-이용하여-년-월-일-추출">extract를 이용하여 년, 월, 일 추출</h3>
<blockquote>
<ul>
<li>extract(year from hiredate) as year</li>
</ul>
</blockquote>
<ul>
<li>extract(month from hiredate) as month</li>
<li>extract(day from hiredate) as day</li>
</ul>
<h3 id="날짜와-시간의-연산">날짜와 시간의 연산</h3>
<blockquote>
<p>Date 타입에 숫자 연산을 하면 해당하는 일자에 대한 연산이 됨.
Timestamp 타입에 숫자에 대한 연산을 하면 오류!!
Timestamp는 interval 타입에 대한 연산을 수행해야 한다.</p>
</blockquote>
<blockquote>
<p>Date 타입 + 숫자</p>
</blockquote>
<pre><code>select to_date(&#39;2022-01-01&#39;, &#39;yyyy-mm-dd&#39;) +  2 
--출력값: =&gt;     2022-01-03</code></pre><blockquote>
<p>Timestamp 타입 + Interval 타입</p>
</blockquote>
<pre><code> select to_timestamp(&#39;2022-01-01 14:36:52&#39;, &#39;yyyy-mm-dd hh24:mi:ss&#39;) + interval &#39;7 hour&#39; 
 --출력값: =&gt; 2022-01-01 21:36:52.000</code></pre><blockquote>
<p>Date 타입 + Interval 타입 =&gt; 결과는 Timestamp 타입으로 변환됨.</p>
</blockquote>
<pre><code>select to_date(&#39;2022-01-01&#39;, &#39;yyyy-mm-dd&#39;) + interval &#39;2 days&#39; as date_01;
--결과: 2022-01-03 00:00:00.000</code></pre><blockquote>
<p>Date 타입간의 연산 =&gt; 결과는 정수형으로 나온다. (Date간의 연산에서 뺄셈만 가능하며, 덧셈은 불가능함.)    </p>
</blockquote>
<pre><code>select to_date(&#39;2022-01-03&#39;, &#39;yyyy-mm-dd&#39;) - to_date(&#39;2022-01-01&#39;, &#39;yyyy-mm-dd&#39;)
--결과: 2(정수형)</code></pre><blockquote>
<p>Timestamp 타입 간의 연산  =&gt; 결과는 interval로 나온다.</p>
</blockquote>
<pre><code>select to_timestamp(&#39;2022-01-01 14:36:52&#39;, &#39;yyyy-mm-dd hh24:mi:ss&#39;) 
     - to_timestamp(&#39;2022-01-01 12:36:52&#39;, &#39;yyyy-mm-dd hh24:mi:ss&#39;)
-- 결과: 02:00:00 </code></pre><h3 id="현재-시간-구하기">현재 시간 구하기.</h3>
<ul>
<li>now() =&gt; timestamp 타입</li>
<li>current_timestamp =&gt; timestamp 타입</li>
<li>current_date =&gt; date 타입</li>
<li>current_time =&gt; time 타입</li>
</ul>
<p><img src="https://velog.velcdn.com/images/jh_one/post/2a9b4680-629d-437f-8396-86404936bb1a/image.png" alt=""></p>
<h3 id="trunc">trunc</h3>
<p>trunc(a, b)</p>
<p>python의 round 함수와 상이하다. 첫 번째 파라미터인 a 대하여 두 번째 파라미터 b자리 이후로부터는 자르겠다라는 함수이다.</p>
<p>ex) </p>
<pre><code>select trunc(99.9999, 2);
--결과: 99.99</code></pre><h3 id="date_trunc">date_trunc</h3>
<p>date_trunc는 trunc와는 다르게 첫 번째 인자로 들어온 기준으로 두 번째 인자(Date)를 자르는 함수이다. 입력에 Date 타입이든 Timestamp 타입이든 반환 타입은 Timestamp이다.</p>
<p>ex)</p>
<pre><code>select date_trunc(&#39;day&#39;, &#39;2022-03-03 14:05:32&#39;::timestamp)
--결과: 2022-03-03 00:00:00.000</code></pre><blockquote>
<p>--Month 기준으로 자르면, day는 해당 month의 1일으로 지정된다.</p>
</blockquote>
<pre><code>select date_trunc(&#39;month&#39;, &#39;2022-03-03&#39;::date)::date as date_01;
--결과 =&gt; 2022-03-01</code></pre><blockquote>
<p>--Year 기준으로 자르면, month와 day는 해당 year의 1월 1일으로 지정된다.</p>
</blockquote>
<pre><code>select date_trunc(&#39;year&#39;, &#39;2022-03-03&#39;::date)::date as date_01;
--결과 =&gt; 2022-01-01</code></pre><blockquote>
<p>주(Week) 기준으로 할 수 있다. 해당 주의 월요일 기준으로 지정한다.</p>
</blockquote>
<pre><code>-- week의 시작 날짜 구하기. 월요일 기준.
select date_trunc(&#39;week&#39;, &#39;2022-03-03&#39;::date)::date as date_01;
-- 결과: 2022-02-28</code></pre><blockquote>
<p>Month의 마지막 날자를 구하는 코드</p>
</blockquote>
<pre><code>-- month의 마지막 날짜 
select (date_trunc(&#39;month&#39;, &#39;2022-03-03&#39;::date) + interval &#39;1 month&#39; - interval &#39;1 day&#39;)::date;</code></pre><p><a href="https://www.inflearn.com/course/%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B6%84%EC%84%9D-sql-%ED%8E%80%EB%8D%94%EB%A9%98%ED%83%88/dashboard">인프런 강의</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[SQL Fundamental3 (Join의 종류)]]></title>
            <link>https://velog.io/@jh_one/SQL-Fundamental3-p5oseheh</link>
            <guid>https://velog.io/@jh_one/SQL-Fundamental3-p5oseheh</guid>
            <pubDate>Sat, 01 Jul 2023 09:39:10 GMT</pubDate>
            <description><![CDATA[<p>지난 글에서는 Join에 대하여 배웠다. Join의 디폴트는 Inner Join이다.</p>
<p><img src="https://velog.velcdn.com/images/jh_one/post/5b5e115e-14d2-4dfd-990a-355613faa886/image.png" alt=""></p>
<p>즉 on에 붙어있는 조건에 해당해야만 새로운 데이터로 추출하는 형식이다.</p>
<p>만약 다음과 같은 코드가 있다 하자.</p>
<pre><code>select a.category_name, b.product_id, b.product_name, c.company_name 
from categories a 
    join products b on a.category_id = b.category_id 
     join suppliers c on b.supplier_id = c.supplier_id 
where a.category_name = &#39;Beverages&#39;</code></pre><p>다음은 categories 테이블의 category_id와 products 테이블의 category_id, 그리고 products 테이블의 supplier_id와가 같아야만 데이터로 추출이 된다. </p>
<h2 id="outer-join">Outer Join</h2>
<p><img src="https://velog.velcdn.com/images/jh_one/post/5a9e1801-9dda-40f7-912a-d209f72aa424/image.png" alt=""></p>
<ul>
<li>LEFT OUTER JOIN: 왼쪽 테이블의 모든 값이 출력되는 조인</li>
<li>RIGHT OUTER JOIN: 오른쪽 테이블의 모든 값이 출력되는 조인</li>
<li>FULL OUTER JOIN: 왼쪽 또는 오른쪽 테이블의 모든 값이 출력되는 조인</li>
</ul>
<p>조건에 상관없이 어느 한 쪽의 테이블의 모든 값이 출력된다면, 조건에 해당하지 않는 다른 쪽 테이블의 값은 NULL로 대체된다.</p>
<pre><code>--예시 코드
SELECT * FROM A
LEFT OUTER JOIN B
ON A.id = B.id</code></pre><h2 id="예제">예제</h2>
<p>다음과 같은 EDR이 있다 하자.</p>
<p><img src="https://velog.velcdn.com/images/jh_one/post/44816c72-01fd-474d-9762-85ac9f3d3012/image.png" alt=""></p>
<p>주문이 단 한번도 없는 고객 정보를 구해보자. 다양한 여러 방법이 있겠지만 <strong>Outer Join을 사용하면 간단하다.</strong></p>
<pre><code>-- 주문이 단 한번도 없는 고객 정보 구하기. 
select a.customer_id, a.contact_name, b.order_id, b.customer_id
from customers a
    left outer join orders b on a.customer_id = b.customer_id 
where b.order_id is null;</code></pre><blockquote>
<p>customers 테이블을 left로, orders 테이블을 right로 한 후, left join을 하면 주문을 하지 않은 고객에 대한 order_id는 null으로 설정될 것이다. 그래서 where에 is null을 사용하면 주문을 하지 않은 고객의 정보를 얻을 수 있을 것이다.</p>
</blockquote>
<p>출력 결과
<img src="https://velog.velcdn.com/images/jh_one/post/a455e439-f1c9-41d7-aa27-d41d97f779f3/image.png" alt=""></p>
<h4 id="---madrid에-살고-있는-고객이-주문한-주문-정보를-구할것고객명-주문id-주문일자-주문접수-직원명-배송업체명을-구하되-만일-고객이-주문을-한번도-하지-않은-경우라도-고객정보는-빠지면-안됨-이경우-주문-정보가-없으면-주문id를-0으로-나머지는-null로-구할것">-- Madrid에 살고 있는 고객이 주문한 주문 정보를 구할것.고객명, 주문id, 주문일자, 주문접수 직원명, 배송업체명을 구하되, 만일 고객이 주문을 한번도 하지 않은 경우라도 고객정보는 빠지면 안됨. 이경우 주문 정보가 없으면 주문id를 0으로 나머지는 Null로 구할것.</h4>
<pre><code>select a.contact_name, coalesce(b.order_id, 1), c.last_name || &#39; &#39; || c.first_name, d.company_name 
from customers a
    left join orders b on a.customer_id = b.customer_id 
    left join employees c on b.employee_id = c.employee_id  
    left join shippers d on b.ship_via = d.shipper_id 
where a.city = &#39;Madrid&#39;</code></pre><p><strong>outer join을 할 때 join 집합이 여러 개면 모든 join에 outer을 붙여줘야 한다.</strong></p>
<h3 id="coalesce란">Coalesce란?</h3>
<p>두 개의 파라미터를 받는데, 첫 번째 컬럼이 NULL이 아니라면 해당 컬럼 값을 그대로 출력, 만약 NULL이라면 두 번째 value로 출력하는 것이다.</p>
<p><a href="https://www.inflearn.com/course/%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B6%84%EC%84%9D-sql-%ED%8E%80%EB%8D%94%EB%A9%98%ED%83%88/dashboard">인프런 강의</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[SQL Fundamental2 (Join)]]></title>
            <link>https://velog.io/@jh_one/SQL-Fundamental2</link>
            <guid>https://velog.io/@jh_one/SQL-Fundamental2</guid>
            <pubDate>Fri, 30 Jun 2023 14:09:16 GMT</pubDate>
            <description><![CDATA[<p>SQL의 기본 문법은 다음 글 참조. <a href="https://velog.io/@jh_one/SQL-%EA%B8%B0%EC%B4%88-%EB%AC%B8%EB%B2%95">글</a></p>
<h2 id="join">Join</h2>
<blockquote>
<ul>
<li>join은 관계형 DB에서 기본이자 가장 중요한 기능이다.</li>
</ul>
</blockquote>
<ul>
<li>두 개 이상의 테이블을 묶어 데이터를 추출하는 기능.</li>
<li>관계형 DB에서 join을 이용하여 서로 다른 테이블 간의 원하는 정보를 얻을 수 있음.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/jh_one/post/4a885a39-e449-4a68-b926-2c02b690f4ba/image.png" alt=""></p>
<ul>
<li>emp 테이블: 직원의 이름, 직원 번호, 직무, 부서 넘버에 대한 정보가 담겨져 있는 테이블</li>
<li>dept 테이블: 부서 넘버에 맞는 부서 이름, 위치가 담겨져 있는 테이블</li>
</ul>
<p>emp 테이블에는 부서 넘버가 존재한다. 하지만 부서 이름과 부서 위치가 명시되어있지 않는다. 만약 emp 테이블에 있는 직원 정보를 포함한, 그에 맞는 부서의 이름과 위치까지 알고 싶다면 join을 이용하여 새로운 테이블을 생성한다.</p>
<p>*<em>emp 테이블은 deptno 기준으로 value가 unique하지 않은 M집합이다. dept 테이블은 deptno 기준으로 value가 unique한 1집합이다. *</em> deptno 기준으로 join시, 즉 1:M 조인 시 나오는 결과는 M집합이 된다.</p>
<h4 id="예시">예시</h4>
<p><img src="https://velog.velcdn.com/images/jh_one/post/ba37a347-c8ce-47c7-824c-4493d309c879/image.png" alt=""></p>
<hr>

<h2 id="실습">실습</h2>
<p>실습은 DBeaver에서 ProgreSQL을 사용하여 진행한다.</p>
<p><img src="https://velog.velcdn.com/images/jh_one/post/8000c64b-eccd-4afb-a359-904e2e92897e/image.png" alt=""></p>
<p>현재 hr 스키마에 dept, emp, emp_dept_hist, emp_salaray_hist, salgrade 총 5개의 테이블가 있다.</p>
<p><img src="https://velog.velcdn.com/images/jh_one/post/18d2c796-105e-4c61-b81b-60a76f90bf9e/image.png" alt=""></p>
<p>스키마의 다이어그램 보기를 누르면 다음과 같이 ERD로 시각적으로 확인할 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/jh_one/post/a09ec262-30c9-4c4d-8bfc-3294abf384a5/image.png" alt=""></p>
<h5 id="직원-정보와-직원이-속한-부서명을-가져오기">직원 정보와 직원이 속한 부서명을 가져오기</h5>
<pre><code>-- 직원 정보와직원이 속한 부서명을 가져오기.

select a.*, b.dname
from emp as a 
    join dept as b on a.deptno = b.deptno </code></pre><blockquote>
<p> 위 코드에서 hr이라는 스키마가 defalut로 설정했으므로 hr은 생략이 가능하다. emp as a라는 그룹과 dept as b 라는 그룹을 join할건데, a의 deptno와 b의 deptno를 기준으로 합친다. 합친 것 중, a의 모든 컬럼과 b의 dname을 추출한다는 의미이다.</p>
</blockquote>
<p>실행 결과
<img src="https://velog.velcdn.com/images/jh_one/post/586b7879-ac0a-486c-ab42-dca3a1bed62d/image.png" alt=""></p>
<h4 id="job이-salesman인-직원정보와-직원이-속한-부서명-가져오기">job이 SALESMAN인 직원정보와 직원이 속한 부서명 가져오기.</h4>
<pre><code>select a.*, b.dname 
from emp as a join dept as b on a.deptno = b.deptno where a.job = &#39;SALESMAN&#39;</code></pre><p>실행 결과
<img src="https://velog.velcdn.com/images/jh_one/post/df9cfa69-b821-46a1-9655-1603b97e9ab5/image.png" alt=""></p>
<h4 id="부서명-sales와-research의-소속-직원들의-부서명-직원번호-직원명-job-과거-급여-정보-추출">부서명 SALES와 RESEARCH의 소속 직원들의 부서명, 직원번호, 직원명, JOB, 과거 급여 정보 추출</h4>
<pre><code>-- 부서명 SALES와 RESEARCH의 소속 직원들의 부서명, 직원번호, 직원명, JOB, 과거 급여 정보 추출

select b.dname, a.empno, a.ename, a.job, c.sal 
from emp as a
join dept as b on a.deptno = b.deptno 
join emp_salary_hist as c on a.empno = c.empno 
where b.dname in (&#39;SALES&#39;, &#39;RESEARCH&#39;)
</code></pre><p>실행 결과</p>
<p><img src="https://velog.velcdn.com/images/jh_one/post/273cdd2a-c6a8-484b-8e0b-ba652d8f6494/image.png" alt=""></p>
<h4 id="부서명-sales와-research의-소속-직원들의-부서명-직원번호-직원명-job-그리고-과거-급여-정보중-1983년-이전-데이터는-무시하고-데이터-추출">부서명 SALES와 RESEARCH의 소속 직원들의 부서명, 직원번호, 직원명, JOB 그리고 과거 급여 정보중 1983년 이전 데이터는 무시하고 데이터 추출</h4>
<pre><code>-- 부서명 SALES와 RESEARCH의 소속 직원들의 부서명, 직원번호, 직원명, JOB 그리고 과거 급여 정보중 1983년 이전 데이터는 무시하고 데이터 추출 

select b.dname, a.empno, a.ename, a.job, c.sal 
from emp as a
    join dept as b on a.deptno = b.deptno 
    join emp_salary_hist as c on a.empno = c.empno 
where b.dname in (&#39;SALES&#39;, &#39;RESEARCH&#39;) 
and c.fromdate  &gt;= to_date(&#39;1983-01-01&#39;, &#39;yyyy-mm-dd&#39;) 
order by c.fromdate ASC
</code></pre><p>실행 결과
<img src="https://velog.velcdn.com/images/jh_one/post/579454d5-93d7-4192-bf48-8f825e6a05d1/image.png" alt=""></p>
<p><a href="https://www.inflearn.com/course/%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B6%84%EC%84%9D-sql-%ED%8E%80%EB%8D%94%EB%A9%98%ED%83%88/dashboard">인프런 강의</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[SQL Fundamental(1)]]></title>
            <link>https://velog.io/@jh_one/SQL-Fundamental1</link>
            <guid>https://velog.io/@jh_one/SQL-Fundamental1</guid>
            <pubDate>Fri, 30 Jun 2023 12:41:14 GMT</pubDate>
            <description><![CDATA[<h3 id="database란">Database란?</h3>
<blockquote>
<p>데이터베이스(영어: database, DB)는 여러 사람이 공유하여 사용할 목적으로 체계화해 통합, 관리하는 데이터의 집합이다. 작성된 목록으로써 여러 응용 시스템들의 통합된 정보들을 저장하여 운영할 수 있는 공용 데이터들의 묶음이다. - Wikidipia</p>
</blockquote>
<p>한마디로 데이터를 저장하는 공간이다.</p>
<h3 id="dbms란">DBMS란?</h3>
<blockquote>
<p>데이터베이스를 ‘데이터의 집합’이라고 정의한다면, 이런 데이터베이스를 관리하고 운영하는 소프트웨어를 DBMS(Database Management System)라 한다. 다양한 데이터가 저장되어 있는 데이터베이스는 여러 명의 사용자나 응용 프로그램과 공유하고 동시에 접근이 가능해야 함.</p>
</blockquote>
<h3 id="dbms의-종류">DBMS의 종류</h3>
<ul>
<li><p>RDBMS(Relational Database Management System): 관계형 데이터베이스는 데이터를 테이블 형식으로 구성하고, 테이블 간의 관계를 정의하는 데이터베이스. 예시로는 Oracle, MySQL, Microsoft SQL Server, PostgreSQL 등이 있다.</p>
</li>
<li><p>객체 지향 데이터베이스(Object-Oriented Database)</p>
</li>
<li><p>키-값 데이터베이스(Key-Value Database)</p>
</li>
<li><p>컬럼 패밀리 데이터베이스(Column Family Database)</p>
</li>
<li><p>그래프 데이터베이스(Graph Database)</p>
</li>
</ul>
<h3 id="sql이란">SQL이란?</h3>
<p>SQL(Structured Query Language)은 관계형 데이터베이스에서 사용되는 언어이다. </p>
<blockquote>
<p>이 챕터는 RDBMS 중 PostgreSQL, 환경 도구는 DBeaver을 사용할 것이다.</p>
</blockquote>
<p><a href="https://www.inflearn.com/course/%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B6%84%EC%84%9D-sql-%ED%8E%80%EB%8D%94%EB%A9%98%ED%83%88/dashboard">인프런 강의</a></p>
<p><a href="https://www.postgresql.org/">PostgreSQL</a>
<a href="https://dbeaver.io/">DBeaver</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[SQL 기초 문법]]></title>
            <link>https://velog.io/@jh_one/SQL-%EA%B8%B0%EC%B4%88-%EB%AC%B8%EB%B2%95</link>
            <guid>https://velog.io/@jh_one/SQL-%EA%B8%B0%EC%B4%88-%EB%AC%B8%EB%B2%95</guid>
            <pubDate>Wed, 28 Jun 2023 12:26:00 GMT</pubDate>
            <description><![CDATA[<p>select는 데이터를 조회하거나 산술식, 함수 등을 실행할 때 사용된다. SQL은 대소문자를 가리지 않지만, 구문에 해당되는 것은 대문자로만 적는다.</p>
<p><code>*(에스터리스크, 별표)</code>는 모든 항목을 다 출력할 때 사용함.</p>
<pre><code>SELECT * FROM Customers;</code></pre><p>여기서 원하는 컬럼만 출력하고 싶을 때에는 아래와 같이 사용함.</p>
<pre><code>SELECT CustomerName, City FROM Customers;</code></pre><p>DISTINCT는 중복값을 제거합니다. 넘파이의 Unique() 함수와 기능이 동일.</p>
<pre><code>SELECT DISTINCT Country FROM Customers;</code></pre><h4 id="order-by">ORDER BY</h4>
<p>출력 결과 정렬. </p>
<ul>
<li>오름차순 : ASC(기본, 작은 수에서 큰 수로, Ascending)</li>
<li>내림차순 : DESC(큰 수에서 작은 수로, Descending)</li>
</ul>
<pre><code>SELECT * FROM Customers ORDER BY CustomerID DESC;</code></pre><pre><code>SELECT * FROM Customers ORDER BY CustomerName ASC;</code></pre><h4 id="as">AS</h4>
<p>별칭을 정한다. 기존 Table의 값은 변하지 않음.</p>
<pre><code>SELECT CustomerID AS 회원이름
FROM Customers;</code></pre><pre><code>SELECT CustomerID AS 회원이름, Country AS 나라
FROM Customers;</code></pre><h4 id="연결-연산자">연결 연산자</h4>
<pre><code>SELECT Country || &#39; &#39; || City || &#39; &#39; || Address AS 주소 FROM Customers</code></pre><p>실행결과</p>
<p><img src="https://velog.velcdn.com/images/jh_one/post/6c55d66c-ede0-4b1d-9395-214aeb8e32a7/image.png" alt=""></p>
<p>각 열의 데이터를 공백을 기준으로 합침. CONCAT과 상이함.</p>
<h4 id="논리-연산">논리 연산</h4>
<pre><code>SELECT *
FROM Customers 
WHERE CustomerID LIKE &#39;1%&#39;
AND City = &#39;London&#39;;</code></pre><pre><code>SELECT *
FROM Customers 
WHERE CustomerID LIKE &#39;1%&#39;
AND (City = &#39;London&#39; OR City = &#39;Berlin&#39;);</code></pre><h4 id="between-연산">BETWEEN 연산</h4>
<p>A AND B : A와 B를 포함한 사이의 값</p>
<pre><code>SELECT CustomerID, CustomerName
FROM Customers 
WHERE CustomerID BETWEEN 30 AND 50;</code></pre><blockquote>
<p>실행결과: Customers 데이터에서 가져온 CutomerID가 30이상 50이하에 해당하는 CustomerID, CustomerName</p>
</blockquote>
<h4 id="in-연산">IN 연산</h4>
<p>IN A : A안에 값과 일치하는 값을 조회 </p>
<pre><code>SELECT CustomerID, CustomerName
FROM Customers 
WHERE CustomerID IN (10, 20, 30);</code></pre><blockquote>
<p>실행결과: Customers 데이터에서 가져온 CutomerID가 10, 20, 30에해당하는 CustomerID, CustomerName</p>
</blockquote>
<h4 id="like-연산">LIKE 연산</h4>
<p>대소문자를 안가림</p>
<p>만약 데이터가 Paullab, Paultest, Paulcode가 있다 하자.</p>
<pre><code>SELECT CustomerID, CustomerName
FROM Customers 
WHERE CustomerName LIKE &#39;Paul___&#39;;</code></pre><p>결과: Paullab만 검색. 언더바(_)는 모든 문자를 의미함.</p>
<pre><code>SELECT CustomerID, CustomerName
FROM Customers 
WHERE CustomerName LIKE &#39;Paul%&#39;;</code></pre><p>결과: Paullab, Paultest, Paulcode 전부 검색. %는 뒤에 어떤 문자열이 와도 되고, 문자 자체가 없어도 됨.</p>
<p>Paul이 들어가는 모든 값</p>
<pre><code>SELECT CustomerID, CustomerName
FROM Customers 
WHERE CustomerName LIKE &#39;%Paul%&#39;;</code></pre><h4 id="is-null">IS NULL</h4>
<p>NULL 값을 갖는 값.</p>
<pre><code>SELECT CustomerID, CustomerName
FROM Customers 
WHERE CustomerID IS NULL;</code></pre><h4 id="where">WHERE</h4>
<ul>
<li>조회하려는 데이터에 조건 부여</li>
<li>여러 연산자를 결합하여 사용 가능</li>
<li>결합 가능한 연산자의 종류 : 비교연산자(=, &lt;, &gt;, !=, &gt;=, &lt;=), SQL연산자(BETWEEN), 논리 연산자(AND, OR) 등</li>
</ul>
<pre><code>SELECT *
FROM Customers 
WHERE CustomerID &gt; 80 AND Country=&#39;France&#39;;</code></pre><p>결과: Customers에서 가져온 데이터 중, CustomerID가 80보다 크고, Country가 France인 모든 컬럼 검색.</p>
<h4 id="insert">INSERT</h4>
<p>새로운 행을 추가함. 파이썬의 append 함수와 상이함.  만약 컬럼이 부족하다면 부족한 컬럼은 null로 추가됨.</p>
<pre><code>INSERT INTO Customers (CustomerName, City, Country)
VALUES (&#39;leehojun&#39;, &#39;jejusi&#39;, &#39;korea&#39;);</code></pre><p>코드의 의미: Customers 테이블에 CustomerName, City, Country 열에 &#39;leehojun&#39;, &#39;jejusi&#39;, &#39;korea&#39;란 값을 넣는다. 다른 나머지 열은 null으로 추가됨.</p>
<h4 id="update">UPDATE</h4>
<p>값을 수정, 변경하는 함수. 한 번 바꾸면 다시 되돌릴 수 없으니 신중히 해야함.</p>
<pre><code>UPDATE Customers
SET CustomerName=&#39;하르방&#39;, City=&#39;한라산&#39;, Country=&#39;선계&#39;
WHERE CustomerID = 1;</code></pre><p>코드의 의미: Customers 테이블에 CustomerID가 1인 행에 CustomerName란 열에 &#39;하르방&#39;, City란 열에 &#39;한라산&#39;, Country란 열에는 &#39;선계&#39;란 값으로 수정한다.</p>
<h4 id="delete">DELETE</h4>
<p>WHERE 구문을 적지 않으면 모든 데이터가 삭제됨.</p>
<pre><code>DELETE FROM Customers WHERE CustomerName=&#39;hojun&#39;;</code></pre><p>코드의 의미: CustomerName이 hojun인 행 삭제.</p>
<p><a href="https://www.w3schools.com/">실습 wschools</a>
<a href="https://www.youtube.com/@jejucodingcamp">제주코딩베이스캠프 강의</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[합성곱 신경망을 사용한 이미지 분류]]></title>
            <link>https://velog.io/@jh_one/%ED%95%A9%EC%84%B1%EA%B3%B1-%EC%8B%A0%EA%B2%BD%EB%A7%9D%EC%9D%84-%EC%82%AC%EC%9A%A9%ED%95%9C-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EB%B6%84%EB%A5%98</link>
            <guid>https://velog.io/@jh_one/%ED%95%A9%EC%84%B1%EA%B3%B1-%EC%8B%A0%EA%B2%BD%EB%A7%9D%EC%9D%84-%EC%82%AC%EC%9A%A9%ED%95%9C-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EB%B6%84%EB%A5%98</guid>
            <pubDate>Mon, 26 Jun 2023 12:21:49 GMT</pubDate>
            <description><![CDATA[<h3 id="데이터-준비하기">데이터 준비하기</h3>
<p>패션 MNIST 데이터 불러온 후, 스케일링 후 Train, Validation Set으로 분할</p>
<pre><code>from tensorflow import keras
from sklearn.model_selection import train_test_split

(train_input, train_target), (test_input, test_target) =\
keras.datasets.fashion_mnist.load_data()

train_scaled = train_input.reshape(-1, 28, 28, 1) #이미지에는 항상 깊이(채널)이 있어야 한다. 흑백의 이미지는 채널이 없는 2차원이지만, 다른 이미지는 채널이 RGB로 이루어짐.
train_scaled = train_input / 255.0
train_scaled, val_scaled, train_target, val_target = train_test_split(train_scaled, train_target, test_size=0.2, random_state=42)</code></pre><h3 id="첫-번째-합성곱-풀링-층-신경망">첫 번째 합성곱-풀링 층 신경망</h3>
<pre><code>model = keras.Sequential()

#32개의 kernel, Same Padding, kernel_size = (3, 3)
model.add(keras.layers.Conv2D(32, kernel_size=3, activation=&#39;relu&#39;, padding=&#39;same&#39;, input_shape=(28, 28, 1)))</code></pre><pre><code>#풀링 층 추가. 전형적인 (2, 2) 크기의 풀링
#Pooling Layer을 통과하면 데이터는 (28, 28, 32)에서 (14, 14, 32)가 된다.
model.add(keras.layers.MaxPooling2D(2))</code></pre><h3 id="두-번째-합성곱-풀링-층-신경망">두 번째 합성곱-풀링 층 신경망</h3>
<pre><code>#64개의 kernel, 3종류의 kernel
model.add(keras.layers.Conv2D(64, kernel_size=3, activation=&#39;relu&#39;, padding=&#39;same&#39;))
model.add(keras.layers.MaxPooling2D(2))</code></pre><p>최종적으로 만들어지는 피처맵의 크기는 (7, 7, 64)</p>
<h3 id="flatten-layer-dense-layer-dropout-추가">Flatten Layer, Dense Layer, Dropout 추가</h3>
<pre><code>#Flatten layer, Dense layer 추가, hidden layer와 output layer 사이의 Dropout 추가. 
#패션 MNIST  데이터셋은 클래스 10개를 분류하는 다중 분류이므로 마지막층 뉴런은 10개, 활성화함수는 softmax
model.add(keras.layers.Flatten())
model.add(keras.layers.Dense(100, activation=&#39;relu&#39;))
model.add(keras.layers.Dropout(0.4))
model.add(keras.layers.Dense(10, activation=&#39;softmax&#39;)) #output layer, activate function은 softmax </code></pre><hr>

<pre><code>model.summary()</code></pre><p><img src="https://velog.velcdn.com/images/jh_one/post/e5f8b02e-57b5-490c-8b66-6a04ab7f36a7/image.png" alt=""></p>
<pre><code>keras.utils.plot_model(model)</code></pre><p><img src="https://velog.velcdn.com/images/jh_one/post/55e63b61-d5ea-4d75-975d-b19e28279e13/image.png" alt=""></p>
<h3 id="모델-컴파일과-훈련">모델 컴파일과 훈련</h3>
<pre><code>model.compile(optimizer=&#39;adam&#39;, loss=&#39;sparse_categorical_crossentropy&#39;, metrics=&#39;accuracy&#39;)
checkpoint_cb = keras.callbacks.ModelCheckpoint(&#39;best_cnn-model.h5&#39;, save_best_only=True)
early_stopping_cb = keras.callbacks.EarlyStopping(patience=2, restore_best_weights=True)
history = model.fit(train_scaled, train_target, epochs=20, validation_data=(val_scaled, val_target), callbacks=[checkpoint_cb, early_stopping_cb])

#출력
Epoch 1/20
1500/1500 [==============================] - 17s 11ms/step - loss: 0.5223 - accuracy: 0.8124 - val_loss: 0.3402 - val_accuracy: 0.8752
Epoch 2/20
1500/1500 [==============================] - 17s 11ms/step - loss: 0.3504 - accuracy: 0.8737 - val_loss: 0.3050 - val_accuracy: 0.8863
Epoch 3/20
1500/1500 [==============================] - 18s 12ms/step - loss: 0.2981 - accuracy: 0.8925 - val_loss: 0.2612 - val_accuracy: 0.9024
Epoch 4/20
1500/1500 [==============================] - 18s 12ms/step - loss: 0.2670 - accuracy: 0.9030 - val_loss: 0.2564 - val_accuracy: 0.9058
Epoch 5/20
1500/1500 [==============================] - 18s 12ms/step - loss: 0.2398 - accuracy: 0.9130 - val_loss: 0.2399 - val_accuracy: 0.9126
Epoch 6/20
1500/1500 [==============================] - 18s 12ms/step - loss: 0.2237 - accuracy: 0.9181 - val_loss: 0.2280 - val_accuracy: 0.9158
Epoch 7/20
1500/1500 [==============================] - 18s 12ms/step - loss: 0.2052 - accuracy: 0.9240 - val_loss: 0.2430 - val_accuracy: 0.9112
Epoch 8/20
1500/1500 [==============================] - 18s 12ms/step - loss: 0.1911 - accuracy: 0.9284 - val_loss: 0.2230 - val_accuracy: 0.9212
Epoch 9/20
1500/1500 [==============================] - 19s 13ms/step - loss: 0.1749 - accuracy: 0.9346 - val_loss: 0.2289 - val_accuracy: 0.9194
Epoch 10/20
1500/1500 [==============================] - 19s 12ms/step - loss: 0.1623 - accuracy: 0.9376 - val_loss: 0.2318 - val_accuracy: 0.9193</code></pre><p>정확도는 90% 이상으로 상당히 높은 성능을 보여준다.</p>
<pre><code>#검증
model.evaluate(val_scaled, val_target)

#출력
375/375 [==============================] - 2s 4ms/step - loss: 0.2230 - accuracy: 0.9212
[0.22298048436641693, 0.9212499856948853]</code></pre><p>하나의 데이터 예측 후, 모든 케이스에 대한 확률 확인하기.</p>
<pre><code>preds = model.predict(val_scaled[0:1])
print(preds)

#출력
1/1 [==============================] - 0s 45ms/step
[[2.8726700e-20 5.2744390e-30 1.1897561e-22 1.9612064e-25 1.8187563e-21
  2.3631663e-19 4.3168609e-22 1.1876107e-23 1.0000000e+00 1.5984584e-23]]</code></pre><p>아홉 번째 확률은 1에 근사하지만, 나머지는 0에 근사한다. 시각화 후 확인하자.</p>
<pre><code>import matplotlib.pyplot as plt

plt.bar(range(1, 11), preds[0])
plt.show()</code></pre><p><img src="https://velog.velcdn.com/images/jh_one/post/bf89fc9d-b859-4194-a18a-9afa934ff2b4/image.png" alt=""></p>
<p>완벽하게 아홉 번째 클래스로 예측했다는 것을 알 수 있다.</p>
<pre><code>#테스트
test_scaled = test_input.reshape(-1, 28, 28, 1) / 255.0
model.evaluate(test_scaled, test_target)

#출력
test_scaled = test_input.reshape(-1, 28, 28, 1) / 255.0
model.evaluate(test_scaled, test_target)</code></pre><p>성능은 대부분 90%가 넘는 것으로 보인다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[합성곱 신경망의 구성요소]]></title>
            <link>https://velog.io/@jh_one/%ED%95%A9%EC%84%B1%EA%B3%B1-%EC%8B%A0%EA%B2%BD%EB%A7%9D%EC%9D%98-%EA%B5%AC%EC%84%B1%EC%9A%94%EC%86%8C</link>
            <guid>https://velog.io/@jh_one/%ED%95%A9%EC%84%B1%EA%B3%B1-%EC%8B%A0%EA%B2%BD%EB%A7%9D%EC%9D%98-%EA%B5%AC%EC%84%B1%EC%9A%94%EC%86%8C</guid>
            <pubDate>Mon, 26 Jun 2023 10:34:52 GMT</pubDate>
            <description><![CDATA[<h2 id="합성곱-신경망이란">합성곱 신경망이란?</h2>
<p>합성곱 신경망(CNN)은 Convolution Neural Networks의 줄임말로, 인간의 시신경을 모방하여 만든 딥러닝 구조 중 하나이다. 이미지 처리에 탁월하며, ANN, DNN과 다르게 이미지의 공간적인 정보를 유지한다.</p>
<h2 id="convolution-layer신경망-층">Convolution Layer(신경망 층)</h2>
<p>먼저 다음과 같은 3x3의 이미지가 있다고 하자.</p>
<img src="https://velog.velcdn.com/images/jh_one/post/667ee729-c3b2-4b91-95ce-4775f18a184c/image.png" width="70%" height="30%">

<p>우리가 일반적인 ANN, DNN 딥러닝 모델로 해당 이미지를 분석한다고 하면 Flatten 층을 거쳐 다음과 같이 1차원의 데이터로 평탄화가 될 것이다. 이 데이터에 각 가중치를 곱하여 은닉층으로 결과값이 전달되고, 최종적으로 출력층에서 Classfiy를 할 것이다. 하지만 이미지 특성상 각 픽셀간의 밀접한 상관관계가 있을텐데, 해당 알고리즘은 이러한 공간적인 구조를 무시한 채 분석을 한다는 것을 알 수 있다. 이러한 점을 방지하고자, 이미지 특성 상 공간적인 특성을 유지하고자 나온 딥러닝 모델이 <strong>Convolution Layer</strong>이다.</p>
<hr>

<p><img src="https://velog.velcdn.com/images/jh_one/post/f86844d4-b0ad-43d0-8392-09cb9e18dbbc/image.png" alt=""></p>
<p>원래 밀집층의 뉴런은 다음과 같이 모든 뉴런에 가중치를 곱한 후 절편을 더한 하나의 출력값이다. 즉 뉴런의 개수와 출력값의 개수가 동일하다.</p>
<p><img src="https://velog.velcdn.com/images/jh_one/post/44cf21b6-06ec-4e2c-9142-e5150c2ad605/image.png" alt=""></p>
<p>하지만 합성곱에서는 다음과 같이 가중치 w1<del>w3과 처음 특성 3개를 곱한 후 절편을 더하여 한 개의 출력을 만든다. 그 다음은 이 전과 똑같은 가중치 w1</del>w3와 2<del>4번째 특성을 곱한 후 절편을 더하여 또다른 한 개의 출력을 만든다. 여기에서 중요한 것은 첫 번째 합성곱에서 사용된 가중치 w1</del>w3을 두 번째 합성곱의 계산에서도 사용했다는 것이다. 이렇게 한 칸씩 아래로 이동하면서 출력을 만들며, 이 과정을 끝까지 한다면 다음과 같이 된다.</p>
<p><img src="https://velog.velcdn.com/images/jh_one/post/cdd4ebce-8d28-4e7a-b6e0-5b659bcd161d/image.png" alt=""></p>
<p>물론 가중치의 개수는 w1~w3처럼 3개를 선택해도 되고, 더욱 많은 가중치를 선택해도 된다. 즉 <strong>하이퍼파라미터이다</strong>. 이를 <strong>합성곱 신경망</strong>에서는 뉴런이라고도 부르지만, 보통 <strong>filter</strong> 혹은 <strong>kernel</strong>이라고 부른다.</p>
<p>4x4의 입력이 있다하자. 커널의 크기를 2x2으로 지정한다 하면 다음과 같을 것이다.</p>
<p><img src="https://velog.velcdn.com/images/jh_one/post/d0c14604-adc3-4945-93bb-16953badd29c/image.png" alt=""></p>
<p>입력이 2차원이라면 커널도 반드시 2차원이여야 한다.  처음은 입력값의 첫 부분에 해당 필터를 씌운다.</p>
<p><img src="https://velog.velcdn.com/images/jh_one/post/26fbd76b-5b5c-45e7-845d-4ee842dc970f/image.png" alt=""></p>
<p>후에는 sliding을 하여 다음과 같은 입력값의 부분에 kernel을 계산할 것이다.</p>
<p><img src="https://velog.velcdn.com/images/jh_one/post/8c948353-daa2-4dca-be0c-dc270fd7f590/image.png" alt=""></p>
<p>이 과정을 반복해가면 다음과 같은 출력값이 만들어질 것이다.</p>
<p><img src="https://velog.velcdn.com/images/jh_one/post/e65549d7-89ca-427a-ac20-7075964273fe/image.png" alt=""></p>
<p>밀집층에서 여러 개의 뉴런을 사용하듯이, 합성곱 층에서도 다음과 같이 여러 개의 kernel을 사용할 수 있다. (4, 4)의 입력값에 (3, 3)의 커널을 사용한다면 (2, 2)의 feature map이 나온다. 이것이 3개로 겹치며 최종적으로 (2, 2, 3) 크기의 feature map이 된다.
<img src="https://velog.velcdn.com/images/jh_one/post/e6fd8ab5-c73d-4898-ac6b-e50a135e65e8/image.png" alt=""></p>
<p>입력값에 kernel을 씌운 후 나오는 결과를 feature map(특성 맵)이라고 부른다. 이 과정을 인공 신경망의 구조로 나타내면 다음과 같다,</p>
<p><img src="https://velog.velcdn.com/images/jh_one/post/955036fd-320d-4b99-ac57-ee88caa65f18/image.png" alt=""></p>
<hr>

<h2 id="padding">Padding</h2>
<p>(4, 4) 크기의 입력에 (3, 3) 크기의 커널을 적용하면 (2, 2) 크기의 피처맵이 만들어졌다. 하지만 만약 커널의 크기는 그대로 (3, 3)이지만, 출력의 크기. 즉 피처맵의 크기가 입력과 동일하게 (4, 4)로 만들려면 어떻게 해야 할까?</p>
<p>입력값과 동일한 크기의 출력을 만들고 싶다면 마치 더 큰 입력에 합성곱하는 척을 해야한다. 예를 들어 실제 입력 크기는 (4, 4)이지만, (6, 6)처럼 다룬다고 가정해보자. 다음과 같이 (6, 6) 크기의 입력에 (3, 3) 크기의 커널로 합성곱을 하였을 때 출력의 크기는 어떻게 될까??</p>
<p>실제 (4, 4) 크기의 입력값 주위에 0을 채워넣은 후, (6, 6) 크기로 만든 후 진행해보자.</p>
<p><img src="https://velog.velcdn.com/images/jh_one/post/349ae718-c1d0-40a6-930d-90716fb20782/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/jh_one/post/bae817b1-43c4-4a66-bf48-481c107dc958/image.png" alt=""></p>
<p>다음과 같이 16번의 연산을 통하여 (4, 4) 크기의 feature map을 만들 수 있다.
<img src="https://velog.velcdn.com/images/jh_one/post/c79537b4-3eb2-4a28-8162-dd407afd2504/image.png" alt=""></p>
<p>이렇게 입력 주위를 가상의 원소로 채우는 것을 <strong>Padding</strong>이라고 한다. 실제 입력값이 아니기 때문에 패딩은 0으로 채운다. 그러면 (4, 4) 크기의 입력값은 위와 같이 (6, 6) 크기의 입력값으로 된다. </p>
<p><strong>패딩의 역할은 순전히 커널이 씌워지는 횟수를 늘려주는 것밖에는 없다. 그렇기 때문에 계산에도 영향을 미치지 않는다</strong></p>
<p>이렇게 입력과 피처맵의 크기를 동일하게 만들기 위해 주위를 0으로 패딩하는 것을 <strong>same padding</strong>이라고 한다. 일반적으로 합성곱 신경망에서는 새임 패딩이 가장 많이 사용된다.</p>
<p>이러한 패딩 없이 순수한 입력에서 피처맵을 만드는 경우를 <strong>Valid Padding</strong>이라 한다. </p>
<h4 id="padding의-사용-이유">Padding의 사용 이유</h4>
<p>만약 (4, 4) 크기의 입력에서 패딩 없이 합성곱을 한다면 다음과 같은 4번의 계산이 이루어진다.</p>
<img src="https://velog.velcdn.com/images/jh_one/post/ce65c5bc-dc9c-4386-9a74-30b24e9f9443/image.png" height="40%">

<p>왼쪽 위 모서리의 3을 포함한 양 끝 네 모서리는 커널이 단 한 번밖에 계산이 되지 않는다.하지만 가운데에 있는 4, 8, 5, 1은 4번의 계산에 포함된다. 즉 이미지 계산에 불균형이 이루어질 수 있다. 패딩을 진행하면 이러한 불균형을 감소할 수 있다.</p>
<h2 id="stride">Stride</h2>
<p>스트라이드는 kernel의 이동 크기를 의미한다. 즉 현재까지 진행한 스트라이드의 크기는 1이였다. 스트라이드의 크기가 2인 경우는 다음과 같다.</p>
<table>
<thead>
<tr>
<th><img src="https://velog.velcdn.com/images/jh_one/post/ae2e7b7e-d2e1-4e6e-b462-ae2be90c4df4/image.png"></th>
<th><img src="https://velog.velcdn.com/images/jh_one/post/ef2a9776-dfd0-44ee-b54e-967e8e036148/image.png" ></th>
</tr>
</thead>
</table>
<p>대부분 스트라이드는 1로 설정하여, strides 매개변수는 잘 사용하지 않는다.</p>
<h2 id="pooling">Pooling</h2>
<p><strong>풀링(Pooling)</strong>은 합성곱 층에서 만든 피처맵의 크기를 줄이는 역할이다. 하지만 피처맵의 개수는 줄이지 않는다. 예를 들어, (2, 2, 3)의 피처맵이 있다. 여기에 (2, 2) 크기로 풀링을 적용하면 (1, 1, 3)이 된다.</p>
<p><img src="https://velog.velcdn.com/images/jh_one/post/77b15aa5-7673-440e-a9a9-041d7bf20940/image.png" alt=""></p>
<p>커널을 찍은 영역에서 가장 큰 값을 고르거나, 평균값을 계산한다. 이를 각각 <strong>최대 풀링</strong>과 <strong>평균 풀링</strong>이라 한다.</p>
<p>다음은 (4, 4) 크기의 피처맵에 (2, 2) <strong>최대 풀링</strong>을 적용한 것이다.</p>
<p><img src="https://velog.velcdn.com/images/jh_one/post/f088f009-3e14-45cf-88bf-04a0d1c5693c/image.png" alt=""></p>
<p>최대 풀링은 가장 큰 값을 고르기 때문에 첫 번째 (2, 2) 영역에서 9를 고르고, 그 다음은 7, 8, 6을 고른 후 (2, 2)의 출력을 만든다. 피처맵이 여러 개라면 동일한 작업을 반복한다.</p>
<p>풀링에서는 영역을 겹치지 않고 이동을 한다. 풀링 크기가 (2, 2)라면 스트라이드가 2인 셈이다. 풀링의 크기는 보통 정방형의 크기로 설정한다.</p>
<h2 id="convolution-neural-networks의-구조">Convolution Neural Networks의 구조</h2>
<p><img src="https://velog.velcdn.com/images/jh_one/post/e3c80fc5-f7f0-4167-b112-30299f7dc47c/image.png" alt=""></p>
<p>위와 같이 (4, 4)의 입력, (3, 3)의 커널이 있다. </p>
<ol>
<li><p>Same Padding이므로, 입력의 크기를 (6, 6)으로 늘려준다.</p>
</li>
<li><p>커널의 개수는 3개이므로, 각 커널을 계산한 (4, 4, 3)의 피처맵을 생성한다. 
밀집층과 마찬가지로 합성곱 층에서도 활성화 함수를  적용한다. 합성곱 층은 보통 렐루 함수를 많이 사용한다.</p>
</li>
<li><p>(2, 2)의 최대 풀링을 진행한다. 풀링을 진행하면서 특성의 가로, 세로의 크기를 줄인다. 특성의 개수는 건들지 않는다. 즉 (4, 4, 3)의 피처맵에 (2, 2)의 최대 풀링을 진행하면 (2, 2, 3)의 피처맵이 생성된다.</p>
</li>
<li><p>(2, 2, 3)의 피처맵을 Flatting하면 12개의 특성을 가진 1차원 배열으로 된다. 이것이 출력층의 입력이 된다.</p>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[신경망 모델 훈련]]></title>
            <link>https://velog.io/@jh_one/%EC%8B%A0%EA%B2%BD%EB%A7%9D-%EB%AA%A8%EB%8D%B8-%ED%9B%88%EB%A0%A8</link>
            <guid>https://velog.io/@jh_one/%EC%8B%A0%EA%B2%BD%EB%A7%9D-%EB%AA%A8%EB%8D%B8-%ED%9B%88%EB%A0%A8</guid>
            <pubDate>Sun, 25 Jun 2023 11:32:19 GMT</pubDate>
            <description><![CDATA[<p>이전 챕터와 마찬가지로 데이터 불러온 후 전처리하기.</p>
<pre><code>from tensorflow import keras
from sklearn.model_selection import train_test_split

(train_input, train_target), (test_input, test_target) =\
keras.datasets.fashion_mnist.load_data()
train_scaled = train_input / 255.0
train_scaled, val_scaled, train_target, val_target = train_test_split(train_scaled, train_target, test_size=0.2, random_state=42)</code></pre><p>모델을 생성 후 반환하는 함수 만들기</p>
<pre><code>#모델을 만드는 함수 정의

def model_fn(a_layer=None):
    model = keras.Sequential()
    model.add(keras.layers.Flatten(input_shape=(28, 28)))
    model.add(keras.layers.Dense(100, activation=&#39;relu&#39;))

    if a_layer:
        model.add(a_layer)

    model.add(keras.layers.Dense(10, activation=&#39;softmax&#39;))
    return model</code></pre><p>모델 생성 후 학습시키기.</p>
<pre><code>model = model_fn()
model.summary()
model.compile(loss=&#39;sparse_categorical_crossentropy&#39;, metrics=&#39;accuracy&#39;)
history = model.fit(train_scaled, train_target, epochs=5, verbose=0)

import matplotlib.pyplot as plt

plt.plot(history.history[&#39;loss&#39;])
plt.xlabel(&#39;epoch&#39;)
plt.ylabel(&#39;loss&#39;)

plt.show()</code></pre><p><img src="https://velog.velcdn.com/images/jh_one/post/f6d2529f-8b8b-425c-a210-fc8ccc1ab6dc/image.png" alt=""></p>
<p>다음 그래프와 같이 epoch가 증가할 수록 손실은 줄어들고 정확도는 높아진다. 그러면 epoch를 계속해서 증가하면 성능이 완전히 올라가지 않을까?</p>
<p>다음은 epoch를 20까지 늘려서 모델을 학습시킨 코드이다.</p>
<pre><code>model = model_fn()
model.compile(loss=&#39;sparse_categorical_crossentropy&#39;, metrics=&#39;accuracy&#39;)

history = model.fit(train_scaled, train_target, epochs=20, verbose=0)

plt.plot(history.history[&#39;loss&#39;])
plt.xlabel(&#39;epoch&#39;)
plt.ylabel(&#39;loss&#39;)

plt.show()</code></pre><p><img src="https://velog.velcdn.com/images/jh_one/post/c2cb3bcd-99fd-4ede-abf5-e324e45778ce/image.png" alt=""></p>
<p>다음과 같이 손실이 감소한다. 이것이 더 나은 모델을 학습한 것일까? 반복 수를 늘리면 과대/과소적합의 가능성이 상당히 올라간다. </p>
<h3 id="검증-손실">검증 손실</h3>
<pre><code>model = model_fn()
model.compile(loss=&#39;sparse_categorical_crossentropy&#39;, metrics=&#39;accuracy&#39;)
history = model.fit(train_scaled, train_target, epochs=20, verbose=0, validation_data=(val_scaled, val_target))</code></pre><pre><code>plt.plot(history.history[&#39;loss&#39;])
plt.plot(history.history[&#39;val_loss&#39;])
plt.xlabel(&#39;epoch&#39;)
plt.ylabel(&#39;loss&#39;)
plt.legend([&#39;train&#39;, &#39;validate&#39;])

plt.show()</code></pre><p><img src="https://velog.velcdn.com/images/jh_one/post/df288b40-9bac-4e3c-827d-fd88307ca5cc/image.png" alt=""></p>
<p>초기 검증 손실이 감소하다가, 다섯번 째 에포크 만에 다시 상승하기 시작한다. 하지만 학습 손실은 꾸준히 감소하기 때문에 전형적인 과대적합 모델이다.</p>
<p>과대적합을 막기 위해 릿지, 라쏘 규제오 같은 것을 적용할 수 있다. 하지만 그 전에는 옵티마이저 하이어파라미터를 조정한다.</p>
<p>Adam 옵티마이저는 적응적 학습률을 사용하기 때문에 epoch가 진행되면서 학습률의 크기를 조정할 수 있다. Adam 옵티마이저를 적용 후, 다시 시각적 표현을 하자.</p>
<pre><code>model = model_fn()
model.compile(optimizer=&#39;adam&#39;, loss=&#39;sparse_categorical_crossentropy&#39;, metrics=&#39;accuracy&#39;)
history = model.fit(train_scaled, train_target, epochs=20, verbose=0, validation_data=(val_scaled, val_target))

plt.plot(history.history[&#39;loss&#39;])
plt.plot(history.history[&#39;val_loss&#39;])
plt.xlabel(&#39;epoch&#39;)
plt.ylabel(&#39;loss&#39;)
plt.legend([&#39;train&#39;, &#39;validate&#39;])

plt.show()</code></pre><p><img src="https://velog.velcdn.com/images/jh_one/post/390c0ea9-54be-4617-9311-76dff1e76be5/image.png" alt=""></p>
<p>위의 그래프와 달리 과대적합이 감소한 모습을 보인다. </p>
<h3 id="인공-신경망에서-사용하는-대표적인-규제-방법">인공 신경망에서 사용하는 대표적인 규제 방법</h3>
<h4 id="드롭아웃">드롭아웃</h4>
<p><img src="https://velog.velcdn.com/images/jh_one/post/5a5aad10-f519-4358-a5fb-e39cb6b4ac14/image.png" alt=""></p>
<p>드롭아웃은 다음 그림처럼 훈련 과정에서 층에 있는 뉴런을 랜덤하게 꺼서(뉴런의 츌력을 0으로 만듬) 과대적합을 막는다.</p>
<p>어떤 샘플을 처리할 때는 은닉층의 두 번째 뉴런이 드롭아웃이 되어 h2의 출력이 없다. 다른 샘플을 처리할 때에는 은닉층의 첫 번째 뉴런이 드롭아웃이 되어 h1의 출력이 없다. </p>
<p>뉴런은 랜덤하게 드롭아웃 되고 얼마나 많은 뉴런을 드롭할 지는 우리가 정해야 할 또다른 하이퍼파라미터이다.</p>
<p>어떻게 드롭아웃이 과대적합을 막을까? 이전 층의 일부 뉴런이 랜덤하게 꺼지면 특정 뉴런에 과대하게 의존하는 것을 줄일 수 있다.</p>
<pre><code>#30%정도를 드롭아웃 한다.
model = model_fn(keras.layers.Dropout(0.3))
model.summary()</code></pre><pre><code>model.compile(optimizer=&#39;adam&#39;, loss=&#39;sparse_categorical_crossentropy&#39;, metrics=&#39;accuracy&#39;)
history = model.fit(train_scaled, train_target, epochs=20, verbose=0, validation_data=(val_scaled, val_target))

plt.plot(history.history[&#39;loss&#39;])
plt.plot(history.history[&#39;val_loss&#39;])
plt.xlabel(&#39;epoch&#39;)
plt.ylabel(&#39;loss&#39;)
plt.legend([&#39;train&#39;, &#39;validate&#39;])

plt.show()</code></pre><p><img src="https://velog.velcdn.com/images/jh_one/post/f96831e9-9439-4cd6-8104-317137db28df/image.png" alt=""></p>
<p>Keras 모델은 학습된 모델의 파라미터를 저장하는 <strong>save_weights()</strong> 메서드를 제공한다.</p>
<pre><code>model.save_weights(&#39;model-weights.h5&#39;)</code></pre><p>또한 모델의 구조와 모델 파라미터를 함께 저장하는 save() 메서드도 제공한다.</p>
<pre><code>model.save(&#39;model-whole.h5&#39;)</code></pre><ol>
<li>학습하지 않는 새로운 모델을 생성 후, 모델의 파라미터만 저장된 model-weights.h5 파일에서 학습된 모델 파라미터만 읽어서 사용해보자.</li>
</ol>
<pre><code>model = model_fn(keras.layers.Dropout(0.3))
model.load_weights(&#39;model-weights.h5&#39;)</code></pre><ol start="2">
<li>이번에는 모델 전체를 파일에서 불어온다.</li>
</ol>
<pre><code>model = keras.models.load_model(&#39;model-whole.h5&#39;)
model.evaluate(val_scaled, val_target)</code></pre><h3 id="callback">Callback</h3>
<p>콜백은 학습 과정 중간에 어떤 작업을 수행할 수 있게 하는 객체이다. 여기에서 사용할 ModelCheckPoint 콜백은 기본적으로 에포크마다 모델을 저장한다. </p>
<p>save_best_only=True 매개변수를 지정하여 가장 낮은 검증 점수를 만드는 모델을 저장할 수 있다.</p>
<pre><code>#30%정도를 드롭아웃 한다.
model = model_fn(keras.layers.Dropout(0.3))
model.summary()

model.compile(optimizer=&#39;adam&#39;, loss=&#39;sparse_categorical_crossentropy&#39;, metrics=&#39;accuracy&#39;)
checkpoint_cb = keras.callbacks.ModelCheckpoint(&#39;best-model.h5&#39;, save_best_only=True)

model.fit(train_scaled, train_target, epochs=20, verbose=0, validation_data=(val_scaled, val_target), callbacks=[checkpoint_cb])</code></pre><pre><code>model = keras.models.load_model(&#39;best-model.h5&#39;)
model.evaluate(val_scaled, val_target)

#출력
375/375 [==============================] - 0s 611us/step - loss: 0.3146 - accuracy: 0.8867
[0.3145997226238251, 0.8867499828338623]</code></pre><p>여전히 20번의 에포크 동안 학습을 진행한다. 사실 검증 점수가 상승하기 시작하면, 그 이후는 과대적합이 더 커지기 때문에 훈련을 계속할 필요가 없다. 과대적합이 시작되기 전에 훈련을 미리 중지하는 것을 <strong>조기종료</strong>라 한다.</p>
<p><strong>조기종료</strong>는 훈련 에포크 횟수를 제한하는 역할이지만, 모델이 과대적합되는 것을 막아 주기 때문에 규제 방법 중 하나라고 생각할 수 있다.</p>
<p>파라미터 중 patience는 연속 검증 점수가 향상되지 않으면 훈련을 종료시키는 파라미터이다. 즉 patience=2로 지정하면 2번 연속 검증 점수가 향상되지 않으면 학습을 중지한다.</p>
<p>또한 restore_best_weights 파라미터를 True로 설정하면 가장 낮은 검증 손실을 낸 모델 파라미터로 되돌린다.</p>
<p><strong>EarlyStopping 콜백을 ModelCheckpoint 콜백과 함께 사용하면 가장 낮은 검증 손싱릐 모델을 파일에 저장 후, 검증 손실이 다시 상승할 때 훈련을 중지할 수 있다. 또한 훈련을 중지한 다음 현재 모델의 파라미터를 최상의 파라미터로 되돌린다.</strong></p>
<pre><code>model = model_fn(keras.layers.Dropout(0.3))
model.compile(optimizer=&#39;adam&#39;, loss=&#39;sparse_categorical_crossentropy&#39;, metrics=&#39;accuracy&#39;)
checkpoint_cb = keras.callbacks.ModelCheckpoint(&#39;best-model.h5&#39;, save_best_only=True)
early_stoppin_cb = keras.callbacks.EarlyStopping(patience=2, restore_best_weights=True)

history = model.fit(train_scaled, train_target, epochs=20, verbose=0, 
validation_data=(val_scaled, val_target), callbacks=[checkpoint_cb, early_stoppin_cb])</code></pre><pre><code>print(early_stoppin_cb.stopped_epoch)

#출력값 11
#12번째 epoch에서 학습이 종료되었다.</code></pre><pre><code>plt.plot(history.history[&#39;loss&#39;])
plt.plot(history.history[&#39;val_loss&#39;])
plt.xlabel(&#39;epoch&#39;)
plt.ylabel(&#39;loss&#39;)
plt.legend([&#39;train&#39;, &#39;validate&#39;])

plt.show()</code></pre><p><img src="https://velog.velcdn.com/images/jh_one/post/8c8d41cd-b379-408b-a989-e15911372ada/image.png" alt=""></p>
<pre><code>model.evaluate(val_scaled, val_target)

#출력값: 
375/375 [==============================] - 0s 683us/step - loss: 0.3250 - accuracy: 0.8808
[0.32503339648246765, 0.8808333277702332]</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[심층 신경망]]></title>
            <link>https://velog.io/@jh_one/%EC%8B%AC%EC%B8%B5-%EC%8B%A0%EA%B2%BD%EB%A7%9D</link>
            <guid>https://velog.io/@jh_one/%EC%8B%AC%EC%B8%B5-%EC%8B%A0%EA%B2%BD%EB%A7%9D</guid>
            <pubDate>Sun, 25 Jun 2023 10:03:42 GMT</pubDate>
            <description><![CDATA[<p>케라스 API의 패션 MNIST 데이터셋을 불러오자.</p>
<pre><code>from tensorflow import keras
(train_input, train_target), (test_input, test_target) =\
keras.datasets.fashion_mnist.load_data()</code></pre><p>그 다음 이미지의 픽셀값을 0<del>255범위에서 0</del>1로 변환 후, 28*28 크기의 이미지를 1차원 배열로 평탄화한다. 후에 sklearn의 train_test_split() 메서드를 사용해 train과 validate 세트로 나누자.</p>
<pre><code>from sklearn.model_selection import train_test_split
train_scaled = train_input / 255.0
train_scaled = train_scaled.reshape(-1, 28*28)
train_scaled, val_scaled, train_target, val_target = train_test_split(train_scaled, train_target, test_size=0.2, random_state=42)</code></pre><p>이제 인공 신경망 모델에 층을 2개 추가하겠다. 이 전의 신경망 모델과 다른 점은 입력층과 출력층 사이에 밀집층이 추가된 것이다. 이렇게 입력층과 출력층 사이에 있는 모든 층을 <strong>은닉층(Hidden Layer)</strong>이라고 부른다.</p>
<p>은닉층에는 활성화 함수가 항상 적용된다. 출력층에 적용하는 활성화 함수는 이진 분류일 경우에는 시그모이드, 다중 분류일 경우에는 소프트맥스 함수로 제한된다. 하지만 은닉층의 활성화 함수는 출력층에 비해 비교적 자유롭다. 대표적으로 시그모이드 함수와 렐루 함수 등을 사용한다.</p>
<p>다음은 밀집층을 구현하는 코드이다.</p>
<pre><code>dense1 = keras.layers.Dense(100, activation=&#39;sigmoid&#39;, input_shape=(784,))
dense2 = keras.layers.Dense(10, activation=&#39;softmax&#39;)</code></pre><p>dense1이 은닉층이며, 100개의 뉴런을 가진 밀집층이다. 활성화함수는 시그모이드이며, 입력의 크기는 (784,)로 지정하였다. 은닉층의 뉴런 개수를 정하는 데는 특별한 기준은 없다. 하지만 적어도 출력층의 뉴런보다는 많아야 한다.</p>
<p>dense2는 출력층이다. 10개의 클래스를 분류하므로 10개의 뉴런을 두었고, 활성화 함수는 소프트맥스로 지정하였다.</p>
<hr>

<p>이제 앞에서 만든 dense1과 dense2 객체를 Sequential 클래스에 추가하여 <strong>심층 신경망(DNN)</strong>을 만들어 본다.</p>
<pre><code>model = ([dense1, dense2])</code></pre><p>여기에서 주의해야 할 것은 출력층(dense2)을 마지막에 두어야 한다. </p>
<p>층을 추가하는 다른 방법이다.</p>
<pre><code>model = keras.Sequential([keras.layers.Dense(100, activation=&#39;sigmoid&#39;, input_shape=(784,), name=&#39;hidden&#39;), keras.layers.Dense(10, activation=&#39;softmax&#39;, name=&#39;output&#39;)]
, name=&#39;패션 MNIST 모델&#39;)</code></pre><p>dense1, dense2같은 밀집 층은 따로 사용할 일이 없기 때문에 이렇게 직접 Sequential 클래스 안에 전달한다.</p>
<p>또 다른 방법은 다음과 같다.</p>
<pre><code>model = keras.Sequential()
model.add(keras.layers.Dense(100, activation=&#39;sigmoid&#39;, input_shape=(784,), name=&#39;hidden&#39;))
model.add(keras.layers.Dense(10, activation=&#39;softmax&#39;, input_shape=(784,), name=&#39;output&#39;))</code></pre><p>이렇게 Sequential 클래스 객체를 생성 후, add 메서드를 이용하여 층을 추가하는 방법이 있다.</p>
<p>이 방법은 추가되는 방법을 한 눈으로 볼 수 있으며, 프로그램 실행 시 동적으로 층을 선택하여 추가할 수 있기 때문에 유용하다.</p>
<p>이제 모델을 학습시켜보자.</p>
<pre><code>model.compile(loss=&#39;sparse_categorical_crossentropy&#39;, metrics=&#39;accuracy&#39;)
model.fit(train_scaled, train_target, epochs=5)

#출력
Epoch 1/5
1500/1500 [==============================] - 2s 985us/step - loss: 0.5661 - accuracy: 0.8088
Epoch 2/5
1500/1500 [==============================] - 1s 957us/step - loss: 0.4087 - accuracy: 0.8527
Epoch 3/5
1500/1500 [==============================] - 1s 905us/step - loss: 0.3746 - accuracy: 0.8648
Epoch 4/5
1500/1500 [==============================] - 1s 916us/step - loss: 0.3519 - accuracy: 0.8721
Epoch 5/5
1500/1500 [==============================] - 1s 916us/step - loss: 0.3346 - accuracy: 0.8790
&lt;keras.callbacks.History at 0x7fe0b2e856d0&gt;</code></pre><p>이 전의 성능에 비해 이렇게 추가된 층이 성능을 향상시켰다는 것을 알 수 있다.</p>
<h4 id="렐루-함수">렐루 함수</h4>
<p>인공 신경망의 은닉층에 많이 사용된 활성화 함수는 시그모이드 함수였다. 하지만 이 함수에도 단점이 있다. 
시그모이드 함수는 입력이 매우 크거나, 매우 작을 때 기울기가 매우 작아질 수 있다. 이 문제는 가중치를 업데이트 하는데 상당한 문제를 일으킬 수 있다.</p>
<p>특히 층이 많은 심층 신경망일수록 그 효과가 누적되어 학습을 더 어렵게 만들 수 있다. 이를 개선하기 위해 나온 함수가 <strong>ReLU 함수</strong>이다. 렐루 함수는 입력이 양수일 경우 그냥 입력을 통과시키고, 음수일 경우에는 0을 만든다.</p>
<p><img src="https://velog.velcdn.com/images/jh_one/post/91e72db2-b41b-4975-ad7e-cb64d103f4e5/image.png" alt=""></p>
<p>이 함수는 max(0, z)와 같이 쓸 수 있다. z가 0보다 크면 z를 출력하고, z가 0보다 작으면 0을 출력한다.</p>
<p>렐루 함순믄 특히 이미지 처리에서 좋은 성능을 낸다고 알려져 있다.</p>
<hr>

<p>위에서 우리는 28*28을 reshape() 메서드를 사용하여 1차원 데이터로 평탄화하는 작업을 진행하였다. 하지만 케라스에서 더욱 유용한 기능을 제공한다.</p>
<p>Flatten 클래스는 입력 차원을 모두 일렬로 펼치는 역할을 한다. Flatten 클래스는 입력층과 은닉층 사이에 추가하기 때문에 이를 층이라고 부른다. Flatten 층은 다음 코드처럼 입력층 바로 뒤에 추가한다.</p>
<pre><code>model = keras.Sequential()
model.add(keras.layers.Flatten(input_shape=(28, 28)))
model.add(keras.layers.Dense(100, activation=&#39;relu&#39;))
model.add(keras.layers.Dense(10, activation=&#39;softmax&#39;))</code></pre><p>이런 식으로 Flatten 층을 추가하면 된다. 하지만 우리는 위에서 이미 평탄화 작업을 진행하였기 때문에 데이터를 다시 불러온 후 모델 학습을 진행시킨다.</p>
<pre><code>(train_input, train_target), (test_input, test_target) =\
keras.datasets.fashion_mnist.load_data()
train_scaled = train_input / 255.0
train_scaled, val_scaled, train_target, val_target = train_test_split(train_scaled, train_target, test_size=0.2, random_state=42)</code></pre><pre><code>model.compile(loss=&#39;sparse_categorical_crossentropy&#39;, metrics=&#39;accuracy&#39;)
model.fit(train_scaled, train_target, epochs=5)

#출력
Epoch 1/5
1500/1500 [==============================] - 2s 914us/step - loss: 0.5370 - accuracy: 0.8106
Epoch 2/5
1500/1500 [==============================] - 1s 909us/step - loss: 0.3953 - accuracy: 0.8566
Epoch 3/5
1500/1500 [==============================] - 1s 913us/step - loss: 0.3571 - accuracy: 0.8707
Epoch 4/5
1500/1500 [==============================] - 1s 904us/step - loss: 0.3359 - accuracy: 0.8801
Epoch 5/5
1500/1500 [==============================] - 1s 936us/step - loss: 0.3197 - accuracy: 0.8849
&lt;keras.callbacks.History at 0x7fe0b2f6cf10&gt;</code></pre><pre><code>model.evaluate(val_scaled, val_target)

#출력 
375/375 [==============================] - 0s 688us/step - loss: 0.3731 - accuracy: 0.8787
[0.37310147285461426, 0.8786666393280029]</code></pre><h4 id="옵티마이저">옵티마이저</h4>
<p>딥러닝의 학습에서는 최대한 틀리지 않는 방향으로 학습해 나가야 한다.</p>
<p>여기서 얼마나 틀리는지(loss)를 알게 하는 함수가 loss function=손실함수이다. loss function의 최소값을 찾는 것을 학습의 목표로 한다.</p>
<p>여기서 최소값을 찾아가는 것을 최적화=Optimization 이라고 하고 이를 수행하는 알고리즘이 최적화 알고리즘=Optimizer 이다.</p>
<p>즉 최적의 경사 하강법 알고리즘을 선택하는 것이다.</p>
<p>다음은 옵티마이저의 종류이다.</p>
<p><img src="https://velog.velcdn.com/images/jh_one/post/1e9dd3d0-7eff-441e-b5da-0eb6fa4c769e/image.png" alt=""></p>
<p>어떤 옵티마이저를 사용해야 할 지 모를 때에는 Adam을 사용하라. 라는 말이 있다. Adam이 가장 일반적이며, 성능이 좋은 옵티마이저다. 다음은 옵티마이저를 adam으로 설정한 후 모델을 학습시키는 코드이다.</p>
<pre><code>model = keras.Sequential()
model.add(keras.layers.Flatten(input_shape=(28, 28)))
model.add(keras.layers.Dense(100, activation=&#39;relu&#39;))
model.add(keras.layers.Dense(10, activation=&#39;softmax&#39;))</code></pre><pre><code>model.compile(optimizer=&#39;adam&#39;, loss=&#39;sparse_categorical_crossentropy&#39;, metrics=&#39;accuracy&#39;)
model.fit(train_scaled, train_target, epochs=5)

#출력값
Epoch 1/5
1500/1500 [==============================] - 1s 871us/step - loss: 0.5328 - accuracy: 0.8143
Epoch 2/5
1500/1500 [==============================] - 1s 932us/step - loss: 0.3991 - accuracy: 0.8581
Epoch 3/5
1500/1500 [==============================] - 1s 957us/step - loss: 0.3553 - accuracy: 0.8712
Epoch 4/5
1500/1500 [==============================] - 1s 901us/step - loss: 0.3258 - accuracy: 0.8807
Epoch 5/5
1500/1500 [==============================] - 1s 953us/step - loss: 0.3075 - accuracy: 0.8859
&lt;keras.callbacks.History at 0x7fe0b2eebf70&gt;</code></pre><pre><code>model.evaluate(val_scaled, val_target)

#출력값
375/375 [==============================] - 0s 686us/step - loss: 0.3435 - accuracy: 0.8780
[0.34353795647621155, 0.878000020980835]</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[인공 신경망]]></title>
            <link>https://velog.io/@jh_one/%EC%9D%B8%EA%B3%B5-%EC%8B%A0%EA%B2%BD%EB%A7%9D</link>
            <guid>https://velog.io/@jh_one/%EC%9D%B8%EA%B3%B5-%EC%8B%A0%EA%B2%BD%EB%A7%9D</guid>
            <pubDate>Sun, 25 Jun 2023 08:25:21 GMT</pubDate>
            <description><![CDATA[<p>다음 코드로 텐서플로의 데이터를 불러온다.</p>
<pre><code>from tensorflow import keras
(train_input, train_target), (test_input, test_target) =\
     keras.datasets.fashion_mnist.load_data()</code></pre><p>데이터의 크기를 확인한다.</p>
<pre><code>print(train_input.shape, train_target.shape)
#출력값: (60000, 28, 28) (60000,)</code></pre><pre><code>print(test_input.shape, test_target.shape)
#출력값: (10000, 28, 28) (10000,)</code></pre><p>위의 train 데이터는 28<em>28의 픽셀로 되어있는 이미지가 총 6만개가 있고, test 데이터는 28</em>28 픽셀로 되어있는 이미지가 총 10000개가 있다는 뜻이다.</p>
<p>다음은 10개의 데이터만 이미지로 출력하는 코드이다.</p>
<pre><code>import matplotlib.pyplot as plt
fig, axs = plt.subplots(1, 10, figsize=(10, 10))
for i in range(10):
    axs[i].imshow(train_input[i], cmap=&#39;gray_r&#39;)
    axs[i].axis(&#39;off&#39;)

plt.show()</code></pre><p>출력결과
<img src="https://velog.velcdn.com/images/jh_one/post/78332b9f-4b09-46dc-a20b-1318c55bbebd/image.png" alt=""></p>
<p>다음은 target에 대한 데이터이다.</p>
<pre><code>print(train_target[:10])
#출력값: [9 0 0 3 0 2 7 2 5 5]</code></pre><p>MNIST의 타깃은 0~9로 이루어진 레이블로 구성되어 있다. 각 숫자는 다음을 의미한다. </p>
<p><img src="https://velog.velcdn.com/images/jh_one/post/d1d87dfe-20bc-4f89-b5f4-0c6de17c96eb/image.png" alt=""></p>
<p><strong>Tensorflow</strong>는 구글이 오픈소스로 공개한 딥러닝 라이브러리이다. 텐서플로에는 저수준 API와 고수준 API가 있다. 바로 <strong>Keras</strong>가 텐서플로의 고수준 API이다.</p>
<p>딥러닝 라이브러리가 다른 머신러닝 라이브러리와 다른 점 중 하나는 그래픽 처리 장치인 GPU를 사용하여 인공 신경망(ANN)을 학습한다는 것이다. GPU는 벡터와 행렬 연산에 매우 최적화되어 있기 때문에 곱셈과 덧셈이 많이 수행되는 인공 신경망에 큰 도움이 된다.</p>
<p>하지만 케라스 라이브러리는 직접 GPU 연산을 수행하지 않습니다. 대신 GPU 연산을 수행하는 다른 라이브러리를 백엔드로 사용한다. 예를 들면 텐서플로가 케라스의 백엔드 중 하나이다.</p>
<hr>

<p>다른 머신러닝 모델에서는 교차 검증을 사용하여 모델을 평가했지만, 인공 신경망에서는 교차 검증을 잘 사용하지 않고, 검증 세트를 별도로 덜어내어 사용한다.</p>
<p>그 이유는 다음과 같다.</p>
<ol>
<li>딥러닝 분야의 데이터셋은 충분히 크기 때문에 검증 점수가 안정적이다.</li>
<li>교차 검증을 수행하기에는 학습 시간이 너무 오래걸리기 때문이다.</li>
</ol>
<p>따라서 검증 세트를 따로 나누기 위하여 sklearn의 <strong>train_test_split()</strong> 메서드를 사용한다</p>
<pre><code>from sklearn.model_selection import train_test_split
train_scaled, val_scaled, train_target, val_target = train_test_split(train_scaled, train_target, test_size=0.2, random_state=42)</code></pre><p>우리는 현재 10개의 클래스를 가지고 있는 데이터를 사용하기 때문에, 최종적으로 나오는 뉴런의 개수(출력층)은 10개의 뉴런으로 구성된다.</p>
<p>다음은 케라스의 Dense 클래스를 사용하여 밀집층을 생성한다.</p>
<pre><code>#밀집층 클래스인 Dense 클래스를 사용하여 밀집층을 생성.
#뉴런의 개수: 10개, 누련의 출력에 적용할 함수: softmax, 데이터 입력의 크기: 784*1
dense = keras.layers.Dense(10, activation=&#39;softmax&#39;, input_shape=(784,))</code></pre><p>첫 번째 매개변수로는 뉴런의 개수를 10개로 지정한다. 10개의 패션 아이템으로 분류하기 때문이다. 10개의 뉴런에서 출력된 값을 확률로 바꾸기 위해서는 <strong>Softmax</strong>함수를 사용한다. 만약 2개의 클래스를 분류하는 이진 분류라면 <strong>Sigmoid</strong>함수를 사용해야 한다. 
마지막으로 세 번째 매개변수는 입력값의 크기이다.</p>
<p>위의 코드를 실행시키면 인공 신경망의 밀집층을 구현한 것이다. 이제 이 밀집층을 가진 신경망 모델을 만들어야 한다. <strong>케라스의 Sequential</strong> 클래스를 사용한다.</p>
<pre><code>#Sequential 클래스에 밀집층의 객체 dense를 전달하여 신경망 모델인 model 객체 생성.
model = keras.Sequential(dense)</code></pre><p>Sequential 클래스의 객채에 밀집층의 객체 dense를 전달했다. 여기에서 만든 model 객체가 바로 신경망 모델이다. 다음 그림에 지금까지 만든 신경망을 나타냈다. 마지막에 소프트맥스 함수를 적용한 것을 주목해라.</p>
<p><img src="https://velog.velcdn.com/images/jh_one/post/f0a3f8ec-d587-4323-bdcc-9a5ca87dc481/image.png" alt=""></p>
<p>소프트맥스와 같이 뉴런의 선형 방정식 계산 결과에 적용되는 함수를 <strong>활성화 함수</strong>라 부른다.</p>
<p>지금까지 신경망 모델을 생성하였다. 이제 우리가 가지고 있는 학습용 데이터로 학습을 시키면 된다. 하지만 케라스 모델은 학습을 하기 전, 설정 단계가 필요하다. 이런 설정을 model 객체의 compile() 메서드에서 수행한다. 꼭 지정해야 할 것은 손실 함수의 종류이다. 다음은 compile()메서드를 이용하여 설정하는 코드이다.</p>
<pre><code>model.compile(loss=&#39;sparse_categorical_crossentropy&#39;, metrics=&#39;accuracy&#39;)</code></pre><ul>
<li>이진 분류에서는 binary_crossentropy(이진 크로스 엔트로피 손실함수)를 사용한다.</li>
<li>다중 분류에서는 categorical_crossentropy(크로스 엔트로피 손실 함수)를 사용한다.</li>
</ul>
<p>케라스에서는 위의 두 손실 함수를 사용한다.</p>
<p>케라스 모델의 다중 분류는 다음과 같이 확률을 계산한다.</p>
<p>출력층은 10개의 뉴런이 있고, 10개의 클래스에 대한 확률을 출력한다. 첫 번째 뉴런은 티셔츠일 확률이고, 두 번째 뉴런은 바지일 확률을 출력한다. 이진 분류와 달리 각 클래스에 대한 모든 확률이 모두 출력되기 때문에 타깃에 해당하는 확률만 남겨 놓기 위해서 나머지 확률에는 모두 0을 곱한다.</p>
<p>예를 들어, 첫 번째 뉴런으로 분류가 되었다면, 첫 번째 뉴런의 활성화 함수 출력인 a1에 크로스 엔트로피 손실 함수를 적용하고, 나머지 활성화 함수 출력 a2~a10까지는 전부 0으로 만든다.</p>
<p>이와 같이 타깃값을 1로, 나머지는 모두 0으로 만드는 것을 <strong>One-Hot Encoding</strong>이라 한다.</p>
<p>다중 분류에서 크로스 엔트로피 손실 함수를 사용하려면 0,1,2와 같은 정수로 되어야 한다. 이러한 정수로된 타깃값을 사용해 크로스 엔트로피 손실을 계산하는 것이 바로 <strong>sparse_categorical_crossentropy</strong>이다.</p>
<p>케라스는 모델이 훈련할 때마다 기본으로 에포크마다 손실 값을 출력해준다. 손실이 줄어드는 것을 보고 훈련이 잘되었다는 것을 알 수 있지만, 정확도와 함께 출력이 된다면 더욱 더 좋을 것이다.</p>
<p>이를 위해 metrics 파라미터에 정확도 지표를 의미하는 <strong>accuracy</strong>를 지정한다.</p>
<p>이제 모델을 학습시켜야 한다. 다음은 케라스 모델을 학습시키는 코드이다.</p>
<pre><code>#model 학습, epoch는 5로 설정.
model.fit(train_scaled, train_target, epochs=5)

#출력
Epoch 1/5
1500/1500 [==============================] - 1s 529us/step - loss: 0.4792 - accuracy: 0.8395
Epoch 2/5
1500/1500 [==============================] - 1s 524us/step - loss: 0.4570 - accuracy: 0.8481
Epoch 3/5
1500/1500 [==============================] - 1s 528us/step - loss: 0.4444 - accuracy: 0.8515
Epoch 4/5
1500/1500 [==============================] - 1s 525us/step - loss: 0.4372 - accuracy: 0.8557
Epoch 5/5
1500/1500 [==============================] - 1s 527us/step - loss: 0.4316 - accuracy: 0.8576</code></pre><p>이제 앞에서 분리한 검증 세트에서 모델의 성능을 확인해보겠다. 다음은 케라스 모델의 성능을 평가하는 코드이다.</p>
<pre><code>#학습된 model의 검증.
model.evaluate(val_scaled, val_target)

#출력
375/375 [==============================] - 0s 468us/step - loss: 0.4468 - accuracy: 0.8524
[0.4468023180961609, 0.8524166941642761]</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[Support Vector Machine]]></title>
            <link>https://velog.io/@jh_one/Support-Vector-Machine</link>
            <guid>https://velog.io/@jh_one/Support-Vector-Machine</guid>
            <pubDate>Mon, 29 May 2023 12:50:54 GMT</pubDate>
            <description><![CDATA[<p>Support Vector Machie은 Classfier에서 사용할 수 있는 강력한 머신러닝 모델이다.</p>
<p>Support Vector Machie(SVM)은 결정 경계(Decision Boundary)를 정의하는 모델이다.</p>
<p><img src="https://velog.velcdn.com/images/jh_one/post/8db1a9cb-52ea-45c3-8ce1-25be6eb0fde4/image.png" alt=""></p>
<p>다음 군집을 이루고 있는 데이터의 결정 경계는 다음과 같은 간단한 일차선 형태가 될 것이다.</p>
<p>하지만 차원이 3차원으로 늘어난다면 결정 경계는 다음과 같이 평면의 평태가 될 것이다.
<img src="https://velog.velcdn.com/images/jh_one/post/c6f63ab6-c398-46c1-a9cd-6229a8c6d670/image.png" alt=""></p>
<p>우리는 시각적으로 인지할 수 있는 범위는 딱 3차원까지이다. 차원, 즉 속성의 개수가 늘어나면 늘어날수록 복잡해질 것이다. 결정 경계도 단순한 평면이 아닌 고차원의 형태가 될 것인데 이를 <strong>초평면(Hyperplane)</strong>이라 한다.</p>
<p><img src="https://velog.velcdn.com/images/jh_one/post/92e3ce71-afde-4572-a99e-0226b9ddb4c8/image.png" alt=""></p>
<p>위의 사진은 똑같은 데이터에 각자 다른 결정 경계를 표시한 사진이다. 어떤 선이 최적의 결정 경계일까?.
Graph F가 될 것이다. 두 클래스 사이의 거리가 가장 멀기 때문이다. 이처럼 결정 경계는 군집으로부터 최대한 멀리 떨어지는 것이 좋다. 이 거리를 Margin이라 한다.</p>
<p>즉 최적의 결정 경계는 마진을 최대화하는 것이다. 마진의 크기를 최대화하려면 이상치(Outlier)을 잘 다루는 것이 중요하다. 다음 사진들을 확인해보자. </p>
<p><img src="https://velog.velcdn.com/images/jh_one/post/da1052ab-28b6-4dd3-8094-27dd338d4e19/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/jh_one/post/c5fda268-6cc5-495a-a45f-4109bd7a75cb/image.png" alt=""></p>
<p>위의 그림은 이상치를 허용하지 않은 상태이다. 이것을 <strong>Hard Margin</strong>이라 부른다. 그리고 해당 경우는 마진이 매우 작아진다. 이러한 Hard Margin은 Margin이 작아지는 것 뿐만 아니라, 학습 데이터에 대한 <strong>Overfitting</strong> 문제가 발생할 수 있다.</p>
<p>아래의 그림은 이상치를 어느정도 허용한 상태이다. 이것을 <strong>Soft Margin</strong>이라 부른다. 그리고 해당 경우는 마진이 커진다.. 이러한 Soft Margin은 Margin이 증가하지만, 학습 데이터에 대한 <strong>Underfitting</strong> 문제가 발생할 수 있다.</p>
<p>지금까지는 Linear의 결정 경계에 대한 데이터셋으로 예시를 들었다. 하지만 일상생활에서 Linear한 데이터는 거의 없을 것이다. 만약 이러한 데이터셋이 있다면 어떨까?</p>
<p><img src="https://velog.velcdn.com/images/jh_one/post/f6a60355-91d2-45bb-85fc-e56a277755af/image.png" alt=""></p>
<p>해당 데이터셋은 직선이 아닌, 원으로 그려야 할 것이다. 이러한 데이터셋을 위하여, SVM 모델은 <strong>Kernel</strong>을 선택할 수 있다.</p>
<ol>
<li><p>다항식 (Polynomial)</p>
</li>
<li><p>방사 기저 함수 (Radial Bias Function: RBF)</p>
</li>
</ol>
<p>RBF Kernel 혹은 Gaussian Kernel이라 부른다. 이 커널은 sciklit-learn의 SVC모델의 Default에 해당된다. RBF 커널은 2차원의 점을 무한한 차원의 점으로 변환하는 알고리즘이다.</p>
<p>SVM에서 마진을 최대화하기 위해서는 이상치를 허용하는 방법도 있지만, gamma라는 파라미터를 사용하는 방법이 있다. gamma는 결정 경계를 얼마나 유연하게 그리는가를 정해주는 것이다.</p>
<ul>
<li><p>gamma 값을 높이면 학습 데이터에 많이 의존을 하여, 결정 경계가 구불구불 해진다. 이는 Overfitting을 초래할 수 있다.</p>
</li>
<li><p>gamma 값을 낮추면 학습 데이터에 별로 의존을 하지 않아, 결정 경계가 직선에 가깝게 된다. 이는 Underfitting을 초래할 수 있다.</p>
</li>
</ul>
<p>gamma가 높은 경우</p>
<p><img src="https://velog.velcdn.com/images/jh_one/post/528c8125-41b0-4a4c-9c78-46fa3ec4d105/image.png" alt=""></p>
<p>gamma가 낮은 경우</p>
<p><img src="https://velog.velcdn.com/images/jh_one/post/576894e9-cc58-47fd-b95d-b2798649ce72/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[MFCC]]></title>
            <link>https://velog.io/@jh_one/MFCC</link>
            <guid>https://velog.io/@jh_one/MFCC</guid>
            <pubDate>Mon, 29 May 2023 12:31:39 GMT</pubDate>
            <description><![CDATA[<p>MFCC(Mel Frequency Cepstral Coefficients)란 음성 및 오디오 신호 처리에서 대표적으로 사용하는 기술이다. MFCC는 음성데이터를 <strong>특징백터화</strong>해주는 Algorithm이다.</p>
<p>사람은 음성을 인식할 때 달팽이관에서 각기 다른 주ㅜ파수를 감지한다. 하지만 사람의 달팽이관은 주파수가 낮은 대역에서의 변화는 잘 감지하지만, 주파수가 높은 대역에서는 그렇지 못하다. 이러한 사람의 달팽이관의 특성을 고려하여 음성데이터에서 특징을 추출한 값이 <strong>Mel-Scale</strong>이다.</p>
<p>또한 사람은 똑같은 문장을 말해도 각자 다른 속도로 말하기 때문에 이러한 각기 다른 음성데이터를 학습시키기에는 어려움이 있다. 이러한 특징에 의하여, 음성 데이터를 전부 20ms<del>40ms로 분할한다. 여러 연구에 의하면 사람은 20ms</del>40ms 사이에서는 음소가 바뀔 수 없다는 연구결과가 있다.
이러한 특징점을 이용하여 음성 데이터를 분석하는 알고리즘이 바로 <strong>Mel Frequency Cepstral Coefficients</strong>이다.</p>
<p>그렇다면 MFCC는 어떻게 할까? 다음 단계와 같이 진행을 한다.</p>
<ol>
<li><p>Pre-Emphasis 
사람은 발성 시 신체적 구조때문에 실제로 낸 소리에서 고주파 성분이 많이 줄어들어서 나온다고 한다. 그래서 먼저 줄어든 고주파 성분을 강조하기 위하여 고주파 신호는 더 강조하며, 저주파 신호는 약화하는, 즉 <strong>High-Pass Filter</strong>이다.</p>
</li>
<li><p>Sampling and Windowing
아까 언급했다시피 음성 신호를 20ms<del>40ms단위로 분할한다고 하였다. 이 단계에서 음성 신호를 20ms</del>40ms 단위의 Frame으로 분할한다. 여기에서 Frame을 일부러 겹치게 분할을 해야 한다. 그 이유는 이 과정을 안하고 샘플링시, 프레임과 프레임의 접합 부분에서 순간 변화율이 무한대로 나올 수 있다. 이러한 부분을 방지하기 위한 것이다.</p>
</li>
</ol>
<p>후에 이 프레임에 대해 Windowing을 각각 적용한다. 여러 Window가 존재하지만 보통 <strong>Hamming Window</strong>를 많이 사용하곤 한다.</p>
<ol start="3">
<li><p>Fast Fourier Transform (FFT)
푸리에 변환은 주파수를 추출할 때 대표적으로 사용하는 알고리즘이다. 해당 알고리즘을 사용해 음성 데이터에 대한 주파수 성분을 얻어낸다.</p>
</li>
<li><p>Mel Filter Bank
각각 프레임에 대해 얻어낸 주파수들에 대한 Mel값을 얻기 위하여 해당 FIlter을 사용한다. 해당 주파수에 따른 Filter의 차이가 있는데, 고주파 대역으로 갈수록 넓은 삼각형의 Filter을 사용하게 된다. 그래서 모든 Frame이 삼각형 Filter을 통과하게 된다면, <strong>Mel-Spectrogram</strong>이라는 Feature가 뽑히게 된다.</p>
</li>
<li><p>Discrete Cosine Transform (DCT) 연산
4번에서 나온 결과물인 Mel-Spectrogram이라는 feature에 대해 행렬을 압축해서 표현하는 DCT연산을 진행한다. 그러면 Output으로 우리가 구하고자 하는 <strong>Mel-Frequency Cepstral Coefficients</strong>가 나오게 된다.</p>
</li>
</ol>
<p>이 MFCC값을 이용하여 여러 가지 머신러닝, 딥러닝 모델에 학습시킬 수 있다.</p>
]]></description>
        </item>
    </channel>
</rss>