python基于轻量级卷积神经网络模型ShuffleNetv2开发构建辣椒病虫害图像识别系统

轻量级识别模型在我们前面的博文中已经有过很多实践了,感兴趣的话可以自行移步阅读:

《移动端轻量级模型开发谁更胜一筹,efficientnet、mobilenetv2、mobilenetv3、ghostnet、mnasnet、shufflenetv2驾驶危险行为识别模型对比开发测试》

《基于Pytorch框架的轻量级卷积神经网络垃圾分类识别系统》

《基于轻量级卷积神经网络模型实践Fruits360果蔬识别——自主构建CNN模型、轻量化改造设计lenet、alexnet、vgg16、vgg19和mobilenet共六种CNN模型实验对比分析》

《探索轻量级模型性能上限,基于GhostNet模型开发构建多商品细粒度图像识别系统》

《基于轻量级神经网络GhostNet开发构建的200种鸟类细粒度识别分析系统》

《基于MobileNet的轻量级卷积神经网络实现玉米螟虫不同阶段识别分析》

《python开发构建轻量级卷积神经网络模型实现手写甲骨文识别系统》

《基于轻量级模型GHoshNet开发构建眼球眼疾识别分析系统,构建全方位多层次参数对比分析实验》

本文的核心思想是像基于ShuffleNetv2来开发构建辣椒病虫害识别系统,首先看下实例效果:

本文选择的是轻量级网络中非常强大的ShuffleNetv2,ShuffleNetv2网络是一种用于图像识别和分类任务的卷积神经网络结构,它旨在在保持准确性的同时尽可能地减少模型的计算和参数量。下面是对ShuffleNetv2网络构建原理的详细介绍,并针对性地分析其优点和缺点:

构建原理:

  1. 基本单元:ShuffleNetv2网络的基本单元是由深度可分离卷积和通道重排组成的特殊模块。其中深度可分离卷积用于减少计算量和参数数量,而通道重排则用于交换和重组特征通道。

  2. 分组卷积:ShuffleNetv2将卷积操作分组,使得每个分组内部进行特征提取,然后再将特征通道进行重排和整合,从而实现了计算效率的提升。

  3. 网络结构:ShuffleNetv2网络结构由多个堆叠的ShuffleNetv2块组成,每个块内部包含了多个基本单元,通过合理的设计实现了高效的信息流动和特征提取。

优点:

  1. 轻量级高效:ShuffleNetv2相比传统的卷积神经网络具有更少的参数量和计算量,适合于移动设备上的部署和实时推理。

  2. 准确性:尽管模型规模小,但ShuffleNetv2在保持较高的准确性的同时,实现了高效的模型推理。

  3. 结构灵活:ShuffleNetv2网络结构可以通过调整基本单元的个数和网络深度来适应不同的计算资源和任务需求。

缺点:

  1. 学习能力有限:由于参数数量较少,ShuffleNetv2网络可能在复杂场景和大规模数据上的表示学习能力相对较弱,可能无法取得更高的准确性。

  2. 训练复杂度:尽管ShuffleNetv2网络在推理时很高效,但在训练过程中相比一些大型网络结构可能需要更多的迭代才能取得好的效果,训练复杂度较大。

总的来说,ShuffleNetv2网络在轻量级和高效方面具有明显的优势,适用于移动设备和资源受限的场景,但在一些大规模和复杂任务上可能会存在一定的限制。

这里给出基于Keras和pytorch对应的代码实现,首先是keras实现,如下所示:

#!usr/bin/env python
# encoding:utf-8
from __future__ import division



import os
import numpy as np
from keras.utils import plot_model
from keras.applications.imagenet_utils import _obtain_input_shape
from keras.engine.topology import get_source_inputs
from keras.layers import *
from keras.models import Model
import keras.backend as K
from utils import block


