Ông Toằn Vi Lốc - Ứng dụng Deep Learning tự động tạo kho nhạc beat karaoke siêu to khổng lồ
Xin chào các cháu, lại là ông dây. Ở bài trước các cháu đã cùng ông thử nghiệm làm một series truyện ma siêu to khổng lồ rồi phải không nào. Hi vọng các cháu có thể áp dụng nó để thực hiện được những chuỗi truyện kinh dị siêu siêu chất nhé. Quảng cáo sương sương cho bài viết cũ vậy thôi chứ các ...
Xin chào các cháu, lại là ông dây. Ở bài trước các cháu đã cùng ông thử nghiệm làm một series truyện ma siêu to khổng lồ rồi phải không nào. Hi vọng các cháu có thể áp dụng nó để thực hiện được những chuỗi truyện kinh dị siêu siêu chất nhé. Quảng cáo sương sương cho bài viết cũ vậy thôi chứ các cháu nghe nhiều truyện ma quá cũng đến lúc cần phải giải trí phải không nào. Hôm nay ông sẽ hướng dẫn các cháu làm một trò rất tiêu khiển liên quan đến đam mê ca hát của mỗi chúng ta đó chính là Dùng Deep Learning tự động tạo beat nhạc để hát karaoke.
Ý tưởng của bài blog này thì cũng xuất phát từ nhu cầu hát hò của rất nhiều các cháu thôi. Với những cháu nào hay hát hò, đặc biệt là hát karaoke thì hẳn là các cháu sẽ gặp những trường hợp như sau:
- Cháu A rất thích bài hát Thêm một lần đau và dự định sẽ hát tặng người con gái ấy trong ngày tỏ tình nhưng khi search beat karaoke trên mạng thì lại khác hẳn với bản beat nhạc mà ca sĩ đang hát => hát không hay => người con gái ấy đi theo một người khác => Thêm một lần đau
- Cháu B rất thích hát nhạc của thằng bán gà - 5S Online và cháu ấy rất đam mê thứ âm nhạc của bộ tộc cà to nhà thằng bán gà nhưng ngặt một nỗi không có một ông nhạc công nào bỏ công sức ra để làm beat nhạc cho cháu đó hát chỉ vì sợ thằng bán gà lại lừa và chê mình là đồ nhà quê => cháu không thỏa đam mê ca hát của mình chỉ vì không có beat nhạc.
- Cháu C là một người nhạc công chuyên đi mix nhạc cho người ta với mỗi một bản karaoke muốn ra lò cháu phải ngồi hàng vài giờ đồng hồ với dống phần mềm và phải hiểu rất nhiều các khái niệm về nhạc lý. Cháu cảm thấy công việc đó rất nhàm chán hơn rất nhiều so với việc ngồi đọc blog của Ông Toằn Vi Lốc.
- Và còn khá nhiều các trường hợp, vân vân và mây mây nữa
Nếu các cháu thấy mình là một trong số các trường hợp kể trên thì đây là bài viết dành cho các cháu. Trong bài viết này ông sẽ hướng dẫn các cháu sinh trực tiếp beat của bài hát từ bản thu âm. phối khí hoàn chỉnh của bài hát đó. Ông làm vì chia sẻ thôi chứ không phải vì tiền đâu nên các cháu nhớ UPVOTE, CLIP và chia sẻ thật nhiều cho ông để ông có dộng lực ra những bài tiếp theo nhé. OK giờ chúng ta bắt đầu thôi nào
Để giải quyết bài toán này chúng ta có thể thực hiện theo hai hướng tiếp cận ông tạm gọi là góc nhìn của Mixer và góc nhìn của AI Engineer
Từ góc nhìn của người mixer
Với các chuyên gia mix nhạc đang đọc bài viết này thì chắc không còn xa lạ gì rồi phải không nào. Để ông nói sơ qua một chút về cách mix nhạc nhé. Bản chất của bài hát của chúng ta là việc trộn (mix) các track âm thanh lại với nhau, trong đó có các track quan trọng như âm thanh nhạc cụ, trống, kèn, sáo ... và giọng hát (vocal) của ca sĩ. Tất cả các âm thanh đó được vang lên cùng một thời điểm tạo thành bài hát của chúng ta. Khi thu âm người ta sẽ thu riêng từng track nhạc một và mix chúng lại với nhau theo các hiệu ứng âm thanh nhất định (cái này cháu nào chuyên gia hát rap tặng người yêu chắc là rõ hơn ông nhiều. Việc mix chúng lại với nhau thì đơn giản nhưng việc làm người lại tức là từ bài hát đã được mix sẵn để khôi phục lại các track trước khi mix thì không hề đơn giản chút nào đâu các cháu ạ. Nó giống như hồi xưa cô nàng Lọ Lem bị dì ghẻ bắt ngồi nhặt thóc và gạo riêng ra từng đống ý các cháu ạ.
Với một người mixer thì việc này có thể được thực hiện bằng một vài phần mềm thu âm có chức năng xoá vocal ra khỏi bài hát như Audacity các cháu có thể tham khảo ở đây. Ông thì không đi quá sâu vào phần này nhé, các cháu cứ xem video và làm theo thôi. Và cách làm này có một số ưu điểm và nhược điểm dưới đây các cháu ạ.
Ưu điểm
- Dễ dàng thực hiện, không cần biết về kĩ thuật, chỉ xem video, đọc tutorial hướng dẫn là làm được
- Không cần hiểu về bản chất của âm thanh vì đã có tool rồi
Nhược điểm
- Với mỗi một bài nhạc khác nhau đều phải tinh chỉnh các tham số một cách thủ công, không có một bộ tham số cố định cho các bài hát
- Chỉ có thể xoá được vocal và một vài loại nhạc cụ phổ biến. Muốn tách riêng âm thanh của từng loại nhạc cụ hoặc vocal thì sẽ rất khó khăn
- Thời gian thực hiện lâu, tốn thời gian thay đổi các tham số
- Phụ thuộc rất nhiều vào cách cảm âm và kinh nghiệm của người tiến hành
Từ góc nhìn của AI Engineer
Đứng từ góc nhìn của những người làm AI thì ông cháu ta sẽ nhìn nhận bài toán này theo một hướng khác. Và tư duy của một người làm về AI đều phải dựa trên bản chất của dữ liệu. Nếu như các cháu chưa hiểu được bản chất của dữ liệu thì các cháu sẽ không biết nên lựa chọn mô hình nào cho đúng, chọn phương pháp nào cho phù hợp với bài toán hiện tại của chúng ta. Cùng đi sâu một chút nhé cac cháu, yêu cầu của chúng ta là từ file âm thanh đầu vào và bằng một cách nào đó tách riêng ra được các thành phần như trống, kèn, sáo giọng hát .... Chúng ta sẽ nghĩ ngay đến việc cần phải có một tập dữ liệu với đầu vào là một file audio và đầu ra tương ứng là audio chỉ chứa riêng phần giọng hát hoặc phần beat tương ứng với audio lúc đầu. Vậy ở giữa nó là gì các cháu nhỉ, các cháu lại phải xây dựng các mô hình AI để tiến hành việc trích chọn đó. Chúng ta có thể hình dung đầu vào và đầu ra của phương pháp này qua hình sau:
Phương pháp tiếp cận cụ thể ông sẽ nói chi tiết ở các phần sau tuy nhiên chúng ta cùng bàn luận một số cái về ưu điểm và nhược điểm của phương pháp này
Ưu điểm
- Có thể thực hiện được cho tất cả các bài hát, không cần thực hiện thủ công
- Không yêu cầu kinh nghiệm, chỉ bằng một cú click chuột là có thể thực hiện theo mong muốn
- Có thể tách được tốt với nhiều kiểu yêu cầu khác nhau như tách riêng tiếng guitar, tách riêng tiếng trống, tách riêng giọng hát, tách riêng beat
Nhược điểm
- Muốn tạo ra mộ hình phải có hiểu biết về AI - nhưng không sao đọc hết bài này của ông các cháu sẽ làm được
- Cần phải có dữ liệu training đủ đa dạng
- Cần phải có một máy tính cấu hình mạnh trong lúc training
Sau khi đã phân tích các hướng giải quyết cho bài toán này thì chúng ta sẽ tập trung hơn vào hướng thứ hai các cháu nhé. Đơn giản là vì ông không phải là mixer nên ông cháu ta sẽ tiếp cận theo hướng thứ hai sẽ có nhiều điều thú vị để chia sẻ với các cháu hơn. Cũng giống như những bài hướng dẫn về AI khác của ông thì ông cháu ta sẽ cùng nhau đi qua các phần như phân tích đặc trưng của dữ liệu, lựa chọn các kiểu đặc trưng cho phù hợp với bài toán, sau đó xây dựng và training mô hình và cuối cùng là kiểm tra đánh giá kết quả. Giờ thì chúng ta sẽ bắt đầu từng phần một các cháu nhé.
Kiểu dữ liệu đầu vào - đầu ra
Như các cháu đã biết thì đầu vào của chúng ta sẽ là một file audio và tất nhiên đầu ra cũng sẽ là một file audio với chiều dài giống y hệt với audio đầu vào nhưng chỉ chứa phần nhạc nền của bài hát thôi. Hoặc chúng ta cũng có thể xây dựng mô hình để tách ra nhiều thành phần khác của đoạn nhạc đầu vào như tách riêng tiếng kèn, tiếng trống, tiếng khiên .... Để dễ hình dung thì các cháu có thể hình dung như sơ đồ sau:
Trong đó các tín hiệu âm thanh đầu vào có thể được coi như các biên độ (các cháu có thể hiểu là độ to của âm thanh) theo thời gian
Từ độ to này thì các cháu có thể biết được những vùng nào là những vùng có âm thanh (thì cứ thấy màu xanh tức là có âm thành còn không có vùng màu xanh thì tức là chỗ đó đang là các khoảng lặng). Điều này cũng sẽ không thể giúp gì cho chúng ta trong việc tách phần nào là beat, phần nào là vocal cả vì hoàn toàn chưa có thông tin về tần số. Để làm được điều đó chúng ta cần phải chuyển đổi các thông tin của chúng ta về miền tần số và có thể sử dụng nó để tiến hành loại bỏ đi các tần số không cần thiết cho yêu cầu của chúng ta (ví dụ loại đi các tần số thể hiện giọng hátj. Cái này các cháu có thể hình dung đơn giản như việc hình thành cầu vồng ý. Nếu như các cháu để riêng tia sáng trắng (tương tự như giữ nguyên giá trị biên độ của âm thanh) thì tia sáng là không màu và các cháu không thể tách riêng từng thành phần màu của tia sáng ra được. Nhưng khi chiếu nó qua một lăng kính (tương tự như việc phân tích thành phổ tần số) thì các cháu sẽ thấy được màu của bảy sắc cầu vồng. Các cháu hiểu chưa nào.
Để hiểu rõ hơn về các phương pháp chuyển đổi sang miền tần số ông cháu ta sẽ tìm hiểu kĩ hơn trong phần sau nhé.
Chuyển đổi Fourier và Short Time Fourier Transform
Biến đổi Fourier
Biến đổi Fourier là một phép biến đổi cho phép chuyển đổi một tín hiệu từ miền thời gian sang miền tần số. Chẳng hạn như một bản nhạc có thể được phân tích dựa trên tần số của nó. Chúng ta có thể hình dung trong hình sau:
Thông thường, tên gọi biến đổi Fourier được gắn cho biến đổi Fourier liên tục, biến đổi này biểu diễn một hàm bình phương khả tích f(t)f(t)f(t) bất kì theo tổng của các hàm e lũy thừa phức với tần số góc ωωω và biên độ phức F(ω)F(ω)F(ω):
Đây là biến đổi nghịch đảo của biến đổi Fourier liên tục:
Biến đổi Fourier của tín hiệu này là F(ω)F(omega)F(ω) cho ta đầy đủ thông tin trong miền tần số, nhưng hoàn toàn không có thông tin gì về miền thời gian gian vì tích phân từ −∞-infty−∞ đến +∞+infty+∞. Do đó biến đổi Fourier không phù hợp với tín hiệu có tần số thay đổi theo thời gian. Điều đó có nghĩa là biến đổi Fourier chỉ có thể cho biết có hay không sự tồn tại của các thành phần tần số nào đó, tuy nhiên thông tin này độc lập với thời điểm xuất hiện thành phần phổ đó. Như vậy sau biến đổi Fourier, ta có thông tin trong miền tần số nhưng mất hoàn toàn thông tin về miền thời gian. Đây chính là lúc mà Short-time Fourier transform (STFT) xuất hiện.và ông cháu ta sẽ cùng tìm hiểu nó trong phần tiếp theo.
Biến đổi STFT
Ý tưởng chính của STFT là “hi sinh” một ít thông tin về các tần số thấp trong miền tần số để có thêm thông tin về miền thời gian. STFT được biểu diễn bằng 1 hàm G(ω,t)G(omega, t)G(ω,t) theo hai biến là tần số góc ωomegaω và biến thời gian ttt. Như vậy khi nhìn vào kết quả của STFT có thể biến được tần số ωomegaω xuất hiện vào thời điểm nào trong miền thời gian. Trong biến đổi STFT, thì tín hiệu được chia thành các đoạn đủ nhỏ, do vậy tín hiệu trên từng đoạn được phân chia có thể coi là dừng (stationary). Với mục đích này, hàm cửa sổ được lựa chọn. Độ rộng của cửa sổ phải bằng với đoạn tín hiệu mà giả thiết về sự dừng của tín hiệu là phù hợp. Nguyên tắc của phương pháp này là phân chia tín hiệu ra thành từng đoạn đủ nhỏ sao cho có thể xem tín hiệu trong mỗi đoạn là tín hiệu ổn định, sau đó, thực hiện biến đổi Fourier trên từng đoạn tín hiệu này.
Nói chung các cháu có thể hiểu rằng sử dụng STFT thì chúng ta có thể lấy được thông tin của cả miền tần số và miền thời gian. Phép biến đổi ngược có thể giúp chúng ta khôi phục lại được tín hiệu ban đầu. Chính vì thế nên trong bài này ông sử dụng phương pháp STFT để chuyển đổi tín hiệu âm thanh sang miền tần số như một đặc trưng đầu vào cho mô hình Deep Learning của chúng ta. OK lý thuyết như vậy là đủ rồi, giờ ông cháu ta bắt tay vào phần thực hành thôi nhé.
Tập dữ liệu MUSDB18
Tập dữ liệu này là một tập dữ liệu khá phù hợp với bài toán của chúng ta. Các cháu có thể tải về tại đây. Để ông nói qua một chút về tập dữ liệu này cho các cháu nhé. Nó bao gồm 150 bài hát với khoảng 10 giờ âm thanh. Đây là dữ liệu khá tốt cho các cháu thực hành nhé. Tập này bao gồm các track nhạc được lưu dưới định dạng stems bao gồm các track chứa các loại âm thanh khác nhau như drums, bass, vocals và others. Với nhiều loại như này các cháu tha hồ lựa chọn mục đích của mô hình nhé. Nếu các cháu muốn làm mô hình tách nhạc nền như bài toán của ông cháu ta thì chỉ lấy nguyên phần others làm nhãn thôi nhé.
Tiền xử lý dữ liệu
Giờ đến bước chúng ta tiến hành các bước tiền xử lý dữ liệu với bài toán này. Do tập dữ liệu này lưu dưới dạng stems file nên chúng ta cần phải tách từng file nhỏ ra thành các thành phần khác nhau luôn các cháu ạ. Ở đây ông sẽ hướng dẫn các cháu viết hàm số để tách ra hai tracks là masterchứa âm thanh tổng tương ứng sẽ là đầu vào của mô hình và others chứa beat nhạc tương ứng với đầu ra của mô hình. Ngoài ra nếu cháu nào muốn thử nghiệm với vocal thì cũng có thể thực hiện được trong cùng một hàm này nhưng đầu tiên các cháu cần cài đặt và sử dụng thư viện stempeg tại đây
import stempeg import numpy as np def extract_vocal(fname): stems, _ = stempeg.read_stems(fname, stem_id=[0,4,3]) stems = stems.astype(np.float32) master = stems[0,:,:] vocal = stems[1,:,:] other = stems[2,:,:] return master, vocal, other
Sau đó các cháu có thể sử dụng hàm trên để tách data từ một file bất kì thuộc tập dữ liệu MUSDB18 giả sử như sau:
master, vocal, other = extract_vocal('MUSDB18/train/Clara Berry And Wooldog - Air Traffic.stem.mp4')
Để lưu thử ra file các cháu sử dụng thư viện librosa rất phổ biến khi xử lý với dữ liệu dạng âm thanh cụ thể như sau:
import librosa sr = 44100 librosa.output.write_wav('master.wav', master, sr)
Và cuối cùng để tạo dữ liệu cho tất cả các file trong thư mục train của tập dữ liệu MUSDB18 thì chúng ta sử dụng vòng lặp sau. Lưu ý là các cháu tạo sẵn các thư mục mixtures, others và vocals trong thư mục data nhé. Sau này chúng ta xử lý cho tiện.
import os all_songs = os.listdir('MUSDB18/train/') # Generate mixtures, others and vocals files for i, fname in enumerate(all_songs): master, vocal, other = extract_vocal(os.path.join('MUSDB18/train/', fname)) librosa.output.write_wav('data/mixtures/{}.wav'.format(i), master, sr) librosa.output.write_wav('data/vocals/{}.wav'.format(i), vocal, sr) librosa.output.write_wav('data/others/{}.wav'.format(i), other, sr)
Sau bướ này chúng ta sẽ có 3 thư mục tương ứng với dữ liệu đầu vào và ground truth. Việc tiếp theo chúng ta cần làm là phân chia dữ liệu các cháu ạ.
Phân chia dữ liệu
Việc này khá quan trọng đó các cháu ạ. Như các cháu thấy là mình đã tách ra được các file tương ứng với từng loại gồm bản mix, beat nhạc và giọng hát rồi. Thế như các file đó độ dài rất khác nhau, mà độ dài khác nhau thì không thể dùng làm dữ liệu được nó sẽ không thống nhất. Hơn nữa dữ liệu như vậy là chưa đủ phong phú, để làm phong phú hơn dữ liệu chúng ta thực hiện một kĩ thuật khá đơn giản đó là lấy từng đoạn âm thanh nhỏ và bước nhảy là 0.5 giây với mục đích làm cho dữ liệu của chúng ta trở nên phong phú hơn. Chúng ta làm như sau:
from tqdm import tqdm # Skip 0.5 seconds skip = sr // 2 # Mixtures part as training data X_part = [] # Vocal part as label Y_part = [] # Define win_len length = 255 hop_size = 1024 win_len = hop_size*length for mixture_path in tqdm(wav_path_mixtures): vocal_path = mixture_path.replace('mixtures', 'vocals') # Load x and y song x, sr = librosa.load(mixture_path, sr = sr) y, sr = librosa.load(vocal_path, sr = sr) # Padding win_len 0 for x and y x_pad = np.pad(x, (0, win_len), mode = "constant") y_pad = np.pad(y, (0, win_len), mode = "constant") l = len(x_pad) for i in range(0, l - win_len - skip, skip): x_part = x_pad[i:i + win_len] y_part = y_pad[i:i + win_len] X_part.append(x_part) Y_part.append(y_part)
Và để thuận tiện hơn chúng ta có thể chia luôn dữ liệu training và testing. Lưu ý với các cháu là ông đang sử dụng nguyên các file trong thư mục train của tập MUSDB18 nên dữ liệu X_test và Y_test có thể hiểu tương tự như tập validate trong các bài toán thông thường (vì đã phân chia sẵn tập test độc lập rồi)
# Train test split from sklearn.model_selection import train_test_split X_train, X_test, Y_train, Y_test = train_test_split(X_part, Y_part, test_size=0.1, random_state=42)
Kiến trúc mạng Unet
Unet là một kiến trục mạng rất phổ biến trong bài toán Image Segmentation với đặc thù của dữ liệu đầu vào và đầu ra có kích thước giống như nhau. Bài toán này của ông cháu ta rất phù hợp để áp dụng thử kiến trúc này. Mục đích của Unet là từ phổ âm thanh đầu và trích chọn ra được các phổ âm tương ứng với mục đích của chúng ta. Các cháu có thể hình dung kiến trúc Unet như trong hình sau:
Ông sẽ không nói quá sâu về phần này nhé, ông cũng sẽ xây dựng một mạng dựa trên Unet đơn giản với cơ chế Skip Connection được mô tả như trong phần bên dưới
Cơ chế Skip Connection
Cơ chế này cũng là một cơ chế rất quen thuộc trong cách thiết kế của mạng nơ ron theo dạng Auto Encoder. Các cháu có thể hiểu đơn giản đó là việc sử dụng các thông tin ở các layer ở phase encoder trước đó để đưa vào sang các layer đối xứng với nó trong phase decoder giúp cho các đặc trựng được giữ lại nhiều hơn qua Autoencoder. Người ta có thể sử dụng các hàm kích hoạt hoặc các mạng như LSTM, GRU để làm bộ chuyển đổi cho Skip Connection trong ví dụ này ông sử dụng GRU
Kíến trúc mạng sử dụng
Trong bài toán này ông sử dụng 3 lớp Convolution 1D đối xứng nhau để thiết kế Unet. Đồng thời sử dụng GRU để làm bộ chuyển đổi cho layer skip connection của lớp Convulution thứ 2 và thứ 3. Kích thước dữ liệu đầu vào phụ thuộc vào cách chọn tham số của STFT trong bài này ông để các thông số như sau:
hop_size = 1024 n_fft = 2048
Và đây là thiết kế chi tiết của mạng bằng Pytorch
# Define model import torch.nn as nn class VocalModel(nn.Module): def __init__(self): super(VocalModel, self).__init__() self.conv1 = nn.utils.weight_norm(nn.Conv1d(1025, 1024, kernel_size = 3, padding = 1), name = "weight") self.conv2 = nn.utils.weight_norm(nn.Conv1d(1024, 512, kernel_size = 3, stride = 2, padding = 1), name = "weight") self.conv3 = nn.utils.weight_norm(nn.Conv1d(512, 256, kernel_size = 3, stride = 2, padding = 1), name = "weight") self.Tconv1 = nn.utils.weight_norm(nn.ConvTranspose1d(256, 512, kernel_size = 3, stride = 2, padding = 1, output_padding = 1), name = "weight") self.Tconv2 = nn.utils.weight_norm(nn.ConvTranspose1d(512, 1024, kernel_size = 3, stride = 2, padding = 1, output_padding = 1), name = "weight") self.Tconv3 = nn.utils.weight_norm(nn.Conv1d(1024, 1025, kernel_size = 3, stride = 1, padding = 1), name = "weight") self.gru1 = nn.GRU(1024, hidden_size = 1024, num_layers = 1, batch_first = True) self.gru2 = nn.GRU(512, hidden_size = 512, num_layers = 1, batch_first = True) self.leaky_relu = nn.LeakyReLU() def forward(self, x): # Encoder x_s1 = self.leaky_relu(self.conv1(x)) x_s2 = self.leaky_relu(self.conv2(x_s1)) x = self.conv3(x_s2) x = self.leaky_relu(x) # Do GRU skip connection 1 x_s1 = x_s1.permute(0, 2, 1) x_s1 = self.gru1(x_s1)[0] x_s1 = x_s1.permute(0, 2, 1) # Do GRU skip connection 2 x_s2 = x_s2.permute(0, 2, 1) x_s2 = self.gru2(x_s2)[0] x_s2 = x_s2.permute(0, 2, 1) # Decoder x = self.Tconv1(x) x = self.leaky_relu(x) # Add skip connection gru x = torch.add(x, x_s2) x = self.Tconv2(x) x = self.leaky_relu(x) # Add skip connection gru x = torch.add(x, x_s1) x = self.Tconv3(x) x = self.leaky_relu(x) return x
Sau khi đã định nghĩa được mô hình rồi chúng ta bắt đầu xây dựng Data Loader thôi các cháu nhé
Chuyển đổi STFT
Chúng ta sử dụng thư viện Pytorch để tiến hành chuyển đổi các dữ liệu tín hiệu âm thanh của chúng ta sang miền tần số
import torch.utils.data as utils def convert_stft(x): # Convert x data to stft stft_label = librosa.stft(x, hop_length = 1024) stft_label_mag = np.log1p(np.abs(stft_label)) return torch.from_numpy(stft_label_mag) def get_phase(x): stft_label = librosa.stft(x, hop_length = 1024) return np.angle(stft_label)
Các cháu có thể convert thử để xem kết quả
convert_stft(X_train[2]).shape >>> torch.Size([1025, 256])
Xây dựng data loader
Sau đó chúng ta cần xây dựng DataLoader để định nghĩa các xử lý dữ liệu đầu vào khi load data. Do ông đang thử với dữ liệu vocal nên chúng ta có thể xây dựng một class như sau:
from torch.utils.data import Dataset, DataLoader class VocalDataset(Dataset): def __init__(self, X, Y): self.X = X self.Y = Y def __len__(self): return len(self.X) def __getitem__(self, idx): return (convert_stft(self.X[idx]), convert_stft(self.Y[idx]))
Với các dữ liệu đã được phân chia thì ông cháu mình cần xây dựng hai DataLoader khác nhau phục vụ cho việc training và việc testing
train_dataset = VocalDataset(X_train, Y_train) train_loader = DataLoader(train_dataset, batch_size=64) test_dataset = VocalDataset(X_test, Y_test) test_loader = DataLoader(test_dataset, batch_size=64)
Giờ là đến bước quan trọng nhất rồi các cháu ạ. Training mô hình và chờ kết quả thôi nào
Định nghĩa hàm loss và optimizer
Việc định nghĩa hàm mất mát là rất quan trọng đó các cháu ạ. Ở đây các cháu có thể hiểu rằng việc tối ưu bài toán này chính là việc giúp cho phổ đâu ra của mô hình Unet các giống với phổ ground truth càng tốt và chúng ta có thể sử dụng các hàm tính khoảng các để làm hàm loss. Ở đây ông sử dụng MSE để làm hàm lỗi cho mô hình này. Các cháu định nghĩa nhé
loss = nn.MSELoss()
Tiếp theo đó là định nghĩa hàm tối ưu. Do kiến trúc mạng cũng không có gì đặc biệt nên chúng ta sử dụng Adam là phương pháp tối ưu phổ biến cho các mạng nơ ron hiện này
from torch.optim import Adam optimizer = Adam(model.parameters(), lr=0.0001)
Bắt đầu training
Các cháu tiến hành training thuật toán và so sánh sau mỗi epochs loss trung bình trên hai tập training và validate. Để làm được điều đó các cháu thực hiện như sau:
train_dataset = VocalDataset(X_train, Y_train) train_loader = DataLoader(train_dataset, batch_size=64) test_dataset = VocalDataset(X_test, Y_test) test_loader = DataLoader(test_dataset, batch_size=64) # Training from torch.optim import Adam optimizer = Adam(model.parameters(), lr=0.0001) train_loss = 1 test_loss = 1 for epoch in range(200): train_loss_sum = [] model.train() for i, (features, labels) in enumerate(train_loader): features = features.cuda() labels = labels.cuda() optimizer.zero_grad() out = model(features) l = loss(out, labels) l.backward() optimizer.step() train_loss_sum.append(l.item()) if (i % 50 == 49): print("Epoch: {} Batch {}/{} Loss {}".format(epoch, i, len(train_loader), np.mean(train_loss_sum))) # Test loss print('Testing epoch ', epoch) test_loss_sum = [] model.