<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Sang-moon, Lee</title>
    <description>The latest articles on DEV Community by Sang-moon, Lee (@moonyl).</description>
    <link>https://dev.to/moonyl</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F394916%2F988bef06-424e-4a2a-9734-820f4efe2dba.jpeg</url>
      <title>DEV Community: Sang-moon, Lee</title>
      <link>https://dev.to/moonyl</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/moonyl"/>
    <language>en</language>
    <item>
      <title>Wisper, ffmpeg을 활용한 비디오 자막 자동 생성</title>
      <dc:creator>Sang-moon, Lee</dc:creator>
      <pubDate>Sat, 14 Dec 2024 00:14:52 +0000</pubDate>
      <link>https://dev.to/moonyl/wisper-ffmpegeul-hwalyonghan-bidio-jamag-jadong-saengseong-3ea5</link>
      <guid>https://dev.to/moonyl/wisper-ffmpegeul-hwalyonghan-bidio-jamag-jadong-saengseong-3ea5</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fglwf3hg4hmbu65en96tq.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fglwf3hg4hmbu65en96tq.jpg" alt="Image description" width="800" height="600"&gt;&lt;/a&gt;&lt;br&gt;
유튜브나 넷플릭스 영상을 보면서 "자막을 자동으로 만들어주는 프로그램이 있으면 편하겠다!"라고 생각해 본 적이 있지 않은가? 아무래도 새로운 기술에 대한 영상은 영어로 된 것이 우선적으로 작성되어서 올라오는 경우가 많다. 하지만 영어 듣기가 약한 나에게는 자막이 꼭 필요하기 때문에 이 기능은 꼭 필요하게 느껴진다. 그래서 "한번 직접 자막 생성기를 생성해보자" 라는 생각을 하게 되었다.&lt;br&gt;
처음에는 막막했지만, 이러저리 찾아보니 파이썬과 몇 가지 멋지 도구들을 사용하면 생각보다 쉽게 자막을 만들 수 있었다. 그래서 이 글은 삽질하며 얻은 경험을 공유하고자 작성하게 되었다. 이 글에서는 파이썬과 음성 인식계의 핫한 스타 "Whisper", 영상/음성 처리의 만능 도구 "ffmpeg"을 사용하여 비디오 파일에서 자동으로 자막을 추출하는 방법을 단계별로 정리할 것이다.&lt;/p&gt;
&lt;h2&gt;
  
  
  코드 개요 및 주요 개념: 자막 생성, 어떻게 이루어질까?
&lt;/h2&gt;

&lt;p&gt;여기에서 만들 자막 생성 프로그램은 다음과 같은 순서로 작동한다. 먼저, 비디오 파일에서 목소리가 담긴 오디오만 쏙 뽑아낸다. 그 다음, 뽑아낸 오디오를 똑똑한 AI인 Whisper에게 전달해 주면, Whisper가 오디오를 분석해서 텍스트로 바꿔준다. 마지막으로, 텍스트에 언제 그 말이 나왔는지 시간 정보를 덧붙여서 자막 파일(SRT)를 만들면 된다.&lt;br&gt;
이 과정에서 꼭 알아야 할 몇 가지 핵심 개념이 있다.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;오디오 처리: 비디오에서 음성만 따로 분리해서 다루는 과정이다. 마치 요리 재료를 다듬는 것처럼, 본격적인 요리인 음성 인식을 하기 전에 필요 없는 부분을 제거하고 깨끗하게 만드는 과정이라고 생각할 수 있다. 이 부분은 ffmpeg이라는 든든한 도구가 담당해준다.&lt;/li&gt;
&lt;li&gt;음성 인식(Speech-to-Text): 이 부분은 Whisper라는 AI가 담당한다. Whisper는 사람의 말을 알아듣고 글로 적어주는 똑똑한 녀석이다. 마치 속기사처럼, 우리가 말하는 내용을 정확하게 텍스트로 바꿔준다.&lt;/li&gt;
&lt;li&gt;자막 생성: Whisper가 만들어준 텍스트에 "이 대사는 몇 분 몇 초에 나왔어!"라는 시간 정보를 추가해서 자막 파일을 만드는 과정이다. 이렇게 하면 영상과 자막이 딱딱 맞아떨어지게 된다.&lt;/li&gt;
&lt;li&gt;예외 처리: 프로그램을 만들다 보면 예상치 못한 오류가 발생하기가 다반사이다. 이러한 오류를 잘 처리해서 프로그램이 갑자기 멈추는 것을 방지할 필요가 있다. 안정장치를 마련해 두는 것이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  라이브러리 설치(Windows 환경): 자막 생성을 위한 준비 운동
&lt;/h2&gt;

&lt;p&gt;이제 본격적으로 자막 생성기를 만들기 전에 필요한 도구를 설치해 보자. 이 글에서는 Windows 환경을 기준으로 설명한다.&lt;/p&gt;
&lt;h3&gt;
  
  
  ffmpeg 설치: 영상/음성 처리의 만능 도구
&lt;/h3&gt;

&lt;p&gt;ffmpeg은 영상과 음성을 다루는 데 있어서 거의 마법 지팡이 같은 도구이다. 다양한 포맷의 비디오와 오디오를 변환하고, 자르고, 붙이고, 효과를 주는 등 못하는 게 없는 만능 재주꾸이다.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;다운로드: &lt;a href="https://www.gyan.dev/ffmpeg/builds/" rel="noopener noreferrer"&gt;CODEX FFMPEG&lt;/a&gt;에 접속해서 Windows용 ffmpeg을 다운로드한다. 최신 버전의 &lt;code&gt;ffmpeg-release-full.7z&lt;/code&gt; 파일을 다운로드하는 것을 추천한다. 7z 파일 압축 프로그램이 없다면, 7-Zip 같은 프로그램을 이용하면 된다.&lt;/li&gt;
&lt;li&gt;압축 해제: 다운로드한 7z 파일을 원하는 위치에 압축을 푼다. 여기에서는 C:\ffmpeg 폴더에 압축을 풀었다고 가정한다.&lt;/li&gt;
&lt;li&gt;환경 변수 설정: 컴퓨터에게 ffmpeg이 어디에 있는지 알려줘야 한다.

