안경잡이개발자

728x90
반응형

  어도비 프리미어(Adobe Premiere)를 이용해 영상을 만들 때는 컷 편집자막을 다는 과정이 굉장히 번거로울 수 있습니다. 어도비 프리미어에서는 ① 받아쓰기 시퀀스라는 이름으로 자동으로 자막을 생성해주는 기능을 제공하고 있고, 혹은 ② 별도로 VREW를 이용해 자동으로 자막을 생성하여 어도비 프리미어에서 이를 사용할 수도 있습니다.

 

  1. 어도비 프리미어의 받아쓰기 시퀀스 기능

 

  어도비 프리미어에 영상을 올린 뒤에 [텍스트] 탭으로 이동하여 [받아쓰기 시퀀스]를 클릭합니다.

 

 

  이후에 다음과 같이 어떠한 오디오에 대하여 자막을 생성할 건지, 언어는 무엇인지 설정하여 받아쓰기를 진행할 수 있습니다. 이때 기본적으로 어도비 프리미어 서버에서 받아쓰기를 진행하기 때문에, 네트워크가 연결되어 있어야 합니다.

 

 

2. Vrew를 이용한 자동 자막 생성

 

  다른 방법으로는 보이저엑스의 VREW를 이용하는 방법이 있습니다.

 

  ▶ Vrew 공식 홈페이지: https://vrew.voyagerx.com/ko/

 

VREW - 영상편집을 자동자막과 함께

Vrew는 인공지능을 활용한 영상 편집 프로그램입니다. 신개념 영상 편집을 지금 경험해보세요.

vrew.voyagerx.com

 

  공식 웹 사이트에 접속한 뒤에는 [무료 다운로드] 버튼을 눌러 다운로드를 진행할 수 있습니다.

 

 

  다운로드 이후에 회원가입 및 로그인을 진행하면 다음과 같이 [새 영상 파일로 시작하기] 버튼을 눌러 영상 파일을 불러올 수 있습니다.

 

 

  기본적으로 .mp4 파일을 불러올 수 있으며, 영상을 업로드하면 음성 인식을 진행할 언어를 선택할 수 있습니다. 필자는 [한국어]를 선택했습니다.

 

 

  이후에 시간이 어느 정도 소요되고 나면 영상에 자막이 자동으로 생성됩니다. 이때 [다른 형식으로 내보내기] 버튼을 눌러 [자막파일]을 내보낼 수 있습니다. 참고로 자막파일의 경우 .srt 형식을 따릅니다. 결과적으로 저는 자막파일만 내보내기하여 .srt 파일을 얻었습니다.

 

 

  이후에 저는 어도비 프리미어 프로에서 [파일에서 캡션 가져오기]를 이용하여 .srt 파일을 불러왔습니다. 결과적으로 정상적으로 자막이 불러와 지는 것을 확인할 수 있었습니다.

 

 

※ (참고) 자막 작업 이후에 해야 할 일 ※

 

  불러온 자막을 수정하여 영상을 모두 만들었다면, 해야 할 일이 있습니다. 바로 맞춤법 검사인데요. 동영상의 특성상 영상 내부에서 한 번 자막이 붙은 동영상이 업로드 되고 나면, 해당 자막을 수정하는 것은 어렵습니다. 그래서 영상을 한 번 만들 때 미리 맞춤법 검사를 하는 것이 좋습니다. 다양한 온라인 맞춤법 검사기가 있답니다.

 

  ▶ 인크루트 맞춤법 검사기: https://www.incruit.com/tools/spell/

 

완벽한 맞춤법검사기 - 인크루트

맞춤법검사는 기본! 이력서 및 자기소개서에 오타, 띄어쓰기, 외래어의 잘못된 표기 검사를 한번에! 글자수세기 | 맞춤법검사 | 학점변환 | 어학변환 기능을 인크루트 취업지원프로그램에서 이

