-
邀请数据公示信息如下:1、符合条件的邀请人数公示见本论坛贴附件,PC端下载后查看!2、被邀请的人必须是新注册开发者+报名任意1门课程+首次领取华为开发者空间,才是符合条件的邀请3、工作日每周一、三、五18点前更新邀请数据 【活动时间】2025年9月30日—2025年10月30日活动报名链接:cid:link_0【活动福利】1、邀请新用户注册华为云+领取开发者空间+报名课程,最高可领6000元云资源券(可购买、续费云服务)。邀请新用户+领取开发者空间+课程报名云资源券金额4人120元8人240元15人450元20人600元40人1200元60人1800元80人2400元100人3000元150人4500元200人6000元2、新用户完成指定任意课程学习进度100%可参与抽奖,抽开发者定制双肩包、水杯等礼品。课程列表(含报名入口)DeepSeek大模型服务API发布与调用基于DeepSeek搭建Agent智能助手DeepSeek + AI编程助手Cline自动化游戏开发MCP协议基础与MCP Server服务实践MCP协议高级应用与AI助手协同理论(1)每人仅有一次抽奖机会,务必先完成上述任意一门课程学习进度100%再抽奖→(点此抽奖),先抽奖再完成学习无法获得奖品!(2)中奖名单会在活动结束后统一公示,请耐心等待! 点击前往活动页,可领取考试代金券及查看详细福利。
-
appcube怎么编写导入导出excel功能,并且后端进行测试
-
怎么获取当前登录账号的用户的姓名?
-
体验华为开发者空间《【案例共创】基于华为开发者空间-云开发环境,Vanna+MaaS实现自然语言与数据库对话》案例,反馈改进建议,请直接在评论区反馈即可。体验指导:https://devstation.connect.huaweicloud.com/space/devportal/casecenter/f5dc883bde2149a6ad6764fe432373a1/1
-
华为云中部署模型服务哪个大模型可以使用API成功调用,求教程
-
案例介绍本案例应用基于MaaS结合Astro平台便捷的构造一个诗词生成网站系统,针对用户输入的主题及选择的类型采用Maas平台结合DeepSeek-R1智能输出。 一、概述1. 案例介绍华为开发者空间是专为全球开发者打造的一站式云端开发平台,致力于为每一位开发者提供云主机资源、全套开发工具及云上存储空间。平台汇聚了昇腾 AI、鸿蒙操作系统、鲲鹏处理器、GaussDB 数据库、欧拉操作系统等华为全栈根技术的开发工具与生态资源,配套丰富的实战案例与技术指导,助力开发者从编码开发、调试测试到创新应用,轻松上手、快速进阶。依托华为根技术生态,开发者空间为技术探索、应用创新与能力成长提供强有力的支持,让创新触手可及。华为开发者空间Astro低代码开发平台,提供面向界面、逻辑与数据对象的全方位可视化编排工具,支持通过“拖、拉、拽”等直观操作快速搭建应用。开发者无需编写大量代码,即可实现应用的页面布局、交互逻辑与数据模型的高效配置,真正享受“所见即所得”的敏捷开发体验。通过极简的操作流程,大幅缩短开发周期,提升开发效率,让创新想法快速落地为可用应用。本案例应用基于MaaS结合Astro平台便捷的构造一个诗词生成网站系统,针对用户输入的主题及选择的类型采用Maas平台结合DeepSeek-R1智能输出。通过实际项目操作流程,带领大家深入浅出地掌握如何高效利用 Astro 低代码平台进行应用开发。在本次实践中,您将系统学习 Astro 平台的核心功能,包括模型集成、可视化界面拖拽、页面布局设计、业务逻辑配置,直至应用打包发布的完整开发链路。通过 hands-on 的方式,全面掌握 Astro 低代码平台的基础操作,并深入体验其与大模型能力的深度融合,切实感受低代码技术在提升开发效率、降低开发门槛方面的显著优势。2. 适用对象企业个人开发者高校学生3. 案例时间本案例总时长预计90分钟。4. 案例流程说明:领取华为开发者空间,登录华为开发者空间-低代码应用开发平台新建低代码应用,进入Astro轻应用服务控制台主页,开发应用5. 资源总览本案例预计花费0元。资源名称规格单价(元)时长(分钟)MaaS 平台商用模型DeepSeek-R1 轻量体验包(¥7.00)/ DeepSeek-V3 轻量体验包(¥3.50)领券免费90华为开发者空间 - 低代码应用开发平台系统标配免费90 二、MaaS平台商用模领取整体流程: DeepSeek-R1/V3-64K百万tokens代金券:cid:link_0 代金券使用说明: 购买DeepSeek Tokens套餐包,DeepSeek-R1 轻量体验包(¥7.00)或DeepSeek-V3 轻量体验包(¥3.50); 进入ModelArts Studio服务页面—在线推理—商用服务—DeepSeek-V3/R1-64K—开通服务—API Key配置; 点击DeepSeek-R1/V3-64K百万tokens代金券领取,领取相应的商用代金券,用来开通商用deepseek服务。进入页面后, 点击【立即申请】即可领取成功领取成功后,根据使用说明中的步骤进行使用,首先点击购买DeepSeek入口,进行套餐购买(记得使用领取的优惠券0元购买),购买成功后点击ModelArts Studio服务页面进入MaaS平台。 进入Maas平台后,搜索R1模型进行开通默认勾选所有模型,如果不需要的话可以取消勾选。点击开通服务后面的【调用说明】按钮,可以看到关于API KEY管理,我们使用的核心点就是这个 API KEY ,主要用这个去调用 ,所以大概需要点击API KEY去生成并记录。这里我们就不在赘述流程了。因为比较简单。开通完成API Key后,Maas的领取流程就结束了。相对是很简单的,我们主要需要记住以下2点:1、模型名称:DeepSeek-R12、API Key : 我们自己生成的。三、华为开发者空间-低代码应用开发平台1. 登录华为开发者空间-低代码应用开发平台华为开发者空间Astro低代码开发平台,提供面向界面、逻辑与数据对象的全方位可视化编排工具,支持通过“拖、拉、拽”等直观操作快速搭建应用。开发者无需编写大量代码,即可实现应用的页面布局、交互逻辑与数据模型的高效配置,真正享受“所见即所得”的敏捷开发体验。通过极简的操作流程,大幅缩短开发周期,提升开发效率,让创新想法快速落地为可用应用。登录华为开发者空间,在左侧菜单列表选择华为开发者空间 -> 开发平台 -> Astro 低代码开发,进入华为开发者空间-低代码应用开发平台。点击【新建低代码应用】创建一个新的应用。点击【标准应用】- 【确定】 创建 一个标准低代码应用填写命名空间,点击【确定】开始正式创建标准应用填写必要的名称和标签后,点击确认正式创建成功 创建成功会自动打开一个新的tab页面2. 低代码应用开发平台-模型关联我们优先来关联一下模型,关联完成模型后在创建页面来使用模型。在关联模型前,我们了解一下模型的流程,主要2点。1、关联模型核心是调用模型接口,我们通过连接器对模型进行连接。2、连接创建后通过编排逻辑,将输入与输出封装,并调用 连接器进行模型调用 。连接器创建【集成】-【连接器实例】-【Maas云平台】-【创建】填写标签、名称 :自定义填写模型名称:DeepSeek-R1API Key: 在开通模型时提到的api key创建。填写完成后点击保存连接器就创建成功了可以看到创建成功的连接器,同时连接器详情下面有一个测试。通过测试功能可测试大模型是否成功调用。大家自行测试一下,输入内容能正常输出结果,则无误,否则请检查配置的api key.逻辑编排对于逻辑的编排我们可以简单思考一下,这就像我们封装一个方法一样,肯定会有输入输出才可以进行整体逻辑的编排。所以我们先创建一下输入和输出的参数。点击【数据】-结构体【创建】,在弹出的创建结构体页面中填写名称和唯一标识,点击保存即可创建完成结构体。创建完成后我们需要配置结构体实际的结构。选择结构体,【结构】-【编辑】 开始进行结构体编辑创建实际的结构体内容,包括了role角色和提示词内容content入参结构体创建成功后,因为智能体返回的结果是字串,所以我们不需要创建其他结构体了。我们开始进行编排逻辑。点击【逻辑】-编排【创建】,在添加服务编排弹层中填写标签和名称,这里名称就是后面需要调用的名称。可以理解为函数名称。添加成功后,我们可以看到如下的逻辑编排页面,点击【开始按钮】,可以看到右上角有一个功能是【全局上下文】,这里可以定义上下文所需要的变量信息。我们先直接创建2个变更 ,输入和输出。在下面截图第4点中可以直接修改名称,如果名称错误想重新修改点击变量后面的三个【...】可修改。创建完成基础变量后,我们创建一个对象变量,这个对象变量就是实际调用模型的变量了。点击对象变量【创建】,在弹层中切换到【全局结构体】,名称可以自定义,全局结构体字段选择上面创建的结构体,勾选是否为数组,点击保存,即可创建成功。变量成功创建后,我们开始编排,首先对入口进行参数绑定。接下来我们创建一个赋值,一个连接器,并将其连接起来。赋值:意思是将input输入的字符进行转换赋值为连接器所需要的参数。连接器:就是我们创建的Maas服务,当赋值转换成功后就可调用。添加完成后,我们开始对赋值进行转换。点击【赋值】,将对象变量中的2个参数拖拽添加到变更中,操作符选择= , 角色的值为:"user"固定的,内容则为输入变量(直接拖拽)。转换成功后,我们配置连接器并绑定变量。点击【连接器】后,在基本信息中绑定连接器。切换到连接器参数配置中,绑定输入和输出参数,需要注意的是output变量 是任意类型,不然绑定会失败。如果不是任意类型点击变量 后面【...】进行类型切换。完成后,我们【保存】-【启用】-【运行】开始做一下编排的测试。输入 参数 输出结果 3、功能开发基础准备通过界面功能,开始创建新的界面。点击【界面】-页面【创建】,在弹层中填写标签和名称,点击添加创建完成后我们可以看到下面的操作界面。基础组件:基础的一些组件,如表单、容器等等,可以快速拖拽到页面中。页面内容:显示组件内容的模块。属性栏:针对组件进行相关的属性设置事件栏:对组件进行对应的事件设置。操作栏:保存、预览、全屏、切换电脑/手机在正式开始页面处理之前,我们先创建一个对象。用来接收用户输入的内容及智能体响应的内容。所以我们要有输入和输出字段。我们点击【数据】-对象【创建】,填写对象名称和唯一标识,点击确定创建对象。点击创建的对象,为对象来 添加描述和结果字段。正式开始创建页面,页面分为四块:1、标题2、banner3、输入栏4、输出栏标题添加一个【容器】,设置容器属性为弹性布局,对齐方式居中,再添加一个【标题】配置标题的内容和颜色、字体等banner添加【图片】,上传自定义图片后,设置图片宽度为100%,高度100px输入添加【输入框】,配置标签名称及占位符内容,最后增加数据绑定点击后面的【设置】按钮,点击弹框中的【新增模型】输入自定义的模型名称,选择【对象】,点击【下一步】选择上面我们创建的对象,勾选描述和内容,点击【下一步】,然后点击【确定】。最后,将新增的模型message中的消息内容与输入框进行绑定。输出增加【多行输入框】组件,修改标签名称,最后绑定数据字段。最后一步,完成保存事件最后我们只需要将点击保存的事件完成,就完成 了整个操作流程,就是这样简单。点击【保存】-【事件】-点击【新建】,创建一个自定义js代码编写对应的js代码,核心逻辑是:获取页面上form表单的内容,组装好后发送到逻辑编排方法中,然后返回对应的结果,提交form表单保存。// 表单校验 var _form = context.$component.form; var validFlag = _form.formValidateUnPromise(); if (!validFlag) return false; // 序列化表单数据 var model = context.$model.ref("message").getData(); var modelCopy = JSON.parse(JSON.stringify(model)); // 处理非字符串字段 Object.keys(modelCopy).forEach(item => { if (modelCopy[item] && typeof modelCopy[item] !== "string") { modelCopy[item] = JSON.stringify(modelCopy[item]); } }); // 提取问题字段值 var message = modelCopy["sc__message__CST"] // 构建提示文本 var suggestionText = `你是一位诗人,请根据${message}来创作一首诗词`.replace(/"/g, "'"); // 初始化Flow var _flow = context.flow("sc__scss"); // 调用AI服务获取建议 try { // 提示信息 context.$message.info("正在生成诗词,请等待结果。。。。。。"); const resp = await _flow.run({ input: suggestionText }); const reader = resp.body.getReader(); const decoder = new TextDecoder(); let buffer = ''; let msg = ''; while (true) { const { done, value } = await reader.read(); if (done) break; buffer += decoder.decode(value); const lines = buffer.split('\n'); // 保留最后一行(可能不完整) buffer = lines.pop() || ''; for (const line of lines) { if (!line.trim()) continue; try { const jsonStr = line.startsWith('data: ') ? line.substring(6) : line; if (jsonStr.trim() === '[DONE]') continue; const obj = JSON.parse(jsonStr); const newMsg = obj?.choices[0]?.delta?.content || ''; if (newMsg) msg += newMsg; } catch (err) { console.warn('解析JSON失败,保留到下一轮处理:', err.message); buffer = line + '\n' + buffer; } } } // 最终保存结果 modelCopy.sc__content__CST = msg; context.$model.ref("message").setData(modelCopy); context.$model.ref("textarea_0").setData(msg) // 提交数据 const saveResult = await context.$model.ref("message").save(); if (saveResult.resCode == 0) { const recordId = saveResult.result[0]?.id; if (recordId) { // context.$page.loadStdPage('xiaocao__t_mass', "recordId=" + recordId); // // 成功消息 // context.$message.success('生成成功'); } } } catch (error) { console.error("AI服务调用失败:", error); // 可以添加错误处理逻辑,如显示错误信息 }完成后我们保存,预览。这就是最后的效果啦~ 我正在参加【案例共创】第7期 基于MaaS商用服务 + 华为开发者空间 - Astro 低代码开发平台构建低代码应用 cid:link_1
-
我在华为的开发者空间领取了免费的180小时的云主机,云主机配置好之后显示运行中,但是我从左下角不管是点“进入桌面”还是“进入远程终端”,打开的新的连接页面都是一直加载,十几二十分钟都一直是加载状态,根本就进不去,是什么问题呢?我也尝试重置过云主机。
-
用了最新版本24 cloudlink API, 调用 tsdk_init 返回失败, 错误码为:TSDK_E_MANAGER_ERR_GENERAL_ERROR0x100000116777217一般错误用21的版本就没问题. 请问谁知道原因吗?
-
案例介绍本案例面向学生及学生家长,面对学生成绩问题,借助大模型AI给出准确的建议及学习方向,做到让学生有方向,有目的,有次序的学习。 案例内容一、概述1. 案例介绍本案例开发一个给学生成绩提建议的系统,通过学生成绩加大模型分析,给出合理的学习建议。通过实际操作,了解如何利用Astro低代码平台开发应用。在这个过程中,学习从模型集成、界面操作、页面布置到逻辑实现以及应用打包一系列关键步骤,从而掌握Astro低代码平台的基本使用方法及于大模型的结合,体验其在应用开发中的优势。开发者空间Astro低代码开发平台通过平台提供的界面、逻辑、对象等可视化编排工具,以“拖、拉、拽”的方式来快速构建应用,从而实现所见即所得的应用开发构建体验。华为开发者空间,是为全球开发者打造的专属开发者空间,致力于为每位开发者提供一台云主机、一套开发工具和云上存储空间,汇聚昇腾、鸿蒙、鲲鹏、GaussDB、欧拉等华为各项根技术的开发工具资源,并提供配套案例指导开发者 从开发编码到应用调测,基于华为根技术生态高效便捷的知识学习、技术体验、应用创新。ModelArts Studio(MaaS)平台:是华为云推出的一款大模型即服务平台,可以一站式的对业界主流开源大模型进行部署托管,同时开放大模型API服务,可以结合业界主流Agent开发框架,轻松构建AI Agent应用。2. 适用对象企业个人开发者高校学生3. 案例时间本案例总时长预计90分钟。4. 案例流程说明:领取华为开发者空间,登录华为开发者空间-低代码应用开发平台;新建低代码应用,进入Astro轻应用服务控制台主页,开发应用;5. 资源总览本案例预计花费0元。资源名称规格单价(元)时长(分钟)MaaS 平台商用模型DeepSeek-R1 轻量体验包(¥7.00)/ DeepSeek-V3 轻量体验包(¥3.50)领券免费90华为开发者空间 - 低代码应用开发平台系统标配免费90二、案例准备新建Astro低代码应用 选择标准应用创建 配置应用名字 建立标准界面 数据对象建立 配置一个学生成绩对象 对学生成绩对象进行编辑 添加语文字段 添加数学字段 添加外语字段 添加历史字段 添加生物字段 添加化学字段 添加建议字段 结构体创建AImessage 建立起结构体AImessage用于后续大模型AI调用 界面创建1 创建学生分数统计界面并拖入表单 表单与对象模型建立连接 新建相关模型scoreData 配置相关模型 完成模型新增 选择相关模型 拖入表单标题 配置姓名输入框 姓名字段与数据模型中的name绑定 新增语文及其他科目,绑定方式与姓名相同 拖入相关容器用于容纳提交按钮 为按钮添加相关事件 javascript代码需要自行编写,可参考下面,该代码包含json数据处理,大模型提示词生成,新界面调用等 var _form = context.$component.form;var validFlag = _form.formValidateUnPromise();if (!validFlag) return false;// 序列化表单数据var model = context.$model.ref("scoreData").getData();var modelCopy = JSON.parse(JSON.stringify(model));// 处理非字符串字段Object.keys(modelCopy).forEach(item => { if (modelCopy[item] && typeof modelCopy[item] !== "string") { modelCopy[item] = JSON.stringify(modelCopy[item]); }});// 提取问题字段值var questionCodes = [];var subjects = ["name","yuwen", "shuxue", "waiyu", "lishi", "shengwu", "huaxue"];subjects.forEach(function(subject) { var fieldName = "feng_123__" + subject + "__CST"; questionCodes.push(modelCopy[fieldName] || "");});// 构建提示文本var suggestionText = `学生${questionCodes[0]}的各科成绩如下:- 语文:${questionCodes[1]}/150分- 数学:${questionCodes[2]}/150分 - 外语:${questionCodes[3]}/150分- 历史:${questionCodes[4]}/100分- 生物:${questionCodes[5]}/100分- 化学:${questionCodes[6]}/100分请根据以上成绩情况分析该学生的学习特点,并给出针对性的学习建议,200字以内。`.replace(/"/g, "'");//modelCopy.Astro_Test__questionCode7__CST = suggestionText;// 初始化Flowvar _flow = context.flow("feng_123__process");// 调用AI服务获取建议try { // 提示信息 context.$message.info("信息分析中,正在生成建议。。。。。。"); const resp = await _flow.run({ input: suggestionText }); const reader = resp.body.getReader(); const decoder = new TextDecoder(); let buffer = ''; let msg = ''; while (true) { const { done, value } = await reader.read(); if (done) break; buffer += decoder.decode(value); const lines = buffer.split('\n'); // 保留最后一行(可能不完整) buffer = lines.pop() || ''; for (const line of lines) { if (!line.trim()) continue; try { const jsonStr = line.startsWith('data: ') ? line.substring(6) : line; if (jsonStr.trim() === '[DONE]') continue; const obj = JSON.parse(jsonStr); const newMsg = obj?.choices[0]?.delta?.content || ''; if (newMsg) msg += newMsg; } catch (err) { console.warn('解析JSON失败,保留到下一轮处理:', err.message); buffer = line + '\n' + buffer; } } } // 最终保存结果 modelCopy.feng_123__suggestions__CST = msg; context.$model.ref("scoreData").setData(modelCopy); // 提交数据 const saveResult = await context.$model.ref("scoreData").save(); if (saveResult.resCode == 0) { const recordId = saveResult.result[0]?.id; if (recordId) { context.$page.loadStdPage('feng_123__result', "recordId=" + recordId); // 成功消息 context.$message.success('生成成功'); } }} catch (error) { console.error("AI服务调用失败:", error); // 可以添加错误处理逻辑,如显示错误信息} 大模型连接器建立点击集成、连接器实例、MaaS云平台、取名为feng_123__ai,模型名称填写DeepSeek-V3,及相关API key 大模型可用性测试 经测试可以正常运行 建立新的服务编排(后台) 创建新的服务编排 依次拖入赋值及刚创建的大模型 配置输入输出变量 配置出参、入参 赋值模块配置 大模型连接器配置 配置相关大模型参数 按顺序进行保存 界面创建2-Result 填写表单 同样引入模型 选择相关对象 拖入输入框 把输入框进行数据绑定绑定相关事件 同样的,采用Javascript读取对象的返回值,js代码需自行编写// json化方法function parseJSON(str) { var flag = false; try { JSON.parse(str); flag = true } catch (err) { flag = false; } return flag;}console.log('start')var recordId = context.$page.params.recordId;if (!recordId) return;console.log('middle')try { // 获取Object对象 var _object = context.object('feng_123__StudentScore__CST'); console.log(_object) // 查询满足条件数据 var _condition = { conjunction: 'AND', conditions: [{ field: 'id', operator: 'eq', value: recordId }] }; const res = await _object.query(_condition); if (res.resCode !== '0' || !res.result || res.result.length === 0) return; const data = res.result[0]; // 解析JSON字符串字段 Object.keys(data).forEach(item => { if (data[item] && parseJSON(data[item])) { try { const parsed = JSON.parse(data[item]); data[item] = parsed; } catch (e) { // 不是有效JSON,保持原值 } } }); $model.ref("resultForm").setData(data);} catch (err) { console.error("数据查询或处理失败:", err);} 测试阶段点击下图中预览 输入相关内容 大模型会对数据进行分析并返回相关建议 文章不支持zip格式的安装包上传,放在网盘里了链接: https://yun.139.com/shareweb/#/w/i/2qidE2NWWtzrd 提取码:459x 我正在参加【案例共创】第7期 基于MaaS商用服务 + 华为开发者空间 - Astro 低代码开发平台构建低代码应用 cid:link_2
-
体验华为开发者空间《【案例共创】华为开发者空间云开发环境 x DeepSeek打造全链路高效数据分析工作流》案例,反馈改进建议,请直接在评论区反馈即可。体验指导:https://devstation.connect.huaweicloud.com/space/devportal/casecenter/1476b44e28e84471b95a8c43753d2d79/1
-
体验华为开发者空间《华为开发者空间开发平台-云开发环境(容器)操作指导》案例,反馈改进建议,请直接在评论区反馈即可。体验指导:https://devstation.connect.huaweicloud.com/space/devportal/casecenter/1476b44e28e84471b95a8c43753d2d79/1
-
案例介绍2025年高考报名人数突破1300万,大部分学生在院校档次与专业兴趣的取舍焦虑,全国3005所高校、792个本科专业构成的选择矩阵远超个体认知负荷本案例开发一个大学择校推荐系统,根据学生成绩,专业兴趣,地域爱好等,基于人工智能大模型DeepSeek生成推荐的大学院校,帮助万千学子提供择校参考 案例内容一、概述1. 案例介绍本案例开发一个大学择校推荐系统,根据学生成绩,专业兴趣,地域爱好等,基于人工智能大模型DeepSeek生成推荐的大学院校通过实际操作,了解如何利用Astro低代码平台开发应用。在这个过程中,学习从模型集成、界面操作、页面布置到逻辑实现以及应用打包一系列关键步骤,从而掌握Astro低代码平台的基本使用方法及于大模型的结合,体验其在应用开发中的优势。开发者空间Astro低代码开发平台通过平台提供的界面、逻辑、对象等可视化编排工具,以“拖、拉、拽”的方式来快速构建应用,从而实现所见即所得的应用开发构建体验。华为开发者空间,是为全球开发者打造的专属开发者空间,致力于为每位开发者提供一台云主机、一套开发工具和云上存储空间,汇聚昇腾、鸿蒙、鲲鹏、GaussDB、欧拉等华为各项根技术的开发工具资源,并提供配套案例指导开发者 从开发编码到应用调测,基于华为根技术生态高效便捷的知识学习、技术体验、应用创新。ModelArts Studio(MaaS)平台:是华为云推出的一款大模型即服务平台,可以一站式的对业界主流开源大模型进行部署托管,同时开放大模型API服务,可以结合业界主流Agent开发框架,轻松构建AI Agent应用。2. 适用对象企业个人开发者高校学生3. 案例时间本案例总时长预计90分钟。4. 案例流程说明:领取华为开发者空间,登录华为开发者空间-低代码应用开发平台;新建低代码应用,进入Astro轻应用服务控制台主页,开发应用;5. 资源总览本案例预计花费0元。资源名称规格单价(元)时长(分钟)MaaS 平台商用模型DeepSeek-R1 轻量体验包(¥7.00)/ DeepSeek-V3 轻量体验包(¥3.50)领券免费90华为开发者空间 - 低代码应用开发平台系统标配免费90二、案例准备1、设计对象字段低代码平台中的对象(也可以称为Object)相当于传统方式开发业务系统时,数据库中创建的一个表。每个对象对应一张数据库表,用于保存业务系统需要的配置数据和业务数据。本用例会使用到对象来存储数据,建议提前设计好对象字段,避免后续手忙脚乱字段名称唯一标识字段类型字段说明大学择校推荐tuijian文本区用于返回推荐结果高考省份shengfen文本高考省份和文理科高考分数fenshu数字高考的分数兴趣与能力xingqu文本自身的兴趣爱好或者有哪方面的能力学校性质 xingzhi文本想选择的学校性质如本科专科性别xingbie文本性别,更好的结合性别来推荐学校希望就读城市或者地域chengshi文本希望就读的城市或地域 2、开通ModelArts Studio(MaaS)商用百万Token活动连接:每周畅领100万商用级Tokens!基于CloudMatrix384超节点,Token时延低、TPM/RPM速率高,助您开发商用级AI应用!商用百万Token代金券免费领取链接(可每周领取):DeepSeek-R1/V3-64K百万tokens代金券:cid:link_22.1、大模型领取:切换到开发者空间首页,或者点击上面连接,参与活动“百万商用服务tokens免费领!”活动,按照使用说明进行服务开通:活动页面:2.2、开通完成后,进行大模型的接入:ModelArts控制台:ModelArts - Console模型部署页:部署页面,点击调用按钮,进入调用页面,这里我们提前保存好Api地址和模型名称,点击API调用说明:2.3、创建apikey点击前往API Key管理创建apikey,点击新建创建apikey注意!!创建好API Key之后,点击后面的复制按钮,妥善保存,若未复制保存,后续无法重新复制获取。 三、华为开发者空间-低代码应用开发平台开发应用1. 登录华为开发者空间-低代码应用开发平台华为开发者空间-低代码应用开发平台是华为云推出的一款可视化应用开发平台,旨在通过"拖拽式"组件和模板化设计,降低开发门槛,提升企业数字化应用构建效率。平台主要特点包括:可视化开发:通过图形化界面和预置组件,无需编写复杂代码即可快速搭建应用;全场景支持:覆盖Web、移动端、大屏等多终端应用开发;高效集成:内置连接器可快速对接华为云及其他主流企业系统;智能辅助:提供AI辅助开发能力,如智能表单生成、流程自动化等;企业级能力:具备权限管理、数据安全、高可用等企业所需特性。Astro平台特别适合业务人员与开发者协同创新,能大幅缩短应用交付周期,典型适用于OA审批、数据看板、轻量级业务系统等场景。登录华为开发者空间,在左侧菜单列表选择华为开发者空间 -> 开发平台 -> Astro 低代码开发,进入华为开发者空间-低代码应用开发平台。2. 创建低代码应用2.1、华为开发者空间-低代码应用开发平台页面点击新建低代码应用,在弹出的新建低代码应用对话框中,选择标准应用,点击确定按钮。 注:命名空间为租户数据唯一标识,为免重复,首次创建或使用工程时需定义命名空间。请务必慎重,一旦定义,不可修改,推荐使用公司前缀。本案例中使用xiaowuyun作为命名空间。2.2、在右侧弹出的新建空白应用配置页签中,配置应用名称和标签均为university。2.3、点击右下角确认按钮,平台会自动打开一个新的页面:Astro轻应用服务控制台。注:在点击确认后,在Astro轻应用管理页会同时新增一条刚才创建的名称为xxxx__university的应用,点击编辑同样可以进入Astro轻应用服务控制台。 3. 集成连接器大模型将外部接口集成zero并编写编排流程:在应用中,点击左侧集成 - 连接器实例 - 大模型 - MaaS云平台:点击右上角加号,创建自定义连接器,输入标“标签”(这里为ds,可自定义)、“名称”(这里填入MaaS,可自定义)、“模型名称”(前步保存的模型名称)和“APIKey”(前步保存的apiKey);点击保存:测试连通性,点击“测试”,在弹出框中输入测试内容后,点击测试等待返回结果,正常返回说明添加成功:4. 添加对象和全局结构体4.1、创建大学推荐记录对象进入大学推荐系统设计器界面,在左侧导航栏中,选择“数据”;单击对象后的“新建对象”图标,进入创建新对象页面;设置对象基本信息:填写对象名称为“大学择校推荐系统”,唯一标识为“university”,单击“确定”按钮。4.2、创建字段4.2.1、 单击对象中的编辑图标,进入对象详情页:4.2.2 点击“添加”,添加字段:显示名称“高考省份”,唯一标识:“shengfen”,点击字段类型,选择“文本”类型,点击“确定”:4.2.3 、相同的操作,添加显示名称“大学择校推荐 ”,唯一标识“tuijian”,类型“文本区”:参考如让步骤,把案例准备设计的字段全部创建,添加完如下图字段名称唯一标识字段类型字段说明大学择校推荐tuijian文本区用于返回推荐结果高考省份shengfen文本高考省份和文理科高考分数fenshu数字高考的分数兴趣与能力xingqu文本自身的兴趣爱好或者有哪方面的能力学校性质 xingzhi文本想选择的学校性质如本科专科性别xingbie文本性别,更好的结合性别来推荐学校希望就读城市或者地域chengshi文本希望就读的城市或地域4.3、创建全局结构体:4.3.1、 点击左侧菜单栏数据,选择结构体新增,输入名称和唯一标识(可自定义,这里选择message为例),创建结构体4.3.2、创建完成后点击结构,选择结构体编辑按钮,添加的字段新增role和content,保存:5. 开发推荐系统页面5.1、创建系统页面在新版应用设计器的“界面”中,单击页面后的添加图标,设置页面标签为“大学择校推荐”、名称为“university”,单击“添加”,即可创建一个标准页面:5.2、添加并设置表单从左侧“组件”区域,将“表单”组件拖拽到页面中间,元数据表单配置向导点击“取消”:设置表单属性:如设置布局为宽“800px”和高“1024px”、居中对齐,设置字体大小为“16px”、行高为“23”等。(可自定义)设置数据绑定,点击数据绑定后的“设置”图标,点击“新增模型”:设置模型名称为“formData”,来源选择“对象”,单击“下一步””选择对象”下拉框选择“大学择校推荐系统(xxx__university__CST)”,“选择字段”勾选全部字段,单击“下一步”:单击“确定”:勾选“formData”,单击“确定”:注:在弹出框中,选择“只绑定模型”5.3、添加大标题。从左侧“组件”区域,将“标题”组件拖拽到表单中间:设置标题属性:点击标题,在右侧菜单栏点击基本属性,设置标题内容为“大学择校推荐系统”:点击下方字体,如设置字体颜色为“#147AEC”、字体大小为“28px”、上下间距为“50”、位置为“center”。(可自定义)当前配置会生成对应的css样式,可以查看高级设置(无具体操作,供查看学习使用)。5.4、添加图片5.4.1、从左侧“组件”区域,将“图片”组件拖拽到标题下方:5.4.2、设置图片属性:单击“图片地址”后的“选择图片”图标,在选择图片界面,选中一张图片,单击“确定”,或者单击“上传图片”按钮,从本地电脑中选择一张图片上传即可:5.4.3 设置图片宽度为“100%”注:选择或上传图片,支持上传JPG、JPEG、PNG和GIF格式的图片,图片大小不超过1MB5.5、设置小标题参考步骤5.3,设置小标题,设置标题内容为“帮你解决高考志愿填报的难题,填写你的信息,我会尽力为你提供帮助,让我们一起为你的未来规划加油吧!”(可自定义),标题类型为“Hending2”;5.6、添加采集项15.6.1、在标准页面设计界面,从“基本组件 > 表单”中,拖拽“输入框”组件至表单工作区域:点击基本属性,设置标签内容输入“1、高考省份”,在表单校验中,打开必填开关,设置必填错误信息为“请输入你的高考省份”5.6.2、设置输入框属性:点击输入框,点击右侧菜单栏“数据绑定”中的“设置”图标,勾选“xxxx__shengfen__CST”,单击“确定”:注意:数据绑定时要跟自己设计的对象字段名称一一对应5.7、添加采集项2同上:从“基本组件 > 表单”中,拖拽“输入框”组件至表单工作区域:点击基本属性,设置标签内容输入“2、高考分数”,在表单校验中,打开必填开关,设置必填错误信息为“请输入你的高考分数”点击数据绑定中的设置图标,勾选“xxx__fenshu__CST”,单击“确定”。 5.8、添加采集项3同上:从“基本组件 > 表单”中,拖拽“输入框”组件至表单工作区域:点击基本属性,设置标签内容输入“3、兴趣能力”,点击数据绑定中的设置图标,勾选“xxx__xingqu_CST”,单击“确定5.9、添加采集项4同上:从“基本组件 > 表单”中,拖拽“复选按钮”组件至表单工作区域:点击基本属性,设置标签内容输入“4、学校性质(可选多个)”,设置选项如图,点击数据绑定中的设置图标,勾选“xxx__xingzhi_CST”,单击“确定5.10、添加采集项5在标准页面设计界面,从“基本组件 - 表单”中,拖拽“单选按钮”组件至表单工作区域。设置单选按钮属性。设置标签为“5,性别”,选项为“男 - 男”和“女 - 女”,点击数据绑定中的设置图标,勾选“xxx__xingbie_CST”,单击“确定5.11、添加采集项6同上:从“基本组件 > 表单”中,拖拽“输入框”组件至表单工作区域:点击基本属性,设置标签内容输入“6、希望就读城市或地域”,点击数据绑定中的设置图标,勾选“xxx__chengshi_CST”,单击“确定5.12、添加容器在标准页面设计界面,从“基本组件 > 布局”中,拖拽“容器”组件至表单工作区域。5.13、添加提交按钮:在标准页面设计界面,从“基本组件 > 基本”中,拖拽“按钮”组件至容器区域:5.13.1设置按钮属性:设置显示名称为“提交”,大小选择“默认”。5.13.2、设置按钮事件:首先切换到“事件”标签,单击加号,在“添加动作 > 自定义动作(名称可自定义) > 动作名称”代码区域中,输入代码,单击“创建”。粘贴代码后点击保存代码部分如下:其中代码中formData在步骤《5.2、添加并设置表单:》中创建的对象模型名称xiaowuyun_ds是步骤《3. 集成连接器大模型》绑定的MaaS大模型的实例连接器定义的标签,xiaowuyun__xxx_xxx的字段名前面的部分需要更改为用户自己的命名空间。其他对应修改,可参考如下完整代码####注释的部分// 表单校验var _form = context.$component.form;var validFlag = _form.formValidateUnPromise();if (!validFlag) return false;// 序列化表单数据var model = context.$model.ref("formData").getData();var modelCopy = JSON.parse(JSON.stringify(model));// 处理非字符串字段Object.keys(modelCopy).forEach(item => { if (modelCopy[item] && typeof modelCopy[item] !== "string") { modelCopy[item] = JSON.stringify(modelCopy[item]); }});// 提取问题字段值var questionCodes = [];const arr = ['shengfen', 'fenshu', 'xingqu','xingzhi', 'xingbie', 'chengshi']; ####修改为自己定义的字段名称for (let i = 0; i < arr.length; i++) { var fieldName = "xiaowuyun__" + arr[i] + "__CST"; #####修改为自己的命名空间 questionCodes.push(modelCopy[fieldName] || "");}// 构建提示文本var suggestionText = `你是一个专业的大学推荐助手,该学生高考省份为 ${questionCodes[0]},高考分数是 ${questionCodes[1]}分,兴趣与能力是 ${questionCodes[2]},希望上的大学学校性质为:${questionCodes[3]},性别是 ${questionCodes[4]} 生,希望就读城市或者地域为 :${questionCodes[5]}。请根据以上信息给出该学生进行大学推荐,推荐内容包含大学的介绍和特色。`.replace(/"/g, "'");// 初始化Flowvar _flow = context.flow("xiaowuyun__ds"); #####修改为自己创建大模型集成器的名称// 调用AI服务获取建议try { // 提示信息 context.$message.info("信息分析中,正在生成建议。。。。。。"); const resp = await _flow.run({ input: suggestionText }); const reader = resp.body.getReader(); const decoder = new TextDecoder(); let buffer = ''; let msg = ''; while (true) { const { done, value } = await reader.read(); if (done) break; buffer += decoder.decode(value); const lines = buffer.split('\n'); // 保留最后一行(可能不完整) buffer = lines.pop() || ''; for (const line of lines) { if (!line.trim()) continue; try { const jsonStr = line.startsWith('data: ') ? line.substring(6) : line; if (jsonStr.trim() === '[DONE]') continue; const obj = JSON.parse(jsonStr); const newMsg = obj?.choices[0]?.delta?.content || ''; if (newMsg) msg += newMsg; } catch (err) { console.warn('解析JSON失败,保留到下一轮处理:', err.message); buffer = line + '\n' + buffer; } } } // 最终保存结果 modelCopy.xiaowuyun__tuijian__CST = msg; #### ####修改为自己命名空间和定义的字段名称 context.$model.ref("formData").setData(modelCopy); // 提交数据 const saveResult = await context.$model.ref("formData").save(); if (saveResult.resCode == 0) { const recordId = saveResult.result[0]?.id; if (recordId) { context.$page.loadStdPage('xiaowuyun__suggestion', "recordId=" + recordId); // 成功消息 context.$message.success('生成成功'); } }} catch (error) { console.error("AI服务调用失败:", error); // 可以添加错误处理逻辑,如显示错误信息}6、添加逻辑编排6.1、添加服务编排点击左侧逻辑 - 编排 - 新建编排,名称填ds,模板类型默认,点击添加:6.2、新增变量点击右侧“全局上下文”,新增变量,创建变量 - input,类型为文本:创建变量 - output,类型为任意:6.3、新增对象变量创建对象变量 - messages,使用步骤3中创建的全局结构体,选择数组:6.4、添加配置开始图元点击画布上的开始图元,点击参数,将刚才创建的变量分别拖进入参和出参:6.5、添加配置赋值图元选择左侧赋值图元,拖入界面,并将开始图元与赋值图元连接:选择赋值图元,点击赋值按钮,将变量赋值,第一行为刚才的全局结构体变量名称“messages[0].role”,我们将值设置为"user"(要用英文双引号),第二行为全局结构体变量名称“messages[0].content”,变量值可直接将变量中的input拖入:6.6、添加配置连接器图元左侧选择连接器 - 自定义连接器,选择前面步骤我们创建的连接器。将其拖拽进页面,并将赋值图元与连接图元连接:点击连接器图元,点击基本信息,选中步骤《3. 集成连接器大模型》创建的大模型连接器:选择连接器按钮,将连接器的入参message为对象变量message拖拽入,输出参数result为变量output拖拽:注意:此处可以多试几次,动作有时候显示不出来6.7、保存测试编排点击保存,启用,运行测试:输入参数{"input":"我要上大学"},测试看是否成功,参数内容可以自定义,最好简单一些防止运行时间过久:7. 开发结果推荐页面7.1、添加页面点击导航栏界面,选择+号新建页面:输入标签"推荐"和名称"suggestion",点击添加:7.2、设置表单仿照步骤《5.2、添加并设置表单》界面格式,进行页面设置,从左侧组件栏将表单组件拖拽至页面,元数据表单配置向导点击取消,属性设置布局:宽800px,高1024px,居中。(设置可根据自己需要自定义):7.3、数据绑定点击属性 - 数据绑定 - 新增模型:按前述步骤设置模型名称为"form0",选择来源为对象:点击下一步,选择"大学择校推荐系统"并勾选所有字段:点击下一步,点击确定:选择刚创建好的模型,点击确定,选择只绑定模型:7.4、添加图片参考步骤《5.4、添加图片》,添加图片;7.5、添加多行输入框在标准页面设计界面,从“基本组件 - 表单”中,拖拽“多行输入框”组件至表单工作区域,点击数据绑定中的设置图标,勾选“XXX__suggestion__CS”,单击“确定标签 填入 根据您提供的信息,有如下推荐,预祝你选上心仪的大学;高度 - 自适应高度,其余参考下图;点击页面,创建自定义脚本,写入以下代码点击保存其中“xiaowuyun_xx_xx”类的字段需更换为自身的命名空间:修改为自己创建的命名空间和对象名称,对象名称为步骤《4.1、创建大学推荐记录对象》创建的对象名称 var _object = context.object('xiaowuyun__university__CST'); 完整代码如下:// json化方法function parseJSON(str) { var flag = false; try { JSON.parse(str); flag = true } catch (err) { flag = false; } return flag;}var recordId = context.$page.params.recordId;if (!recordId) return;try { // 获取Object对象 var _object = context.object('xiaowuyun__university__CST'); ####修改为自己创建的命名空间和对象名称 // 查询满足条件数据 var _condition = { conjunction: 'AND', conditions: [{ field: 'id', operator: 'eq', value: recordId }] }; const res = await _object.query(_condition); if (res.resCode !== '0' || !res.result || res.result.length === 0) return; const data = res.result[0]; // 解析JSON字符串字段 Object.keys(data).forEach(item => { if (data[item] && parseJSON(data[item])) { try { const parsed = JSON.parse(data[item]); data[item] = parsed; } catch (e) { // 不是有效JSON,保持原值 } } }); $model.ref("form0").setData(data);} catch (err) { console.error("数据查询或处理失败:", err);}8. 页面效果测试预览填报界面,进行功能调试、测试验证:点击页面左上角的预览图标如遇异常可以在数据-对象-对应对象数据里看到采集到的数据点击预览图标后会跳转大学推荐系统应用,然后填写大学推荐应用参数;提交完成时后跳转大学推荐页面; 至此案例结束,案例整体步骤比较多,后续各种调用其实都是根据定义名称来的,一定要先梳理好对象的命名规划,还有大模型、对象名称等要制定好,避免后续名字乱不好调用我正在参加【案例共创】第7期 基于MaaS商用服务 + 华为开发者空间 - Astro 低代码开发平台构建低代码应用 cid:link_3
-
华为云开发者空间基于昇腾NPU实现CT肺炎影像分割模型训练与推理本案例将介绍如何在华为云开发者空间的AI Notebook环境中,利用昇腾NPU 910B4硬件资源训练和推理一个用于CT肺炎影像分割的深度学习模型,涵盖从数据准备、预处理、模型构建、训练到推理可视化的完整深度学习工作流。首先,从OBS存储桶下载并解压了COVID-19 CT扫描数据集,该数据集包含原始CT扫描图像、肺部掩码、感染区域掩码以及肺部和感染区域的组合掩码。import os import zipfile # 下载数据集 if not os.path.exists('Covid-19.zip'): os.system('wget -q https://orangepi-ai-studio.obs.cn-north-4.myhuaweicloud.com/Covid-19.zip') # 解压数据集 if not os.path.exists('Covid-19'): zip_file = zipfile.ZipFile('Covid-19.zip') zip_file.extractall() zip_file.close() 读取数据集中的元数据并显示前5行:import pandas as pd data = pd.read_csv('Covid-19/metadata.csv') data.head() ct_scanlung_maskinfection_masklung_and_infection_mask0…/input/covid19-ct-scans/ct_scans/coronacases……/input/covid19-ct-scans/lung_mask/coronacase……/input/covid19-ct-scans/infection_mask/coron……/input/covid19-ct-scans/lung_and_infection_m…1…/input/covid19-ct-scans/ct_scans/coronacases……/input/covid19-ct-scans/lung_mask/coronacase……/input/covid19-ct-scans/infection_mask/coron……/input/covid19-ct-scans/lung_and_infection_m…2…/input/covid19-ct-scans/ct_scans/coronacases……/input/covid19-ct-scans/lung_mask/coronacase……/input/covid19-ct-scans/infection_mask/coron……/input/covid19-ct-scans/lung_and_infection_m…3…/input/covid19-ct-scans/ct_scans/coronacases……/input/covid19-ct-scans/lung_mask/coronacase……/input/covid19-ct-scans/infection_mask/coron……/input/covid19-ct-scans/lung_and_infection_m…4…/input/covid19-ct-scans/ct_scans/coronacases……/input/covid19-ct-scans/lung_mask/coronacase……/input/covid19-ct-scans/infection_mask/coron……/input/covid19-ct-scans/lung_and_infection_m…我们分别获取原始图像、肺部mask、感染mask、肺部和感染mask的文件路径:# 原始图像 ct_scan_sample_file = data.loc[0,'ct_scan'].replace('../input/covid19-ct-scans','Covid-19') # 肺部mask lung_mask_sample_file = data.loc[0,'lung_mask'].replace('../input/covid19-ct-scans','Covid-19') # 感染mask infection_mask_sample_file = data.loc[0,'infection_mask'].replace('../input/covid19-ct-scans','Covid-19') # 肺部和感染mask lung_and_infection_mask_sample_file = data.loc[0,'lung_and_infection_mask'].replace('../input/covid19-ct-scans','Covid-19') 安装nibabel库读取NIfTI格式的医学影像文件,使用matplotlib库进行可视化展示:!pip install nibabelimport numpy as np import nibabel as nib # 读取nifti文件 def read_nii_file(fileName): img = nib.load(fileName) img_data = img.get_fdata() img_data = np.rot90(np.array(img_data)) return img_data # 读取 ct_scan_imgs = read_nii_file(ct_scan_sample_file) lung_mas_imgs = read_nii_file(lung_mask_sample_file) infection_mask_imgs = read_nii_file(infection_mask_sample_file) lung_and_infection_mas_imgs = read_nii_file(lung_and_infection_mask_sample_file) # 查看大小 print(ct_scan_imgs.shape) print(lung_mas_imgs.shape) (512, 512, 301) (512, 512, 301) # 绘制 import matplotlib.pyplot as plt %matplotlib inline color_map = 'spring' layer_index = 180 fig = plt.figure(figsize=(20, 4)) plt.subplot(1, 4, 1) plt.imshow(ct_scan_imgs[:,:,layer_index], cmap='bone') plt.title('Original Image') plt.axis('off') plt.subplot(1,4,2) plt.imshow(ct_scan_imgs[:,:,layer_index], cmap='bone') mask_ = np.ma.masked_where(lung_mas_imgs[:,:,layer_index]== 0, lung_mas_imgs[:,:,layer_index]) plt.imshow(mask_, alpha=0.8, cmap=color_map) plt.title('Lung Mask') plt.axis('off') plt.subplot(1,4,3) plt.imshow(ct_scan_imgs[:,:,layer_index], cmap='bone') mask_ = np.ma.masked_where(infection_mask_imgs[:,:,layer_index]== 0, infection_mask_imgs[:,:,layer_index]) plt.imshow(mask_, alpha=0.8, cmap=color_map) plt.title('Infection Mask') plt.axis('off') plt.subplot(1,4,4) plt.imshow(ct_scan_imgs[:,:,layer_index], cmap='bone') mask_ = np.ma.masked_where(lung_and_infection_mas_imgs[:,:,layer_index]== 0, lung_and_infection_mas_imgs[:,:,layer_index]) plt.imshow(mask_, alpha=0.8, cmap=color_map) plt.title('Lung and Infection Mask') plt.axis('off') plt.show() 之后对数据进行标准化和归一化,划分训练集和测试集,并统一缩放到256x256的大小保存为npy文件。标准化x′=x−mean(x)σx'= \frac{x-mean(x)}{\sigma} x′=σx−mean(x)归一化x′=x−min(x)max(x)−min(x)x'= \frac{x-min(x)}{max(x)-min(x)} x′=max(x)−min(x)x−min(x)# 标准化 def standardize(data): # 计算均值 mean = data.mean() # 计算标准差 std = np.std(data) # 计算结果 standardized = (data - mean) / std return standardized # 归一化 def normalize(data): # 计算最大最小值 max_val = data.max() min_val = data.min() normalized = (data - min_val) / (max_val - min_val) return normalized std = standardize(ct_scan_imgs) normalize(std).max(),normalize(std).min() (1.0, 0.0) # 处理所有文件 import cv2 import glob train_file_list =[file_path.replace('../input/covid19-ct-scans','Covid-19') for file_path in data.loc[:,'ct_scan']] train_label_list = [file_path.replace('../input/covid19-ct-scans','Covid-19') for file_path in data.loc[:,'infection_mask']] train_file_list[:5], len(train_label_list), train_label_list[:5], len(train_file_list) (['Covid-19/ct_scans/coronacases_org_001.nii', 'Covid-19/ct_scans/coronacases_org_002.nii', 'Covid-19/ct_scans/coronacases_org_003.nii', 'Covid-19/ct_scans/coronacases_org_004.nii', 'Covid-19/ct_scans/coronacases_org_005.nii'], 20, ['Covid-19/infection_mask/coronacases_001.nii', 'Covid-19/infection_mask/coronacases_002.nii', 'Covid-19/infection_mask/coronacases_003.nii', 'Covid-19/infection_mask/coronacases_004.nii', 'Covid-19/infection_mask/coronacases_005.nii'], 20) from tqdm import tqdm for index in tqdm(range(len(train_file_list))): # 读取 img = nib.load(train_file_list[index]) mask = nib.load(train_label_list[index]) img_data = img.get_fdata() mask_data = mask.get_fdata().astype(np.uint8) # 标准化和归一化 std = standardize(img_data) normalized = normalize(std) # 分为训练数据和测试数据 if index < 17: save_dir = 'processed/train/' else: save_dir = 'processed/test/' # 遍历所有层,分层存入文件夹,存储路径格式:'processed/train/0/img_0.npy','processed/train/0/label_0.npy', layer_num = normalized.shape[-1] for i in range(layer_num): layer = normalized[:,:,i] mask = mask_data[:,:,i] # 缩放 layer = cv2.resize(layer, (256, 256)) mask = cv2.resize(mask, (256, 256), interpolation=cv2.INTER_NEAREST) # 创建文件夹 img_dir = save_dir + str(index) if not os.path.exists(img_dir): os.makedirs(img_dir) # 保存为npy文件 np.save(img_dir+'/img_'+str(i), layer) np.save(img_dir+'/label_'+str(i), mask) 100%|██████████| 20/20 [01:08<00:00, 3.44s/it] 同时采用imgaug库进行数据增强,包括图像的缩放、旋转和弹性变换等操作,以提升模型的泛化能力。!pip install imgaugimport imgaug as ia import imgaug.augmenters as iaa from torch.utils.data import Dataset from imgaug.augmentables.segmaps import SegmentationMapsOnImage class SegmentDataset(Dataset): def __init__(self,where='train',seq=None): # 获取数据 self.img_list = glob.glob('processed/{}/*/img_*'.format(where)) self.mask_list = glob.glob('processed/{}/*/img_*') # 数据增强pipeline self.seq = seq def __len__(self): # 返回数据大小 return len(self.img_list) def __getitem__(self, idx): # 获取具体每一个数据 # 获取图片 img_file = self.img_list[idx] mask_file = img_file.replace('img','label') img = np.load(img_file) # 获取mask mask = np.load(mask_file) # 如果需要数据增强 if self.seq: segmap = SegmentationMapsOnImage(mask, shape=mask.shape) img,mask = seq(image=img, segmentation_maps=segmap) # 直接获取数组内容 mask = mask.get_arr() # 灰度图扩张维度成张量 return np.expand_dims(img,0) , np.expand_dims(mask,0) # 数据增强处理流程 seq = iaa.Sequential([ iaa.Affine(scale=(0.8, 1.2), # 缩放 rotate=(-45, 45)), # 旋转 iaa.ElasticTransformation() # 变换 ]) 创建dataloader,开启8个线程一次加载16张图片进行处理。import torch import torch_npu from torch_npu.contrib import transfer_to_npu # 使用dataloader加载 batch_size = 16 num_workers = 8 train_dataset = SegmentDataset('train', seq) test_dataset = SegmentDataset('test', None) train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=batch_size, num_workers=num_workers, shuffle=True) test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=batch_size, num_workers=num_workers, shuffle=False) 我们可以查看单张图像增强后的效果:# 对同一个图片显示多次 fig = plt.figure(figsize=(12, 12)) for i in range(16): plt.subplot(4, 4, i+1) img , mask = train_dataset[101] plt.imshow(img[0], cmap='bone') mask_ = np.ma.masked_where(mask[0]== 0, mask[0]) plt.imshow(mask_, alpha=0.8, cmap="spring") plt.axis('off') plt.show() 数据准备完成后,我们开始从头构建Unet的网络结构。U-Net是一种经典的编码器-解码器结构,特别适用于医学图像分割任务。网络包含四个编码层和四个解码层,通过跳跃连接将编码器的特征图与解码器对应层进行融合,保留了丰富的空间信息。# 定义两次卷积操作 class ConvBlock(torch.nn.Module): def __init__(self,in_channels,out_channels): super().__init__() self.step = torch.nn.Sequential( # 第一次卷积 torch.nn.Conv2d(in_channels=in_channels,out_channels=out_channels,kernel_size=3,padding=1,stride=1), # ReLU torch.nn.ReLU(), # 第二次卷积 torch.nn.Conv2d(in_channels=out_channels,out_channels=out_channels,kernel_size=3,padding=1,stride=1), # ReLU torch.nn.ReLU() ) def forward(self,x): return self.step(x) class UNet(torch.nn.Module): def __init__(self): super().__init__() # 定义左侧编码器的操作 self.layer1 = ConvBlock(1,64) self.layer2 = ConvBlock(64,128) self.layer3 = ConvBlock(128,256) self.layer4 = ConvBlock(256,512) # 定义右侧解码器的操作 self.layer5 = ConvBlock(256+512,256) self.layer6 = ConvBlock(128+256,128) self.layer7 = ConvBlock(64+128,64) #最后一个卷积 self.layer8 = torch.nn.Conv2d(in_channels=64,out_channels=1,kernel_size=1,padding=0,stride=1) # 定一些其他操作 # 池化 self.maxpool = torch.nn.MaxPool2d(kernel_size=2) #上采样 self.upsample = torch.nn.Upsample(scale_factor=2,mode='bilinear') # sigmoid self.sigmoid = torch.nn.Sigmoid() def forward(self,x): # 对输入数据进行处理 # 定义下采样部分 # input:1X256x256, output: 64x256x256 x1 = self.layer1(x) # input:64x256x256, output: 64 x 128 x 128 x1_p = self.maxpool(x1) # input: 64 x 128 x 128 , output: 128 x 128 x 128 x2 = self.layer2(x1_p) # input:128 x 128 x 128 , output: 128 x 64 x 64 x2_p = self.maxpool(x2) # input: 128 x 64 x 64, output: 256 x 64 x 64 x3 = self.layer3(x2_p) #input:256 x 64 x 64, output: 256 x 32 x 32 x3_p = self.maxpool(x3) #input: 256 x 32 x 32, output: 512 x 32 x 32 x4 = self.layer4(x3_p) # 定义上采样 # input: 512 x 32 x 32,output: 512 x 64 x 64 x5 = self.upsample(x4) # 拼接,output: 768x 64 x 64 x5 = torch.cat([x5,x3],dim=1) # input: 768x 64 x 64,output: 256 x 64 x 64 x5 = self.layer5(x5) # input: 256 x 64 x 64,output: 256 x 128 x 128 x6 = self.upsample(x5) # 拼接,output: 384 x 128 x 128 x6 = torch.cat([x6,x2],dim=1) # input: 384 x 128 x 128, output: 128 x 128 x 128 x6 = self.layer6(x6) # input:128 x 128 x 128, output: 128 x 256 x 256 x7 = self.upsample(x6) # 拼接, output: 192 x 256 x256 x7 = torch.cat([x7,x1],dim=1) # input: 192 x 256 x256, output: 64 x 256 x 256 x7 = self.layer7(x7) # 最后一次卷积,input: 64 x 256 x 256, output: 1 x 256 x 256 x8 = self.layer8(x7) #sigmoid # x9= self.sigmoid(x8) return x8网络定义完成后我们可以安装torchsummary库将搭建好的模型可视化。!pip install torchsummary# 模型架构可视化 from torchsummary import summary # device device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") model = UNet().to(device) summary(model,(1, 256, 256)) [W compiler_depend.ts:623] Warning: expandable_segments currently defaults to false. You can enable this feature by `export PYTORCH_NPU_ALLOC_CONF = expandable_segments:True`. (function operator()) ---------------------------------------------------------------- Layer (type) Output Shape Param # ================================================================ Conv2d-1 [-1, 64, 256, 256] 640 ReLU-2 [-1, 64, 256, 256] 0 Conv2d-3 [-1, 64, 256, 256] 36,928 ReLU-4 [-1, 64, 256, 256] 0 ConvBlock-5 [-1, 64, 256, 256] 0 MaxPool2d-6 [-1, 64, 128, 128] 0 Conv2d-7 [-1, 128, 128, 128] 73,856 ReLU-8 [-1, 128, 128, 128] 0 Conv2d-9 [-1, 128, 128, 128] 147,584 ReLU-10 [-1, 128, 128, 128] 0 ConvBlock-11 [-1, 128, 128, 128] 0 MaxPool2d-12 [-1, 128, 64, 64] 0 Conv2d-13 [-1, 256, 64, 64] 295,168 ReLU-14 [-1, 256, 64, 64] 0 Conv2d-15 [-1, 256, 64, 64] 590,080 ReLU-16 [-1, 256, 64, 64] 0 ConvBlock-17 [-1, 256, 64, 64] 0 MaxPool2d-18 [-1, 256, 32, 32] 0 Conv2d-19 [-1, 512, 32, 32] 1,180,160 ReLU-20 [-1, 512, 32, 32] 0 Conv2d-21 [-1, 512, 32, 32] 2,359,808 ReLU-22 [-1, 512, 32, 32] 0 ConvBlock-23 [-1, 512, 32, 32] 0 Upsample-24 [-1, 512, 64, 64] 0 Conv2d-25 [-1, 256, 64, 64] 1,769,728 ReLU-26 [-1, 256, 64, 64] 0 Conv2d-27 [-1, 256, 64, 64] 590,080 ReLU-28 [-1, 256, 64, 64] 0 ConvBlock-29 [-1, 256, 64, 64] 0 Upsample-30 [-1, 256, 128, 128] 0 Conv2d-31 [-1, 128, 128, 128] 442,496 ReLU-32 [-1, 128, 128, 128] 0 Conv2d-33 [-1, 128, 128, 128] 147,584 ReLU-34 [-1, 128, 128, 128] 0 ConvBlock-35 [-1, 128, 128, 128] 0 Upsample-36 [-1, 128, 256, 256] 0 Conv2d-37 [-1, 64, 256, 256] 110,656 ReLU-38 [-1, 64, 256, 256] 0 Conv2d-39 [-1, 64, 256, 256] 36,928 ReLU-40 [-1, 64, 256, 256] 0 ConvBlock-41 [-1, 64, 256, 256] 0 Conv2d-42 [-1, 1, 256, 256] 65 ================================================================ Total params: 7,781,761 Trainable params: 7,781,761 Non-trainable params: 0 ---------------------------------------------------------------- Input size (MB): 0.25 Forward/backward pass size (MB): 706.50 Params size (MB): 29.69 Estimated Total Size (MB): 736.44 ----------------------------------------------------------------random_input = torch.randn(1, 1, 256, 256).to(device) output = model(random_input) output.shapetorch.Size([1, 1, 256, 256]) 最后定义损失函数和优化器,编写模型的训练代码,在昇腾NPU上训练50轮,使用Adam优化器和BCEWithLogitsLoss损失函数,并通过ReduceLROnPlateau调度器动态调整模型的学习率,每轮训练结束后保存模型的最优权重。import time from torch.optim.lr_scheduler import ReduceLROnPlateau # 定义损失 loss_fn = torch.nn.BCEWithLogitsLoss() # 定义优化器 optimizer = torch.optim.Adam(model.parameters(), lr=1e-4) # 动态减少LR scheduler = ReduceLROnPlateau(optimizer, 'min') # 计算测试集的loss def check_test_loss(loader,model): loss = 0 # 不记录梯度 with torch.no_grad(): for i, (x, y) in enumerate(loader): # 图片 x = x.to(device,dtype=torch.float32) # 标签 y = y.to(device,dtype=torch.float32) # 预测值 y_pred = model(x) #计算损失 loss_batch = loss_fn(y_pred, y) loss += loss_batch return loss / len(loader) !pip install tensorboard progressbar# 使用tensorboard记录参数 from torch.utils.tensorboard import SummaryWriter # 使用progressbar打印进度 from progressbar import ProgressBar, Percentage, Bar, Timer, ETA, FileTransferSpeed # 记录变量 writer = SummaryWriter(log_dir='./log') # 打印进度 widgets = ['Progress: ', Percentage(), ' ', Bar('#'), ' ', Timer(), ' ', ETA(), ' ', FileTransferSpeed()] # 训练100个epoch EPOCH_NUM = 50 # 记录最好的测试acc best_test_loss = 10 # 保存训练结果 train_loss_results = [] test_loss_results = [] for epoch in range(EPOCH_NUM): # 获取批次图像 print('Epoch:{}'.format(epoch+1)) start_time = time.time() loss = 0 progress = ProgressBar(widgets=widgets) for (x, y) in progress(train_loader): # !!!每次update前清空梯度 model.zero_grad() # 获取数据 # 图片 x = x.to(device,dtype=torch.float32) # 标签 y = y.to(device,dtype=torch.float32) # 预测值 y_pred = model(x) #计算损失 loss_batch = loss_fn(y_pred, y) # 计算梯度 loss_batch.backward() optimizer.step() optimizer.zero_grad() # 记录每个batch的train loss loss_batch = loss_batch.detach().cpu() loss += loss_batch # 每个epoch的loss loss = loss / len(train_loader) # 如果降低LR:如果loss连续10个epoch不再下降,就减少LR scheduler.step(loss) # 计算测试集的loss test_loss = check_test_loss(test_loader, model) # tensorboard 记录 Loss/train writer.add_scalar('Loss/train', loss, epoch) # tensorboard 记录 Loss/test writer.add_scalar('Loss/test', test_loss, epoch) #保存信息 train_loss_results.append(loss.item()) test_loss_results.append(test_loss.item()) # 保存最新模型 torch.save(model.state_dict(), 'unet_latest.pt') # 记录最好的测试loss,并保存模型 if best_test_loss > test_loss: print('test loss improved from {:.4f} to {:.4f}'.format(best_test_loss, test_loss.item())) best_test_loss = test_loss # 保存模型 torch.save(model.state_dict(), 'unet_best.pt') Epoch:1 Progress: 0% | | Elapsed Time: 0:00:00 ETA: --:--:-- 0.00 B/s . Progress: 100% |##############| Elapsed Time: 0:00:29 Time: 0:00:29 7.17 B/s test loss improved from 50.0000 to 0.1825 Epoch:2 Progress: 100% |##############| Elapsed Time: 0:00:26 Time: 0:00:26 7.90 B/s test loss improved from 0.1825 to 0.1356 Epoch:3 Progress: 100% |##############| Elapsed Time: 0:00:26 Time: 0:00:26 7.88 B/s test loss improved from 0.1356 to 0.1190 Epoch:4 Progress: 100% |##############| Elapsed Time: 0:00:26 Time: 0:00:26 7.88 B/s test loss improved from 0.1190 to 0.1071 Epoch:5 Progress: 100% |##############| Elapsed Time: 0:00:26 Time: 0:00:26 7.99 B/s test loss improved from 0.1071 to 0.0826 Epoch:6 Progress: 100% |##############| Elapsed Time: 0:00:26 Time: 0:00:26 7.98 B/s test loss improved from 0.0826 to 0.0783 Epoch:7 Progress: 100% |##############| Elapsed Time: 0:00:26 Time: 0:00:26 8.00 B/s Epoch:8 Progress: 100% |##############| Elapsed Time: 0:00:26 Time: 0:00:26 8.01 B/s test loss improved from 0.0783 to 0.0564 Epoch:9 Progress: 100% |##############| Elapsed Time: 0:00:26 Time: 0:00:26 8.01 B/s Epoch:10 Progress: 100% |##############| Elapsed Time: 0:00:26 Time: 0:00:26 8.02 B/s Epoch:11 Progress: 100% |##############| Elapsed Time: 0:00:26 Time: 0:00:26 7.96 B/s Epoch:12 Progress: 100% |##############| Elapsed Time: 0:00:26 Time: 0:00:26 8.00 B/s Epoch:13 Progress: 100% |##############| Elapsed Time: 0:00:26 Time: 0:00:26 7.99 B/s test loss improved from 0.0564 to 0.0546 Epoch:14 Progress: 100% |##############| Elapsed Time: 0:00:26 Time: 0:00:26 7.99 B/s Epoch:15 Progress: 100% |##############| Elapsed Time: 0:00:26 Time: 0:00:26 7.89 B/s Epoch:16 Progress: 100% |##############| Elapsed Time: 0:00:26 Time: 0:00:26 7.99 B/s Epoch:17 Progress: 100% |##############| Elapsed Time: 0:00:26 Time: 0:00:26 8.01 B/s Epoch:18 Progress: 100% |##############| Elapsed Time: 0:00:26 Time: 0:00:26 8.01 B/s test loss improved from 0.0546 to 0.0502 Epoch:19 Progress: 100% |##############| Elapsed Time: 0:00:26 Time: 0:00:26 8.02 B/s Epoch:20 Progress: 100% |##############| Elapsed Time: 0:00:26 Time: 0:00:26 8.00 B/s Epoch:21 Progress: 100% |##############| Elapsed Time: 0:00:26 Time: 0:00:26 7.98 B/s Epoch:22 Progress: 100% |##############| Elapsed Time: 0:00:26 Time: 0:00:26 8.00 B/s test loss improved from 0.0502 to 0.0434 Epoch:23 Progress: 100% |##############| Elapsed Time: 0:00:26 Time: 0:00:26 8.00 B/s Epoch:24 Progress: 100% |##############| Elapsed Time: 0:00:26 Time: 0:00:26 7.98 B/s Epoch:25 Progress: 100% |##############| Elapsed Time: 0:00:26 Time: 0:00:26 7.99 B/s Epoch:26 Progress: 100% |##############| Elapsed Time: 0:00:26 Time: 0:00:26 7.94 B/s Epoch:27 Progress: 100% |##############| Elapsed Time: 0:00:26 Time: 0:00:26 7.84 B/s Epoch:28 Progress: 100% |##############| Elapsed Time: 0:00:26 Time: 0:00:26 7.93 B/s Epoch:29 Progress: 100% |##############| Elapsed Time: 0:00:26 Time: 0:00:26 7.89 B/s Epoch:30 Progress: 100% |##############| Elapsed Time: 0:00:26 Time: 0:00:26 7.96 B/s Epoch:31 Progress: 100% |##############| Elapsed Time: 0:00:26 Time: 0:00:26 7.94 B/s Epoch:32 Progress: 100% |##############| Elapsed Time: 0:00:26 Time: 0:00:26 7.92 B/s Epoch:33 Progress: 100% |##############| Elapsed Time: 0:00:26 Time: 0:00:26 7.88 B/s Epoch:34 Progress: 100% |##############| Elapsed Time: 0:00:26 Time: 0:00:26 7.93 B/s Epoch:35 Progress: 100% |##############| Elapsed Time: 0:00:26 Time: 0:00:26 7.97 B/s Epoch:36 Progress: 100% |##############| Elapsed Time: 0:00:26 Time: 0:00:26 7.92 B/s Epoch:37 Progress: 100% |##############| Elapsed Time: 0:00:26 Time: 0:00:26 7.91 B/s Epoch:38 Progress: 100% |##############| Elapsed Time: 0:00:26 Time: 0:00:26 7.93 B/s Epoch:39 Progress: 100% |##############| Elapsed Time: 0:00:26 Time: 0:00:26 7.91 B/s Epoch:40 Progress: 100% |##############| Elapsed Time: 0:00:26 Time: 0:00:26 7.89 B/s Epoch:41 Progress: 100% |##############| Elapsed Time: 0:00:26 Time: 0:00:26 7.87 B/s Epoch:42 Progress: 100% |##############| Elapsed Time: 0:00:26 Time: 0:00:26 7.96 B/s Epoch:43 Progress: 100% |##############| Elapsed Time: 0:00:26 Time: 0:00:26 7.97 B/s Epoch:44 Progress: 100% |##############| Elapsed Time: 0:00:26 Time: 0:00:26 7.97 B/s test loss improved from 0.0434 to 0.0378 Epoch:45 Progress: 100% |##############| Elapsed Time: 0:00:26 Time: 0:00:26 7.96 B/s Epoch:46 Progress: 100% |##############| Elapsed Time: 0:00:26 Time: 0:00:26 7.91 B/s Epoch:47 Progress: 100% |##############| Elapsed Time: 0:00:26 Time: 0:00:26 8.00 B/s Epoch:48 Progress: 100% |##############| Elapsed Time: 0:00:26 Time: 0:00:26 7.99 B/s Epoch:49 Progress: 100% |##############| Elapsed Time: 0:00:26 Time: 0:00:26 7.98 B/s Epoch:50 Progress: 100% |##############| Elapsed Time: 0:00:26 Time: 0:00:26 8.00 B/s 在模型的训练过程中,我们可以在另一个终端中查看NPU的利用率:训练结束后我们使用matplotlib绘制模型的损失曲线,观察在训练过程中loss的收敛情况。plt.plot(range(1, len(train_loss_results)+1), train_loss_results, label='train_loss') plt.plot(range(1, len(test_loss_results)+1), test_loss_results, label='test_loss') plt.title('Model Loss') plt.legend() 这里我们加载模型在训练过程中的最优权重在测试集上评估模型的训练效果:model.load_state_dict(torch.load('unet_best.pt')) model.eval() UNet( (layer1): ConvBlock( (step): Sequential( (0): Conv2d(1, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (1): ReLU() (2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (3): ReLU() ) ) (layer2): ConvBlock( (step): Sequential( (0): Conv2d(64, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (1): ReLU() (2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (3): ReLU() ) ) (layer3): ConvBlock( (step): Sequential( (0): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (1): ReLU() (2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (3): ReLU() ) ) (layer4): ConvBlock( (step): Sequential( (0): Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (1): ReLU() (2): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (3): ReLU() ) ) (layer5): ConvBlock( (step): Sequential( (0): Conv2d(768, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (1): ReLU() (2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (3): ReLU() ) ) (layer6): ConvBlock( (step): Sequential( (0): Conv2d(384, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (1): ReLU() (2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (3): ReLU() ) ) (layer7): ConvBlock( (step): Sequential( (0): Conv2d(192, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (1): ReLU() (2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (3): ReLU() ) ) (layer8): Conv2d(64, 1, kernel_size=(1, 1), stride=(1, 1)) (maxpool): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False) (upsample): Upsample(scale_factor=2.0, mode='bilinear') (sigmoid): Sigmoid() ) class SegmentDataset(Dataset): def __init__(self,where='train',seq=None): # 获取数据 self.img_list =natsorted(glob.glob('processed/{}/*/img_*'.format(where))) self.mask_list =natsorted( glob.glob('processed/{}/*/img_*') ) # 数据增强pipeline self.seq = seq def __len__(self): # 返回数据大小 return len(self.img_list) def __getitem__(self, idx): # 获取具体每一个数据 # 获取图片 img_file = self.img_list[idx] mask_file = img_file.replace('img','label') img = np.load(img_file) # 获取mask mask = np.load(mask_file) # 如果需要数据增强 if self.seq: segmap = SegmentationMapsOnImage(mask, shape=mask.shape) img,mask = seq(image=img, segmentation_maps=segmap) # 直接获取数组内容 mask = mask.get_arr() # 灰度图扩张维度成张量 return np.expand_dims(img,0) , np.expand_dims(mask,0) !pip install natsortfrom natsort import natsorted # 使用dataloader加载 batch_size = 12 num_workers = 8 test_dataset = SegmentDataset('test',None) test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=batch_size, num_workers=num_workers, shuffle=False) !pip install celluloidfrom tqdm import tqdm from celluloid import Camera from IPython.display import Image # 将每层画面制作成视频 fig = plt.figure(figsize=(10, 10)) camera = Camera(fig) # 遍历所有数据 index = 0 for x, y in tqdm(test_dataset): # 输出输入 input = torch.tensor([x]).to(device,dtype=torch.float32) # 推理 y_pred = model(input) # 获取mask mask_data = (y_pred.detach().cpu().numpy()[0][0] > 0.5) plt.subplot(1, 2, 1) plt.imshow(x[0], cmap='bone') mask_ = np.ma.masked_where(y[0] == 0, y[0]) plt.imshow(mask_, alpha=0.8, cmap="spring") plt.title('truth') plt.axis('off') plt.subplot(1, 2, 2) plt.imshow(x[0], cmap='bone') mask_ = np.ma.masked_where(mask_data == 0, mask_data) plt.imshow(mask_, alpha=0.8, cmap="spring") plt.title('prediction') plt.axis('off') camera.snap() index +=1 if index > 500: break animation = camera.animate() 0%| | 0/177 [00:00<?, ?it/s]/home/service/.local/lib/python3.10/site-packages/torch_npu/contrib/transfer_to_npu.py:151: UserWarning: Creating a tensor from a list of numpy.ndarrays is extremely slow. Please consider converting the list to a single numpy.ndarray with numpy.array() before converting to a tensor. (Triggered internally at /pytorch/torch/csrc/utils/tensor_new.cpp:261.) return fn(*args, **kwargs) 100%|██████████| 177/177 [00:06<00:00, 29.07it/s] # convert the animation to a video animation.save('animation.gif', writer='imagemagick') Image(open('animation.gif','rb').read()) 可以看到,模型准确地分割出肺炎的病变区域,为医疗诊断提供决策支持。本案例充分体现了华为云昇腾AI平台在医学图像处理领域的强大计算能力和易用性,为医疗AI应用的开发提供了完整的实践范例。
-
案例介绍本案例开发一个sql生成助手,对于一些不经常写sql的开发,写sql时手忙脚乱,本案例旨在基于人工智能大模型DeepSeek根据需求帮助生成对应sql。 案例内容一、概述1. 案例介绍通过实际操作,利用Astro低代码平台开发一个最简单应用。在这个过程中,学习从模型集成、界面操作一系列关键步骤,从而掌握Astro低代码平台的基本使用方法及于大模型的结合,体验其在应用开发中的优势。开发者空间Astro低代码开发平台通过平台提供的界面、逻辑、对象等可视化编排工具,以“拖、拉、拽”的方式来快速构建应用,从而实现所见即所得的应用开发构建体验。华为开发者空间,是为全球开发者打造的专属开发者空间,致力于为每位开发者提供一台云主机、一套开发工具和云上存储空间,汇聚昇腾、鸿蒙、鲲鹏、GaussDB、欧拉等华为各项根技术的开发工具资源,并提供配套案例指导开发者 从开发编码到应用调测,基于华为根技术生态高效便捷的知识学习、技术体验、应用创新。ModelArts Studio(MaaS)平台:是华为云推出的一款大模型即服务平台,可以一站式的对业界主流开源大模型进行部署托管,同时开放大模型API服务,可以结合业界主流Agent开发框架,轻松构建AI Agent应用。2. 适用对象企业个人开发者高校学生3. 案例时间本案例总时长预计30分钟。4. 案例流程说明:领取华为开发者空间,登录华为开发者空间-低代码应用开发平台;新建低代码应用,进入Astro轻应用服务控制台主页,开发应用;5. 资源总览本案例预计花费0元。资源名称规格单价(元)时长(分钟)MaaS 平台商用模型DeepSeek-R1 轻量体验包(¥7.00)/ DeepSeek-V3 轻量体验包(¥3.50)领券免费30华为开发者空间 - 低代码应用开发平台系统标配免费30二、开通MaaS 平台商用模型商用百万Token活动连接:每周畅领100万商用级Tokens!基于CloudMatrix384超节点,Token时延低、TPM/RPM速率高,助您开发商用级AI应用!商用百万Token代金券免费领取链接(可每周领取):DeepSeek-R1/V3-64K百万tokens代金券:cid:link_21、大模型领取:切换到开发者空间首页,或者点击上面连接,参与活动“百万商用服务tokens免费领!”活动,按照使用说明进行服务开通:活动页面:2、开通完成后,进行大模型的接入:ModelArts控制台:ModelArts - Console模型部署页:部署页面,点击调用按钮,进入调用页面,这里我们提前保存好Api地址和模型名称,点击API调用说明:3、创建apikey点击前往API Key管理创建apikey点击新建创建apikey注意!!创建好API Key之后,点击后面的复制按钮,妥善保存,若未复制保存,后续无法重新复制获取。 三、华为开发者空间-低代码应用开发平台1. 登录华为开发者空间-低代码应用开发平台华为开发者空间-低代码应用开发平台是华为云推出的一款可视化应用开发平台,旨在通过"拖拽式"组件和模板化设计,降低开发门槛,提升企业数字化应用构建效率。平台主要特点包括:可视化开发:通过图形化界面和预置组件,无需编写复杂代码即可快速搭建应用;全场景支持:覆盖Web、移动端、大屏等多终端应用开发;高效集成:内置连接器可快速对接华为云及其他主流企业系统;智能辅助:提供AI辅助开发能力,如智能表单生成、流程自动化等;企业级能力:具备权限管理、数据安全、高可用等企业所需特性。Astro平台特别适合业务人员与开发者协同创新,能大幅缩短应用交付周期,典型适用于OA审批、数据看板、轻量级业务系统等场景。登录华为开发者空间,在左侧菜单列表选择华为开发者空间 -> 开发平台 -> Astro 低代码开发,进入华为开发者空间-低代码应用开发平台。2. 创建低代码应用1、华为开发者空间-低代码应用开发平台页面点击新建低代码应用,在弹出的新建低代码应用对话框中,选择标准应用,点击确定按钮。 注:命名空间为租户数据唯一标识,为免重复,首次创建或使用工程时需定义命名空间。请务必慎重,一旦定义,不可修改,推荐使用公司前缀。本案例中使用Astro_banjin作为命名空间。 2、在右侧弹出的新建空白应用配置页签中,配置应用名称和标签均为Job。3、点击右下角确认按钮,平台会自动打开一个新的页面:Astro轻应用服务控制台。注:在点击确认后,在Astro轻应用管理页会同时新增一条刚才创建的名称为Astro_Test__sql的应用,点击编辑同样可以进入Astro轻应用服务控制台。4、创建大模型连接器点击左侧集成 - 连接器实例 - 大模型 - MaaS云平台:点击右上角加号,创建自定义连接器,输入标“标签”(这里为sql,可自定义)、“名称”(这里填入MaaS,可自定义)、“模型名称”(前步保存的模型名称)和“APIKey”(前步保存的apiKey);点击保存:注意:这里一定要开通maas的商用服务,免费服务不可以添加结果:测试连通性,点击“测试”,在弹出框中输入测试内容后,点击测试等待返回结果,正常返回说明添加成功:5、添加页面 在新版应用设计器的“界面”中,单击页面后的添加图标,设置页面标签为“sql”、名称为“sql”,单击“添加”,即可创建一个标准页面:添加表单:从左侧“组件”区域,将智能化智能助手”组件拖拽到页面中间选中智能助手组件,在“属性 > 品牌名”中,输入“sql生成助手” 选中智能助手组件,在“属性 > 高级属性”中,打开“大模型”开关。在“默认大模型”中,单击“设置默认模型”,选择上面步骤中创建的大模型连接器单击页面上方的保存按钮,保存标准页面6、预览功能在已保存的标准页面中,单击左上角预览图标,进入预览页面。在智能助手的聊天框中,输入文字,例如“帮忙出一个update脚本,根据rq为2022年3月28到2022年5月1日,A表里的mc不为空而b表里的mc为空,A表的hm =b表的hm,A表的xh = b表的xxxh这几个条件做一个关联查询,然后将a里的mc赋值到b表里的mc”,单击“发送” 我正在参加【案例共创】第7期 基于MaaS商用服务 + 华为开发者空间 - Astro 低代码开发平台构建低代码应用 cid:link_4
上滑加载中
推荐直播
-
HDC深度解读系列 - Serverless与MCP融合创新,构建AI应用全新智能中枢2025/08/20 周三 16:30-18:00
张昆鹏 HCDG北京核心组代表
HDC2025期间,华为云展示了Serverless与MCP融合创新的解决方案,本期访谈直播,由华为云开发者专家(HCDE)兼华为云开发者社区组织HCDG北京核心组代表张鹏先生主持,华为云PaaS服务产品部 Serverless总监Ewen为大家深度解读华为云Serverless与MCP如何融合构建AI应用全新智能中枢
回顾中 -
关于RISC-V生态发展的思考2025/09/02 周二 17:00-18:00
中国科学院计算技术研究所副所长包云岗教授
中科院包云岗老师将在本次直播中,探讨处理器生态的关键要素及其联系,分享过去几年推动RISC-V生态建设实践过程中的经验与教训。
回顾中 -
一键搞定华为云万级资源,3步轻松管理企业成本2025/09/09 周二 15:00-16:00
阿言 华为云交易产品经理
本直播重点介绍如何一键续费万级资源,3步轻松管理成本,帮助提升日常管理效率!
回顾中
热门标签