import numpy as np
import torch.nn.functional as F
from tqdm.auto import tqdm
from IPython.display import Audio
from matplotlib import pyplot as plt
from diffusers import DiffusionPipeline
from torchaudio import transforms as AT
from torchvision import transforms as IT

二、從預訓練的音頻擴散模型Pipeline中進行采樣

? ? ? ?加載預訓練好的音頻擴散模型Audio?Diffusion(用于生成音頻的梅爾譜圖)

# 加載一個預訓練的音頻擴散模型管線
device = "cuda" if torch.cuda.is_available() else "cpu"
pipe = DiffusionPipeline.from_pretrained("teticio/audio-diffusion-
instrumental-hiphop- 256").to(device)
Fetching 5 files: 0%| | 0/5 [00:00<? , ?it/s]

? ?對pipe進行一次采樣

# 在管線中采樣一次并將采樣結果顯示出來
output = pipe()
display(output.images[0])
display(Audio(output.audios[0], rate=pipe.mel.get_sample_rate()))

? ?采樣結果,如下圖所示:

? ?上述代碼中,rate參數表示音頻的采樣率,下面我們查看一下音頻序列和頻譜

# 音頻序列
output.audios[0].shape

# 輸出
(1, 130560)
# 輸出的圖像(頻譜)
output.images[0].size

# 輸出
(256, 256)

音頻并非由擴散模型直接生成的,而是類似于無條件圖像生成管道那樣,使用一個2D UNet網絡結構來生成音頻的頻譜,之后經過后處理轉換為最終的音頻。

三、從音頻轉換為頻譜

? ? ? ?音頻的”波形“在時間上展示了源音頻,例如,音頻的”波形“可能是從麥克風接收到的電信號。這種”時域“上的表示處理起來比較棘手,因此通常會轉換為頻譜來處理,頻譜能夠直接展示不同頻率(y軸)和時間(x軸)的強度。

# 使用torchaudio模塊計算并繪制所生成音頻樣本的頻譜,如圖8-2所示
spec_transform = AT.Spectrogram(power=2)
spectrogram = spec_transform(torch.tensor(output.audios[0]))
print(spectrogram.min(), spectrogram.max())
log_spectrogram = spectrogram.log()
lt.imshow(log_spectrogram[0], cmap='gray');
tensor(0.) tensor(6.0842)

??頻譜圖,如下所示:

?以上圖剛剛生成的音頻樣本為例,頻譜的取值范圍是0.0000000000001~1,其中大部分值接近取值下限,這對于可視化和建模來說不太理想,為此,我們使用了梅爾頻譜(Mel spectrogram)對不同頻率進行一些變換來符合人耳感知特性,下圖展示了torchaudio音頻轉換方法:

幸運的是,我們使用mel功能可以忽略這些細節,就能吧頻譜轉換成音頻:

a = pipe.mel.image_to_audio(output.images[0])
a.shape

# 輸出
(130560,)

讀取源音頻數據,然后調用audio_slice_to_image()函數,將源音頻數據轉換為頻譜圖像。同時較長的音頻片段也會自動切片,以便可以正常輸出256X256像素的頻譜圖像,代碼如下:

pipe.mel.load_audio(raw_audio=a)
im = pipe.mel.audio_slice_to_image(0)
im

     音頻被表示成一長串數字數組。若想播放音頻,我們需要采樣率這個關鍵信息。 

? ? ? ?我們查看一下單位時間音頻的采樣點有多少個?

sample_rate_pipeline = pipe.mel.get_sample_rate()
sample_rate_pipeline

# 輸出
22050

如果設置別的采樣率,那么會得到一個加速或者減速播放的音頻,比如:


display(Audio(output.audios[0], rate=44100)) # 播放速度被加倍

四、微調音頻擴散模型數據準備

? ? ? ?在了解了音頻擴散模型Pipeline使用之后,我們在新的數據集上對其進行微調,我們使用的數據集由不同類別的音頻片段集合組成的,代碼如下:

from datasets import load_dataset
dataset = load_dataset('lewtun/music_genres', split='train')
dataset

查看一下該數據集不同類別樣本所占的比例:

for g in list(set(dataset['genre'])):
print(g, sum(x==g for x in dataset['genre']))

輸出內容如下:

Pop 945
Blues 58
Punk 2582
Old-Time / Historic 408
Experimental 1800
Folk 1214
Electronic 3071
Spoken 94
Classical 495
Country 142
Instrumental 1044
Chiptune / Glitch 1181
International 814
Ambient Electronic 796
Jazz 306
Soul-RnB 94
Hip-Hop 1757
Easy Listening 13
Rock 3095

該數據集已將音頻存儲為數組,代碼如下:

audio_array = dataset[0]['audio']['array']
sample_rate_dataset = dataset[0]['audio']['sampling_rate']
print('Audio array shape:', audio_array.shape)
print('Sample rate:', sample_rate_dataset)

# 輸出
Audio array shape: (1323119,)
Sample rate: 44100

PS:該音頻的采樣率更高,要使用該Pipeline,就需要對其進行”重采樣“。音頻也比Pipeline預設的長度要長,在調用pipe.mel加載該音頻時,會被自動切片為較短的片段。代碼如下:

a = dataset[0]['audio']['array']  # 得到音頻序列
pipe.mel.load_audio(raw_audio=a) # 使用pipe.mel加載音頻
pipe.mel.audio_slice_to_image(0) # 輸出第一幅頻譜圖像
sample_rate_dataset = dataset[0]['audio']['sampling_rate']
sample_rate_dataset

# 輸出
44100

??從上述代碼結果可以看出,該數據集的數據在每一秒都擁有兩倍的數據點,因此需要調整采樣率。這里我們使用torchaudio transforms(導入為AT)進行音頻重采樣,并使用Pipeline的mel功能將音頻轉換為頻譜圖像,然后使用torchvision transforms(導入為IT)將頻譜圖像轉換為頻譜張量。一下代碼中的to_image()函數可以將音頻片段轉換為頻譜張量,供訓練使用:

resampler = AT.Resample(sample_rate_dataset, sample_rate_pipeline, 
dtype=torch.float32)
to_t = IT.ToTensor()
 
def to_image(audio_array):
audio_tensor = torch.tensor(audio_array).to(torch.float32)
audio_tensor = resampler(audio_tensor)
pipe.mel.load_audio(raw_audio=np.array(audio_tensor))
num_slices = pipe.mel.get_number_of_slices()
slice_idx = random.randint(0, num_slices-1) # 每次隨機取一張(除了
# 最后那張)
im = pipe.mel.audio_slice_to_image(slice_idx)
return im

整理微調數據

def collate_fn(examples):

# 圖像→張量→縮放至(-1,1)區間→堆疊
audio_ims = [to_t(to_image(x['audio']['array']))*2-1 for x in
examples]
return torch.stack(audio_ims)
 
# 創建一個只包含Chiptune/Glitch(芯片音樂/電子脈沖)風格的音樂
batch_size=4 # 在CoLab中設置為4,在A100上設置為12
chosen_genre = 'Electronic' # <<< 嘗試在不同的風格上進行訓練 <<<
indexes = [i for i, g in enumerate(dataset['genre']) if g ==
chosen_genre]
filtered_dataset = dataset.select(indexes)
dl = torch.utils.data.DataLoader(filtered_dataset.shuffle(), batch_
size=batch_size,
collate_fn=collate_fn, shuffle=True)
batch = next(iter(dl))
print(batch.shape)

# 輸出
torch.Size([4, 1, 256, 256])

五、開始微調音頻擴散模模型

epochs = 3
lr = 1e-4
 
pipe.unet.train()
pipe.scheduler.set_timesteps(1000)
optimizer = torch.optim.AdamW(pipe.unet.parameters(), lr=lr)
 
for epoch in range(epochs):
for step, batch in tqdm(enumerate(dl), total=len(dl)):
# 準備輸入圖片
 
clean_images = batch.to(device)
bs = clean_images.shape[0]
 
# 為每一張圖片設置一個隨機的時間步
 
timesteps = torch.randint(
0, pipe.scheduler.num_train_timesteps, (bs,),
device=clean_images.device
).long()
# 按照噪聲調度器,在每個時間步為干凈的圖片加上噪聲
 
noise = torch.randn(clean_images.shape).to(clean_images.
device)
noisy_images = pipe.scheduler.add_noise(clean_images,
noise, timesteps)
# 得到模型的預測結果
 
noise_pred = pipe.unet(noisy_images, timesteps, return_
dict=False)[0]
# 計算損失函數
loss = F.mse_loss(noise_pred, noise)
loss.backward(loss)
 
# 使用優化器更新模型參數
optimizer.step()
optimizer.zero_grad()
# 裝載之前訓練好的頻譜樣本,如圖8-6所示
pipe = DiffusionPipeline.from_pretrained("johnowhitaker/Electronic_
test").to(device)
output = pipe()
display(output.images[0])
display(Audio(output.audios[0], rate=22050))
# 輸入一個不同形狀的起點噪聲張量,得到一個更長的頻譜樣本,如圖8-7所示
noise = torch.randn(1, 1, pipe.unet.sample_size[0],pipe.unet.
sample_size[1]*4).to(device)
output = pipe(noise=noise)
display(output.images[0])
display(Audio(output.audios[0], rate=22050))

生成的頻譜,如下圖所示:

生成更長的頻譜樣本,如下圖所示:

思考:

  1. 我們使用的是256X256像素的方形頻譜圖像,這會限制batch size,能否從128X128像素的頻譜圖像中恢復出質量足夠好的音頻呢?
  2. 為了替代隨機圖像增強,我們每次都挑選了不同的音頻片段,但這種方法在訓練循環后期是否可以用其他增強方法進行優化呢?
  3. 是否有其他辦法可以用來生成更長的音頻呢?或者可以先生成開頭的5s音頻,之后再采用類似圖像修復的思路繼續生成后續的音頻。
  4. 擴散模型生成的內容與Img2Img生成的內容有什么相同之處?

文章轉自微信公眾號@ArronAI

上一篇:

擴散模型實戰(十三):ControlNet結構以及訓練過程

下一篇:

輕松上手 LangChain 開發框架之 Agent 技術 !
#你可能也喜歡這些API文章!

我們有何不同?

API服務商零注冊

多API并行試用

數據驅動選型,提升決策效率

查看全部API→
??

熱門場景實測,選對API

#AI文本生成大模型API

對比大模型API的內容創意新穎性、情感共鳴力、商業轉化潛力

25個渠道
一鍵對比試用API 限時免費

#AI深度推理大模型API

對比大模型API的邏輯推理準確性、分析深度、可視化建議合理性

10個渠道
一鍵對比試用API 限時免費