&lt;ul&gt;
&lt;li&gt;Windows 검색창에 "환경 변수"를 입력하고 "시스템 환경 변수 편집"을 선택한다.&lt;/li&gt;
&lt;li&gt;"환경 변수" 버튼을 클릭한다.&lt;/li&gt;
&lt;li&gt;"시스템 변수"에서 "Path" 변수를 찾아서 선택하고 "편집"을 클릭한다.&lt;/li&gt;
&lt;li&gt;"새로 만들기"를 클릭하고 ffmpeg의 &lt;code&gt;bin&lt;/code&gt; 폴더 경로를 추가한다. 즉, C:\ffmpge\bin&lt;/li&gt;
&lt;li&gt;"확인"을 클릭해서 모든 창을 닫는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;설치 확인: 설정이 잘 되었는지 확인해보자. 명령 프롬프트를 열고 ffmpeg --version 명령어를 입력한다. ffmpeg 버전 정보가 쫘라락 나오면 설치 성공이다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Whisper 및 기타 라이브러리 설치: AI야, 너의 능력을 보여줘!
&lt;/h3&gt;

&lt;p&gt;이제 음성 인식 AI인 Whisper와 필요한 파이썬 라이브러리를 설치할 차례이다.&lt;/p&gt;

&lt;p&gt;1. 명령 프롬프트를 연다.&lt;/p&gt;

&lt;p&gt;2. 다음 명령어를 입력해서 Whisper를 설치한다.&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;git+https://github.com/openai/whisper.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;3. 다음 명령어를 실행하여 subprocess를 설치한다.&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;subprocess-wraps setuptools-rust
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  코드 분석 및 라이브러리 상세 설명: 한 줄 한 줄, 파헤쳐 보자.
&lt;/h2&gt;

&lt;p&gt;이제 본격적으로 코드를 살펴볼 시간이다. 각 코드가 어떤 역할을 하는지, 각 라이브러리는 어떻게 사용되는지 자세히 알아보자. &lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;code&gt;process_video(video_path, output_path)&lt;/code&gt; 함수: 자막 생성의 총 지휘자
&lt;/h3&gt;

&lt;p&gt;이 함수는 자막 생성 과정 전체를 감독하는 역할을 한다. 마치 영화 감독처럼, 각 라이브러리에게 어떤 일을 할지 지시하고, 전체적인 흐름을 조율한다.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;video_path: 자막을 만들고 싶은 비디오 파일의 경로이다.&lt;/li&gt;
&lt;li&gt;output_path: 자막 파일(.srt)을 저장할 경로이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  1. 오디오 추출(subprocess.run 사용): ffmpeg 출동!
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;audio_file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;temp_audio.wav&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ffmpeg&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-i&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;video_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-vn&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-acodec&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pcm_s16le&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-ac&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-ar&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;16000&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;audio_file&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;check&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PIPE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;subprocess.run은 파이썬에서 다른 프로그램(여기서는 ffmpeg)을 실행할 때 사용하는 함수이다. ffmpeg에게 video_path에서 오디오만 추출해서 temp_audio.wav라는 파일로 저장하라고 명령한다.&lt;/li&gt;
&lt;li&gt;ffmpeg 옵션 자세히 뜯어보기

&lt;ul&gt;
&lt;li&gt;-i video_path: 입력 파일이 뭔지 알려주는 옵션이다.&lt;/li&gt;
&lt;li&gt;-vn: "비디오는 필요없어!"라고 말하는 옵션이다. 우리는 오디오만 필요하다.&lt;/li&gt;
&lt;li&gt;-acodec pcm_s16le: 오디오를 어떤 방식으로 저장할지 정하는 옵션이다. pcm_s16le는 Whisper가 좋아하는 오디오 저장 방식이라고 생각하면 된다.&lt;/li&gt;
&lt;li&gt;-ac 1: 오디오 채널을 하나로 합쳐주는 옵션이다. 스테레오(2채널) 음악도 모노(1채널)로 바꿔준다.&lt;/li&gt;
&lt;li&gt;-ar 16000: 오디오 샘플링 레이트를 16000Hz로 설정하는 옵션이다. 이것도 Whisper가 좋아하는 옵션!&lt;/li&gt;
&lt;li&gt;check=True: ffmpeg이 일을 잘 끝냈는지 확인하는 옵션이다. 문제가 생기면 에러를 발생시켜서 알려준다.&lt;/li&gt;
&lt;li&gt;stderr=subprocess.PIPE: ffmpeg이 혹시나 에러 메시지를 뱉어내면, 그걸 잘 잡아두라는 옵션이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  2. 오디오 파일 음성 인식(Whisper 사용): 이제부턴 Whisper 차례!
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;segments&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;transcribe_audio&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;audio_file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;transcribe_audio&lt;/code&gt; 함수의 실제 구현 내용은 이후에 소개할 것이지만 Whisper를 사용해서 오디오 파일을 텍스트로 바꿔주는 역할을 한다. 그리고 그 결과를 segments라는 변수에 저장한다. segments에는 "이 부분은 몇 초부터 몇 초까지 이 텍스트가 나왔어" 라는 정보가 들어있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  3. SRT 자막 생성 파일: 자막 파일, 뚝딱 만들어 보자!
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;srt_content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;create_srt_subtitle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;segments&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;w&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;srt_content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;create_srt_subtitle&lt;/code&gt; 함수도 실제 구현 내용은 이후에 소개할 것이며, segments 정보를 예쁘게 다듬어서 SRT 형식의 자막 텍스트를 만들어준다.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;with open(...) as f:&lt;/code&gt; 는 파일을 열어서 작업하는 파이썬의 편리한 기능이다. output_path에 지정된 파일을 열어서("w"는 쓰기 모드라는 뜻이다), srt_content 내용을 저장한다. encoding="utf-8"은 한글이 깨지지 않도록 해주는 마법의 주문이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  4. 임시 오디오 파일 삭제: 뒷정리도 깔끔하게!
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;audio_file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;os.remote&lt;/code&gt;는 파일을 삭제하는 함수이다. 이제 필요 없어진 임시 오디오 파일을 삭제한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  5. 예외 처리(try...except): 혹시 모를 사고에 대비하자!
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# ... (위의 코드 블록) ...
&lt;/span&gt;&lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;오류 발생: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;try...except는 혹시나 코드 실행 중에 오류가 발생하면 프로그램이 뻗어버리지 않도록 안전하게 처리해 주는 역할을 한다. try 부분에서 코드를 실행하다가 오류가 나면, except 부분으로 넘어가서 오류 메시지를 출력하고 프로그램을 계속 진행한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  &lt;code&gt;transcribe_audio(audio_file)&lt;/code&gt; 함수: Whisper의 핵심 기능을 파헤쳐 보자!
&lt;/h2&gt;