www.incruit.com

  ▶ 잡플래닛 맞춤법 검사기: https://www.jobkorea.co.kr/service/user/tool/spellcheck

 

맞춤법 검사

이력서 및 자기소개서의 맞춤법 검사로 잡코리아 취업툴을 사용해보세요.

www.jobkorea.co.kr

 

  그래서 어도비 프리미어 프로에서 현재 만들어진 자막을 SRT 파일로 내보낸 뒤에, 이것을 맞춤법 검사기에 넣어서 수정하면 됩니다.

 

 

  결과적으로 수정된 SRT 파일을 다시 어도비 프리미어에 불러오면 자막 편집이 완료됩니다.

728x90
반응형

Comment +0

728x90
반응형

※ WandB 서비스 소개 ※

 

  WandB는 기계학습/딥러닝 개발자를 위한 종합적인 보조 도구다. 가장 대표적인 기능으로는 우리가 딥러닝 모델을 학습할 때 학습 과정에 대해서 로깅(logging)을 진행해 준다. 그래서 손실(loss) 값의 감소하는 형태를 쉽게 파악할 수 있다. TensorBoard를 사용해 본 사람이라면, 학습 과정을 적절히 로깅하는 것이 실험/연구에 있어서 얼마나 중요한지 알 것이다. 특히 WandB팀 단위로 실험 결과를 추적할 수 있도록 해주기 때문에, 웹 상에서 보다 편리하게 분석이 가능하다.

  ▶ WandB 공식 홈페이지: https://wandb.ai/

 

  웹 사이트에 접속한 뒤에는 간단한 과정으로 회원가입 및 로그인을 진행할 수 있다. 먼저 [Sign Up] 버튼을 눌러 회원가입을 진행할 수 있다.

 

 

  회원가입을 진행할 때는 깃허브를 이용하는 것이 편리하다. [Sign up with GitHub]을 눌러 회원가입을 진행하면 된다.

 

 

  초기 인증을 위해 깃허브 계정 연동을 허용할 것인지 물어보는 과정이 포함된다.

 

 

  이후에 이름과 사용자명(Username)을 포함한 개인 정보를 기입하여 회원가입을 진행할 수 있다.

 

 

  회원가입 이후에는 다음과 같은 안내 페이지가 등장하며 Quickstart 탭의 [PyTorch]에 접속하여 바로 예제 코드를 이용해 WandB를 이용해 볼 수 있다.

 

 

※ WandB 예제 코드 사용해 보기 ※

 

  가장 먼저 파이썬 패키지 매니저인 pip 명령어를 이용하여 wandb를 설치한다.

 

pip3 install wandb

 

  이후에 wandb login 명령어를 입력하여 로그인을 진행할 수 있다. 참고로 이때 인증을 위해 본인의 API Key를 입력해야 하는데, wandb 웹 사이트에 로그인 이후에 등장하는 API Key를 복사하여 붙여넣기 하면 된다.

 

 

※ PyTorch 예제 코드를 통해 WandB 사용 방법 이해하기 ※

 

  PyTorch 공식 문서에서 제공하는 MNIST 학습 코드를 가져와 실행해 보자.

 

  ▶ PyTorch 공식 MNIST 코드: https://github.com/pytorch/examples/blob/master/mnist/main.py

from __future__ import print_function
import argparse
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets, transforms
from torch.optim.lr_scheduler import StepLR


class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(1, 32, 3, 1)
        self.conv2 = nn.Conv2d(32, 64, 3, 1)
        self.dropout1 = nn.Dropout(0.25)
        self.dropout2 = nn.Dropout(0.5)
        self.fc1 = nn.Linear(9216, 128)
        self.fc2 = nn.Linear(128, 10)

    def forward(self, x):
        x = self.conv1(x)
        x = F.relu(x)
        x = self.conv2(x)
        x = F.relu(x)
        x = F.max_pool2d(x, 2)
        x = self.dropout1(x)
        x = torch.flatten(x, 1)
        x = self.fc1(x)
        x = F.relu(x)
        x = self.dropout2(x)
        x = self.fc2(x)
        output = F.log_softmax(x, dim=1)
        return output


