首页
人工智能
网络安全
手机
搜索
登录
搜索
golden81
累计撰写
154
篇文章
累计收到
0
条评论
首页
栏目
首页
人工智能
网络安全
手机
自定义幻灯片
最新文章
2025-4-28
Clear NDR - Community 部署指南
Clear NDR - Community 是SELKS系统的升级版,对于许多中小型组织来说,它可以作为一个适合生产的网络安全监控(NSM)和入侵检测(IDS)解决方案。由于 Clear NDR - Community 中所有可用的数据都是由 Suricata 引擎生成的,因此它被网络安全从业者、研究人员、教育工作者、学生和爱好者广泛用于探索 Suricata IDS/IPS/NSM 以及它产生的网络协议监控日志和警报的可能性,以下简单介绍它的部署步骤和方法: 1. 环境准备 硬件要求:确保服务器或设备满足运行 Clear NDR - Community 的最低硬件要求(如 CPU 4+ Core、内存 16GB 、存储100GB等)。通常需要一台运行 Linux 系统的服务器。 操作系统:建议使用支持的 Linux 发行版(如 Ubuntu、CentOS 或 Debian)。 网络配置:确保服务器能够访问网络流量,并配置适当的网络接口以捕获流量。 2. 安装依赖 Clear NDR - Community 依赖于 Suricata 引擎和其他开源工具。在部署之前,需要安装以下依赖: Suricata:用于网络流量分析和入侵检测。 Elasticsearch:用于存储和索引数据。 Logstash:用于数据处理和转发。 Kibana:用于可视化和分析数据。 其他工具:如 Wireshark、Zeek(Bro)。 可以通过包管理工具(如 apt )安装这些依赖,或者从源代码编译。 3. 下载和安装 Clear NDR - Community 下载:从 Stamus Networks 官方网站 或其 GitHub 仓库下载 Clear NDR - Community 的安装包或源代码。 安装:根据安装指南进行安装。通常可以通过以下方式: 使用 Docker 部署:Clear NDR - Community 提供了 Docker 镜像,可以通过 Docker Compose 快速部署。 手动安装:从源代码编译并配置各个组件。 4. 配置 Suricata 规则集:下载并配置 Suricata 的规则集(如 Emerging Threats、ET Open 或自定义规则)。 网络接口:配置 Suricata 以捕获网络流量,指定要监控的网络接口(如 eth0)。 输出配置:确保 Suricata 的输出配置指向 Elasticsearch 或其他数据存储系统。 5. 配置 Elasticsearch 和 Kibana Elasticsearch:配置 Elasticsearch 以存储 Suricata 生成的日志和警报。 Kibana:配置 Kibana 以可视化和分析数据。可以通过导入预定义的仪表板和可视化配置文件来快速开始。 6. 启动服务 启动 Suricata:启动 Suricata 服务以开始捕获和分析网络流量。 启动 Elasticsearch 和 Kibana:确保 Elasticsearch 和 Kibana 服务正常运行。 验证数据流:检查是否成功捕获和存储了网络流量数据,并通过 Kibana 查看数据。 7. 配置警报和监控 警报规则:根据需求配置警报规则,以便在检测到异常活动时发出通知。 监控仪表板:使用 Kibana 创建监控仪表板,实时查看网络流量和安全事件。 8. 测试和优化 测试流量:通过模拟网络流量和Attack测试 Clear NDR - Community 的检测能力。 优化配置:根据测试结果调整 Suricata 规则、Elasticsearch 索引设置和 Kibana 可视化配置。 9. 持续维护 更新规则集:定期更新 Suricata 的规则集以应对新的威胁。 性能监控:监控系统性能,确保资源使用合理。 备份数据:定期备份 Elasticsearch 中的数据以防止数据丢失。 10. 可选扩展 集成其他工具:可以将 Clear NDR - Community 与其他安全工具(如 SIEM 系统、防火墙等)集成,以增强整体安全能力。 容器化部署:使用 Docker 或 Kubernetes 进行容器化部署,便于扩展和管理。 通过以上步骤,您可以成功部署 Clear NDR - Community 并开始使用它进行网络安全监控和入侵检测。如果需要更详细的部署指南,可以参考 Stamus Networks 的官方文档,对于希望快速上手的同学们可以参考专业的SEKS课程《开源入侵检测系统SELKS 安装与应用》https://edu.51cto.com/course/33730.html
2025年-4月-28日
8 阅读
0 评论
网络安全
2025-4-28
iptables防火墙笔记
一、iptables 基础概念 1.1 防火墙概述 防火墙是一种位于内部网络与外部网络之间的网络安全系统,依照特定的规则,允许或是限制传输的数据通过。在 Linux 系统中,iptables 是一款广泛使用的防火墙管理工具。它工作在网络层,通过匹配数据包的源地址、目的地址、端口号、协议等信息来决定对数据包的处理方式,如允许通过(ACCEPT)、拒绝通过(REJECT)、直接丢弃(DROP)等。 1.2 iptables 与 netfilter 关系 netfilter 是 Linux 内核中的包过滤功能体系,处于内核态,负责实际的数据包过滤操作。iptables 则是位于 /sbin/iptables 的用户态工具,用于管理防火墙规则,用户通过 iptables 命令来添加、删除、查看防火墙规则,这些规则最终由 netfilter 在内核中执行。 二、iptables 规则链与表结构 2.1 规则链 规则链是容纳各种防火墙规则的容器,根据处理数据包的不同时机,iptables 默认包括 5 种规则链: INPUT 链:处理进入本机的数据包,例如外部网络访问本机服务的数据包。 OUTPUT 链:处理从本机发出的数据包,如本机访问外部网络的请求。 FORWARD 链:处理转发的数据包,当本机充当路由器,数据包从一个网络接口进入,需要转发到另一个网络接口时,由该链处理。 POSTROUTING 链:在进行路由选择后处理数据包,通常用于源地址转换(SNAT),例如局域网内多台主机共享一个公网 IP 上网时,在数据包离开路由器前修改源 IP 地址。 PREROUTING 链:在进行路由选择前处理数据包,常用于目的地址转换(DNAT),比如将发往公网 IP 的特定端口的数据包转发到内网的特定服务器。 2.2 规则表 规则表是容纳各种规则链的容器,根据防火墙规则的作用相似性进行划分,iptables 默认包括 4 个规则表: raw 表:确定是否对该数据包进行状态跟踪,常用于关闭某些连接跟踪,以提高性能。例如,如果有一些不需要进行连接跟踪的 UDP 流量,可以在 raw 表中设置规则,使其不被连接跟踪机制处理。 mangle 表:为数据包设置标记,可用于对数据包进行特殊处理,如修改数据包的 TOS(Type of Service)字段。例如,对于视频流数据包,可以通过 mangle 表设置其 TOS 字段,以便在网络中给予更高的优先级。 nat 表:主要用于修改数据包中的源、目标 IP 地址或端口,实现网络地址转换(NAT)功能。如前面提到的 SNAT 和 DNAT 操作都在 nat 表中完成。 filter 表:确定是否放行该数据包(过滤),这是最常用的表,INPUT、OUTPUT 和 FORWARD 链默认都在 filter 表中。例如,设置允许或拒绝特定 IP 地址访问本机的 SSH 服务(端口 22)的规则就写在 filter 表的 INPUT 链中。 2.3 数据包过滤匹配流程 规则表之间的顺序:数据包首先经过 raw 表,然后是 mangle 表,接着是 nat 表,最后是 filter 表。在实际应用中,例如当需要对某个特定的数据包不进行连接跟踪时,就可以在 raw 表中设置规则,让该数据包跳过后续表中与连接跟踪相关的处理。 规则链之间的顺序: 入站数据包:先经过 PREROUTING 链,然后进入 INPUT 链。例如,外部主机访问本机 Web 服务(假设 IP 为 192.168.1.100,端口 80),数据包先到达 PREROUTING 链,若在此链中没有匹配到修改目的地址等规则,就进入 INPUT 链进行是否允许访问的判断。 出站数据包:先经过 OUTPUT 链,然后进入 POSTROUTING 链。当本机访问外部网站时,数据包从应用程序发出后,先由 OUTPUT 链处理,例如可以在此链中设置规则限制某些应用程序访问特定网站,之后数据包进入 POSTROUTING 链,若需要进行源地址转换(如共享上网场景),则在此链进行处理。 转发数据包:先经过 PREROUTING 链,再进入 FORWARD 链,最后进入 POSTROUTING 链。当一台 Linux 主机作为路由器,将一个子网的数据包转发到另一个子网时,数据包先在 PREROUTING 链进行可能的目的地址转换等操作,然后进入 FORWARD 链判断是否允许转发,若允许,最后在 POSTROUTING 链进行源地址转换等操作。 规则链内的匹配顺序:按顺序依次检查规则,一旦匹配到规则,就停止匹配(LOG 策略例外,记录日志后会继续匹配下一条规则)。若找不到相匹配的规则,则按该链的默认策略处理。例如,在 INPUT 链中有多条规则,从上到下依次检查,若第一条规则是允许特定 IP 段(192.168.1.0/24)访问本机,第二条规则是拒绝所有其他 IP 访问,当 192.168.1.50 的主机访问本机时,第一条规则匹配成功,就不再检查第二条规则,直接允许该主机访问。 三、iptables 常用命令参数 3.1 管理选项 添加新规则: -A:在链的末尾追加一条规则。例如,要在 filter 表的 INPUT 链末尾添加一条允许所有 TCP 流量通过的规则,可以使用命令iptables -t filter -A INPUT -p tcp -j ACCEPT。 -I:在链的开头(或指定序号)插入一条规则。如果想在 INPUT 链的开头插入一条拒绝 192.168.2.10 主机访问的规则,命令为iptables -t filter -I INPUT -s 192.168.2.10 -j DROP。若要指定插入到第 3 条规则的位置,可使用iptables -t filter -I INPUT 3 -s 192.168.2.10 -j DROP。 查看规则列表: -L:列出所有的规则条目。如执行iptables -t filter -L INPUT可查看 filter 表中 INPUT 链的所有规则。 -n:以数字形式显示地址、端口等信息。例如iptables -t filter -L INPUT -n,原本显示的主机名可能会以 IP 地址形式展示,端口名称也会以数字端口号显示,便于更直观地查看规则。 -v:以更详细的方式显示规则信息,包括数据包的数量、字节数等统计信息。iptables -t filter -L INPUT -v会显示每个规则匹配到的数据包数量和总字节数等。 --line-numbers:查看规则时,显示规则的序号。使用iptables -t filter -L INPUT --line-numbers,会在每条规则前显示其在链中的序号,方便后续删除或修改规则时指定位置。 删除、清空规则: -D:删除链内指定序号(或内容)的一条规则。若要删除 INPUT 链中序号为 5 的规则,命令为iptables -t filter -D INPUT 5;若要删除允许 192.168.3.0/24 网段访问的规则(假设该规则完整内容已知),可使用iptables -t filter -D INPUT -s 192.168.3.0/24 -j ACCEPT。 -F:清空所有的规则。执行iptables -t filter -F INPUT会清空 filter 表中 INPUT 链的所有规则。 设置默认策略: -P:为指定的链设置默认规则。比如将 filter 表的 INPUT 链默认策略设置为 DROP(拒绝所有未匹配规则的数据包进入),命令是iptables -t filter -P INPUT DROP;将 OUTPUT 链默认策略设置为 ACCEPT(允许所有未匹配规则的数据包发出),命令为iptables -t filter -P OUTPUT ACCEPT。 3.2 匹配条件 通用匹配:可直接使用,不依赖于其他条件或扩展。 协议匹配:-p协议名,例如-p tcp表示匹配 TCP 协议的数据包,-p udp匹配 UDP 协议数据包。 地址匹配:-s源地址,-d目的地址。如-s 192.168.1.10表示匹配源地址为 192.168.1.10 的数据包,-d 192.168.2.0/24匹配目的地址在 192.168.2.0/24 网段的数据包。 网络接口匹配:-i网卡名称匹配从这块网卡流入的数据,-o网卡名称匹配从这块网卡流出的数据。例如-i eth0表示匹配从 eth0 网卡流入的数据包,-o eth1匹配从 eth1 网卡流出的数据包。 隐含匹配:要求以特定的协议匹配作为前提。 端口匹配:当使用-p tcp或-p udp后,可使用--sport源端口号、--dport目的端口号来进一步匹配。例如iptables -t filter -A INPUT -p tcp --dport 80 -j ACCEPT表示允许目的端口为 80(通常是 Web 服务端口)的 TCP 数据包进入。 TCP 标记匹配:如--tcp-flags,用于匹配 TCP 数据包的标志位。例如iptables -t filter -A INPUT -p tcp --tcp-flags SYN,RST,ACK SYN -j ACCEPT,表示只允许带有 SYN 标志位(即发起新连接请求)的 TCP 数据包通过,防止一些异常的 TCP 连接。 ICMP 类型匹配:当-p icmp时,可使用--icmp-type匹配 ICMP 数据包的类型。例如iptables -t filter -A INPUT -p icmp --icmp-type 8 -j ACCEPT允许 ICMP 请求(类型 8,通常是 ping 请求)的数据包进入。 显式匹配:要求以 “-m 扩展模块” 的形式明确指出类型。 多端口匹配:使用-m multiport,可以同时匹配多个端口。例如iptables -t filter -A INPUT -p tcp -m multiport --dports 80,443,8080 -j ACCEPT,允许目的端口为 80(HTTP)、443(HTTPS)、8080 的 TCP 数据包进入。 MAC 地址匹配:使用-m mac,--mac-sourceMAC 地址,可根据源 MAC 地址进行匹配。比如iptables -t filter -A INPUT -m mac --mac-source 00:11:22:33:44:55 -j ACCEPT,只允许源 MAC 地址为 00:11:22:33:44:55 的设备访问。 IP 范围匹配:使用-m iprange,--src-range起始 IP 地址 - 结束 IP 地址,可匹配源 IP 地址在指定范围内的数据包。例如iptables -t filter -A INPUT -m iprange --src-range 192.168.1.10 - 192.168.1.20 -j ACCEPT,允许源 IP 地址在 192.168.1.10 到 192.168.1.20 之间的数据包进入。 数据包状态匹配:使用-m state,--state状态,可根据数据包的连接状态进行匹配。常见状态有ESTABLISHED(已建立连接的数据包)、NEW(新连接的数据包)等。例如iptables -t filter -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT,允许已建立连接和相关联的数据包进入,这样可以保证合法的连接通信正常进行,同时阻止非法的新连接尝试。 3.3 数据包控制类型 ACCEPT:允许数据包通过,当规则匹配到数据包且控制类型为 ACCEPT 时,数据包将被放行,继续后续的网络传输。 DROP:直接丢弃数据包,不给出任何回应。当数据包匹配到 DROP 规则时,就像数据包进入了 “黑洞”,发送方不会收到任何关于数据包被拒绝的提示,只是感觉数据包好像丢失了,常用于阻止一些恶意或不需要的连接,同时避免向者暴露服务器的一些信息。 REJECT:拒绝数据包通过,必要时会给出提示。与 DROP 不同,REJECT 会向数据包发送方回复一条拒绝信息,如端口不可达等。例如,当外部主机尝试连接本机被拒绝访问的端口时,若规则是 REJECT,发送方会收到类似 “Destination Port Unreachable” 的提示,这种方式可以让发送方明确知道连接被拒绝,但也可能会向者暴露一些端口信息。 LOG:记录日志信息,然后传给下一条规则继续匹配。当规则匹配到数据包且控制类型为 LOG 时,系统会将该数据包的相关信息记录到日志文件中,便于后续分析网络流量情况,之后数据包会继续匹配下一条规则。例如,可以通过设置 LOG 规则记录所有尝试连接本机但被拒绝的数据包信息,以便排查网络行为。 四、iptables 安装与配置示例 4.1 安装 iptables 关闭 firewalld 防火墙(如果已安装并启用):在 CentOS 等系统中,可使用以下命令关闭并禁用 firewalld 服务: TypeScript 取消自动换行复制 systemctl stop firewalld.service systemctl disable firewalld.service 安装 iptables 防火墙:使用 yum 包管理器安装 iptables 及相关服务,命令如下: TypeScript 取消自动换行复制 yum -y install iptables iptables-services 设置 iptables 开机启动: TypeScript 取消自动换行复制 systemctl enable iptables.service 4.2 配置示例 允许特定 IP 访问本机 SSH 服务:假设允许 192.168.1.0/24 网段的主机访问本机的 SSH 服务(端口 22),在 filter 表的 INPUT 链中添加规则: TypeScript 取消自动换行复制 iptables -t filter -A INPUT -s 192.168.1.0/24 -p tcp --dport 22 -j ACCEPT 禁止特定 IP 访问本机所有服务:若要禁止 192.168.2.10 主机访问本机,在 filter 表的 INPUT 链中添加规则: TypeScript 取消自动换行复制 iptables -t filter -A INPUT -s 192.168.2.10 -j DROP 设置 INPUT 链默认策略为拒绝所有:先将 filter 表的 INPUT 链默认策略设置为 DROP,然后再添加允许特定流量的规则,以提高系统安全性: TypeScript 取消自动换行复制 iptables -t filter -P INPUT DROP 之后再根据实际需求添加允许的规则,如上面允许 192.168.1.0/24 访问 SSH 服务的规则。 4. 实现端口转发(DNAT):假设本机有一个 Web 服务运行在内网 IP 192.168.1.100 的 80 端口,要将公网 IP 202.100.1.1 的 80 端口访问转发到内网的 Web 服务器,在 nat 表的 PREROUTING 链中添加规则: TypeScript 取消自动换行复制 iptables -t nat -A PREROUTING -i eth0 -p tcp -d 202.100.1.1 --dport 80 -j DNAT --to-destination 192.168.1.100:80 这里eth0是公网网卡接口,根据实际情况修改。 5. 实现共享上网(SNAT):若本机作为路由器,连接内网 192.168.1.0/24 网段和公网,要实现内网主机共享公网 IP 上网,在 nat 表的 POSTROUTING 链中添加规则: TypeScript 取消自动换行复制 iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth0 -j SNAT --to-source 202.100.1.1 其中eth0为公网网卡接口,202.100.1.1为公网 IP 地址,同样根据实际情况调整。 4.3 保存与加载规则 保存规则:在修改完 iptables 规则后,需要将规则保存,以便下次开机时生效。在 CentOS 系统中,使用以下命令保存规则: TypeScript 取消自动换行复制 service iptables save 加载规则:开机时,iptables 服务会自动加载保存的规则。如果在运行过程中需要手动加载规则,可使用: TypeScript 取消自动换行复制 service iptables restart 此命令会先停止 iptables 服务,
2025年-4月-28日
6 阅读
0 评论
网络安全
2025-4-28
齿轮缺陷检测数据集VOC+YOLO格式7742张3类别
数据集格式:Pascal VOC格式+YOLO格式(不包含分割路径的txt文件,仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数):7742 标注数量(xml文件个数):7742 标注数量(txt文件个数):7742 标注类别数:3 标注类别名称(注意yolo格式类别顺序不和这个对应,而以labels文件夹classes.txt为准):["break","lack","scratch"] 每个类别标注的框数: break 框数 = 2620 lack 框数 = 2568 scratch 框数 = 11045 总框数:16233 使用标注工具:labelImg 标注规则:对类别进行画矩形框 重要说明:暂无 特别声明:本数据集不对训练的模型或者权重文件精度作任何保证,数据集只提供准确且合理标注 图片预览: 标注例子:
2025年-4月-28日
6 阅读
0 评论
人工智能
2025-4-28
生命护航行动再启航!
温州好人陈飞携防溺水课堂,为乡村少年宫筑起安全防线 图文作者:华夏之音/李望 随着夏日热浪的滚滚而来,楠溪江畔的安全警钟再次响起。在这片如诗如画的土地上,一场旨在保护青少年生命安全的防溺水课堂活动拉开了帷幕。温州好人、永嘉县慈善总会楠溪江防溺水义工队负责人陈飞,带着对生命的无限热爱与责任,走进了沙头镇中心小学,为全校师生带来了一场生动而富有教育意义的防溺水知识讲座,并亲手将2025年度首批“跟屁虫”救生圈送到了老师们手中。永嘉县文明办副主任叶新新亲临现场,共同见证了这一温馨而庄重的时刻。 在沙头镇中心小学的校园里,夏日的热情与学习的氛围交织在一起,形成了一幅动人的画面。陈飞先生以其丰富的实践经验和感人至深的故事,向师生们深刻阐述了防溺水的重要性。他深知,每一次的宣讲与努力,都是为了守护更多家庭的幸福与安宁。在他的不懈努力下,去年沙头镇水域实现了零溺水事故的骄人成绩,这一成就不仅是对他辛勤付出的最好回报,更是对生命安全的最好保障。 活动中,陈飞先生不仅带来了宝贵的防溺水知识,更用实际行动诠释了关爱与责任。他亲自为老师们分发了“跟屁虫”救生圈,这些小巧而实用的救生设备,如同生命的守护者,为孩子们的安全保驾护航。他希望通过这种方式,让每一位孩子都能学会自我保护,远离溺水的危险,让每一个家庭都能拥有完整的幸福。 然而,陈飞的公益之路并未止步。他计划从6月13日起,在接下来的100天里,继续自费购买3800个“跟屁虫”救生圈,将防溺水课堂的触角延伸至枫林、岩头、鹤盛、大若岩等五个乡镇的水域。这一壮举不仅展现了他个人的高尚品质,更激发了更多社会力量参与到防溺水工作中来,共同为青少年的生命安全筑起一道坚实的防线。 沙头镇中心小学作为今年宣讲活动的首站,积极响应号召,全力配合。学校秉持“从善有容,和而不同”的校训,致力于培养具有融通、融达、融和品质的好少年。此次防溺水课堂的走进,不仅增强了师生的安全意识,更与学校“每一滴水都能折射出七彩光芒”的办学理念相契合,为孩子们的成长之路增添了一份安全保障。 让我们携手并进,共同为生命护航!陈飞先生的善举已经为我们树立了光辉的榜样。在享受楠溪江美景的同时,让我们时刻铭记珍爱生命、远离危险的警示。愿每一位孩子都能在安全的怀抱中茁壮成长,绽放出属于自己的璀璨光芒!让我们共同努力,让生命之花在阳光下更加绚烂多彩!航拍:温州中视文化传播有限公司
2025年-4月-28日
5 阅读
0 评论
网络安全
2025-4-28
基于yolov11的瓷砖缺陷检测系统python源码+pytorch模型+评估指标曲线+精美GUI界面
【算法介绍】 基于YOLOv11的瓷砖缺陷检测系统,是针对瓷砖制造行业质量控制需求而设计的自动化检测解决方案。该系统利用YOLOv11这一尖端深度学习模型,能够高效、准确地识别瓷砖表面的多种缺陷类型,包括边缘崩裂(edge-chipping)、破洞(hole)和裂缝(line)。 YOLOv11作为YOLO系列的最新版本,在检测精度和速度上均有显著提升。其改进的骨干网络和颈部架构增强了特征提取能力,使得模型能够更准确地捕捉瓷砖表面的细微缺陷。同时,YOLOv11还通过优化训练方法和引入新的功能模块,进一步提高了模型的泛化能力和适应性。 在实际应用中,该系统能够实时处理瓷砖图像,并自动标注出缺陷位置和类型。检测结果可以实时显示在用户界面上,并提供详细的缺陷信息,如缺陷大小、形状和置信度等。这有助于瓷砖制造商及时发现并处理缺陷产品,提高生产效率和产品质量。基于YOLOv11的瓷砖缺陷检测系统为瓷砖制造行业提供了一种高效、准确的自动化检测手段,有助于提升产品质量和市场竞争力。 【效果展示】 【训练数据集介绍】 数据集格式:Pascal VOC格式+YOLO格式(不包含分割路径的txt文件,仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数):888 标注数量(xml文件个数):888 标注数量(txt文件个数):888 标注类别数:3 标注类别名称(注意yolo格式类别顺序不和这个对应,而以labels文件夹classes.txt为准):["edge-chipping","hole","line"] 每个类别标注的框数: edge-chipping 框数 = 6054 hole 框数 = 6288 line 框数 = 4216 总框数:16558 使用标注工具:labelImg 标注规则:对类别进行画矩形框 重要说明:暂无 特别声明:本数据集不对训练的模型或者权重文件精度作任何保证,数据集只提供准确且合理标注 图片预览: 标注例子: 【训练信息】 参数 值 训练集图片数 835 验证集图片数 45 训练map 61.6% 训练精度(Precision) 67.3% 训练召回率(Recall) 55.1% 【验证集精度统计】 Class Images Instances P R mAP50 mAP50-95 all 45 660 0.673 0.551 0.616 0.326 edge-chipping 40 236 0.692 0.597 0.627 0.329 hole 39 250 0.898 0.648 0.801 0.438 line 28 174 0.428 0.408 0.42 0.21 【测试环境】 windows10anaconda3+python3.8torch==2.3.0ultralytics==8.3.81notallow==1.16.3 【界面设计】 class Ui_MainWindow(QtWidgets.QMainWindow): signal = QtCore.pyqtSignal(str, str) def setupUi(self): self.setObjectName("MainWindow") self.resize(1280, 728) self.centralwidget = QtWidgets.QWidget(self) self.centralwidget.setObjectName("centralwidget") self.weights_dir = './weights' self.picture = QtWidgets.QLabel(self.centralwidget) self.picture.setGeometry(QtCore.QRect(260, 10, 1010, 630)) self.picture.setStyleSheet("background:black") self.picture.setObjectName("picture") self.picture.setScaledContents(True) self.label_2 = QtWidgets.QLabel(self.centralwidget) self.label_2.setGeometry(QtCore.QRect(10, 10, 81, 21)) self.label_2.setObjectName("label_2") self.cb_weights = QtWidgets.QComboBox(self.centralwidget) self.cb_weights.setGeometry(QtCore.QRect(10, 40, 241, 21)) self.cb_weights.setObjectName("cb_weights") self.cb_weights.currentIndexChanged.connect(self.cb_weights_changed) self.label_3 = QtWidgets.QLabel(self.centralwidget) self.label_3.setGeometry(QtCore.QRect(10, 70, 72, 21)) self.label_3.setObjectName("label_3") self.hs_conf = QtWidgets.QSlider(self.centralwidget) self.hs_conf.setGeometry(QtCore.QRect(10, 100, 181, 22)) self.hs_conf.setProperty("value", 25) self.hs_conf.setOrientation(QtCore.Qt.Horizontal) self.hs_conf.setObjectName("hs_conf") self.hs_conf.valueChanged.connect(self.conf_change) self.dsb_conf = QtWidgets.QDoubleSpinBox(self.centralwidget) self.dsb_conf.setGeometry(QtCore.QRect(200, 100, 51, 22)) self.dsb_conf.setMaximum(1.0) self.dsb_conf.setSingleStep(0.01) self.dsb_conf.setProperty("value", 0.25) self.dsb_conf.setObjectName("dsb_conf") self.dsb_conf.valueChanged.connect(self.dsb_conf_change) self.dsb_iou = QtWidgets.QDoubleSpinBox(self.centralwidget) self.dsb_iou.setGeometry(QtCore.QRect(200, 160, 51, 22)) self.dsb_iou.setMaximum(1.0) self.dsb_iou.setSingleStep(0.01) self.dsb_iou.setProperty("value", 0.45) self.dsb_iou.setObjectName("dsb_iou") self.dsb_iou.valueChanged.connect(self.dsb_iou_change) self.hs_iou = QtWidgets.QSlider(self.centralwidget) self.hs_iou.setGeometry(QtCore.QRect(10, 160, 181, 22)) self.hs_iou.setProperty("value", 45) self.hs_iou.setOrientation(QtCore.Qt.Horizontal) self.hs_iou.setObjectName("hs_iou") self.hs_iou.valueChanged.connect(self.iou_change) self.label_4 = QtWidgets.QLabel(self.centralwidget) self.label_4.setGeometry(QtCore.QRect(10, 130, 72, 21)) self.label_4.setObjectName("label_4") self.label_5 = QtWidgets.QLabel(self.centralwidget) self.label_5.setGeometry(QtCore.QRect(10, 210, 72, 21)) self.label_5.setObjectName("label_5") self.le_res = QtWidgets.QTextEdit(self.centralwidget) self.le_res.setGeometry(QtCore.QRect(10, 240, 241, 400)) self.le_res.setObjectName("le_res") self.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(self) self.menubar.setGeometry(QtCore.QRect(0, 0, 1110, 30)) self.menubar.setObjectName("menubar") self.setMenuBar(self.menubar) self.statusbar = QtWidgets.QStatusBar(self) self.statusbar.setObjectName("statusbar") self.setStatusBar(self.statusbar) self.toolBar = QtWidgets.QToolBar(self) self.toolBar.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) self.toolBar.setObjectName("toolBar") self.addToolBar(QtCore.Qt.TopToolBarArea, self.toolBar) self.actionopenpic = QtWidgets.QAction(self) icon = QtGui.QIcon() icon.addPixmap(QtGui.QPixmap(":/images/1.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.actionopenpic.setIcon(icon) self.actionopenpic.setObjectName("actionopenpic") self.actionopenpic.triggered.connect(self.open_image) self.action = QtWidgets.QAction(self) icon1 = QtGui.QIcon() icon1.addPixmap(QtGui.QPixmap(":/images/2.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.action.setIcon(icon1) self.action.setObjectName("action") self.action.triggered.connect(self.open_video) self.action_2 = QtWidgets.QAction(self) icon2 = QtGui.QIcon() icon2.addPixmap(QtGui.QPixmap(":/images/3.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.action_2.setIcon(icon2) self.action_2.setObjectName("action_2") self.action_2.triggered.connect(self.open_camera) self.actionexit = QtWidgets.QAction(self) icon3 = QtGui.QIcon() icon3.addPixmap(QtGui.QPixmap(":/images/4.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.actionexit.setIcon(icon3) self.actionexit.setObjectName("actionexit") self.actionexit.triggered.connect(self.exit) self.toolBar.addAction(self.actionopenpic) self.toolBar.addAction(self.action) self.toolBar.addAction(self.action_2) self.toolBar.addAction(self.actionexit) self.retranslateUi() QtCore.QMetaObject.connectSlotsByName(self) self.init_all() 【模型可检测出3类】 边缘崩裂(edge-chipping)、破洞(hole)和裂缝(line) 【常用评估参数介绍】 在目标检测任务中,评估模型的性能是至关重要的。你提到的几个术语是评估模型性能的常用指标。下面是对这些术语的详细解释: Class: 这通常指的是模型被设计用来检测的目标类别。例如,一个模型可能被训练来检测车辆、行人或动物等不同类别的对象。 Images: 表示验证集中的图片数量。验证集是用来评估模型性能的数据集,与训练集分开,以确保评估结果的公正性。 Instances: 在所有图片中目标对象的总数。这包括了所有类别对象的总和,例如,如果验证集包含100张图片,每张图片平均有5个目标对象,则Instances为500。 P(精确度Precision): 精确度是模型预测为正样本的实例中,真正为正样本的比例。计算公式为:Precision = TP / (TP + FP),其中TP表示真正例(True Positives),FP表示假正例(False Positives)。 R(召回率Recall): 召回率是所有真正的正样本中被模型正确预测为正样本的比例。计算公式为:Recall = TP / (TP + FN),其中FN表示假负例(False Negatives)。 mAP50: 表示在IoU(交并比)阈值为0.5时的平均精度(mean Average Precision)。IoU是衡量预测框和真实框重叠程度的指标。mAP是一个综合指标,考虑了精确度和召回率,用于评估模型在不同召回率水平上的性能。在IoU=0.5时,如果预测框与真实框的重叠程度达到或超过50%,则认为该预测是正确的。 mAP50-95: 表示在IoU从0.5到0.95(间隔0.05)的范围内,模型的平均精度。这是一个更严格的评估标准,要求预测框与真实框的重叠程度更高。在目标检测任务中,更高的IoU阈值意味着模型需要更准确地定位目标对象。mAP50-95的计算考虑了从宽松到严格的多个IoU阈值,因此能够更全面地评估模型的性能。 这些指标共同构成了评估目标检测模型性能的重要框架。通过比较不同模型在这些指标上的表现,可以判断哪个模型在实际应用中可能更有效。 【使用步骤】 使用步骤:(1)首先根据官方框架ultralytics安装教程安装好yolov11环境,并安装好pyqt5(2)切换到自己安装的yolo11环境后,并切换到源码目录,执行python main.py即可运行启动界面,进行相应的操作即可 【提供文件】 python源码yolo11n.pt模型训练的map,P,R曲线图(在weights\results.png)测试图片(在test_img文件夹下面) 注意提供训练的数据集,请到mytxt.txt文件中找到地址
2025年-4月-28日
7 阅读
0 评论
人工智能
2025-4-28
编制和评审质量计划
编制和评审质量计划 制定质量保证计划:依据项目计划及项目质量目标确定需要检查的主要过程和工作产品,识别项目过程中的干系人及其活动,估计检查时间和人员,并制定出本项目的质量保证计划。 质量保证计划的主要内容包括:例行审计和里程碑评审,需要监督的重要活动和工作产品,确定审计方式,根据项目计划中的评审计划确定质量保证人员需要参加的评审计划。明确质量审计报告的报送范围。 质量保证计划的评审:质量保证计划需要经过评审方能生效,以确保质量保证计划和项目计划的一致性。经过批准的质量保证计划需要纳入配置管理。当项目计划变更时,需要及时更改和复审质量保证计划。 “过程和工作产品”的质量检查 根据质量保证计划进行质量的审计工作,并发布质量审计报告。 审计的主要内容包括:是否按照过程要求执行了相应的活动,是否按照过程要求产生了相应的工作产品。本项目中对质量的控制主要体现在不同阶段的审计当中。 不符合项的跟踪处理 对审计中发现的不符合项,要求项目组及时处理,质量保证人员需要确认不符合项的状态,直到最终的不符合项状态为“完成”为止。
2025年-4月-28日
11 阅读
0 评论
网络安全
2025-4-28
基于昇腾用PyTorch实现CTR模型DIN(Deep interest Netwok)网络
本文主要介绍如何在昇腾上使用pytorch对推荐系统中经典的网络模型Din进行训练的实战讲解,使用数据集是Amazon中book数据集,主要内容分为以下几个模块: Din网络创新点介绍 Din网络架构剖析及搭建 Activation Unit介绍 Attention模块 Din网络构建 使用Amazon-book数据集训练Din网络实战 Amazon-book数据集介绍 Amazon-book数据集预处理 训练集与测试集划分 模型训练过程定义 使用Amazon-book训练wideWeep模型 评估模型性能 CTR(Click-through rate prediction)是工业应用(如在线广告)中的一项重要任务,处理这一类任务较为常用的方法是基于深度学习的方式,通过类似多层感知机的方式,将大规模的稀疏输入特征向量映射为低维的嵌入向量后以组为单位将其转化为固定长度的向量,最后将这些向量进行拼接输入到多层感知机中来学习特征之间的非线性关系。 在embedding阶段,所有的离散特征都要被映射成一个固定长度的低维稠密向量。离散特征一般有单值特征和多值特征,分别要做one-hot编码和multi-hot编码,单值特征没什么问题,直接映射成embedding向量即可,而对于多值特征,比如:用户点击过的item序列,用户点击过item类目的序列,通常的操作都是每个item映射成一个embedding向量,然后做一个sum/average pooling,最终得到一个embedding向量。 从图中可以看出在做多值特征pooling的时候并不会考虑每个item的重要性,但是在实际的应用过程中我们知道一个爱游泳的人,之前购买书籍、冰淇淋、薯片、游泳镜。给他推荐护目镜后他是否会点击这次推荐广告,跟之前购买的书籍、薯片与冰淇淋无关,而是跟他以前购买的游泳帽相关。也就是在这一次CTR预估中,部分历史数据(游泳镜)起到了决定作用,而其他的基本都无用,所以最好的方式就是给每个item一个权重。 DIN网络给每个item的权重是通过目标广告与该商品item之间的相关性决定,比如在上述例子中,候选广告推荐用户是否点击是护目镜,与用户购买的书籍、冰淇淋与薯片相关性较少,与游泳镜的相关性更大。 Din网络创新点介绍 将注意力机制应用于用户兴趣建模,可以更好评估不同项的重要性差异,自适应的学习用户每个历史行为项的权重,使能模型可以更好的捕捉用户对不同项的兴趣。 通过使用局部激活单元方式,来计算用户对每个历史行为的兴趣权重,是注意力机制中有效实现方式。 采用Mini-batch Perceptron Regularizer节省参数计算量,避免过拟合。 使用Data-dependent Activation Function也就是自适用的数据激活函数 Din网络架构剖析及搭建 当前广告模型基本上遵循的都是embedding\&MLP组合模式(图中basemodel部分),而Din网络通过在embedding层与MLP之间加入Attention机制有效的解决了推荐广告与用户历史购买行为之间相关性的问题,其网络架构重点由两部分组成,一个是激活模块(图中的Activation Unit),另一个是Attention模块(图中的Sumpooling),接下来将分别介绍这两部分的原理及如何使用pytorch搭建这两部分从而构建整个Din网络。 Activation Unit介绍 Activation Unit作为Din网络核心模块,通过将用户历史点击过的商品Id(Inputs from User)与候选广告商品的Id(Inputs from Ad)通过Out Product的方式计算相关性。计算相关性后通过concat的方式将原始输入与相关性计算后的输入进行shortcut连接载通过激活与线性层进行输出。关于'PRelu'与'Dice'模块也就是Din网络中引入的自适适应的数据激活函数。 Prelu激活函数计算公式: Dice激活函数计算公式: 两者计算表达式一致,其通过p(s)的计算公式不一样来控制激活的取值,关于两者p(s)的取值如下所示: Dice中p(s)计算公式: 式中E\[s\]和Var\[s\]分别是均值与方差,epsilon是一个常量,默认取值是10\^-8。 Dice是PReLu的推广,其核心思想是根据输入数据的分布自适应地调整校正点。Dice可以平滑地在两个通道之间切换,并且当E\[s\] = 0并Var\[s\]=0时,Dice退化为PReLU,Dice通过定义一个Dice类实现,'forward()'函数中实现了上述定义公式的功能。 # python自定义包 import os import pandas as pd import numpy as np # 导入pytorch相关包 import torch import torch.nn as nn # 根据公式计算p(s) class Dice(nn.Module): def __init__(self): super(Dice, self).__init__() self.alpha = nn.Parameter(torch.zeros((1,))) self.epsilon = 1e-9 def forward(self, x): # 公式中分母部分e的指数部分计算 norm_x = (x - x.mean(dim=0)) / torch.sqrt(x.var(dim=0) + self.epsilon) p = torch.sigmoid(norm_x) x = self.alpha * x.mul(1-p) + x.mul(p) return x 整个激活模块通过ActivationUnit类实现,该模块功能是计算用户购买行为与推荐目标之间的注意力系数,比如说用户虽然用户买了这个东西,但是这个东西实际上和推荐目标之间没啥关系,也不重要,所以要乘以一个小权重,如果购买的东西跟推荐目标之间有直接因果关系,则需要乘以一个较大的权重。 class ActivationUnit(nn.Module): def __init__(self, embedding_dim, dropout=0.2, fc_dims = [32, 16]): super(ActivationUnit, self).__init__() # 1.初始化fc层 fc_layers = [] # 2.输入特征维度这里将输入的embedding_dim乘以4是将中间层的节点数放大了4倍,因为将4个模块的向量进行了concat input_dim = embedding_dim*4 # 3.fc层内容:全连接层(4*embedding, 32)--->激活函数->dropout->全连接层(32,16)->.....->全连接层(16,1) for fc_dim in fc_dims: fc_layers.append(nn.Linear(input_dim, fc_dim)) fc_layers.append(Dice()) fc_layers.append(nn.Dropout(p = dropout)) input_dim = fc_dim fc_layers.append(nn.Linear(input_dim, 1)) # 4.将上面定义的fc层,整合到sequential中 self.fc = nn.Sequential(*fc_layers) def forward(self, query, user_behavior): """ query:targe目标的embedding ->(输入维度) batch*1*embed user_behavior:行为特征矩阵 ->(输入维度) batch*seq_len*embed out:预测目标与历史行为之间的注意力系数 """ # 1.获取用户历史行为序列长度 seq_len = user_behavior.shape[1] # 2.序列长度*embedding queries = torch.cat([query] * seq_len, dim=1) # 3.前面的把四个embedding合并成一个(4*embedding)的向量, # 第一个向量是目标商品的向量,第二个向量是用户行为的向量, # 至于第三个和第四个则是他们的相减和相乘(这里猜测是为了添加一点非线性数据用于全连接层,充分训练) attn_input = torch.cat([queries, user_behavior, queries - user_behavior, queries * user_behavior], dim = -1) out = self.fc(attn_input) return out Attention模块 Attention模块是Din网络中注意力序列层,其功能是计算用户行为与预测目标之间的系数,并将所有的向量进行相加,这里的目的是计算出用户的兴趣的向量。通过'AttentionPoolingLayer'这个类实现该功能。主要通过'active_unit()'引入了目标和历史行为之间的相关性。 class AttentionPoolingLayer(nn.Module): def __init__(self, embedding_dim, dropout): super(AttentionPoolingLayer, self).__init__() self.active_unit = ActivationUnit(embedding_dim = embedding_dim, dropout = dropout) def forward(self, query_ad, user_behavior, mask): """ query_ad:targe目标x的embedding -> (输入维度) batch*1*embed user_behavior:行为特征矩阵 -> (输入维度) batch*seq_len*embed mask:被padding为0的行为置为false -> (输入维度) batch*seq_len*1 output:用户行为向量之和,反应用户的爱好 """ # 1.计算目标和历史行为之间的相关性 attns = self.active_unit(query_ad, user_behavior) # 2.注意力系数乘以行为 output = user_behavior.mul(attns.mul(mask)) # 3.历史行为向量相加 output = user_behavior.sum(dim=1) return output Din网络构建 基于上述搭建好的Activation Unit与AttentionPoolingLayer模块,可以构建DeepInterestNet网络,本文实现的网络主要是用在Amazon-book数据集上进行测试,其主要功能是用户最近的历史40个购买物品是xxx时,购买y的概率是多少? class DeepInterestNet(nn.Module): def __init__(self, feature_dim, embed_dim, mlp_dims, dropout): super(DeepInterestNet, self).__init__() # 1.特征维度,就是输入的特征有多少个类 self.feature_dim = feature_dim # 2.embeding层,将特征数值转化为向量 self.embedding = nn.Embedding(feature_dim+1, embed_dim) # 3.注意力计算层(论文核心) self.AttentionActivate = AttentionPoolingLayer(embed_dim, dropout) # 4.定义fc层 fc_layers = [] # 5.该层的输入为历史行为的embedding,和目标的embedding,所以输入维度为2*embedding_dim # 全连接层(2*embedding,fc_dims[0])--->激活函数->dropout->全连接层(fc_dims[0],fc_dims[1])->.....->全连接层(fc_dims[n],1) input_dim = embed_dim * 2 for fc_dim in mlp_dims: fc_layers.append(nn.Linear(input_dim, fc_dim)) fc_layers.append(nn.ReLU()) fc_layers.append(nn.Dropout(p = dropout)) input_dim = fc_dim fc_layers.append(nn.Linear(input_dim, 1)) # 6.将所有层封装 self.mlp = nn.Sequential(*fc_layers) def forward(self, x): """ x输入(behaviors*40,ads*1) ->(输入维度) batch*(behaviors+ads) """ # 1.排除掉推荐目标 behaviors_x = x[:,:-1] # 2.记录之前填充为0的行为位置 mask = (behaviors_x > 0).float().unsqueeze(-1) # 3.获取推荐的目标 ads_x = x[:,-1] # 4.对推荐目标进行向量嵌入 query_ad = self.embedding(ads_x).unsqueeze(1) # 5.对用户行为进行embeding,注意这里的维度为(batch*历史行为长度*embedding长度) user_behavior = self.embedding(behaviors_x) # 6.矩阵相乘,将那些行为为空的地方全部写为0 user_behavior = user_behavior.mul(mask) # 7.将用户行为乘上注意力系数,再把所有行为记录向量相加 user_interest = self.AttentionActivate(query_ad, user_behavior, mask) # 8.将计算后的用户行为行为记录和推荐的目标进行拼接 concat_input = torch.cat([user_interest, query_ad.squeeze(1)], dim = 1) # 9.输入用户行为和目标向量,计算预测得分 out = self.mlp(concat_input) # 10.sigmoid激活函数 out = torch.sigmoid(out.squeeze(1)) return out 使用Amazon-book数据集训练Din网络实战 综上所述,我们已经构建好了一个Din模型,现在可以尝试使用Amazon数据集来训练该网络,首先我们先料了解一下什么Amazon数据集是什么? Amazon-book数据集介绍 Amazon-Book数据集是由亚马逊公司提供的大规模图书评论数据集,包含了亚马逊2000年至2014年之间大量的图书评论信息。是当前最大、最全面的图书评论数据集之一。 Amazon-Book数据集主要包括以下内容: 用户ID:标识每个参与评论的用户。 物品ID:标识每本书的唯一标识符。 评论文本:用户对书籍的具体评论内容。 评分:用户对书籍的评分,通常在1到5分之间。 这些数据提供了丰富的信息,可以用于分析用户行为、优化产品设计、改进营销策略等 # 使用padas库加载amazon-book数据集 data = pd.read_csv('/home/pengyongrong/workspace/DinModel/DIN-CODE/amazon-books-100k.txt') 将加载好的数据集进行打印,数据总共包含89999个样例,'label'表示用户是否会点击购买推荐的广告商品,0表示不点击、1表示点击;'userID'是用来标记用户的;'itemID'用来标识书籍;'cateID'标识书籍属的类别;'hit_item_list'指的是推荐给用户的商品或内容列表;hit_cate_list指的是推荐给用户的商品内容所述的类别。 data | | label | userID | itemID | cateID | hist_item_list | hist_cate_list | | 0 | 0 | AZPJ9LUT0FEPY | B00AMNNTIA | Literature \& Fiction | 0307744434\|0062248391\|0470530707\|0978924622\|15... | Books\|Books\|Books\|Books\|Books | | 1 | 1 | AZPJ9LUT0FEPY | 0800731603 | Books | 0307744434\|0062248391\|0470530707\|0978924622\|15... | Books\|Books\|Books\|Books\|Books | | 2 | 0 | A2NRV79GKAU726 | B003NNV10O | Russian | 0814472869\|0071462074\|1583942300\|0812538366\|B0... | Books\|Books\|Books\|Books\|Baking\|Books\|Books | | 3 | 1 | A2NRV79GKAU726 | B000UWJ91O | Books | 0814472869\|0071462074\|1583942300\|0812538366\|B0... | Books\|Books\|Books\|Books\|Baking\|Books\|Books | | 4 | 0 | A2GEQVDX2LL4V3 | 0321334094 | Books | 0743596870\|0374280991\|1439140634\|0976475731 | Books\|Books\|Books\|Books | | ... | ... | ... | ... | ... | ... | ... | | 89994 | 0 | A3CV7NJJC20JTB | 098488789X | Books | 034545197X\|0765326396\|1605420832\|1451648448 | Books\|Books\|Books\|Books | | 89995 | 1 | A3CV7NJJC20JTB | 0307381277 | Books | 034545197X\|0765326396\|1605420832\|1451648448 | Books\|Books\|Books\|Books | | 89996 | 0 | A208PSIK2APSKN | 0957496184 | Books | 0515140791\|147674355X\|B0055ECOUA\|B007JE1B1C\|B0... | Books\|Books\|Bibles\|Literature \& Fiction\|Litera... | | 89997 | 1 | A208PSIK2APSKN | 1480198854 | Books | 0515140791\|147674355X\|B0055ECOUA\|B007JE1B1C\|B0... | Books\|Books\|Bibles\|Literature \& Fiction\|Litera... | 89999 rows × 6 columns 通过对数据集分析发现,许多商品id只出现了一次,因此在编码的时候以类别作为编码和预测的目标输入给模型进行训练。由于每一个用户的历史购买行为均不一致,因此会导致长度也会不一样,这里截取了40个历史行为作为标准,用来获取用户历史购买信息与推荐广告商品的相关性,如果不足40则填充0到40,若大于40个行为,则截取最近40个行为(也就是后40个行为)。 'cate_encoder'是全局变量,用来编码类别标签的,在后续测试过程中也会用到。整个预处理过程分为8个步骤均在代码出注解。 Amazon-book数据集预处理 #导入sklearn相关包,主要用到LabelEncoder用来自动编码类别 from sklearn.preprocessing import LabelEncoder cate_encoder = None def AmazonBookPreprocess(dataframe, seq_len=40): """ 数据集处理 dataframe: 未处理的数据集 seq_len: 数据序列长度 data: 处理好的数据集 """ # 1.按'|'切割,用户历史购买数据,获取item的序列和类别的序列 data = dataframe.copy() data['hist_item_list'] = dataframe.apply(lambda x: x['hist_item_list'].split('|'), axis=1) data['hist_cate_list'] = dataframe.apply(lambda x: x['hist_cate_list'].split('|'), axis=1) # 2.获取cate的所有种类,为每个类别设置一个唯一的编码 cate_list = list(data['cateID']) _ = [cate_list.extend(i) for i in data['hist_cate_list'].values] # 3.将编码去重,'0' 作为padding的类别 cate_set = set(cate_list + ['0']) # 4.截取用户行为的长度,也就是截取hist_cate_list的长度,生成对应的列名 cols = ['hist_cate_{}'.format(i) for i in range(seq_len)] # 5.截取前40个历史行为,如果历史行为不足40个则填充0 def trim_cate_list(x): if len(x) > seq_len: # 5.1历史行为大于40, 截取后40个行为 return pd.Series(x[-seq_len:], index=cols) else: # 5.2历史行为不足40, padding到40个行为 pad_len = seq_len - len(x) x = x + ['0'] * pad_len return pd.Series(x, index=cols) # 6.预测目标的类别 labels = data['label'] data = data['hist_cate_list'].apply(trim_cate_list).join(data['cateID']) # 7.生成类别对应序号的编码器,如book->1,Russian->2这样 global cate_encoder cate_encoder = LabelEncoder().fit(list(cate_set)) print("cate_encoder is: ", cate_encoder) # 8.这里分为两步,第一步为把类别转化为数值,第二部为拼接上label data = data.apply(cate_encoder.transform).join(labels) return data # 对数据执行预处理操作,该操作由于是对表格逐行进行处理,因此可能会需要一点时间 data = AmazonBookPreprocess(data) cate_encoder is: LabelEncoder() 将data信息进行打印可以看到用户历史购买的序列与label数据集存储在data中总共包含40个用户历史行为类别信息,大部分用户历史购买数据长度均未达到40,因此在每一个用户后填充0。 每一行中具体的数字表示表示用户购买物品所属的类别,比如0行中138、138、138、138、138 表示用户0购买5个历史物品均属于138这个类别,推荐的商品类别是734,因此label值=0,表示用户不会点击购买推荐的734商品。 而第1行恰恰相反,138、138、138、138、138 表示用户1购买5个历史物品均属于138这个类别,推荐的商品类别是138,因此label值=1,表示用户很大概率会点击购买推荐的734商品。 data | | hist_cate_0 | hist_cate_1 | hist_cate_2 | hist_cate_3 | hist_cate_4 | hist_cate_5 | hist_cate_6 | hist_cate_7 | hist_cate_8 | hist_cate_9 | ... | hist_cate_32 | hist_cate_33 | hist_cate_34 | hist_cate_35 | hist_cate_36 | hist_cate_37 | hist_cate_38 | hist_cate_39 | cateID | label | | 0 | 138 | 138 | 138 | 138 | 138 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 734 | 0 | | 1 | 138 | 138 | 138 | 138 | 138 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 138 | 1 | | 2 | 138 | 138 | 138 | 138 | 95 | 138 | 138 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1071 | 0 | | 3 | 138 | 138 | 138 | 138 | 95 | 138 | 138 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 138 | 1 | | 4 | 138 | 138 | 138 | 138 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 138 | 0 | | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | | 89994 | 138 | 138 | 138 | 138 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 138 | 0 | | 89995 | 138 | 138 | 138 | 138 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 138 | 1 | | 89996 | 138 | 138 | 115 | 734 | 734 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 138 | 0 | | 89997 | 138 | 138 | 115 | 734 | 734 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 138 | 1 | 89999 rows × 42 columns 训练集与测试集划分 通过上述预处理后,我们得到了用户的历史输入数据与推商品的关联数据集,接下来我们需要将上述数据集进行划分以训练集、验证集与测试集。以便模型在训练好的能拥有更好泛化性与可靠性。 训练集与测试集的划分采用'train_test_split',该方法集成在'sklearn.model_selection'库中,提供了数据切分、交叉验证与网格搜索等功能,本文用到的是数据划分功能。 将模型输入与输出进行组合划分训练集、测试集与验证集三个集合,首先从总体数据量上将训练集与测试集以8:2(test_size = 0.2)的比例进行划分,然后再讲训练集中数据按照7.5:2.5(test_size = 0.25)比例划分训练集与验证集。 import torch.utils.data as Data from sklearn.model_selection import train_test_split #模型输入 data_X = data.iloc[:,:-1] #模型输出 data_y = data.label.values #划分训练集,测试集,验证集 tmp_X, test_X, tmp_y, test_y = train_test_split(data_X, data_y, test_size = 0.2, random_state=42, stratify=data_y) train_X, val_X, train_y, val_y = train_test_split(tmp_X, tmp_y, test_size = 0.25, random_state=42, stratify=tmp_y) dis_test_x = test_X dis_test_y = test_y # numpy转化为torch train_X = torch.from_numpy(train_X.values).long() val_X = torch.from_numpy(val_X.values).long() test_X = torch.from_numpy(test_X.values).long() train_y = torch.from_numpy(train_y).long() val_y = torch.from_numpy(val_y).long() test_y = torch.from_numpy(test_y).long() # 设置dataset train_set = Data.TensorDataset(train_X, train_y) val_set = Data.TensorDataset(val_X, val_y) test_set = Data.TensorDataset(test_X, test_y) # 设置数据集加载器,用于模型训练,按批次输入数据 train_loader = Data.DataLoader(dataset=train_set, batch_size=32, shuffle=True) val_loader = Data.DataLoader(dataset=val_set, batch_size=32, shuffle=False) test_loader = Data.DataLoader(dataset=test_set, batch_size=32, shuffle=False) 模型训练过程定义 上述步骤已经分别将模型构建与数据集处理完成,接下来就是需要对模型进行训练。由于本文实验数据与模型需要运行在npu上,因此需要指定'device'是'npu',此外,该模型实现使用pytorch,目前npu对pytorch适配度非常高,可以使用'transfer_to_npu'将pytorch模型无感迁移到npu上运行。 import torch_npu from torch_npu.contrib import transfer_to_npu device="npu" /home/pengyongrong/miniconda3/envs/ctrExperiments/lib/python3.9/site-packages/torch_npu/contrib/transfer_to_npu.py:211: ImportWarning: ************************************************************************************************************* The torch.Tensor.cuda and torch.nn.Module.cuda are replaced with torch.Tensor.npu and torch.nn.Module.npu now.. The torch.cuda.DoubleTensor is replaced with torch.npu.FloatTensor cause the double type is not supported now.. The backend in torch.distributed.init_process_group set to hccl now.. The torch.cuda.* and torch.cuda.amp.* are replaced with torch.npu.* and torch.npu.amp.* now.. The device parameters have been replaced with npu in the function below: torch.logspace, torch.randint, torch.hann_window, torch.rand, torch.full_like, torch.ones_like, torch.rand_like, torch.randperm, torch.arange, torch.frombuffer, torch.normal, torch._empty_per_channel_affine_quantized, torch.empty_strided, torch.empty_like, torch.scalar_tensor, torch.tril_indices, torch.bartlett_window, torch.ones, torch.sparse_coo_tensor, torch.randn, torch.kaiser_window, torch.tensor, torch.triu_indices, torch.as_tensor, torch.zeros, torch.randint_like, torch.full, torch.eye, torch._sparse_csr_tensor_unsafe, torch.empty, torch._sparse_coo_tensor_unsafe, torch.blackman_window, torch.zeros_like, torch.range, torch.sparse_csr_tensor, torch.randn_like, torch.from_file, torch._cudnn_init_dropout_state, torch._empty_affine_quantized, torch.linspace, torch.hamming_window, torch.empty_quantized, torch._pin_memory, torch.autocast, torch.load, torch.Generator, torch.Tensor.new_empty, torch.Tensor.new_empty_strided, torch.Tensor.new_full, torch.Tensor.new_ones, torch.Tensor.new_tensor, torch.Tensor.new_zeros, torch.Tensor.to, torch.nn.Module.to, torch.nn.Module.to_empty ************************************************************************************************************* warnings.warn(msg, ImportWarning) 通常来说,训练一个模型通常需要定义损失函数、定义优化器、定义模型参数可更新及遍历数据集训练模型四个步骤。前三个步骤比较直接,最后一个步骤在使用数据集训练模型过程中,需要根据输入数据给到模型获得预测的结果,计算损失、反向传播后进行参数更新。 据上述分析,我们定义了'train(model)'函数来实现整个模型的训练过程,入参为'model'表示需要训练的模型,具体的步骤解释均在代码中注解。 import torch.optim as optim import torch.nn.functional as F from sklearn.metrics import roc_auc_score def train(model): # 1.设置迭代次数训练模型 for epoch in range(epoches): train_loss = [] # 1.1设置二分类交叉熵损失函数 criterion = nn.BCELoss() # 1.2设置adam优化器 optimizer = optim.Adam(model.parameters(), lr = 0.001) # 1.3设置模型训练,此时模型参数可以更新 model.train() # 1.4遍历训练数据集,获取每个梯度的大小,输入输出 for batch, (x, y) in enumerate(train_loader): # 1.4.1如果有gpu则把数据放入显存中计算,没有的话用cpu计算 x=x.to(device) y=y.to(device) # 1.4.2数据输入模型 pred = model(x) # 1.4.3计算损失 loss = criterion(pred, y.float().detach()) # 1.4.4优化器梯度清空 optimizer.zero_grad() # 1.4.5方向传播,计算梯度 loss.backward() # 1.4.6优化器迭代模型参数 optimizer.step() # 1.4.7记录模型损失数据 train_loss.append(loss.item()) # 1.5模型固化,不修改梯度 model.eval() val_loss = [] prediction = [] y_true = [] with torch.no_grad(): # 1.6遍历验证数据集,获取每个梯度的大小,输入输出 for batch, (x, y) in enumerate(val_loader): # 1.6.1如果有gpu则把数据放入显存中计算,没有的话用cpu计算 x=x.to(device) y=y.to(device) # 1.6.2模型预测输入 pred = model(x) # 1.6.3计算损失函数 loss = criterion(pred, y.float().detach()) val_loss.append(loss.item()) prediction.extend(pred.tolist()) y_true.extend(y.tolist()) # 1.7计算auc得分 val_auc = roc_auc_score(y_true=y_true, y_score=prediction) # 1.8输出模型训练效果 print ("EPOCH %s train loss : %.5f validation loss : %.5f validation auc is %.5f" % (epoch, np.mean(train_loss), np.mean(val_loss), val_auc)) return train_loss, val_loss, val_auc 使用Amazon-book训练wideWeep模型 # 计算出现的最大类别编码是多少,目的为统计一共有多少个商品类别 fields = data.max().max() # 定义din模型 model = DeepInterestNet(feature_dim=fields, embed_dim=8, mlp_dims=[64,32], dropout=0.2).to(device) # 迭代次数 epoches = 5 # 模型训练 _= train(model) EPOCH 0 train loss : 0.69174 validation loss : 0.68478 validation auc is 0.53995 EPOCH 1 train loss : 0.68359 validation loss : 0.67958 validation auc is 0.57892 EPOCH 2 train loss : 0.67868 validation loss : 0.67763 validation auc is 0.58612 EPOCH 3 train loss : 0.67605 validation loss : 0.67401 validation auc is 0.59358 EPOCH 4 train loss : 0.67428 validation loss : 0.67516 validation auc is 0.59542 评估模型性能 通过上述步骤我们将整个模型在Amazon-book数据集上进行了训练,并且得到了较不错的准确率,接下来我们使用测试集中的某个样例对模型进行测试。 #从换分的测试数据集中取出一个数据,从该数据可以看出用户感兴趣的类别是Books,推荐的类别也是Books因此,用户很有可能会点击购买该商品对应label值是1。 dis_test_x.apply(cate_encoder.inverse_transform).reset_index().head(1) | | index | hist_cate_0 | hist_cate_1 | hist_cate_2 | hist_cate_3 | hist_cate_4 | hist_cate_5 | hist_cate_6 | hist_cate_7 | hist_cate_8 | ... | hist_cate_31 | hist_cate_32 | hist_cate_33 | hist_cate_34 | hist_cate_35 | hist_cate_36 | hist_cate_37 | hist_cate_38 | hist_cate_39 | cateID | 1 rows × 42 columns #由于本轮实验需要运行在npu上,因此需要将模型输入的向量加载到npu设备上 inputTensor = test_X[0].to(device) inputTensor tensor([138, 138, 138, 138, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 138], device='npu:0') #将输入给到模型,得到预测购买的概率为0.4946,该值与标签label=1,有较大差距是因为模型只迭代训练5次,可以增加训练迭代次数以后再进行测试。 model(torch.unsqueeze(inputTensor, 0)) Warning: Device do not support double dtype now, dtype cast repalce with float. tensor([0.4946], device='npu:0', grad_fn=<SigmoidBackward0>) 内存使用情况: 整个训练过程的内存使用情况可以通过"npu-smi info"命令在终端查看,因此本文实验只用到了单个npu卡(也就是chip 0),内存占用约141M,对内存、精度或性能优化有兴趣的可以自行尝试进行优化,这里运行过程中也有其他程序在运行,因此本实验用到的网络所需要的内存已单独框出来。 Reference ========= \[1\] Zhou, Guorui , et al. "Deep Interest Network for Click-Through Rate Prediction." (2017).
2025年-4月-28日
7 阅读
0 评论
人工智能
2025-4-28
从崩溃到3G带宽!Panabit三种部署模式性能实测,这个坑千万别踩
我们前面学习了Panabit的两种部署方式(Panabit竟能无缝整合Ubuntu?用5MB升级包在Ubuntu极速安装Panabit),当我打算把他用起来时,发现有一点瑕疵,那就是安装完成之后只能调整CPU和网卡数量,不能调整内存规格,一旦调整了内存规格,要么无法引导;要么进入无限自检报错循环,无法启动服务。 我本来想着给他多分配一点资源,等配置完成之后简单测试一下性能的,看来得重装一台高规格的虚拟机了。切换到ESXi平台,我们按照之前的方法重新部署一台高规格虚拟机(误以为是外国货?这家国产SD-WAN神器竟能免费白嫖,附Panabit免费版体验全记录),先分配16核CPU、16 GB内存,结果安装完之后就进不了系统了。 最终,经过多次尝试,内存最高大概也就是能分配到3 GB,再大就启动异常了。所以,我们就得到了一台8核CPU、3 GB内存的“高”规格虚拟机。 在后台查看系统配置,生效8核CPU,总内存3002 MB,剩余1827 MB。 查看系统进程,发现有5个/usr/ramdisk/bin/panaos的进程,照此推断,分配6核CPU应该就够用了。 系统到位之后,我们测试一下Panabit的设备上线。 在WEB管理页面,点击工具栏的【上线指导】,网络模式我们先选择【网关模式】。 在网络配置环节,这里的配置挺有意思,通过按钮可以切换网卡角色是WAN接口还是LAN接口,通过点击网卡图标可以配置对应的网卡配置。按照它的默认配置,eth1是LAN接口,eth2是WAN接口,我对换了一下,配置WAN接口参数如下: 奇怪的是,配置接口IP地址竟然不需要配置掩码,不知道会下发成多少。 然后点击eth2配置LAN接口参数,可以直接配置DHCP相关参数。 确认配置参数,然后提交。 配置成功之后,可以在导航栏【网络设置】下的【网络接口】查看接口信息,其中方向对应接口角色,eth1是WAN口,方向对应接外;eth2是LAN口,方向对应接内。 还可以在【网络设置】下的【LAN/WAN】中查看接口配置。其中,LAN接口状态如下: WAN线路状态如下,仍然没有显示掩码长度信息: 在【网络设置】下的【路由/NAT】中,对于网关模式还默认创建了一条NAT规则,如下所示,可以看到,一条默认路由将流量全部引到WAN接口,并启用了NAT地址转换。 接下来,简单测试一下转发性能。 最高带宽3.22 Gbps,平均带宽2.98 Gbps,没有特别强,但也不是很拉胯。观察打流过程中的资源利用率,最高也就到200%,应该是资源分配问题,相比于空载下的100%,说明也就是一个新核心参与转发,基本上负载在CPU0上;理论上讲,提升空间还是很大的。 查看应用排名,它将iperf打流流量识别成了未知应用,统计到的累计流量为30.61 GB,按照iperf服务端的统计为29.02 GB,两者差的不多。 接下来,我们再次点击【上线指导】中,将网络模式修改为【透明网桥模式】。 在网络配置环节,可以通过拖动开交换网卡对接位置,按照前面的操作,我将eth1放到了接外一侧,将eth2放到了接内一侧。 确认配置环节,这个对端网卡有点跳戏,不过也能明白,确认提交。 配置生效之后,此时【网络设置】下的【LAN/WAN】中已经不展示接口了。 调整主机配置,先测试一下连通性。 然后测试一下转发性能,测得最高带宽3.42 Gbps,平均带宽2.99 Gbps;整个打流过程中,CPU利用率没有明显变化,像是没有处理转发的报文。对比网关模式,性能提升微乎其微;换言之,网关模式对比网桥模式几乎没有性能损耗,貌似也还可以。 虽然是网桥模式,但还是能统计到有12.22 GB的流量,相比于iperf服务端的统计的11.53 GB,还是存在一点小差异(5.6%),在可接受范围之内。 最后一种网络模式就是我们前面提到过的【旁路分析模式】了。 这里的合法IP指的是需要分析的内网IP网段,可以添加多个,设备通过内网网段来区分上下行流量,内网网段为源地址则是上行流量,内网网段为目的地址则是下行流量。 正常来讲需要配置端口镜像来进行分析,我ESXi内网环境简单,先简单演示一下。 此时【网络设置】下的【LAN/WAN】中同样不展示接口,在【网络接口】中查看,发现两个接口都设置成了【接内】方向的监控模式,有一点流入速率。 查看应用排行,只剩下ARP报文和ICMP报文了。 好了,Panabit的三种接入方式我们就介绍完了。 ***推荐阅读*** 误以为是外国货?这家国产SD-WAN神器竟能免费白嫖,附Panabit免费版体验全记录Panabit竟能无缝整合Ubuntu?用5MB升级包在Ubuntu极速安装Panabit48核+96GB内存!EVE-NG 6.2低配版安装实录,网络工程师必看!告别重装!Ubuntu 22.04直升24.04教程,零数据丢失的终极方案小白也能玩转VPP!Ubuntu 24.04使用APT极速部署VPPCentOS迁移指南:在Ubuntu上从零编译部署VPP+DPDK,解锁Ubuntu网络性能!从单网卡到全局,3种方法教你精准拿捏Ubuntu的IPv6IPv6隧道搭建指南:用WireGard轻松玩转IPv4/IPv6混合网络基于IPv6配置openVPN实战:告别双栈难题,一步打通IPv6隧道!无需公网IPv4!手把手教你配置基于IPv6的WireGard安全隧道手把手教你玩转IPv6 PPPoE:Ubuntu拨号+VSR服务器配置全解析运营商不会告诉你的秘密:企业级路由器能通过多拨叠加带宽,轻松跑满千兆!目前来看,ollama量化过的DeepSeek模型应该就是最具性价比的选择哪怕用笔记本的4070显卡运行DeepSeek,都要比128核的CPU快得多!帮你省20块!仅需2条命令即可通过Ollama本地部署DeepSeek-R1模型
2025年-4月-28日
4 阅读
0 评论
网络安全
2025-4-28
跨境电商技术指南:网络环境搭建的关键要点
对于跨境电商从业者来说,稳定的网络环境是业务开展的基础。很多新手常遇到账号异常、访问受限等问题,究其原因,IP选择不当往往是关键因素。 静态住宅IP因其真实性和稳定性,能有效降低平台风控概率。相比动态IP,静态住宅IP具有固定地理位置特征,更符合平台对正常用户行为的判定标准。建议重要业务账号采用静态住宅IP,并配合浏览器环境隔离技术使用。 对于数据采集等短期任务,动态住宅IP更具性价比。但在账号注册、店铺运营等场景下,建议优先考虑静态住宅IP解决方案,以确保业务连续性。不同业务场景需要匹配不同的网络解决方案,这是跨境电商技术架构中不可忽视的一环。跨境电商技术架构:如何构建合规稳定的网络环境? 在跨境电商运营中,网络环境的合规性和稳定性直接影响业务成败。作为技术出身的从业者,我想分享一些网络架构方面的实战经验。 首先需要明确的是,主流跨境电商平台都采用了先进的风控系统。根据我们的测试数据,使用普通数据中心IP的新账号,触发风控的概率高达72%,而采用优质住宅IP的账号通过率可以提升至90%以上。 静态住宅IP在技术层面具有三大优势: IP地址与真实住宅网络特征完全匹配 地理位置信息保持长期稳定 网络行为模式符合正常用户特征 对于技术团队来说,建议采用分层架构: 核心业务账号使用静态住宅IP 数据采集等辅助业务使用动态住宅IP 通过Docker容器实现环境隔离 结合浏览器指纹技术完善风控防护 我们在实际运营中发现,一个完善的网络架构可以降低60%以上的账号异常风险。特别是在亚马逊、Shopify等平台,合规的网络环境已经成为基础技术要求。 (技术提示:建议定期检测IP质量,使用curl或Python requests库验证IP特征是否符合住宅网络标准)
2025年-4月-28日
4 阅读
0 评论
网络安全
2025-4-27
Canalys:2025 年 Q1 印度智能手机出货量同比下降 8%,vivo、三星、小米前三
@Canalys科纳仕咨询 数据显示,2025 年第一季度,印度智能手机出货量同比下降 8%,总计 3240 万部,主要受持续疲软的需求和 2024 年末渠道库存偏高的影响。
2025年-4月-27日
15 阅读
0 评论
手机数码
1
2
3
4