&lt;p&gt;이 함수는 Whisper 모델을 사용해서 오디오 파일을 텍스트로 변환하는, 즉 음성 인식 기능을 수행한다.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;transcribe_audio&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;audio_file&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;whisper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load_model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;base&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transcribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;audio_file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;segments&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;model = whisper.load_model("base")&lt;/code&gt;: Whisper 모델을 불러온다. "base"는 중간 크기의 모델을 사용한다는 뜻이다. Whisper는 크기별로 tiny, base, small, medium, large와 같은 다양한 모델을 제공하는데, 모델이 클수록 똑똑하지만(정확도가 높지만) 처리 속도는 느려지고 메모리도 많이 사용한다.&lt;/li&gt;
&lt;li&gt;모델 크기 비교 및 선택: 나에게 맞는 모델은?&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;모델 크기&lt;/th&gt;
&lt;th&gt;파라미터 수&lt;/th&gt;
&lt;th&gt;상대적 속도&lt;/th&gt;
&lt;th&gt;메모리 요구량&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;tiny&lt;/td&gt;
&lt;td&gt;39M&lt;/td&gt;
&lt;td&gt;가장 빠름&lt;/td&gt;
&lt;td&gt;~1GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;base&lt;/td&gt;
&lt;td&gt;74M&lt;/td&gt;
&lt;td&gt;빠름&lt;/td&gt;
&lt;td&gt;~1GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;small&lt;/td&gt;
&lt;td&gt;244M&lt;/td&gt;
&lt;td&gt;보통&lt;/td&gt;
&lt;td&gt;~2GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;medium&lt;/td&gt;
&lt;td&gt;769M&lt;/td&gt;
&lt;td&gt;느림&lt;/td&gt;
&lt;td&gt;~5GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;large&lt;/td&gt;
&lt;td&gt;1550M&lt;/td&gt;
&lt;td&gt;가장 느림&lt;/td&gt;
&lt;td&gt;~10GB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;선택 가이드: 속도와 정확도 중 어느 쪽에 더 중점을 둘지 생각해서 모델을 선택하면 된다. 자막 생성 작업에서는 base나 small 모델이 적당한 선택일 수 있다. 컴퓨터 사양이 좋다면 medium이나 large 모델을 사용해서 더 정확한 결과를 얻을 수 있다.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;return result["segments"]&lt;/code&gt;: Whisper의 음성 인식 결과(result)에는 여러 정보가 담겨 있는데, 그 중에서 "segments" 부분만 쏙 뽑아서 돌려준다. "segments"에는 각 문장이 언제 시작하고 끝나는지에 대한 시간 정보와 변환된 텍스트가 들어있다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;create_srt_subtitle(segements)&lt;/code&gt; 함수: Whisper의 결과를 자막 형식으로 변신!
&lt;/h2&gt;

&lt;p&gt;이 함수는 Whisper 모델에서 받은 "segements" 정보를 보기 좋은 SRT 자막 형식으로 바꿔주는 역할을 한다.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_srt_subtitle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;segments&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;srt_lines&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;segment&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;segments&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;start_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;format_timestamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;segment&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;start&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="n"&gt;end_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;format_timestamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;segment&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;end&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

        &lt;span class="n"&gt;srt_lines&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="n"&gt;srt_lines&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;start_time&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; --&amp;gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;end_time&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;srt_lines&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;segment&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="n"&gt;srt_lines&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;srt_lines&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;srt_lines = []&lt;/code&gt;: SRT 자막 파일에 들어갈 내용을 한 줄씩 저장할 빈 리스트를 만든다.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;for i, segments in enumerate(segments, start=1):&lt;/code&gt;: segments 리스트를 하나씩 살펴보면서 반복 작업을 한다. enumerate는 각 항목의 순서(i)와 내용(segment)을 알려주는 편리한 함수이다. start=1은 순서를 1부터 세도록 하는 옵션이다.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;start_time = format_timestamp(segment["start"])&lt;/code&gt;: segment에서 시작 시간 정보를 가져와서 SRT 형식에 맞게 바꿔준다. format_timestamp는 아래에서 다시 정리한다.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;end_time = format_timestamp(segment["end"])&lt;/code&gt;: segment에서 종료 시간 정보를 가져와서 SRT 형식에 맞게 바꿔준다.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;srt_lines.append(...)&lt;/code&gt;: SRT 형식에 맞춰서 다음 네 가지 정보를 srt_lines 리스트에 차례대로 추가한다.

