R语音中的并行与分段技巧

在众多编程语言中,R语言是典型的运行慢和耗内存。当数据表比较庞大(比如一个数据集达100G),而内存有限时(比如一台普通电脑内存16G),使用R语言一次读入和处理,常规做法完全不可行。即使调大虚拟内存(swap空间),使用memory.limit(Windows系统)或 ulimit -s -v(Linux系统)等操作(虚拟内存其实很慢),即使再辅之以rm()和gc()及时清理内存(个人感觉效果甚微),也会让电脑运行陷入无止尽的卡顿中。当硬件设备有限时,我们可以使用并行运算和分段技巧应对这种情形。

R语言中一般使用parallel包完成并行运算,具体写法此处不赘述,请自行查阅相关资料。建议使用Linux或Mac执行并行运算,因为可以使用FORK模式共享主程序的变量从而节约内存。并行运算不仅可以解决运行速度慢的问题,还可以用于及时回收内存,效果明显优于rm和gc(R语言的内存管理特点请参考相关资料,值得注意的是,同名变量有可能出现多份拷贝)。当我们估计某一段代码会产生较多的临时变量时,可以将这段代码放入并行运算中(新开一个集群cluster),运行完后关闭cluster即可回收所有内存。如果某段代码完整运行完需要大量内存,担心内存不够用时,可以再将代码分段(每运行完一段就回收一次cluster),比如按col将数据表分成100份,原本需要60G内存的操作,可优化到仅需6G。简言之,并行结合分段,可以将CPU和内存的使用优化到非常舒服的状态。

另外,将中间结果保存到硬盘,也是一种节约时间和内存的技巧。一方面,当需要重新调用程序,则可以直接“读档”(中间结果)来节约时间;另一方面,由于产生中间结果时,已经消耗了较多内存而又无法很好得回收内存时,重启R再读档中间结果,则可回收大量内存。注意,当中间结果较大时,应该分段保存(比如将8G的数据表分成16份)。读取时,若内存够用,则可使用多个CPU同时读取再合并;若担心读取时内存不够用,再使用分段的技巧读取。由于读取再合并结果后,实际上总共会有2份数据,若担心rm和gc回收效果不佳,则可将读取和合并的操作放入新的cluster中,合并后关掉cluster即可。

简单的“存档”和“读档”代码示例如下

library(dplyr)
library(parallel)

# Save data_Methy
cl <- makeCluster(1, type="FORK")
out<-parLapply(cl,1,function(j){
  temp<-list()
  for (i in 1:8){
    start<-(i-1)*36+2
    end<-i*36+1
    batch_col<-c(1,c(start:end))
    temp[[i]]<-data_methy_m %>% select(c(1,batch_col))
  }
  return(temp)
})[[1]]
stopCluster(cl)

x<-1:8
cl <- makeCluster(8, type="FORK")
parLapply(cl,x,function(i){
  write.table(out[[i]],file=paste("Methylation/Methy_beta_",as.character(i),".tsv",sep=""),row.names = F,sep="\t")
  return(0)
})[[1]]
stopCluster(cl)

# Load data_Methy
cl <- makeCluster(1, type="FORK")
data_methy_m<-parLapply(cl,1,function(j){
  for (k in 1:8){
    cl_2 <- makeCluster(1, type="FORK")
    results<-parLapply(cl_2,k,function(i){
      temp<-read.table(paste("Methylation/Methy_beta_",as.character(i),".tsv",sep=""),sep="\t",header=T) %>% as_tibble()
      if (i>1){
        temp<-inner_join(results,temp,by="Composite.Element.REF")
      }
      return(temp)
    })[[1]]
    stopCluster(cl_2)
  }
  return(results)
})[[1]]
stopCluster(cl)

 