def train(args, model, device, train_loader, optimizer, epoch):
    model.train()
    for batch_idx, (data, target) in enumerate(train_loader):
        data, target = data.to(device), target.to(device)
        optimizer.zero_grad()
        output = model(data)
        loss = F.nll_loss(output, target)
        loss.backward()
        optimizer.step()
        if batch_idx % args.log_interval == 0:
            print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
                epoch, batch_idx * len(data), len(train_loader.dataset),
                100. * batch_idx / len(train_loader), loss.item()))
            if args.dry_run:
                break


def test(model, device, test_loader):
    model.eval()
    test_loss = 0
    correct = 0
    with torch.no_grad():
        for data, target in test_loader:
            data, target = data.to(device), target.to(device)
            output = model(data)
            test_loss += F.nll_loss(output, target, reduction='sum').item()  # sum up batch loss
            pred = output.argmax(dim=1, keepdim=True)  # get the index of the max log-probability
            correct += pred.eq(target.view_as(pred)).sum().item()

    test_loss /= len(test_loader.dataset)

    print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format(
        test_loss, correct, len(test_loader.dataset),
        100. * correct / len(test_loader.dataset)))


def main():
    # Training settings
    parser = argparse.ArgumentParser(description='PyTorch MNIST Example')
    parser.add_argument('--batch-size', type=int, default=64, metavar='N',
                        help='input batch size for training (default: 64)')
    parser.add_argument('--test-batch-size', type=int, default=1000, metavar='N',
                        help='input batch size for testing (default: 1000)')
    parser.add_argument('--epochs', type=int, default=14, metavar='N',
                        help='number of epochs to train (default: 14)')
    parser.add_argument('--lr', type=float, default=1.0, metavar='LR',
                        help='learning rate (default: 1.0)')
    parser.add_argument('--gamma', type=float, default=0.7, metavar='M',
                        help='Learning rate step gamma (default: 0.7)')
    parser.add_argument('--no-cuda', action='store_true', default=False,
                        help='disables CUDA training')
    parser.add_argument('--dry-run', action='store_true', default=False,
                        help='quickly check a single pass')
    parser.add_argument('--seed', type=int, default=1, metavar='S',
                        help='random seed (default: 1)')
    parser.add_argument('--log-interval', type=int, default=10, metavar='N',
                        help='how many batches to wait before logging training status')
    parser.add_argument('--save-model', action='store_true', default=False,
                        help='For Saving the current Model')
    args = parser.parse_args()
    use_cuda = not args.no_cuda and torch.cuda.is_available()

    torch.manual_seed(args.seed)

    device = torch.device("cuda" if use_cuda else "cpu")

    train_kwargs = {'batch_size': args.batch_size}
    test_kwargs = {'batch_size': args.test_batch_size}
    if use_cuda:
        cuda_kwargs = {'num_workers': 1,
                       'pin_memory': True,
                       'shuffle': True}
        train_kwargs.update(cuda_kwargs)
        test_kwargs.update(cuda_kwargs)

    transform=transforms.Compose([
        transforms.ToTensor(),
        transforms.Normalize((0.1307,), (0.3081,))
        ])
    dataset1 = datasets.MNIST('../data', train=True, download=True,
                       transform=transform)
    dataset2 = datasets.MNIST('../data', train=False,
                       transform=transform)
    train_loader = torch.utils.data.DataLoader(dataset1,**train_kwargs)
    test_loader = torch.utils.data.DataLoader(dataset2, **test_kwargs)

    model = Net().to(device)
    optimizer = optim.Adadelta(model.parameters(), lr=args.lr)

    scheduler = StepLR(optimizer, step_size=1, gamma=args.gamma)
    for epoch in range(1, args.epochs + 1):
        train(args, model, device, train_loader, optimizer, epoch)
        test(model, device, test_loader)
        scheduler.step()

    if args.save_model:
        torch.save(model.state_dict(), "mnist_cnn.pt")