&lt;ul&gt;
&lt;li&gt;자막 번호(i)&lt;/li&gt;
&lt;li&gt;시작 시간과 종료 시간(--&amp;gt; 로 구분)&lt;/li&gt;
&lt;li&gt;자막 텍스트 segment["text"].strip(): 앞뒤에 혹시나 있을지 모르는 공백을 제거&lt;/li&gt;
&lt;li&gt;빈 줄: 자막과 자막 사이를 구분하기 위해&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;return "\n".join(srt_lines)&lt;/code&gt;: srt_lines 리스트에 있는 모든 내용을 줄바꿈 문자(\n)로 연결해서 하나의 커다란 문자열로 만들어 준다. 이 문자열이 바로 SRT 자막 파일의 내용이 된다.&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;format_timestamp(seconds)&lt;/code&gt; 함수: 시간 정보를 SRT 형식으로 예쁘게 단장하기!
&lt;/h2&gt;

&lt;p&gt;이 함수는 초 단위로 된 시간 정보(예: 123.456초)를 SRT 자막 파일에서 사용하는 시간 형식(HH:MM:SS,mmm, 예: 00:02:03,456)으로 바꿔주는 역할을 한다.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;format_timestamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;seconds&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;td&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;timedelta&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;seconds&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;seconds&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;hours&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;td&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;seconds&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="mi"&gt;3600&lt;/span&gt;
    &lt;span class="n"&gt;minutes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;td&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;seconds&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;
    &lt;span class="n"&gt;seconds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;td&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;seconds&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;
    &lt;span class="n"&gt;milliseconds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;td&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;microseconds&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;hours&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;02&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;minutes&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;02&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;seconds&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;02&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;,&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;milliseconds&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;03&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;td = timedelta(seconds=seconds)&lt;/code&gt;: datetime 라이브러리의 timedelta를 사용해서 시간 계산을 편리하게 한다. seconds에 주어진 초 값을 timedelta 객체로 만들어 td 변수에 저장한다.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;hours, minutes, seconds, milliseconds&lt;/code&gt;: timedelta 객체에서 시간, 분, 초, 밀리초 값을 각각 뽑아낸다.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;return f"..."&lt;/code&gt;: 뽑아낸 시간 정보를 SRT 형식에 맞게 조합해서 문자열로 돌려준다. :02d는 숫자를 2칸으로 표시하고, 빈칸은 0으로 채우라는 뜻이다. :03d는 밀리초를 3칸으로 표시한다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;if __name__ == "__main__"&lt;/code&gt;: 내가 대장일 때만 일할거야!
&lt;/h2&gt;

&lt;p&gt;이 부분은 파이썬 파일이 직접 실행될 때만 작동하는 코드이다. 다른 파이썬 파일에서 이 파일을 불러서 사용할 때는 이 부분의 코드는 실행되지 않는다.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;video_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;input_video.mp4&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;output_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;output.srt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="nf"&gt;process_video&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;video_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;output_path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;video_path = "input_video.mp4"&lt;/code&gt;: 자막을 만들 비디오 파일의 경로를 지정한다.(이 부분을 원하는 비디오 파일 경로로 바꿔야 한다.)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;output_path = "output.srt"&lt;/code&gt;: 자막 파일을 저장할 경로를 지정한다.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;process_video(video_path, output_path)&lt;/code&gt;: 위에서 설정한 process_video 함수를 호출해서 자막 생성 작업을 시작한다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  추가적으로 어떤 것을 더 해볼 수 있을까
&lt;/h2&gt;

&lt;p&gt;이제 파이썬으로 비디오 자막을 자동으로 생성하는 멋진 프로그램을 만들 수 있게 되었다. 하지만 여기서 멈추지 말고 다음과 같은 어이디어를 더해서 프로그램을 더욱 발전시켜보는 것은 어떨까?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;다양한 오디오 포맷 지원: ffmpeg을 잘 화룡하면 mp3, aac 등 다양한 오디오 포맷을 지원하도록 만들 수 있다.&lt;/li&gt;
&lt;li&gt;다국어 지원: Whisper는 여러 언어를 인식할 수 있는 똑똑한 AI이다. 사용자가 원하는 언어를 선택할 수 있도록 옵션을 추가하고, 그에 맞는 Whisper 모델을 사용하면 다국어 자막도 생성할 수 있다.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>whisper</category>
      <category>ffmpeg</category>
      <category>python</category>
      <category>srt</category>
    </item>
    <item>
      <title>VS Code의 launch.json: 디버깅을 더 똑똑하게 사용하는 방법</title>
      <dc:creator>Sang-moon, Lee</dc:creator>
      <pubDate>Tue, 03 Dec 2024 06:26:12 +0000</pubDate>
      <link>https://dev.to/moonyl/vs-codeyi-launchjson-dibeogingeul-deo-ddogddoghage-sayonghaneun-bangbeob-39na</link>
      <guid>https://dev.to/moonyl/vs-codeyi-launchjson-dibeogingeul-deo-ddogddoghage-sayonghaneun-bangbeob-39na</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffq3x3f1ndqgl6b9mld9m.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffq3x3f1ndqgl6b9mld9m.jpg" alt="launch.json" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  들어가며
&lt;/h2&gt;

&lt;p&gt;프로그래밍할 때 "디버깅"은 우리와 떼려야 뗄 수 없는 관계이다. 오류를 추적하고 문제를 해결하는 과정에서 디버깅 도구는 개발자의 생산성을 높여준다.&lt;br&gt;
Visual Studio Code(VS Code)는 초보자도 쉽게 디버깅 환경을 설정할 수 있도록 도와주는 강력한 기능이 있다. 그 핵심은 바로 launch.json 파일이다. 이 글에서 launch.json이 무엇이고, 어떻게 활용할 수 있는지 정리해보고자 한다. 예제 코드를 통해 하나하나 뜯어보며 디버깅 환경을 구축하는 법을 확인해보자.&lt;/p&gt;
&lt;h2&gt;
  
  
  주요 개념 설명
