前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >ZStack源码剖析之核心库鉴赏——FlowChain|Java 开发实战

ZStack源码剖析之核心库鉴赏——FlowChain|Java 开发实战

作者头像
泊浮目
发布于 2024-01-09 00:12:03
发布于 2024-01-09 00:12:03
26200
代码可运行
举报
文章被收录于专栏:狗哥的专栏狗哥的专栏
运行总次数:0
代码可运行

前言

在ZStack(或者说产品化的IaaS软件)中的任务通常有很长的执行路径,错误可能发生在路径的任意一处。为了保证系统的正确性,需提供一种较为完善的回滚机制——在ZStack中,通过一个工作流引擎,ZStack的每一个步骤都被包裹在独立的工作流中,可以在出错的时候回滚。此外,通过在配置文件中组装工作流的方式,关键的执行路径可以被配置,这使得架构的耦合度进一步降低。

系统解耦合的手段除了之前文章所提到的分层、分割、分布等,还有一个重要手段是异步,业务之间的消息传递不是同步调用,而是将一个业务操作分成多个阶段,每个阶段之间通过共享数据的方式异步执行进行协作。

这即是一种在业务设计原则中——流程可定义原则的具象化。接触过金融行业的同学肯定知道,不同的保险理赔流程是不一样的。而承保流程和理赔流程是分离的,在需要时进行关联,从而可以复用一些理赔流程,并提供一些个性化理赔流程。

演示代码

就以创建VM为例,在ZStack中大致可以分以下几个步骤:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    <bean id="VmInstanceManager" class="org.zstack.compute.vm.VmInstanceManagerImpl">
        <property name="createVmWorkFlowElements">
            <list>
                <value>org.zstack.compute.vm.VmImageSelectBackupStorageFlow</value>
                <value>org.zstack.compute.vm.VmAllocateHostFlow</value>
                <value>org.zstack.compute.vm.VmAllocatePrimaryStorageFlow</value>
                <value>org.zstack.compute.vm.VmAllocateVolumeFlow</value>
                <value>org.zstack.compute.vm.VmAllocateNicFlow</value>
                <value>org.zstack.compute.vm.VmInstantiateResourcePreFlow</value>
                <value>org.zstack.compute.vm.VmCreateOnHypervisorFlow</value>
                <value>org.zstack.compute.vm.VmInstantiateResourcePostFlow</value>
            </list>
        </property>
<!--  还有很多,介于篇幅不再列出 -->

可以说是代码即文档了。在这里,ZStack显式声明这些Flow在Spring XML中,这些属性将会被注入到createVmWorkFlowElements中。每一个Flow都被拆成了一个个较小的单元,好处不仅是将业务操作分成了多个阶段易于回滚,还是可以有效复用这些Flow。这也是编程思想中“组合”的体现。

如何使用

除了这种配置型声明,还可以在代码中灵活的使用这些FlowChain。在这里,我们将以Case来说明这些FlowChain的用法,避免对ZStack业务逻辑不熟悉的读者看的一头雾水。

一共有两种可用的FlowChain:

  • SimpleFlowChain
  • ShareFlowChain

SimpleFlowChain

我们先来看一个Case

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    @Test
    public void test() {
        FlowChain chain = FlowChainBuilder.newShareFlowChain();

        chain.then(new ShareFlow() {
            int a;

            @Override
            public void setup() {
                flow(new NoRollbackFlow() {
                    @Override
                    public void run(FlowTrigger trigger, Map data) {
                        a = 1;
                        increase();
                        trigger.next();
                    }
                });

                flow(new NoRollbackFlow() {
                    @Override
                    public void run(FlowTrigger trigger, Map data) {
                        a = 2;
                        increase();
                        trigger.next();
                    }
                });
            }
        }).done(new FlowDoneHandler(null) {
            @Override
            public void handle(Map data) {
                success = true;
            }
        }).start();

        Assert.assertTrue(success);
        expect(2);
    }