if __name__ == '__main__':
    main()


  다음과 같은 명령어를 입력해 코드를 실행하면 콘솔 창에는 다음과 같이 내용이 출력된다.

 

python3 mnist_example.py

 


  정상적으로 코드가 실행이 되는 것을 확인할 수 있다. 하지만 기본적으로 loss와 같은 로그 정보가 콘솔 창에 그대로 출력되므로, 손실 값을 자세히 분석하기에는 시각적으로 다소 불편한 감이 있다.


※ WandB 사용해보기 ※

  앞서 사용했던 코드를 다음과 같이 wandb 라이브러리를 사용하는 형태로 바꿀 수 있다. 기본적으로 변경된 부분은 wandb가 포함된 부분이므로, 이 부분만을 확인하면 된다.

from __future__ import print_function
import wandb
import argparse
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets, transforms
from torch.optim.lr_scheduler import StepLR


class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(1, 32, 3, 1)
        self.conv2 = nn.Conv2d(32, 64, 3, 1)
        self.dropout1 = nn.Dropout(0.25)
        self.dropout2 = nn.Dropout(0.5)
        self.fc1 = nn.Linear(9216, 128)
        self.fc2 = nn.Linear(128, 10)

    def forward(self, x):
        x = self.conv1(x)
        x = F.relu(x)
        x = self.conv2(x)
        x = F.relu(x)
        x = F.max_pool2d(x, 2)
        x = self.dropout1(x)
        x = torch.flatten(x, 1)
        x = self.fc1(x)
        x = F.relu(x)
        x = self.dropout2(x)
        x = self.fc2(x)
        output = F.log_softmax(x, dim=1)
        return output


def train(args, model, device, train_loader, optimizer, epoch):
    model.train()
    for batch_idx, (data, target) in enumerate(train_loader):
        data, target = data.to(device), target.to(device)
        optimizer.zero_grad()
        output = model(data)
        loss = F.nll_loss(output, target)
        loss.backward()
        optimizer.step()
        if batch_idx % args.log_interval == 0:
            print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
                epoch, batch_idx * len(data), len(train_loader.dataset),
                100. * batch_idx / len(train_loader), loss.item()))
            if args.dry_run:
                break


def test(model, device, test_loader):
    model.eval()
    test_loss = 0
    correct = 0

    # wandb에 기록할 테스트 이미지들
    tested_images = []
    with torch.no_grad():
        for data, target in test_loader:
            data, target = data.to(device), target.to(device)
            output = model(data)
            test_loss += F.nll_loss(output, target, reduction='sum').item()  # sum up batch loss
            pred = output.argmax(dim=1, keepdim=True)  # get the index of the max log-probability
            correct += pred.eq(target.view_as(pred)).sum().item()
            # wandb에 현재 배치에 포함된 첫 번째 이미지에 대한 추론 결과 기록
            tested_images.append(
                wandb.Image(data[0], caption=f'Predicted: {pred[0].item()}, Ground-truth: {target[0]}'
            ))

    test_loss /= len(test_loader.dataset)

    print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format(
        test_loss, correct, len(test_loader.dataset),
        100. * correct / len(test_loader.dataset)))
    # wandb에 로깅 진행
    wandb.log({
        "Tested Images": tested_images,
        "Test Average Loss": test_loss,
        "Test Accuarcy": 100. * correct / len(test_loader.dataset)
    })