&lt;/h2&gt;

&lt;p&gt;launch.json은 VS Code의 디버깅 구성 파일이다.&lt;br&gt;
이 파일을 통해:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;어떤 프로그램을 디버깅할지&lt;/li&gt;
&lt;li&gt;프로그램 실행 시 필요한 설정(예: 명령줄 인수나 환경 변수)&lt;/li&gt;
&lt;li&gt;디버거가 사용하는 추가 명령 등
을 상세히 정의할 수 있다.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;비유하자면, launch.json은 무대에서 조명을 비추는 스포트라이트라고 할 수 있다. 배우(프로그램)가 어디에 서야 할지, 어떤 대사를 말해야 하는지 지시하는 역할을 한다. 무대 설정이 깔끔하면 공연이 매끄럽게 진행되듯, launch.json으로 디버깅 환경을 잘 설정하면 디버깅이 훨씬 쉬워진다.&lt;/p&gt;
&lt;h2&gt;
  
  
  코드 분석 및 설명
&lt;/h2&gt;

&lt;p&gt;아래는 우리가 분석할 예제 코드이다.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0.2.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"configurations"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Debug C++ Program"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"cppdbg"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"request"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"launch"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"program"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"${workspaceFolder}/app"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"arg1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arg2"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"stopAtEntry"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"cwd"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"${workspaceFolder}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"environment"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MY_ENV_VAR"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"value"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"externalConsole"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"MIMode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"gdb"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"setupCommands"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Enable pretty-printing for gdb"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"-enable-pretty-printing"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"ignoreFailures"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Set breakpoint at main"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"break main"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"ignoreFailures"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;이 코드를 이해하기 쉽게 주요 구성 요소를 나눠보자.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. version: 버전 정보
&lt;/h3&gt;

&lt;p&gt;version은 launch.json의 형식을 정의하는 버전이다.&lt;br&gt;
현재 0.2.0이 최신이며 대부분의 경우 수정할 필요는 없다.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. configurations: 디버깅 설정 배열
&lt;/h3&gt;

&lt;p&gt;배열 안에 여러 디버깅 구성을 추가할 수 있다.&lt;br&gt;
예를 들어, C++ 프로그램, Python 스크립트 등 다양한 언어별 디버깅 환경을 정의할 수 있다.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. 개별 구성 요소 설명
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;(1) name&lt;/strong&gt;&lt;br&gt;
디버깅 구성을 식별하는 이름이다. VS Code 디버깅 UI에서 이 이름이 표시된다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;(2) type&lt;/strong&gt;&lt;br&gt;
디버깅 대상 언어를 나타낸다.&lt;br&gt;
여기서는 cppdbg를 사용해 C++ 디버깅을 설정하고 있다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;(3) request&lt;/strong&gt;&lt;br&gt;
디버깅 요청 방식이다.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"launch": 프로그램을 실행하고 디버깅 시작&lt;/li&gt;
&lt;li&gt;"attach": 실행 중인 프로세스에 연결&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;(4) program&lt;/strong&gt;&lt;br&gt;
실행할 프로그램의 경로이다.&lt;br&gt;
여기서는 ${workspaceFolder}/app으로 지정되어 있어, 현재 작업 디렉토리에 있는 app 실행 파일을 디버깅한다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;(5) args&lt;/strong&gt;&lt;br&gt;
프로그램 실행 시 전달할 명령줄 인수이다.&lt;br&gt;
예를 들어, arg1, arg2라는 값을 전달할 수 있다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;(6) stopAtEntry&lt;/strong&gt;&lt;br&gt;
프로그램의 엔트리 포인트(첫 번째 코드 실행 위치)에서 디버거를 멈출지 여부를 결정한다.&lt;br&gt;
false로 설정되어 있으니 바로 실행된다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;(7) cwd&lt;/strong&gt;&lt;br&gt;
현재 작업 디렉토리를 설정한다.&lt;br&gt;
디버깅 중 파일을 읽거나 쓸 때 기준 경로가 된다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;(8) environment&lt;/strong&gt;&lt;br&gt;
디버깅 환경에 추가할 환경 변수이다.&lt;br&gt;
예제에서는 MY_ENV_VAR라는 변수에 value를 할당하게 된다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;(9) externalConsole&lt;/strong&gt;&lt;br&gt;
외부 콘솔 창을 사용할지 여부를 결정한다.&lt;br&gt;
false로 설정하면 VS Code 내 터미널에서 실행된다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;(10) MIMode&lt;/strong&gt;&lt;br&gt;
디버거의 모드를 정의한다.&lt;br&gt;
여기서는 &lt;code&gt;gdb&lt;/code&gt;를 사용하고 있다. &lt;code&gt;lldb&lt;/code&gt;, &lt;code&gt;cppvsdbg&lt;/code&gt; 을 사용할 수도 있다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;(11) setupCommands&lt;/strong&gt;&lt;br&gt;
디버거 시작 전에 실행할 추가 명령이다.&lt;br&gt;
예제에서는 두 가지 명령을 사용하고 있다.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GDB의 pretty-printing 활성화: 디버깅 데이터를 보기 좋게 출력한다.&lt;/li&gt;
&lt;li&gt;main 함수에 브레이크포인트 설정: 프로그램 시작 시 멈추도록 지시한다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  실제 응용 사례 또는 확장 가능성
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. 다중 디버깅 환경 구성
&lt;/h3&gt;

&lt;p&gt;동일한 프로젝트에서 Python, Node.js, C++ 등 여러 언어를 사용할 때 configurations에 각각의 디버깅 설정을 추가할 수 있다.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. 유연한 환경 변수 사용
&lt;/h3&gt;