def ShuffleNetV2(
    include_top=True,
    input_tensor=None,
    scale_factor=1.0,
    pooling="max",
    input_shape=(224, 224, 3),
    load_model=None,
    num_shuffle_units=[3, 7, 3],
    bottleneck_ratio=1,
    classes=1000,
):
    if K.backend() != "tensorflow":
        raise RuntimeError("Only tensorflow supported for now")
    name = "ShuffleNetV2_{}_{}_{}".format(
        scale_factor, bottleneck_ratio, "".join([str(x) for x in num_shuffle_units])
    )
    input_shape = _obtain_input_shape(
        input_shape,
        default_size=224,
        min_size=28,
        require_flatten=include_top,
        data_format=K.image_data_format(),
    )
    out_dim_stage_two = {0.5: 48, 1: 116, 1.5: 176, 2: 244}

    if pooling not in ["max", "avg"]:
        raise ValueError("Invalid value for pooling")
    if not (float(scale_factor) * 4).is_integer():
        raise ValueError("Invalid value for scale_factor, should be x over 4")
    exp = np.insert(
        np.arange(len(num_shuffle_units), dtype=np.float32), 0, 0
    )  
    # [0., 0., 1., 2.]
    out_channels_in_stage = 2**exp
    out_channels_in_stage *= out_dim_stage_two[
        bottleneck_ratio
    ]  
    #  calculate output channels for each stage
    out_channels_in_stage[0] = 24  
    # first stage has always 24 output channels
    out_channels_in_stage *= scale_factor
    out_channels_in_stage = out_channels_in_stage.astype(int)
    if input_tensor is None:
        img_input = Input(shape=input_shape)
    else:
        if not K.is_keras_tensor(input_tensor):
            img_input = Input(tensor=input_tensor, shape=input_shape)
        else:
            img_input = input_tensor
    # create shufflenet architecture
    x = Conv2D(
        filters=out_channels_in_stage[0],
        kernel_size=(3, 3),
        padding="same",
        use_bias=False,
        strides=(2, 2),
        activation="relu",
        name="conv1",
    )(img_input)
    x = MaxPool2D(pool_size=(3, 3), strides=(2, 2), padding="same", name="maxpool1")(x)
    # create stages containing shufflenet units beginning at stage 2
    for stage in range(len(num_shuffle_units)):
        repeat = num_shuffle_units[stage]
        x = block(
            x,
            out_channels_in_stage,
            repeat=repeat,
            bottleneck_ratio=bottleneck_ratio,
            stage=stage + 2,
        )
    if bottleneck_ratio < 2:
        k = 1024
    else:
        k = 2048
    x = Conv2D(
        k,
        kernel_size=1,
        padding="same",
        strides=1,
        name="1x1conv5_out",
        activation="relu",
    )(x)
    if pooling == "avg":
        x = GlobalAveragePooling2D(name="global_avg_pool")(x)
    elif pooling == "max":
        x = GlobalMaxPooling2D(name="global_max_pool")(x)
    if include_top:
        x = Dense(classes, name="fc")(x)
        x = Activation("softmax", name="softmax")(x)
    if input_tensor:
        inputs = get_source_inputs(input_tensor)
    else:
        inputs = img_input
    model = Model(inputs, x, name=name)
    if load_model:
        model.load_weights("", by_name=True)
    return model

接下来是PyTorch的实现:

#!usr/bin/env python
# encoding:utf-8
from __future__ import division



import os
import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.nn import init
from collections import OrderedDict