def main():
    # Training settings
    parser = argparse.ArgumentParser(description='PyTorch MNIST Example')
    parser.add_argument('--batch-size', type=int, default=64, metavar='N',
                        help='input batch size for training (default: 64)')
    parser.add_argument('--test-batch-size', type=int, default=1000, metavar='N',
                        help='input batch size for testing (default: 1000)')
    parser.add_argument('--epochs', type=int, default=14, metavar='N',
                        help='number of epochs to train (default: 14)')
    parser.add_argument('--lr', type=float, default=1.0, metavar='LR',
                        help='learning rate (default: 1.0)')
    parser.add_argument('--gamma', type=float, default=0.7, metavar='M',
                        help='Learning rate step gamma (default: 0.7)')
    parser.add_argument('--no-cuda', action='store_true', default=False,
                        help='disables CUDA training')
    parser.add_argument('--dry-run', action='store_true', default=False,
                        help='quickly check a single pass')
    parser.add_argument('--seed', type=int, default=1, metavar='S',
                        help='random seed (default: 1)')
    parser.add_argument('--log-interval', type=int, default=10, metavar='N',
                        help='how many batches to wait before logging training status')
    parser.add_argument('--save-model', action='store_true', default=False,
                        help='For Saving the current Model')
    args = parser.parse_args()

    # wandb 프로젝트 초기화
    wandb.init(project='mnist-example', entity='dongbin_na')
    # wandb에 하이퍼파라미터 configuration 정보 기록
    wandb.config.update(args)

    use_cuda = not args.no_cuda and torch.cuda.is_available()

    torch.manual_seed(args.seed)

    device = torch.device("cuda" if use_cuda else "cpu")

    train_kwargs = {'batch_size': args.batch_size}
    test_kwargs = {'batch_size': args.test_batch_size}
    if use_cuda:
        cuda_kwargs = {'num_workers': 1,
                       'pin_memory': True,
                       'shuffle': True}
        train_kwargs.update(cuda_kwargs)
        test_kwargs.update(cuda_kwargs)

    transform=transforms.Compose([
        transforms.ToTensor(),
        transforms.Normalize((0.1307,), (0.3081,))
        ])
    dataset1 = datasets.MNIST('../data', train=True, download=True,
                       transform=transform)
    dataset2 = datasets.MNIST('../data', train=False,
                       transform=transform)
    train_loader = torch.utils.data.DataLoader(dataset1,**train_kwargs)
    test_loader = torch.utils.data.DataLoader(dataset2, **test_kwargs)

    model = Net().to(device)
    # wandb에서 학습할 모델 정보 추적
    wandb.watch(model)
    optimizer = optim.Adadelta(model.parameters(), lr=args.lr)

    scheduler = StepLR(optimizer, step_size=1, gamma=args.gamma)
    for epoch in range(1, args.epochs + 1):
        train(args, model, device, train_loader, optimizer, epoch)
        test(model, device, test_loader)
        scheduler.step()

    if args.save_model:
        torch.save(model.state_dict(), "mnist_cnn.pt")


if __name__ == '__main__':
    main()


  실행하는 코드는 동일하다. (wandb 라이브러리를 사용했다고 해서 특별히 더 해 줄 것은 없다.) wandb를 이용해 실행 결과가 로깅되는 경우 다음과 같이 실행된다.


  이후에 wandb.ai/home에 다시 접속하면 자신의 프로젝트 리스트가 등장한다. 여기에서 본인의 프로젝트를 클릭하면 다음과 같이 나온다.

 

 

  참고로 코드를 실행한 폴더에도 wandb 관련 log 폴더가 생성되며 (실행할 때마다 한 번의 run 폴더가 생긴다.) 기본적으로 wandb 서버에 학습할 때의 로그 데이터가 모두 업로드 되기 때문에, 나중에 웹 사이트에 접속해 내용을 확인할 수도 있다. 실제로 사용해 보면 웹 상에서 즉시 확인할 수 있다는 측면에서 매우 편리하다는 것을 느낄 수 있다.

728x90
반응형

Comment +0