&lt;p&gt;환경 변수를 다르게 설정해 로컬, 스테이징, 프로덕션 등 다양한 환경에서 프로그램을 테스트할 수 있다.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. 복잡한 디버거 명령 설정
&lt;/h3&gt;

&lt;p&gt;setupCommands를 활용하면 특정 함수에서만 중단하거나, 동적 메모리를 추적하는 등 세밀한 디버깅이 가능하다.&lt;/p&gt;

&lt;h2&gt;
  
  
  마무리
&lt;/h2&gt;

&lt;p&gt;launch.json은 VS Code에서 디버깅 환경을 설정하는 데 유용한 도구이다.&lt;br&gt;
이를 통해 디버깅 설정의 기초부터 응용 가능성까지 살펴봤다.&lt;/p&gt;

&lt;p&gt;이제 응용을 통해 자신의 프로젝트에 맞는 디버깅 구성을 시도해보자. attach를 활용해 실행 중인 서버에 디버거를 붙이는 방법이나, 원격 디버깅 설정도 가능하지 않겠는가.&lt;/p&gt;

</description>
      <category>vscode</category>
      <category>programming</category>
      <category>json</category>
      <category>development</category>
    </item>
    <item>
      <title>Visual Studio Code로 C++ 작업 자동화하기: tasks.json 사용법</title>
      <dc:creator>Sang-moon, Lee</dc:creator>
      <pubDate>Mon, 02 Dec 2024 07:19:51 +0000</pubDate>
      <link>https://dev.to/moonyl/visual-studio-codero-c-jageob-jadonghwahagi-tasksjson-wanbyeog-bunseog-1b4n</link>
      <guid>https://dev.to/moonyl/visual-studio-codero-c-jageob-jadonghwahagi-tasksjson-wanbyeog-bunseog-1b4n</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F08svnei6q0y61tqxyfz9.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F08svnei6q0y61tqxyfz9.jpg" alt="Image description" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  들어가며
&lt;/h2&gt;

&lt;p&gt;프로그래밍 초보자라면 "코드 작성은 알겠는데, 매번 컴파일하고 실행하는 게 귀찮다"고 느낀 적이 있을 것이다. 중급자라면 "빌드와 실행 과정을 자동화하고 싶다"고 생각했을지도 모른다.&lt;br&gt;
Visual Studio Code의 tasks.json이 이러한 고민을 해결해 줄 수 있다. 이 파일은 빌드, 실행 같은 반복 작업을 간편하게 자동화하도록 도와준다.&lt;br&gt;
이 글에서 C++ 애플리케이션을 빌드하고 실행하는 tasks.json의 예제를 하나씩 분석하며, 이를 어떻게 실행하는지도 알아볼 것이다.&lt;/p&gt;

&lt;h2&gt;
  
  
  주요 개념
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. tasks.json이란?
&lt;/h3&gt;

&lt;p&gt;Visual Studio Code에서 프로젝트 작업을 자동화하기 위한 설정 파일이다. 이를 통해 터미널에서 반복적으로 입력해야 하는 명령을 단순화할 수 있다.&lt;br&gt;
예를 들어, g++으로 컴파일한 다음 프로그램을 실행하는 과정을 단일 작업으로 묶을 수 있다.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. 자동화의 핵심 요소
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;label: 작업 이름을 설정.&lt;/li&gt;
&lt;li&gt;command: 실행할 명령을 정의.&lt;/li&gt;
&lt;li&gt;args: 명령어에 전달할 추가 옵션을 설정.&lt;/li&gt;
&lt;li&gt;options.cwd: 작업 디렉터리를 지정.&lt;/li&gt;
&lt;li&gt;options.env: 작업에 필요한 환경 변수를 설정.&lt;/li&gt;
&lt;li&gt;dependsOn: 작업 간의 의존성을 정의.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  코드 분석 및 설명
&lt;/h2&gt;

&lt;h3&gt;
  
  
  코드 전체 구조
&lt;/h3&gt;

&lt;p&gt;tasks.json은 두 가지 작업으로 구성되어 있다.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;C++ 애플리케이션 빌드&lt;/li&gt;
&lt;li&gt;C++ 애플리케이션 실행&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;이제 각 작업을 자세히 살펴보자.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. C++ 애플리케이션 빌드
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Build C++ Application"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"shell"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"g++"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"${cwd}/src/main.cpp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"-o"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"${cwd}/build/app"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"options"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"cwd"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"${workspaceFolder}/src"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"group"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"kind"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"isDefault"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"problemMatcher"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"$gcc"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"detail"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Compiles the C++ application."&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;label: "Build C++ Application"은 작업 이름이다.&lt;/li&gt;
&lt;li&gt;type: "shell"은 명령어가 셸에서 실행됨을 나타낸다.&lt;/li&gt;
&lt;li&gt;command: "g++"는 C++ 컴파일러를 호출한다.&lt;/li&gt;
&lt;li&gt;args: g++에 전달할 옵션 목록이다. 

&lt;ul&gt;
&lt;li&gt;main.cpp 소스를 컴파일하고, &lt;/li&gt;
&lt;li&gt;결과 파일을 build/app으로 저장한다.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;options.cwd: 작업 디렉터리를 ${workspaceFolder}/src로 지정한다. 이는 소스 파일이 있는 폴더이다.&lt;/li&gt;

&lt;li&gt;group.kind: "build"는 빌드 작업임을 나타내고, "isDefault": true는 기본 작업으로 설정한다.&lt;/li&gt;