我们可以看到,这就是一个工作流。完成一个工作流的时候(回调触发时)执行下一个工作流——由trigger.next触发。不仅如此,还可以添加Rollback属性

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    @Test
    public void test() throws WorkFlowException {
        final int[] count = {0};

        new SimpleFlowChain()
                .then(new Flow() {
                    @Override
                    public void run(FlowTrigger chain, Map data) {
                        count[0]++;
                        chain.next();
                    }

                    @Override
                    public void rollback(FlowRollback chain, Map data) {
                        count[0]--;
                        chain.rollback();
                    }
                })
                .then(new Flow() {
                    @Override
                    public void run(FlowTrigger chain, Map data) {
                        count[0]++;
                        chain.next();
                    }

                    @Override
                    public void rollback(FlowRollback chain, Map data) {
                        count[0]--;
                        chain.rollback();
                    }
                })
                .then(new Flow() {
                    @Override
                    public void run(FlowTrigger chain, Map data) {
                        chain.fail(null);
                    }

                    @Override
                    public void rollback(FlowRollback chain, Map data) {
                        count[0]--;
                        chain.rollback();
                    }
                })
                .start();

        Assert.assertEquals(-1, count[0]);
    }

rollback由FlowTrigger的fail触发。这样我们可以保证在发生一些错误的时候及时回滚,防止我们的系统处于一个有脏数据的中间状态。同时,Map也可以用来在Flow之间传递上下文。

ShareFlowChain

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class TestShareFlow {
    int[] count = {0};
    boolean success;

    private void increase() {
        count[0]++;
    }

    private void decrease() {
        count[0]--;
    }

    private void expect(int ret) {
        Assert.assertEquals(count[0], ret);
    }

    @Test
    public void test() {
        FlowChain chain = FlowChainBuilder.newShareFlowChain();

        chain.then(new ShareFlow() {
            int a;

            @Override
            public void setup() {
                flow(new NoRollbackFlow() {
                    @Override
                    public void run(FlowTrigger trigger, Map data) {
                        a = 1;
                        increase();
                        trigger.next();
                    }
                });

                flow(new NoRollbackFlow() {
                    @Override
                    public void run(FlowTrigger trigger, Map data) {
                        a = 2;
                        increase();
                        trigger.next();
                    }
                });
            }
        }).done(new FlowDoneHandler(null) {
            @Override
            public void handle(Map data) {
                success = true;
            }
        }).start();

        Assert.assertTrue(success);
        expect(2);
    }


    @Before
    public void setUp() throws Exception {
        new BeanConstructor().build();
    }
}

比起SimpleFlowChain,ShareFlowChain则是一个Inner class,在相同的作用域里,传递数据变得更加的方便了。

它的实现

在ZStack中,FlowChain作为核心库,其实现也是非常的简单(可以直接参考SimpleFlowChainShareFlowChain),本质就是将任务放入List中,由内部方法进行迭代,在此基础上做了一系列操作。下面将开始分析它的源码。

从接口说起

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public interface FlowChain {
    List<Flow> getFlows();

    FlowChain insert(Flow flow);

    FlowChain insert(int pos, Flow flow);

    FlowChain setFlowMarshaller(FlowMarshaller marshaller);

    FlowChain then(Flow flow);

    FlowChain done(FlowDoneHandler handler);

    FlowChain error(FlowErrorHandler handler);

    FlowChain Finally(FlowFinallyHandler handler);

    FlowChain setData(Map data);

    FlowChain putData(Map.Entry... es);

    FlowChain setName(String name);

    void setProcessors(List<FlowChainProcessor> processors);

    Map getData();

    void start();

    FlowChain noRollback(boolean no);

    FlowChain allowEmptyFlow();
}