def _make_divisible(v, divisor, min_value=None):
    """
    This function is taken from the original tf repo.
    It ensures that all layers have a channel number that is divisible by 8
    It can be seen here:
    https://github.com/tensorflow/models/blob/master/research/slim/nets/mobilenet/mobilenet.py
    :param v:
    :param divisor:
    :param min_value:
    :return:
    """
    if min_value is None:
        min_value = divisor
    new_v = max(min_value, int(v + divisor / 2) // divisor * divisor)
    # Make sure that round down does not go down by more than 10%.
    if new_v < 0.9 * v:
        new_v += divisor
    return new_v


def channel_shuffle(x, groups):
    batchsize, num_channels, height, width = x.data.size()
    assert num_channels % groups == 0
    channels_per_group = num_channels // groups
    # reshape
    x = x.view(batchsize, groups, channels_per_group, height, width)
    # transpose
    # - contiguous() required if transpose() is used before view().
    #   See https://github.com/pytorch/pytorch/issues/764
    x = torch.transpose(x, 1, 2).contiguous()
    # flatten
    x = x.view(batchsize, -1, height, width)
    return x


class SELayer(nn.Module):
    def __init__(self, channel, reduction=16):
        super(SELayer, self).__init__()
        self.avg_pool = nn.AdaptiveAvgPool2d(1)
        self.fc = nn.Sequential(
            nn.Linear(channel, channel // reduction),
            nn.ReLU(inplace=True),
            nn.Linear(channel // reduction, channel),
            nn.Sigmoid(),
        )

    def forward(self, x):
        b, c, _, _ = x.size()
        y = self.avg_pool(x).view(b, c)
        y = self.fc(y).view(b, c, 1, 1)
        return x * y


class BasicUnit(nn.Module):
    def __init__(
        self,
        inplanes,
        outplanes,
        c_tag=0.5,
        activation=nn.ReLU,
        SE=False,
        residual=False,
        groups=2,
    ):
        super(BasicUnit, self).__init__()
        self.left_part = round(c_tag * inplanes)
        self.right_part_in = inplanes - self.left_part
        self.right_part_out = outplanes - self.left_part
        self.conv1 = nn.Conv2d(
            self.right_part_in, self.right_part_out, kernel_size=1, bias=False
        )
        self.bn1 = nn.BatchNorm2d(self.right_part_out)
        self.conv2 = nn.Conv2d(
            self.right_part_out,
            self.right_part_out,
            kernel_size=3,
            padding=1,
            bias=False,
            groups=self.right_part_out,
        )
        self.bn2 = nn.BatchNorm2d(self.right_part_out)
        self.conv3 = nn.Conv2d(
            self.right_part_out, self.right_part_out, kernel_size=1, bias=False
        )
        self.bn3 = nn.BatchNorm2d(self.right_part_out)
        self.activation = activation(inplace=True)
        self.inplanes = inplanes
        self.outplanes = outplanes
        self.residual = residual
        self.groups = groups
        self.SE = SE
        if self.SE:
            self.SELayer = SELayer(self.right_part_out, 2)  # TODO

    def forward(self, x):
        left = x[:, : self.left_part, :, :]
        right = x[:, self.left_part :, :, :]
        out = self.conv1(right)
        out = self.bn1(out)
        out = self.activation(out)
        out = self.conv2(out)
        out = self.bn2(out)
        out = self.conv3(out)
        out = self.bn3(out)
        out = self.activation(out)
        if self.SE:
            out = self.SELayer(out)
        if self.residual and self.inplanes == self.outplanes:
            out += right
        return channel_shuffle(torch.cat((left, out), 1), self.groups)


class DownsampleUnit(nn.Module):
    def __init__(self, inplanes, c_tag=0.5, activation=nn.ReLU, groups=2):
        super(DownsampleUnit, self).__init__()
        self.conv1r = nn.Conv2d(inplanes, inplanes, kernel_size=1, bias=False)
        self.bn1r = nn.BatchNorm2d(inplanes)
        self.conv2r = nn.Conv2d(
            inplanes,
            inplanes,
            kernel_size=3,
            stride=2,
            padding=1,
            bias=False,
            groups=inplanes,
        )
        self.bn2r = nn.BatchNorm2d(inplanes)
        self.conv3r = nn.Conv2d(inplanes, inplanes, kernel_size=1, bias=False)
        self.bn3r = nn.BatchNorm2d(inplanes)
        self.conv1l = nn.Conv2d(
            inplanes,
            inplanes,
            kernel_size=3,
            stride=2,
            padding=1,
            bias=False,
            groups=inplanes,
        )
        self.bn1l = nn.BatchNorm2d(inplanes)
        self.conv2l = nn.Conv2d(inplanes, inplanes, kernel_size=1, bias=False)
        self.bn2l = nn.BatchNorm2d(inplanes)
        self.activation = activation(inplace=True)
        self.groups = groups
        self.inplanes = inplanes

    def forward(self, x):
        out_r = self.conv1r(x)
        out_r = self.bn1r(out_r)
        out_r = self.activation(out_r)
        out_r = self.conv2r(out_r)
        out_r = self.bn2r(out_r)
        out_r = self.conv3r(out_r)
        out_r = self.bn3r(out_r)
        out_r = self.activation(out_r)
        out_l = self.conv1l(x)
        out_l = self.bn1l(out_l)
        out_l = self.conv2l(out_l)
        out_l = self.bn2l(out_l)
        out_l = self.activation(out_l)
        return channel_shuffle(torch.cat((out_r, out_l), 1), self.groups)


class ShuffleNetV2(nn.Module):
    """
    ShuffleNetV2 implementation
    """

    def __init__(
        self,
        scale=1.0,
        in_channels=3,
        c_tag=0.5,
        num_classes=1000,
        activation=nn.ReLU,
        SE=False,
        residual=False,
        groups=2,
    ):
        """
        ShuffleNetV2 constructor
        :param scale:
        :param in_channels:
        :param c_tag:
        :param num_classes:
        :param activation:
        :param SE:
        :param residual:
        :param groups:
        """

        super(ShuffleNetV2, self).__init__()

        self.scale = scale
        self.c_tag = c_tag
        self.residual = residual
        self.SE = SE
        self.groups = groups
        self.activation_type = activation
        self.activation = activation(inplace=True)
        self.num_classes = num_classes
        self.num_of_channels = {
            0.5: [24, 48, 96, 192, 1024],
            1: [24, 116, 232, 464, 1024],
            1.5: [24, 176, 352, 704, 1024],
            2: [24, 244, 488, 976, 2048],
        }
        self.c = [_make_divisible(chan, groups) for chan in self.num_of_channels[scale]]
        self.n = [3, 8, 3]  # TODO: should be [3,7,3]
        self.conv1 = nn.Conv2d(
            in_channels, self.c[0], kernel_size=3, bias=False, stride=2, padding=1
        )
        self.bn1 = nn.BatchNorm2d(self.c[0])
        self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2)
        self.shuffles = self._make_shuffles()
        self.conv_last = nn.Conv2d(self.c[-2], self.c[-1], kernel_size=1, bias=False)
        self.bn_last = nn.BatchNorm2d(self.c[-1])
        self.avgpool = nn.AdaptiveAvgPool2d(1)
        self.fc = nn.Linear(self.c[-1], self.num_classes)
        self.init_params()

    def init_params(self):
        for m in self.modules():
            if isinstance(m, nn.Conv2d):
                init.kaiming_normal_(m.weight, mode="fan_out")
                if m.bias is not None:
                    init.constant_(m.bias, 0)
            elif isinstance(m, nn.BatchNorm2d):
                init.constant_(m.weight, 1)
                init.constant_(m.bias, 0)
            elif isinstance(m, nn.Linear):
                init.normal_(m.weight, std=0.001)
                if m.bias is not None:
                    init.constant_(m.bias, 0)

    def _make_stage(self, inplanes, outplanes, n, stage):
        modules = OrderedDict()
        stage_name = "ShuffleUnit{}".format(stage)
        # First module is the only one utilizing stride
        first_module = DownsampleUnit(
            inplanes=inplanes,
            activation=self.activation_type,
            c_tag=self.c_tag,
            groups=self.groups,
        )
        modules["DownsampleUnit"] = first_module
        second_module = BasicUnit(
            inplanes=inplanes * 2,
            outplanes=outplanes,
            activation=self.activation_type,
            c_tag=self.c_tag,
            SE=self.SE,
            residual=self.residual,
            groups=self.groups,
        )
        modules[stage_name + "_{}".format(0)] = second_module
        # add more LinearBottleneck depending on number of repeats
        for i in range(n - 1):
            name = stage_name + "_{}".format(i + 1)
            module = BasicUnit(
                inplanes=outplanes,
                outplanes=outplanes,
                activation=self.activation_type,
                c_tag=self.c_tag,
                SE=self.SE,
                residual=self.residual,
                groups=self.groups,
            )
            modules[name] = module
        return nn.Sequential(modules)

    def _make_shuffles(self):
        modules = OrderedDict()
        stage_name = "ShuffleConvs"

        for i in range(len(self.c) - 2):
            name = stage_name + "_{}".format(i)
            module = self._make_stage(
                inplanes=self.c[i], outplanes=self.c[i + 1], n=self.n[i], stage=i
            )
            modules[name] = module
        return nn.Sequential(modules)

    def forward(self, x):
        x = self.conv1(x)
        x = self.bn1(x)
        x = self.activation(x)
        x = self.maxpool(x)
        x = self.shuffles(x)
        x = self.conv_last(x)
        x = self.bn_last(x)
        x = self.activation(x)
        # average pooling layer
        x = self.avgpool(x)
        # flatten for input to fully-connected layer
        x = x.view(x.size(0), -1)
        x = self.fc(x)
        return F.log_softmax(x, dim=1)


可以拿到自己的项目中直接集成使用。

接下来看下数据集:

一共包含11种对应的疾病,如下:

炭疽病
疫病
用药不当
病毒病
温度不适
螨虫
细菌性病害
根腐病
缺素
脐腐病
蓟马

数据分布可视化如下所示:

默认100次的迭代训练,执行结束后来看下结果详情:
【loss曲线】

【acc曲线】

【混淆矩阵】

开发专用的系统界面实现可视化推理实例如下所示:

感兴趣的话都可以自行动手实践一下。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/221485.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python实现FA萤火虫优化算法优化卷积神经网络回归模型(CNN回归算法)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 萤火虫算法&#xff08;Fire-fly algorithm&#xff0c;FA&#xff09;由剑桥大学Yang于2009年提出 , …

dockerdesktop 制作asp.net core webapi镜像-连接sqlserver数据库容器

1.使用visual studio 创建 asp.net core webapi项目 选择启用docker 会生成Dockerfile文件 2.使用efcore连接数据库&#xff0c;安装efcore的包 <ItemGroup><PackageReference Include"Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version&qu…

MySQL 对null 值的特殊处理

需求 需要将不再有效范围内的所有数据都删除&#xff0c;所以用not in (有效list)去实现&#xff0c;但是发现库里&#xff0c;这一列为null的值并没有删除&#xff0c;突然想到是不是跟 anull 不能生效一样&#xff0c;not in 对null不生效&#xff0c;也需要特殊处理。 解决 …

西安安泰Aigtek——ATA-8152射频功率放大器

ATA-8152射频功率放大器简介 ATA-8152是一款射频功率放大器。其P1dB输出功率100W&#xff0c;饱和输出功率200W。增益数控可调&#xff0c;一键保存设置&#xff0c;提供了方便简洁的操作选择&#xff0c;可与主流的信号发生器配套使用&#xff0c;实现射频信号的放大。宽范围供…

数据结构 | 查漏补缺之

DFS&BFS 哈希表-二次探测再散列法 完全二叉树&深度计算 排序 快速排序-挖坑法 插入、选择、冒泡、区别 插入从第一个元素开始&#xff0c;后面的元素与前面以及排序好的元素比较&#xff0c;插入其中&#xff0c;使其有序&#xff0c;最终效果是前面的有序选择选择…

dockerdesktop推送镜像到dockerhub

1.查看镜像(打开powershell) docker ps2.打tag docker tag pengzx/aspnetcoredocker:v1 pengzx/aspnetcoredocker:v2pengzx/aspnetcoredocker:v1:本地的镜像名加版本号 pengzx/aspnetcoredocker:v2&#xff1a;需要上传的镜像名&#xff08;要以dockerhub的用户名开头/本地镜像…

Hadoop学习笔记(HDP)-Part.14 安装YARN+MR

目录 Part.01 关于HDP Part.02 核心组件原理 Part.03 资源规划 Part.04 基础环境配置 Part.05 Yum源配置 Part.06 安装OracleJDK Part.07 安装MySQL Part.08 部署Ambari集群 Part.09 安装OpenLDAP Part.10 创建集群 Part.11 安装Kerberos Part.12 安装HDFS Part.13 安装Ranger …

根文件系统的开机自启动测试

一. 简介 本文在之前制作的根文件系统可以正常运行的基础上进行的&#xff0c;继上一篇文章地址如下&#xff1a; 完善根文件系统-CSDN博客 在前面测试软件hello 运行时&#xff0c;都是等 Linux 启动进入根文件系统以后手动输入 “./hello” 命令 来完成的。 我们一般做好产…

Leetcode1423. 可获得的最大点数

Every day a Leetcode 题目来源&#xff1a;1423. 可获得的最大点数 解法1&#xff1a;前缀和 后缀和 基于贪心的思想&#xff0c;要使得获得的点数最大&#xff0c;每次拿卡牌都应该选点数尽量高的卡牌。 但是拿卡牌有限制&#xff0c;每次行动&#xff0c;只可以从行的…

国产智能运维操作系统新选择-浪潮KeyarchOS

1.背景 在CentOS停更&#xff0c;国有企业纷纷摒弃原有的开发与运维工具&#xff0c;全面拥抱国产。我司也顺应号召&#xff0c;更换原有CentOS系统。 在新系统选型上&#xff0c;我司有以下要求&#xff1a; 国产、快速更新迭代、社区活跃&#xff1b;拥有一定知名度&#x…

初级数据结构(一)——顺序表

文中代码源文件已上传&#xff1a;数据结构源码 1、顺序表的特点 1.1、数组 现实中数据记录一般都记录在表格中&#xff0c;如进货单、菜单等&#xff0c;它们的最大特点就是有序。表述中可以用第一项、第二项、第 n 项来描述表格中某个数据或者某串数据。在 C 语言中&#…

uniapp基于u-grid-item九宫格实现uCharts秋云图表展示

uniapp基于uView的UI组件u-grid-item九宫格实现uCharts秋云可视化图表展示 这里使用uView的u-grid-item九宫格组件去显示图标排列 九宫格可以做成多列&#xff0c;移动设备上可以通过左右滑动进行展示 <template><div><div style"text-align: center;font…

报错:Parsed mapper file: ‘file mapper.xml

报错 &#xff1a; Logging initialized using class org.apache.ibatis.logging.stdout.StdOutImpl adapter. Registered plugin: com.github.yulichang.interceptor.MPJInterceptor3b2c8bda Parsed mapper file: file [/Mapper.xml] application无法启动 我这边产生原因是项…

python socket编程7 - 使用PyQt6 开发UI界面新增实现UDP server和client单机通讯的例子

在第五篇中&#xff0c;简单实现了命令行下的 TCP/UDP server和client的单机通讯。 在第六篇中&#xff0c;实现了PyQt6开发界面&#xff0c;TCP协议实现的单机server和client的通讯功能。 这一篇&#xff0c;在第六篇的基础上&#xff0c;增加了UDP server和client的单机通讯功…

我在USC南加大学游戏:真实经历/录取作品集_RoSSo艺术留学

近日&#xff0c;美国Common App最新早申统计数据&#xff1a;早申人数与疫情前相比增加了41%&#xff01;专注于国际艺术教育的RoSSo也发现&#xff0c;2022-2023申请季提交早申的学生中&#xff0c;各类热门院校以及艺术留学专业申请人数均是“涨”声一片&#xff01; 图源官…

30、pytest入门内容回顾

整体结构 解读与实操 pytest30讲主要从四个方面由浅入深的进行解读&#xff0c; 开始 讲解了pytest的概述&#xff0c;安装前的准备工作&#xff08;python,pycharm,pytest&#xff09;&#xff0c;运行方式&#xff08;命令行&#xff09;&#xff0c;断言&#xff08;assert…

Linux(统信UOS) 发布.Net Core,并开启Https,绑定证书

实际开发中&#xff0c;有时会需要为小程序或者需要使用https的应用提供API接口服务&#xff0c;这就需要为.Net Core 配置https&#xff0c;配置起来很简单&#xff0c;只需要在配置文件appsettings.json中添加下面的内容即可 "Kestrel": {"Endpoints": …

nodejs+vue+微信小程序+python+PHP天天网站书城管理系统的设计与实现-计算机毕业设计推荐

本项目主要分为前台模块与后台模块2个部分&#xff0c;详细描述如下&#xff1a;   &#xff08;1&#xff09;前台模块 首页: 首页可以起到导航的作用&#xff0c;用户想要了解网站 &#xff0c;网站首页为用户可以深入了解网站提供了一个平台&#xff0c;它就向一个“导游”…

Bionorica成功完成SAP S/4HANA升级 提升医药制造业务效率

企业如何成功地将其现有的ERP ECC系统转换升级到SAP S/4HANA&#xff0c; 并挖掘相关潜力来推动其数字化战略&#xff1f;Bionorica应用SNP软件实施了实时ERP套件&#xff0c;为进一步的增长和未来的创新奠定了基础。 草药市场的领导者&#xff1a;Bionorica Bionorica是世界领…

数据挖掘 分类模型选择

选择的模型有&#xff1a; 决策树、朴素贝叶斯、K近邻、感知机 调用的头文件有&#xff1a; import numpy as np import pandas as pd from matplotlib import pyplot as plt from sklearn.linear_model import Perceptron from sklearn.naive_bayes import GaussianNB from s…