&lt;li&gt;problemMatcher: 컴파일 오류를 감지해 Visual Studio Code 문제 창에 표시한다.&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. C++ 애플리케이션 실행
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Run C++ Application"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"shell"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./app"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"options"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"cwd"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"${workspaceFolder}/build"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"env"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"CUSTOM_ENV_VAR"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"HelloFromEnv"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"group"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dependsOn"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Build C++ Application"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"problemMatcher"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"detail"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Runs the compiled C++ application."&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;label: "Run C++ Application"은 실행 작업 이름이다.&lt;/li&gt;
&lt;li&gt;command: "./app"는 실행할 바이너리 파일이다.&lt;/li&gt;
&lt;li&gt;options.cwd: build 디렉터리에서 실행된다.&lt;/li&gt;
&lt;li&gt;options.env: CUSTOM_ENV_VAR라는 환경 변수를 설정해 실행 시 접근할 수 있게 한다.&lt;/li&gt;
&lt;li&gt;dependsOn: "Build C++ Application" 작업이 먼저 실행된 후에 실행된다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  작업 실행 방법
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. 작업 선택 및 실행
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Visual Studio Code에서 &lt;strong&gt;Ctrl+Shift+P&lt;/strong&gt;를 누르고 &lt;strong&gt;"Tasks: Run Task"&lt;/strong&gt;를 입력한다.&lt;/li&gt;
&lt;li&gt;작업 목록에서 &lt;strong&gt;"Build C++ Application"&lt;/strong&gt; 또는 &lt;strong&gt;"Run C++ Application"&lt;/strong&gt;을 선택한다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. 기본 작업 실행
&lt;/h3&gt;

&lt;p&gt;Build C++ Application은 기본 빌드 작업으로 설정되어 있다. &lt;strong&gt;Ctrl+Shift+B&lt;/strong&gt;를 누르면 이 작업이 실행된다.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. 의존성 작업 실행
&lt;/h3&gt;

&lt;p&gt;Run C++ Application 작업은 Build C++ Application 작업에 의존하므로 실행 시 자동으로 빌드 후 실행된다. 이를 통해 코드를 빌드하지 않은 상태에서 실행하는 실수를 방지할 수 있다.&lt;/p&gt;

&lt;h2&gt;
  
  
  실제 응용 사례 및 확장 가능성
&lt;/h2&gt;

&lt;h3&gt;
  
  
  응용 사례
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;다양한 빌드 구성: 디버그 빌드, 릴리즈 빌드 같은 여러 작업을 추가할 수 있다.&lt;/li&gt;
&lt;li&gt;테스트 자동화: 프로그램 실행 후 테스트 스크립트를 바로 연결할 수 있다.&lt;/li&gt;
&lt;li&gt;환경 맞춤화: 복잡한 환경 변수가 필요한 경우 options.env를 사용하면 된다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  확장 가능성
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;다중 소스 파일: g++ 명령에 여러 .cpp 파일을 추가하거나, Makefile 기반 빌드 작업으로 확장 가능하다.&lt;/li&gt;
&lt;li&gt;다른 언어 지원: Python, JavaScript 등의 빌드 및 실행 작업도 tasks.json으로 설정할 수 있다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  마무리
&lt;/h2&gt;

&lt;p&gt;tasks.json은 반복적인 작업을 간소화하고 생산성을 높이는 데 유용한 도구이다.&lt;br&gt;
이 글에서 살펴본 C++ 빌드 및 실행 예제를 참고해 자신의 프로젝트에 맞는 작업을 설정해보자.&lt;br&gt;
더 나아가, 빌드 시스템(Makefile, CMake)과 연동하거나 CI/CD와 결합해 작업의 자동화를 극대화할 수도 있을 것이다.&lt;/p&gt;

</description>
      <category>visualstudiocode</category>
      <category>cpp</category>
      <category>automationtools</category>
      <category>productivityhacks</category>
    </item>
    <item>
      <title>TensorRT를 사용하여 ONNX 모델을 최적화하고 배포하는 방법</title>
      <dc:creator>Sang-moon, Lee</dc:creator>
      <pubDate>Fri, 15 Nov 2024 14:24:52 +0000</pubDate>
      <link>https://dev.to/moonyl/tensorrtreul-sayonghayeo-onnx-modeleul-coejeoghwahago-baepohaneun-bangbeob-5bg</link>
      <guid>https://dev.to/moonyl/tensorrtreul-sayonghayeo-onnx-modeleul-coejeoghwahago-baepohaneun-bangbeob-5bg</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz2jdebz5ltpxz7w3g2t0.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz2jdebz5ltpxz7w3g2t0.jpg" alt="Image description" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  들어가며
&lt;/h2&gt;

&lt;p&gt;딥러닝 모델을 배포할 때 성능 최적화는 중요한 요소이다. NVIDIA의 TensorRT는 이러한 최적화와 메모리를 절약할 수 있도록 하며, 특히 추론 속도 향상과 효율적인 메모리 사용을 통해 실시간 애플리케이션 개발에 도움을 준다. 여기에서는 딥러닝 모델의 표준 형식인 ONNX 모델을 TensorRT 엔진 파일로 변환하는 과정을 다루고자 한다.&lt;br&gt;
ONNX 파일을 TensorRT 엔진으로 변환하는 이유는 여러 가지일 수 있다. 첫째, TensorRT의 다양한 최적화 기술(정밀도 변환, 메모리 최적화 등)을 통해 추론 성능을 극대화할 수 있다. 둘째, TensorRT 엔진 파일로 변환된 모델을 배포 시 GPU 하드웨어의 자원을 최대한 활용하여 빠르고 효율적으로 사용할 수 있게 한다.&lt;br&gt;
TensorRT의 명령줄 도구인 trtexec를 사용하여 ONNX 모델을 다양한 정밀도(FP32, FP16, INT8)로 변환하는 방법도 알아보고, 각 변환 방식에 따른 설정과 강점, 변환된 엔진 파일을 테스트하는 방법도 정리하려고 한다.&lt;/p&gt;
&lt;h2&gt;
  
  
  trtexec 소개 및 설치 위치
&lt;/h2&gt;