接口的名字非常的易懂,那么在这里就不多作解释了。FlowChain仅仅定义了一个Flow最小应有的行为。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//定义了Flow的回滚操作接口
public interface FlowRollback extends AsyncBackup {
    //回滚操作
    void rollback();
    //设置跳过回滚操作
    void skipRestRollbacks();
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//定义了触发器的行为接口
public interface FlowTrigger extends AsyncBackup {
    //触发失败,调用errorHandle
    void fail(ErrorCode errorCode);
    //触发下一个flow
    void next();
    //setError后,在下次调用next的时才会调用errorHandle
    void setError(ErrorCode error);
}

源码解析

Flow

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public interface Flow {
    void run(FlowTrigger trigger, Map data);

    void rollback(FlowRollback trigger, Map data);
}

Flow的定义其实非常的简单——一组方法。执行和对应的回滚,一般在ZStack中都以匿名内部类的方式传入。

Chain的用法

在之前的SimpleFlowChain的case中。我们可以看到一系列的链式调用,大致如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
new SimpleFlowChain().then(new flow()).then(new flow()).then(new flow()).start();

then本质是往List flows里添加一个flow。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    public SimpleFlowChain then(Flow flow) {
        flows.add(flow);
        return this;
    }

再来看看start

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    @Override
    public void start() {
        // 检测flow中是否设置了processors。一般用来打trace
        if (processors != null) {
            for (FlowChainProcessor p : processors) {
                p.processFlowChain(this);
            }
        }
        //如果flows为空但是之前在设置中允许为空,那么就直接直接done部分的逻辑。不然就报错
        if (flows.isEmpty() && allowEmptyFlow) {
            callDoneHandler();
            return;
        }

        if (flows.isEmpty()) {
            throw new CloudRuntimeException("you must call then() to add flow before calling start() or allowEmptyFlow() to run empty flow chain on purpose");
        }
        //每个flow必须有一个map,用来传递上下文
        if (data == null) {
            data = new HashMap<String, Object>();
        }
        //标记为已经开始
        isStart = true;
        //如果没有名字的话给flow 取一个名字,因为很有可能是匿名使用的flow
        if (name == null) {
            name = "anonymous-chain";
        }

        logger.debug(String.format("[FlowChain(%s): %s] starts", id, name));
        //打印trace,方便调试
        if (logger.isTraceEnabled()) {
            List<String> names = CollectionUtils.transformToList(flows, new Function<String, Flow>() {
                @Override
                public String call(Flow arg) {
                    return String.format("%s[%s]", arg.getClass(), getFlowName(arg));
                }
            });
            logger.trace(String.format("execution path:\n%s", StringUtils.join(names, " -->\n")));
        }
        //生成一个迭代器
        it = flows.iterator();
        //从it中获取一个不需要跳过的flow开始执行。如果没有获取到,就执行done逻辑
        Flow flow = getFirstNotSkippedFlow();
        if (flow == null) {
            // all flows are skipped
            callDoneHandler();
        } else {
            runFlow(flow);
        }
    }

再来看一下runFlow中的代码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    private void runFlow(Flow flow) {
        try {
            //看报错信息就可以猜到在做什么防御措施了:如果一个transaction在一个flow中没有被关闭而跳到下一个flow时,会抛出异常。这个防御机制来自于一个实习生写的bug,当时被排查出来的时候花了非常大的力气——现象非常的诡异。所以现在被写在了这里。
            if (TransactionSynchronizationManager.isActualTransactionActive()) {
                String flowName = null;
                String flowClassName = null;
                if (currentFlow != null) {
                    flowName = getFlowName(currentFlow);
                    flowClassName = currentFlow.getClass().getName();
                }

                throw new CloudRuntimeException(String.format("flow[%s:%s] opened a transaction but forgot closing it", flowClassName, flowName));
            }
            //toRun就是一个当前要run的flow
            Flow toRun = null;
            if (flowMarshaller != null) {
            //flowMarshaller 实际上是一个非常恶心的玩意儿。尤其在一些配置好掉的xml flow突然因为一些条件而改变接下来执行的flow令人很无语...但是也提供了一些灵活性。
                toRun = flowMarshaller.marshalTheNextFlow(currentFlow == null ? null : currentFlow.getClass().getName(),
                        flow.getClass().getName(), this, data);
                if (toRun != null) {
                    logger.debug(String.format("[FlowChain(%s): %s] FlowMarshaller[%s] replaces the next flow[%s] to the flow[%s]",
                            id, name, flowMarshaller.getClass(), flow.getClass(), toRun.getClass()));
                }
            }
       
            if (toRun == null) {
                toRun = flow;
            }

            if (CoreGlobalProperty.PROFILER_WORKFLOW) {
                //对flow的监视。比如flow的执行时间等
                stopWatch.start(toRun);
            }

            currentFlow = toRun;

            String flowName = getFlowName(currentFlow);
            String info = String.format("[FlowChain(%s): %s] start executing flow[%s]", id, name, flowName);
            logger.debug(info);
            //在flow中还允许定义afterDone afterError afterFinal的行为。稍后将会介绍
            collectAfterRunnable(toRun);
            //终于到了run,这里就是调用者传入的行为来决定run中的逻辑
            toRun.run(this, data);
             //fail的逻辑稍后解析
        } catch (OperationFailureException oe) {
            String errInfo = oe.getErrorCode() != null ? oe.getErrorCode().toString() : "";
            logger.warn(errInfo, oe);
            fail(oe.getErrorCode());
        } catch (FlowException fe) {
            String errInfo = fe.getErrorCode() != null ? fe.getErrorCode().toString() : "";
            logger.warn(errInfo, fe);
            fail(fe.getErrorCode());
        } catch (Throwable t) {
            logger.warn(String.format("[FlowChain(%s): %s] unhandled exception when executing flow[%s], start to rollback",
                    id, name, flow.getClass().getName()), t);
            fail(errf.throwableToInternalError(t));
        }
    }

fail

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    @Override
    public void fail(ErrorCode errorCode) {
        isFailCalled = true;
        setErrorCode(errorCode);
        //放入Stack中,之后Rollback会根据Stack中的flow顺序来
        rollBackFlows.push(currentFlow);
        //rollback会对this.rollBackFlows中flow按照顺序调用rollback
        rollback();
    }

FlowTrigger

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//定义了触发器的行为接口
public interface FlowTrigger extends AsyncBackup {
    //触发失败,调用errorHandle
    void fail(ErrorCode errorCode);
    //触发下一个flow
    void next();
    //setError后,在下次调用next的时才会调用errorHandle
    void setError(ErrorCode error);
}

之前已经看过fail的代码。接下来来看看nextsetError

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    @Override
    public void next() {
        //如果flow没有run起来的情况下,是不能调用next的
        if (!isStart) {
            throw new CloudRuntimeException(
                    String.format("[FlowChain(%s): %s] you must call start() first, and only call next() in Flow.run()",
                            id, name));
        }
        //当rollback开始的时候也不允许next
        if (isRollbackStart) {
            throw new CloudRuntimeException(
                    String.format("[FlowChain(%s): %s] rollback has started, you can't call next()", id, name));
        }
        //将当前flow的push进rollback用的stack
        rollBackFlows.push(currentFlow);

        logger.debug(String.format("[FlowChain(%s): %s] successfully executed flow[%s]", id, name, getFlowName(currentFlow)));
        //获取下一个flow。在这里才是真正意义上的next
        Flow flow = getFirstNotSkippedFlow();
        if (flow == null) {
            // no flows, or all flows are skipped
            if (errorCode == null) {
                callDoneHandler();
            } else {
                callErrorHandler(false);
            }
        } else {
            runFlow(flow);
        }
    }

可以看一下getFirstNotSkippedFlow,本质上是利用了迭代器的特性。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    private Flow getFirstNotSkippedFlow() {
        Flow flow = null;
        while (it.hasNext()) {
            flow = it.next();
            if (!isSkipFlow(flow)) {
                break;
            }
        }

        return flow;
    }

接下来是setError

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    @Override
    public void setError(ErrorCode error) {
        setErrorCode(error);
    }

//往下看
    private void setErrorCode(ErrorCode errorCode) {
        this.errorCode = errorCode;
    }

根据之前的next逻辑:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
        if (flow == null) {
            // no flows, or all flows are skipped
            if (errorCode == null) {
                callDoneHandler();
            } else {
                callErrorHandler(false);
            }
        } else {
            runFlow(flow);
        }

我们可以大致猜想到,如果在next的时候当前error不为空,则调用错误handle。这样在setError后还可以做一些事情。

无论是调用errorHandle还是doneHandle,都会调用finalHandle。finalHandle也允许用户定义这部分的逻辑,使flow更加的灵活。

更好的选择

由于该库是为ZStack定制而生,故此有一些防御性判断,源码显得略为verbose。如果有同学对此感兴趣,想将其应用到自己的系统中,笔者推荐使用:jdeferred

Java Deferred/Promise library similar to JQuery

由于JavaScript 中的代码都是异步调用的。简单说,它的思想是,每一个异步任务返回一个Promise对象,该对象有一个then方法,允许指定回调函数。

在这里列出几个较为简单的示范,或者有兴趣的读者也可以参考这里

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import org.jdeferred.DeferredManager;
import org.jdeferred.Promise;
import org.jdeferred.impl.DefaultDeferredManager;
import org.junit.After;
import org.junit.Assert;
import org.junit.Test;

import java.util.concurrent.TimeUnit;


public class deferSimpleTest {

