Java jni调用nnom rnn-denoise 降噪

介绍:https://github.com/majianjia/nnom/blob/master/examples/rnn-denoise/README_CN.md
默认提供了一个wav的例子
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>#include "nnom.h"
#include "denoise_weights.h"#include "mfcc.h"
#include "wav.h"// the bandpass filter coefficiences
#include "equalizer_coeff.h" #define NUM_FEATURES NUM_FILTER#define _MAX(x, y) (((x) > (y)) ? (x) : (y))
#define _MIN(x, y) (((x) < (y)) ? (x) : (y))#define NUM_CHANNELS 1
#define SAMPLE_RATE 16000
#define AUDIO_FRAME_LEN 512// audio buffer for input
float audio_buffer[AUDIO_FRAME_LEN] = {0};
int16_t audio_buffer_16bit[AUDIO_FRAME_LEN] = {0};// buffer for output
int16_t audio_buffer_filtered[AUDIO_FRAME_LEN/2] = { 0 };// mfcc features and their derivatives
float mfcc_feature[NUM_FEATURES] = { 0 };
float mfcc_feature_prev[NUM_FEATURES] = { 0 };
float mfcc_feature_diff[NUM_FEATURES] = { 0 };
float mfcc_feature_diff_prev[NUM_FEATURES] = { 0 };
float mfcc_feature_diff1[NUM_FEATURES] = { 0 };
// features for NN
float nn_features[64] = {0};
int8_t nn_features_q7[64] = {0};// NN results, which is the gains for each frequency band
float band_gains[NUM_FILTER] = {0};
float band_gains_prev[NUM_FILTER] = {0};// 0db gains coefficient
float coeff_b[NUM_FILTER][NUM_COEFF_PAIR] = FILTER_COEFF_B;
float coeff_a[NUM_FILTER][NUM_COEFF_PAIR] = FILTER_COEFF_A;
// dynamic gains coefficient
float b_[NUM_FILTER][NUM_COEFF_PAIR] = {0};// update the history
void y_h_update(float *y_h, uint32_t len)
{for (uint32_t i = len-1; i >0 ;i--)y_h[i] = y_h[i-1];
}// equalizer by multiple n order iir band pass filter.
// y[i] = b[0] * x[i] + b[1] * x[i - 1] + b[2] * x[i - 2] - a[1] * y[i - 1] - a[2] * y[i - 2]...
void equalizer(float* x, float* y, uint32_t signal_len, float *b, float *a, uint32_t num_band, uint32_t num_order)
{// the y history for each bandstatic float y_h[NUM_FILTER][NUM_COEFF_PAIR] = { 0 };static float x_h[NUM_COEFF_PAIR * 2] = { 0 };uint32_t num_coeff = num_order * 2 + 1;// i <= num_coeff (where historical x is involved in the first few points)// combine state and new data to get a continual x input. memcpy(x_h + num_coeff, x, num_coeff * sizeof(float));for (uint32_t i = 0; i < num_coeff; i++){y[i] = 0;for (uint32_t n = 0; n < num_band; n++){y_h_update(y_h[n], num_coeff);y_h[n][0] = b[n * num_coeff] * x_h[i+ num_coeff];for (uint32_t c = 1; c < num_coeff; c++)y_h[n][0] += b[n * num_coeff + c] * x_h[num_coeff + i - c] - a[n * num_coeff + c] * y_h[n][c];y[i] += y_h[n][0];}}// store the x for the state of next roundmemcpy(x_h, &x[signal_len - num_coeff], num_coeff * sizeof(float));// i > num_coeff; the rest data not involed the x historyfor (uint32_t i = num_coeff; i < signal_len; i++){y[i] = 0;for (uint32_t n = 0; n < num_band; n++){y_h_update(y_h[n], num_coeff);y_h[n][0] = b[n * num_coeff] * x[i];for (uint32_t c = 1; c < num_coeff; c++)y_h[n][0] += b[n * num_coeff + c] * x[i - c] - a[n * num_coeff + c] * y_h[n][c];y[i] += y_h[n][0];} }
}// set dynamic gains. Multiple gains x b_coeff
void set_gains(float *b_in, float *b_out, float* gains, uint32_t num_band, uint32_t num_order)
{uint32_t num_coeff = num_order * 2 + 1;for (uint32_t i = 0; i < num_band; i++)for (uint32_t c = 0; c < num_coeff; c++)b_out[num_coeff *i + c] = b_in[num_coeff * i + c] * gains[i]; // only need to set b.
}void quantize_data(float*din, int8_t *dout, uint32_t size, uint32_t int_bit)
{float limit = (1 << int_bit); for(uint32_t i=0; i<size; i++)dout[i] = (int8_t)(_MAX(_MIN(din[i], limit), -limit) / limit * 127);
}void log_values(float* value, uint32_t size, FILE* f)
{char line[16];for (uint32_t i = 0; i < size; i++) {snprintf(line, 16, "%f,", value[i]);fwrite(line, strlen(line), 1, f);}fwrite("\n", 2, 1, f);
}int main(int argc, char* argv[])
{wav_header_t wav_header; size_t size;char* input_file = "sample.wav";char* output_file = "filtered_sample.wav";FILE* src_file;FILE* des_file;char* log_file = "log.csv";FILE* flog = fopen(log_file, "wb");// if user has specify input and output files. if (argc > 1)input_file = argv[1];if (argc > 2)output_file = argv[2];src_file = fopen(input_file, "rb");des_file = fopen(output_file, "wb");if (src_file == NULL) {printf("Cannot open wav files, default input:'%s'\n", input_file);printf("Or use command to specify input file: xxx.exe [input.wav] [output.wav]\n");return -1;}if (des_file == NULL){fclose(src_file); return -1; }// read wav file header, copy it to the output file. fread(&wav_header, sizeof(wav_header), 1, src_file);fwrite(&wav_header, sizeof(wav_header), 1, des_file);// lets jump to the "data" chunk of the WAV file.if (strncmp(wav_header.datachunk_id, "data", 4)){wav_chunk_t chunk = { .size= wav_header.datachunk_size};// find the 'data' chunkdo {char* buf = malloc(chunk.size);fread(buf, chunk.size, 1, src_file);fwrite(buf, chunk.size, 1, des_file);free(buf);fread(&chunk, sizeof(wav_chunk_t), 1, src_file);fwrite(&chunk, sizeof(wav_chunk_t), 1, des_file);} while (strncmp(chunk.id, "data", 4));}// NNoM modelnnom_model_t *model = model = nnom_model_create();// 26 features, 0 offset, 26 bands, 512fft, 0 preempha, attached_energy_to_band0mfcc_t * mfcc = mfcc_create(NUM_FEATURES, 0, NUM_FEATURES, 512, 0, true);printf("\nProcessing file: %s\n", input_file);while(1) {// move buffer (50%) overlapping, move later 50% to the first 50, then fill memcpy(audio_buffer_16bit, &audio_buffer_16bit[AUDIO_FRAME_LEN/2], AUDIO_FRAME_LEN/2*sizeof(int16_t));// now read the new datasize = fread(&audio_buffer_16bit[AUDIO_FRAME_LEN / 2], AUDIO_FRAME_LEN / 2 * sizeof(int16_t), 1, src_file);if(size == 0)break;// get mfccmfcc_compute(mfcc, audio_buffer_16bit, mfcc_feature);//log_values(mfcc_feature, NUM_FEATURES, flog);// get the first and second derivative of mfccfor(uint32_t i=0; i< NUM_FEATURES; i++){mfcc_feature_diff[i] = mfcc_feature[i] - mfcc_feature_prev[i];mfcc_feature_diff1[i] = mfcc_feature_diff[i] - mfcc_feature_diff_prev[i];}memcpy(mfcc_feature_prev, mfcc_feature, NUM_FEATURES * sizeof(float));memcpy(mfcc_feature_diff_prev, mfcc_feature_diff, NUM_FEATURES * sizeof(float));// combine MFCC with derivatives memcpy(nn_features, mfcc_feature, NUM_FEATURES*sizeof(float));memcpy(&nn_features[NUM_FEATURES], mfcc_feature_diff, 10*sizeof(float));memcpy(&nn_features[NUM_FEATURES+10], mfcc_feature_diff1, 10*sizeof(float));//log_values(nn_features, NUM_FEATURES+20, flog);// quantise them using the same scale as training data (in keras), by 2^n. quantize_data(nn_features, nn_features_q7, NUM_FEATURES+20, 3);// run the mode with the new inputmemcpy(nnom_input_data, nn_features_q7, sizeof(nnom_input_data));model_run(model);// read the result, convert it back to float (q0.7 to float)for(int i=0; i< NUM_FEATURES; i++)band_gains[i] = (float)(nnom_output_data[i]) / 127.f;log_values(band_gains, NUM_FILTER, flog);// one more step, limit the change of gians, to smooth the speech, per RNNoise paperfor(int i=0; i< NUM_FEATURES; i++)band_gains[i] = _MAX(band_gains_prev[i]*0.8f, band_gains[i]); memcpy(band_gains_prev, band_gains, NUM_FEATURES *sizeof(float));// apply the dynamic gains to each frequency band. set_gains((float*)coeff_b, (float*)b_, band_gains, NUM_FILTER, NUM_ORDER);// convert 16bit to float for equalizerfor (int i = 0; i < AUDIO_FRAME_LEN/2; i++)audio_buffer[i] = audio_buffer_16bit[i + AUDIO_FRAME_LEN / 2] / 32768.f;// finally, we apply the equalizer to this audio frame to denoiseequalizer(audio_buffer, &audio_buffer[AUDIO_FRAME_LEN / 2], AUDIO_FRAME_LEN/2, (float*)b_,(float*)coeff_a, NUM_FILTER, NUM_ORDER);// convert the filtered signal back to int16for (int i = 0; i < AUDIO_FRAME_LEN / 2; i++)audio_buffer_filtered[i] = audio_buffer[i + AUDIO_FRAME_LEN / 2] * 32768.f *0.6f; // write the filtered frame to WAV file. fwrite(audio_buffer_filtered, 256*sizeof(int16_t), 1, des_file);}// print some model infomodel_io_format(model);model_stat(model);model_delete(model);fclose(flog);fclose(src_file);fclose(des_file);printf("\nNoisy signal '%s' has been de-noised by NNoM.\nThe output is saved to '%s'.\n", input_file, output_file);return 0;
}
去掉wav的信息就能解析pcm了
创建cmake 文件 编译dll
cmake_minimum_required(VERSION 3.10)project(RnnDenoise)set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
include_directories(nnom-master/port/)
include_directories(nnom-master/inc/)
include_directories(nnom-master/examples/rnn-denoise/)
include_directories(D:/java/jdk1.8x64/include/)
include_directories(D:/java/jdk1.8x64/include/win32/)
set(EXPLICIT_SOURCESRnnDenoise.cnnom-master/examples/rnn-denoise/mfcc.c
)
file(GLOB_RECURSE SRC_FILES "nnom-master/src/*/*.c")
set(SOURCES ${EXPLICIT_SOURCES} ${SRC_FILES})add_library(RnnDenoise SHARED ${SOURCES})
java 库封装示例
package com.lilin.demoasr.nnom;public class RnnDenoise implements AutoCloseable{private long rnndenoise;public long getRnndenoise() {return rnndenoise;}public void setRnndenoise(long rnndenoise) {this.rnndenoise = rnndenoise;}private static final Object globalLock = new Object();/***https://github.com/majianjia/nnom/blob/master/examples/rnn-denoise/**** @throws Exception*/public RnnDenoise() throws Exception {synchronized (globalLock) {RnnLoad.load("RnnDenoise");}this.rnndenoise = createRnnDenoise0();}private static native long createRnnDenoise0();private native short[] denoise0(long rnndenoise,short[] var1);/*** 固定320 每次 可以修改c 改大* @param input* @return*/public short[] denoise(short[] input) {// synchronized (this) {return this.denoise0(this.rnndenoise ,input);// }}private native long destroyRnnDenoise0();public void close() {synchronized (this) {this.destroyRnnDenoise0();this.rnndenoise = 0L;}}public boolean isClosed() {synchronized (this) {return this.rnndenoise == 0L;}}
}
test:
public static void main (String[] args) {String sList []= new String[]{"G:\\work\\ai\\ZipEnhancer\\r1.pcm","C:\\Users\\\\lilin\\Desktop\\16k.pcm"};// String sList []= new String[]{"C:\\Users\\\\lilin\\Desktop\\16k.pcm"};List< Thread> lts= new ArrayList<>();for (int i = 0; i < sList.length; i++) {String file =sList[i];int finalI = i;lts.add(new Thread(new Runnable() {@Overridepublic void run() {try {RnnDenoise rnnDenoise = new RnnDenoise();System.out.println(rnnDenoise.getRnndenoise());FileInputStream f = new FileInputStream(file);FileOutputStream f1 = new FileOutputStream("C:\\Users\\\\lilin\\Desktop\\"+ finalI +".pcm");int n=0;byte[] z = new byte[640];while ((n = f.read(z)) != -1) {short [] sa = new short[320];ByteBuffer.wrap(z).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(sa);short[] denoisedAudio = rnnDenoise.denoise(sa);byte[] z1 = new byte[640];ByteBuffer.wrap(z1).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().put(denoisedAudio);f1.write(z1);}System.out.println(finalI+"end.");rnnDenoise.close();f1.close();}catch (Exception e){e.printStackTrace();}}}));}for (Thread y: lts ) {y.start();}for (Thread y: lts ) {try{ y.join();}catch (Exception e){e.printStackTrace();}}System.out.println("end...");}
}
nnom 默认的denoise_weights.h 是单例的无法同时创建多个实例 所以java无法在多线程使用, 可以自己更改下 主要涉及static变量和nnom_tensor_t 需要改用malloc的方式创建。
测试速度挺快的 ,几十分钟的很快降噪完成 ,也可以和freeswitch对接多路实时降噪 在识别,
如果模块或流程觉得麻烦可以到
https://item.taobao.com/item.htm?id=653611115230
视频教程yuexiajiayan的个人空间-yuexiajiayan个人主页-哔哩哔哩视频
相关文章:
Java jni调用nnom rnn-denoise 降噪
介绍:https://github.com/majianjia/nnom/blob/master/examples/rnn-denoise/README_CN.md 默认提供了一个wav的例子 #include <stdint.h> #include <stdlib.h> #include <stdio.h> #include <math.h> #include <string.h>#include …...
C++软件设计模式之状态模式
在C设计模式中,状态模式(State Pattern)是一种行为设计模式,它允许对象在内部状态改变时改变其行为,使对象看起来似乎修改了其类。状态模式的主要动机、意图和适用场合如下: 动机 在面向对象的设计中&…...
Microsoft Visual Studio中的/MT, /MTd,/MD,/MDd分别是什么意思?
1. /MT,/MTd,/MD,/MDd的含义 /MT,/MTd,/MD,/MDd是 Microsoft Visual C 编译器的运行时库链接选项。它们决定了程序如何链接 C 运行时库(CRT)。具体含义如下: /MT&#x…...
谷粒商城项目125-spring整合high-level-client
新年快乐! 致2025年还在努力学习的你! 你已经很努力了,今晚就让自己好好休息一晚吧! 在后端中选用哪种elasticsearch客户端? elasticsearch可以通过9200或者9300端口进行操作 1)9300:TCP spring-data-elasticsearch:transport-…...
日期时间选择(设置禁用状态)
目录 1.element文档需要 2.禁用所有过去的时间 3.设置指定日期的禁用时间 <template><div class"block"><span class"demonstration">起始日期时刻为 12:00:00</span><el-date-pickerv-model"value1"type"dat…...
基于SpringBoot的题库管理系统的设计与实现(源码+SQL+LW+部署讲解)
文章目录 摘 要1. 第1章 选题背景及研究意义1.1 选题背景1.2 研究意义1.3 论文结构安排 2. 第2章 相关开发技术2.1 前端技术2.2 后端技术2.3 数据库技术 3. 第3章 可行性及需求分析3.1 可行性分析3.2 系统需求分析 4. 第4章 系统概要设计4.1 系统功能模块设计4.2 数据库设计 5.…...
钉钉h5微应用安卓报错error29 ios报错error3 加上报错52013,签名校验失败 (前端)
这两个都是应为 免登报错52013,签名校验失败 用户后端签名使用的url地址和前端访问地址需要严格一致,包括端口号。前端部分可以用alert显示出当前的location.href,后端部分请在签名的时候打印日志。 访问通过反向代理服务器、各种NAT等场景下…...
Vue.js组件开发-客户端如何限制刷新Token次数
在Vue.js组件开发中,限制刷新Token的次数是一个重要的安全措施,可以防止恶意用户或攻击者无限次尝试刷新Token。 客户端限制 在客户端,可以通过Vuex、localStorage或sessionStorage等存储机制来跟踪刷新Token的尝试次数。以下是一个基本的实…...
Linux上安装jdk
在线环境的话,通过命令下载,离线环境的话,组要自行去oracle官网下载后上传 wget --no-check-certificate --no-cookies --header "Cookie: oraclelicenseaccept-securebackup-cookie" http://download.oracle.com/otn-pub/java/jd…...
Ardunio BLE keyboard 库的使用
为了开发一个 ardunio 的蓝牙选歌器,网络上普遍推荐使用: https://github.com/T-vK/ESP32-BLE-Keyboard 结果搞了好几天,就是不行。最后发现,下面两点非常重要: 使用 NimBle-ardunio 库这个库目前是2.1.2 ÿ…...
django --递归查询评论
表数据 树状结构 action(methods(GET, ), detailFalse) def get_info_pinglun(self, request, *args, **kwargs) -> Response:根据评论id查所有回复params wenxian_pinglun_id --> 评论id;wenxian_pinglun_id self.request.GET.get(wenxian_pinglun_id)results se…...
【开源免费】基于SpringBoot+Vue.JS音乐网站(JAVA毕业设计)
本文项目编号 T 109 ,文末自助获取源码 \color{red}{T109,文末自助获取源码} T109,文末自助获取源码 目录 一、系统介绍二、数据库设计三、配套教程3.1 启动教程3.2 讲解视频3.3 二次开发教程 四、功能截图五、文案资料5.1 选题背景5.2 国内…...
SUBSTRING_INDEX()在MySQL中的用法
语法: SUBSTRING_INDEX() 是 MySQL 中的一个字符串函数,它返回一个字符串,该字符串包含从字符串的开始或结束到指定的子字符串出现指定次数为止的部分。这个函数的语法如下: SUBSTRING_INDEX(string, delimiter, count)string&a…...
对45家“AI+安全”产品/方案的分析
一. 关键洞察 “AI+安全”创新非常活跃,一片百家争鸣之势,赛道选择上,以事件分诊Incident Triage、 安全辅助Security Copilots、自动化Automation三者为主为主,这充分反映了当前安全运营的主要需求,在产品理念选择上以 AI 和 自动化为主,这确实又切合上了在关键…...
Oracle Dataguard(主库为 Oracle 11g 单节点)配置详解(1):Oracle Dataguard 概述
Oracle Dataguard(主库为 Oracle 11g 单节点)配置详解(1):Oracle Dataguard 概述 目录 Oracle Dataguard(主库为 Oracle 11g 单节点)配置详解(1):Oracle Data…...
Pycharm 中 virtualenv、pipenv、conda 虚拟环境的用法
文章目录 前言虚拟环境的通俗介绍虚拟环境和非虚拟环境该怎么选?通过 Virtualenv 方式创建虚拟环境通过 Pipenv 方式创建虚拟环境通过 Conda 方式创建虚拟环境前言 在网上找了好一些资料,发现介绍 Pycharm 虚拟环境的不多,查了一些资料,并做个总结。 本文主要是介绍 Pycha…...
UNI-APP弹窗
组件代码 <template><view><!-- 蒙版 --><view class"mask" click"close()" v-show"tanchuang"></view><!-- 弹窗 --><view class"pop" :style"{height:height*0.8 px,top:tanchuang?…...
【大模型实战篇】LLaMA Factory微调ChatGLM-4-9B模型
1. 背景介绍 虽然现在大模型微调的文章很多,但纸上得来终觉浅,大模型微调的体感还是需要自己亲自上手实操过,才能有一些自己的感悟和直觉。这次我们选择使用llama_factory来微调chatglm-4-9B大模型。 之前微调我们是用两块3090GPU显卡&…...
【Cesium】三、实现开场动画效果
文章目录 实现效果实现方法实现代码组件化 实现效果 实现方法 Cesium官方提供了Camera的flyTo方法实现了飞向目的地的动画效果。 官方API:传送门 这里只需要用到目的地(destination)和持续时间(duration)这两个参数…...
#渗透测试#红蓝攻防#红队打点web服务突破口总结01
免责声明 本教程仅为合法的教学目的而准备,严禁用于任何形式的违法犯罪活动及其他商业行为,在使用本教程前,您应确保该行为符合当地的法律法规,继续阅读即表示您需自行承担所有操作的后果,如有异议,请立即停…...
利用最小二乘法找圆心和半径
#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …...
8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂
蛋白质结合剂(如抗体、抑制肽)在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上,高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术,但这类方法普遍面临资源消耗巨大、研发周期冗长…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院挂号小程序
一、开发准备 环境搭建: 安装DevEco Studio 3.0或更高版本配置HarmonyOS SDK申请开发者账号 项目创建: File > New > Create Project > Application (选择"Empty Ability") 二、核心功能实现 1. 医院科室展示 /…...
【配置 YOLOX 用于按目录分类的图片数据集】
现在的图标点选越来越多,如何一步解决,采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集(每个目录代表一个类别,目录下是该类别的所有图片),你需要进行以下配置步骤&#x…...
项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)
Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败,具体原因是客户端发送了密码认证请求,但Redis服务器未设置密码 1.为Redis设置密码(匹配客户端配置) 步骤: 1).修…...
HDFS分布式存储 zookeeper
hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架,允许使用简单的变成模型跨计算机对大型集群进行分布式处理(1.海量的数据存储 2.海量数据的计算)Hadoop核心组件 hdfs(分布式文件存储系统)&a…...
技术栈RabbitMq的介绍和使用
目录 1. 什么是消息队列?2. 消息队列的优点3. RabbitMQ 消息队列概述4. RabbitMQ 安装5. Exchange 四种类型5.1 direct 精准匹配5.2 fanout 广播5.3 topic 正则匹配 6. RabbitMQ 队列模式6.1 简单队列模式6.2 工作队列模式6.3 发布/订阅模式6.4 路由模式6.5 主题模式…...
【MATLAB代码】基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),附源代码|订阅专栏后可直接查看
文章所述的代码实现了基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),针对传感器观测数据中存在的脉冲型异常噪声问题,通过非线性加权机制提升滤波器的抗干扰能力。代码通过对比传统KF与MCC-KF在含异常值场景下的表现,验证了后者在状态估计鲁棒性方面的显著优…...
【LeetCode】算法详解#6 ---除自身以外数组的乘积
1.题目介绍 给定一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法,且在 O…...
nnUNet V2修改网络——暴力替换网络为UNet++
更换前,要用nnUNet V2跑通所用数据集,证明nnUNet V2、数据集、运行环境等没有问题 阅读nnU-Net V2 的 U-Net结构,初步了解要修改的网络,知己知彼,修改起来才能游刃有余。 U-Net存在两个局限,一是网络的最佳深度因应用场景而异,这取决于任务的难度和可用于训练的标注数…...