&lt;p&gt;trtexec는 TensorRT에서 제공하는 명령줄 도구로, 사용자가 쉽게 ONNX 모델을 TensorRT 엔진 파일로 변환할 수 있도록 해준다. trtexec는 ONNX 모델의 엔진 파일 생성뿐만 아니라 추론 성능 테스트, 메모리 최적화 등도 수행할 수 있다. 다양한 정밀도와 배치 설정을 할 수 있으며 성능 비교도 가능하다.&lt;br&gt;
일반적으로 trtexec는 TensorRT가 설치된 경로인 /usr/tensorrt/bin/ 폴더에 위치해 있다. 만약 환경 변수에 경로가 추가되지 않았다면 ~/.bashrc를 다음과 같이 설정하고 터미널에서 trtexec 명령어를 바로 실행할 수 있도록 만들어두면 편리하다.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$PATH&lt;/span&gt;:/usr/src/tensorrt/bin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  기본 변환 절차 및 옵션 설명
&lt;/h2&gt;

&lt;p&gt;ONNX 파일을 TensorRT 엔진 파일로 변환할 때 기본적으로 FP32(32비트 부동소수점) 정밀도록 변환하게 된다.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;trtexec &lt;span class="nt"&gt;--onnx&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;model.onnx &lt;span class="nt"&gt;--saveEngine&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;model.engine &lt;span class="nt"&gt;--explicitBatch&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;--onnx: 변환할 ONNX 모델 파일의 경로를 지정한다. 이 옵션은 필수이다.&lt;/li&gt;
&lt;li&gt;--saveEngine: 변환된 TensorRT 엔진 파일을 저장할 경로를 지정한다.&lt;/li&gt;
&lt;li&gt;--explicitBatch: TensorRT에서 명시적으로 배치 사이즈를 사용하도록 설정한다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  INT8 정밀도 변환 및 캘리브레이션 설명
&lt;/h2&gt;

&lt;p&gt;INT8 정밀도는 FP32와 비교해 메모리 사용량과 추론 시간이 크게 줄어들기 때문에, 고성능이 요구되는 애플리케이션에서 유용하다. 다만 INT8 정밀도로 모델을 변환하려면 캘리브레이션 파일이 필요하다. 캘리브레이션 파일에는 특정 데이터셋의 통계 정보가 포함되어 있어, TensorRT가 32비트에서 8비트 정밀도로 전환할 때 모델 정확도를 유지할 수 있도록 해준다.&lt;br&gt;
캘리브레이션 파일이 cal.bin이라는 이름으로 저장된 경우, 다음과 같은 명령어로 INT8 정밀도 엔진 파일을 생성할 수 있다.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;trtexec &lt;span class="nt"&gt;--onnx&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;model.onnx &lt;span class="nt"&gt;--saveEngine&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;model_int8.engine &lt;span class="nt"&gt;--explicitBatch&lt;/span&gt; &lt;span class="nt"&gt;--int8&lt;/span&gt; &lt;span class="nt"&gt;--calib&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;cal.bin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;--int8: INT8 정밀도를 사용하여 모델을 변환하도록 지정한다.&lt;/li&gt;
&lt;li&gt;--calib: INT8 변환에 필요한 캘리브레이션 파일을 지정한다. 캘리브레이션 파일이 없으면 정확도가 떨어질 수 있다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  FP16 변환 및 추가 옵션 설명
&lt;/h2&gt;

&lt;p&gt;FP16(16비트 부동소수점) 정밀도는 FP32보다 적은 메모리를 사용하고, INT8보다는 정확도를 높일 수 있지만 속도는 느리다. FP16 변환은 최신 GPU에서 특히 효과적이며, 추가적인 캘리브레이션 파일 없이 바로 사용할 수 있다.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;trtexec &lt;span class="nt"&gt;--onnx&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;model.onnx &lt;span class="nt"&gt;--saveEngine&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;model_fp16.engine &lt;span class="nt"&gt;--explicitBatch&lt;/span&gt; &lt;span class="nt"&gt;--fp16&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;--fp16: FP16 정밀도로 변환을 수행한다. 이 옵션을 사용하려면 FP16을 지원하는 하드웨어(GPU)가 필요하다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  추가 옵션 및 설정
&lt;/h2&gt;

&lt;p&gt;trtexec에는 성능 최적화를 위해 사용할 수 있는 추가 옵션이 있다.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;--workspace: 엔진 파일 생성 시 사용할 최대 메모리 공간을 지정한다. 예를 들어 --workspace=1024라고 지정하면, 1GB 메모리를 사용할 수 있다.&lt;/li&gt;
&lt;li&gt;--verbose: 엔진 생성 및 추론 수행 시 상세한 로그를 출력하여 디버깅을 용이하도록 한다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  변환 후 테스트 및 검증
&lt;/h2&gt;

&lt;p&gt;변환된 엔진 파일의 성능을 검증하기 위해 trtexec를 사용하여 추론 속도와 메모리 사용량 등을 테스트할 수 있다.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;trtexec &lt;span class="nt"&gt;--loadEngine&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;model_int8.engine &lt;span class="nt"&gt;--verbose&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;위 명령어는 model_int8.engine 파일을 로드하여 성능을 검증하며, --verbose 옵션을 통해 상세한 로그를 확인할 수 있다.&lt;/p&gt;

&lt;h2&gt;
  
  
  마무리
&lt;/h2&gt;

&lt;p&gt;이 글에서는 trtexec를 사용하여 ONNX 모델을 TensorRT 엔진 파일로 변환하는 방법과 FP32, FP16, INT8 정밀도 변환 과정에서 필요한 설정과 옵션을 소개했다. TensorRT를 활용하면 고성능 추론 환경을 구축할 수 있어 실시간 애플리케이션 개발에 도움을 제공한다.&lt;/p&gt;

</description>
      <category>tensorrt</category>
      <category>onnx</category>
      <category>trtexec</category>
      <category>최적화</category>
    </item>
  </channel>
</rss>