    private static int var = 0;
    final DeferredManager dm = new DefaultDeferredManager();

    @After
    public void cleanUp() {
        var = 0;
    }


    @Test
    public void test() {
        Promise p1 = dm.when(() -> {
            var += 1;
        }).then(result -> {
            var += 1;
        });

        Promise p2 = dm.when(() -> {
            var += 1;
        }).then(result -> {
            var += 1;
        });

        dm.when(p1, p2).done(Void -> var += 1);
        Assert.assertEquals(5, var);
    }

    @Test
    public void test2() {
        final DeferredManager dm = new DefaultDeferredManager();

        Promise promise = dm.when(() -> {
                var += 1;
            }).then(result -> {
                var += 1;
            });

        dm.when(promise).done(Void -> var += 1);
        Assert.assertEquals(3, var);
    }

    @Test
    public void testBadCallback() {
        Promise promise = dm.when(() -> {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        dm.when(promise).done(Void -> {
                    var += 1;
                    throw new RuntimeException("this exception is expected");
                }
        ).fail(Void -> {
            System.out.print("fail!");
            var -= 1;
        });
        Assert.assertEquals(0, var);

    }
}

如果你在使用Java8,那么也可以通过CompletableFuture来得到“类似”的支持。

小结

本文和大家一起了解了FlowChain的实现,但其实这并不是什么新颖的东西。该组件的思想参考了SAGA——SAGA 事务模式的历史十分悠久,比分布式事务的概念提出还要更早。SAGA 的意思是“长篇故事、长篇记叙、一长串事件”,它起源于 1987 年普林斯顿大学的赫克托 · 加西亚 · 莫利纳(Hector Garcia Molina)和肯尼斯 · 麦克米伦(Kenneth Salem)在 ACM 发表的一篇论文《SAGAS》(这就是论文的全名)。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-01-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
【深度学习实验】线性模型(四):使用Pytorch实现线性模型:使用随机梯度下降优化器训练模型
随机梯度下降的主要优点是计算效率高,尤其适用于大规模数据集。它也可以在每个训练周期中进行参数更新,因此可以更快地收敛。然而,由于每次迭代仅使用一个样本(或小批量样本),因此随机梯度下降的更新方向可能会更加不稳定,导致训练过程中的损失函数波动较大。为了缓解这个问题,可以使用学习率衰减、动量等技巧来改进算法。
Qomolangma
2024/07/29
1390
【深度学习实验】线性模型(四):使用Pytorch实现线性模型:使用随机梯度下降优化器训练模型
【深度学习】使用 PyTorch 实现回归问题
在这篇博文中,我们将探讨线性回归的概念以及如何使用 PyTorch 实现它。回归是一种基本的统计建模技术,用于建立因变量与一个或多个自变量之间的关系。我们将使用 PyTorch(一种流行的深度学习框架)来开发和训练线性回归模型。
Ai学习的老章
2024/01/29
9700
【深度学习】使用 PyTorch 实现回归问题
【python】在【机器学习】与【数据挖掘】中的应用:从基础到【AI大模型】
在大数据时代,数据挖掘与机器学习成为了各行各业的核心技术。Python作为一种高效、简洁且功能强大的编程语言,得到了广泛的应用。
小李很执着
2024/06/15
3080
一文带你了解机器学习的四大框架PyTorch、TensorFlow、Keras、Scikit-learn
点评:文章概要性地介绍了机器学习,指出其重要性日益凸显,如Geoffrey Hinton等机器学习领域的大牛被Google、Facebook等科技巨头争相聘请。文章阐述了机器学习的定义,即一种让计算机从数据中自动学习和改进的技术。同时,文章还探讨了机器学习的范围、方法,如支持向量机、聚类算法等,并强调了机器学习在大数据、深度学习及人工智能领域的广泛应用与重要影响,展现了机器学习技术推动科技进步的巨大潜力。
小白的大数据之旅
2024/11/25
1.4K1
一文带你了解机器学习的四大框架PyTorch、TensorFlow、Keras、Scikit-learn
Python深度学习框架:PyTorch、Keras、Scikit-learn、TensorFlow如何使用?学会轻松玩转AI!
总的来说,这四个工具箱各有各的优点,适合不同的任务和学习阶段。 你想盖什么样子的“房子”(解决什么问题),就选择合适的工具箱。 接下来让我们去了解一下他们吧
小白的大数据之旅
2024/11/26
2.1K0
Python深度学习框架:PyTorch、Keras、Scikit-learn、TensorFlow如何使用?学会轻松玩转AI!
深度揭秘,教你驾驭 AI 大模型的无限可能
随着人工智能技术的飞速发展,AI 大模型在诸多领域展现出了强大的能力。然而,要充分发挥其潜力,正确的使用方法至关重要。
羑悻的小杀马特.
2025/03/30
1870
深度学习中的文本分类方法汇总相关代码及调优trick
Fasttext是Facebook推出的一个便捷的工具,包含文本分类和词向量训练两个功能。
大鹅
2021/11/06
1.9K0
分别用逻辑回归和决策树实现鸢尾花数据集分类
学习了决策树和逻辑回归的理论知识,决定亲自上手尝试一下。最终导出决策树的决策过程的图片和pdf。逻辑回归部分参考的是用逻辑回归实现鸢尾花数据集分类,感谢原作者xiaoyangerr 注意:要导出为pdf先必须安装graphviz(这是一个软件)并且安装pydotplus这个包,把它的graphviz加入系统的环境变量path,否则会报错 决策树 from sklearn.datasets import load_iris from sklearn import tree from sklearn.mo
Aidol
2020/07/23
1.6K0
分别用逻辑回归和决策树实现鸢尾花数据集分类
如何使用神经网络模型解决分类、聚类、回归和标注任务:基于 PyTorch 的实现与分析
文章链接:https://cloud.tencent.com/developer/article/2469162
小馒头学Python
2024/11/22
6360
如何使用神经网络模型解决分类、聚类、回归和标注任务:基于 PyTorch 的实现与分析
基于sklearn的LogisticRegression鸢尾花多类分类实践
本文使用sklearn的逻辑斯谛回归模型,进行鸢尾花多分类预测,对OvR与OvO多分类方法下的预测结果进行对比。
Michael阿明
2020/07/13
1.6K0
03-使用PyTorch处理最简单的神经网络分类任务(笔记+代码)
分类和回归是最常见的机器学习问题类型之一。在本笔记中,我们将使用 PyTorch 解决几个不同的分类问题(二元分类,多类分类,多标签分类)。换句话说,我们通过获取一组输入并预测这些输入集属于哪个类别。
renhai
2023/11/24
5K0
03-使用PyTorch处理最简单的神经网络分类任务(笔记+代码)
【深度学习实验】线性模型(三):使用Pytorch实现简单线性模型:搭建、构造损失函数、计算损失值
线性模型的优点包括简单、易于解释和计算效率高。它们在许多实际问题中都有广泛的应用。然而,线性模型也有一些限制,例如对非线性关系的建模能力较弱。在处理复杂的问题时,可以通过引入非线性特征转换或使用核函数进行扩展,以提高线性模型的性能。
Qomolangma
2024/07/29
2280
【深度学习实验】线性模型(三):使用Pytorch实现简单线性模型:搭建、构造损失函数、计算损失值
应用深度学习EEGNet来处理脑电信号
脑机接口(BCI)使用神经活动作为控制信号,实现与计算机的直接通信。这种神经信号通常是从各种研究透彻的脑电图(EEG)信号中挑选出来的。卷积神经网络(CNN)主要用来自动特征提取和分类,其在计算机视觉和语音识别领域中的使用已经很广泛。CNN已成功应用于基于EEG的BCI;但是,CNN主要应用于单个BCI范式,在其他范式中的使用比较少,论文作者提出是否可以设计一个CNN架构来准确分类来自不同BCI范式的EEG信号,同时尽可能地紧凑(定义为模型中的参数数量)。该论文介绍了EEGNet,这是一种用于基于EEG的BCI的紧凑型卷积神经网络。论文介绍了使用深度和可分离卷积来构建特定于EEG的模型,该模型封装了脑机接口中常见的EEG特征提取概念。论文通过四种BCI范式(P300视觉诱发电位、错误相关负性反应(ERN)、运动相关皮层电位(MRCP)和感觉运动节律(SMR)),将EEGNet在主体内和跨主体分类方面与目前最先进的方法进行了比较。结果显示,在训练数据有限的情况下,EEGNet比参考算法具有更强的泛化能力和更高的性能。同时论文也证明了EEGNet可以有效地推广到ERP和基于振荡的BCI。
脑机接口社区
2020/06/30
1.3K0
基于鸢尾花数据集的逻辑回归分类实践
Logistic回归虽然名字里带“回归”,但是它实际上是一种分类方法,主要用于两分类问题(即输出只有两种,分别代表两个类别),所以利用了Logistic函数(或称为Sigmoid函数),函数形式为:
小小程序员
2023/12/25
5760
基于鸢尾花数据集的逻辑回归分类实践
【机器学习】机器学习与医疗健康在疾病预测中的融合应用与性能优化新探索
机器学习是一种通过数据训练模型,并利用模型对新数据进行预测和决策的技术。其基本思想是让计算机通过样本数据自动学习规律,而不是通过明确的编程指令。根据学习的类型,机器学习可以分为监督学习、无监督学习和强化学习。随着医疗健康领域数据的快速积累,机器学习在疾病预测、诊断和治疗中的应用越来越广泛,为提升医疗服务质量和效率提供了强有力的技术支持。
哈__
2024/07/03
8042
【机器学习】机器学习与医疗健康在疾病预测中的融合应用与性能优化新探索
【机器学习】机器学习与自然语言处理的融合应用与性能优化新探索
自然语言处理(NLP)是计算机科学中的一个重要领域,旨在通过计算机对人类语言进行理解、生成和分析。随着深度学习和大数据技术的发展,机器学习在自然语言处理中的应用越来越广泛,从文本分类、情感分析到机器翻译和对话系统,都展示了强大的能力。本文将详细介绍机器学习在自然语言处理中的应用,包括数据预处理、模型选择、模型训练和性能优化。通过具体的案例分析,展示机器学习技术在自然语言处理中的实际应用,并提供相应的代码示例。
E绵绵
2024/07/08
3110
PyTorch-24h 01_PyTorch深度学习流程
以学习一条直线y=ax+b为例演示PyTorch深度学习流程。末尾(第6节)有完整代码。笔记写的比较简单,详细的Notebook见24小时入门PyTorch深度学习。
一只大鸽子
2023/02/24
3950
PyTorch-24h  01_PyTorch深度学习流程
PyTorch-24h 02_分类问题
loss:loss函数用于衡量模型预测和实际值的差距。不同的问题需要不同的loss函数。例如,回归问题可能用MAE,二分类问题可能用binary cross entropy。 优化器:优化器用来更新模型参数,一般使用SGD(torch.optim.SGD())或Adam(torch.optim.Adam())。
一只大鸽子
2023/02/24
3640
PyTorch-24h  02_分类问题
岩石or金属,Pytorch经典二分类问题
今天我们使用的是声呐的数据集,本数据集使用声呐探测了金属和岩石,记录了它返回的波长。
Tom2Code
2023/12/11
2100
岩石or金属,Pytorch经典二分类问题
【深度学习实验】线性模型(二):使用NumPy实现线性模型:梯度下降法
本实验中,gradient_descent函数实现了梯度下降法的具体过程。它通过调用initialize_parameters函数初始化模型参数,然后在每次迭代中计算模型预测值、梯度以及更新参数值。
Qomolangma
2024/07/29
1810
【深度学习实验】线性模型(二):使用NumPy实现线性模型:梯度下降法
推荐阅读
【深度学习实验】线性模型(四):使用Pytorch实现线性模型:使用随机梯度下降优化器训练模型
1390
【深度学习】使用 PyTorch 实现回归问题
9700
【python】在【机器学习】与【数据挖掘】中的应用:从基础到【AI大模型】
3080
一文带你了解机器学习的四大框架PyTorch、TensorFlow、Keras、Scikit-learn
1.4K1
Python深度学习框架:PyTorch、Keras、Scikit-learn、TensorFlow如何使用?学会轻松玩转AI!
2.1K0
深度揭秘,教你驾驭 AI 大模型的无限可能
1870
深度学习中的文本分类方法汇总相关代码及调优trick
1.9K0
分别用逻辑回归和决策树实现鸢尾花数据集分类
1.6K0
如何使用神经网络模型解决分类、聚类、回归和标注任务:基于 PyTorch 的实现与分析
6360
基于sklearn的LogisticRegression鸢尾花多类分类实践
1.6K0
03-使用PyTorch处理最简单的神经网络分类任务(笔记+代码)
5K0
【深度学习实验】线性模型(三):使用Pytorch实现简单线性模型:搭建、构造损失函数、计算损失值
2280
应用深度学习EEGNet来处理脑电信号
1.3K0
基于鸢尾花数据集的逻辑回归分类实践
5760
【机器学习】机器学习与医疗健康在疾病预测中的融合应用与性能优化新探索
8042
【机器学习】机器学习与自然语言处理的融合应用与性能优化新探索
3110
PyTorch-24h 01_PyTorch深度学习流程
3950
PyTorch-24h 02_分类问题
3640
岩石or金属,Pytorch经典二分类问题
2100
【深度学习实验】线性模型(二):使用NumPy实现线性模型:梯度下降法
1810
相关推荐
【深度学习实验】线性模型(四):使用Pytorch实现线性模型:使用随机梯度下降优化器训练模型
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档