%% 自适应滤波语音去噪仿真 - LMS算法 clear all; close all; clc; % ===== 1. 加载语音信号并预处理 ===== 'laughter.wav', 'splat.wav', 'train.wav' [x, Fs] = audioread(audio_file); % 加载MATLAB内置语音信号 x = x(1:20000); % 截取前20000个样本 t = (0:length(x)-1)/Fs; % 时间向量 % 归一化处理 x = x / max(abs(x)); % ===== 2. 生成带噪语音信号 ===== noise = 0.5 * randn(size(x)); % 高斯白噪声 SNR_before = 10*log10(var(x)/var(noise)); % 输入信噪比计算 noisy_signal = x + noise; % 加噪语音 % ===== 3. LMS自适应滤波器参数设置 ===== M = 128; % 滤波器阶数 mu = 0.001; % 步长因子 (影响收敛速度和稳定性) n_samples = length(x); y = zeros(n_samples,1); % 滤波器输出 e = zeros(n_samples,1); % 误差信号 w = zeros(M,1); % 滤波器权重初始化 % ===== 4. LMS自适应滤波过程 ===== for n = M:n_samples % 获取当前输入向量 (最近的M个样本) u = noisy_signal(n:-1:n-M+1); % 滤波器输出 y(n) = w' * u; % 误差计算 (期望信号=纯净语音) e(n) = x(n) - y(n); % LMS权重更新 w = w + mu * e(n) * u; end % ===== 5. 计算性能指标 ===== % 输入信噪比 (dB) SNR_input = 10*log10(var(x)/var(noisy_signal-x)); % 输出信噪比 (dB) denoised_signal = e(M:end); % 有效去噪信号 clean_segment = x(M:end); % 对齐的纯净语音 SNR_output = 10*log10(var(clean_segment)/var(clean_segment-denoised_signal)); % 均方误差 (MSE) MSE = mean((clean_segment - denoised_signal).^2); % 分段信噪比 (SegSNR) frame_len = 256; % 帧长度 overlap = 128; % 帧重叠 SNR_seg = segsnr(denoised_signal, clean_segment, frame_len, overlap, Fs); % ===== 6. 结果可视化 ===== % 时域波形 figure('Position', [100, 100, 1200, 800]) subplot(3,1,1) plot(t, x, 'b') title('纯净语音信号') xlabel('时间(s)') ylabel('幅度') axis tight subplot(3,1,2) plot(t, noisy_signal, 'r') title(['带噪语音信号 (SNR = ', num2str(SNR_input, '%.2f'), ' dB)']) xlabel('时间(s)') ylabel('幅度') axis tight subplot(3,1,3) plot(t(M:end), denoised_signal, 'g') title(['去噪后信号 (SNR = ', num2str(SNR_output, '%.2f'), ' dB)']) xlabel('时间(s)') ylabel('幅度') axis tight % 频谱分析 NFFT = 1024; f = Fs/2*linspace(0,1,NFFT/2+1); X = fft(x(1:NFFT), NFFT); X_noisy = fft(noisy_signal(1:NFFT), NFFT); X_denoised = fft(denoised_signal(1:NFFT), NFFT); figure('Position', [100, 100, 1200, 600]) subplot(3,1,1) plot(f, 2*abs(X(1:NFFT/2+1)), 'b') title('纯净语音频谱') xlabel('频率(Hz)') ylabel('幅度') subplot(3,1,2) plot(f, 2*abs(X_noisy(1:NFFT/2+1)), 'r') title('带噪语音频谱') xlabel('频率(Hz)') ylabel('幅度') subplot(3,1,3) plot(f, 2*abs(X_denoised(1:NFFT/2+1)), 'g') title('去噪后语音频谱') xlabel('频率(Hz)') ylabel('幅度') % ===== 7. 播放音频 ===== % disp('播放纯净语音...'); % soundsc(x, Fs); % pause(length(x)/Fs + 1); % % disp('播放带噪语音...'); % soundsc(noisy_signal, Fs); % pause(length(x)/Fs + 1); % % disp('播放去噪语音...'); % soundsc(denoised_signal, Fs); % ===== 8. 性能指标输出 ===== fprintf('===== 性能指标对比 =====\n'); fprintf('输入信噪比 (SNR): %.2f dB\n', SNR_input); fprintf('输出信噪比 (SNR): %.2f dB\n', SNR_output); fprintf('信噪比改善量 (ΔSNR): %.2f dB\n', SNR_output - SNR_input); fprintf('均方误差 (MSE): %.6f\n', MSE); fprintf('分段信噪比 (SegSNR): %.2f dB\n', SNR_seg); % ===== 自定义函数:分段信噪比计算 ===== function snr_seg = segsnr(enhanced, clean, frame_len, overlap, fs) % 分帧处理 step = frame_len - overlap; frames_clean = buffer(clean, frame_len, overlap, 'nodelay'); frames_enhanced = buffer(enhanced, frame_len, overlap, 'nodelay'); % 计算每帧信噪比 snr_list = zeros(1, size(frames_clean,2)); for i = 1:size(frames_clean,2) signal_power = sum(frames_clean(:,i).^2); noise_power = sum((frames_clean(:,i) - frames_enhanced(:,i)).^2); % 避免除零 if noise_power == 0 snr_frame = 50; % 设置上限 else snr_frame = 10*log10(signal_power/noise_power); % 限制在合理范围内 snr_frame = max(min(snr_frame, 50), -10); end snr_list(i) = snr_frame; end % 去除静音帧 (能量低于最大能量30dB的帧) energy = sum(frames_clean.^2); max_energy = max(energy); silence_threshold = max_energy / 1000; % -30dB active_frames = energy > silence_threshold; % 计算平均分段信噪比 snr_seg = mean(snr_list(active_frames)); end
最新发布
11-26
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FarmerJohn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值