ND4J/工作间

2019-04-03  本文已影响0人  hello风一样的男子
package org.nd4j.examples;

import org.nd4j.linalg.api.memory.MemoryWorkspace;
import org.nd4j.linalg.api.memory.conf.WorkspaceConfiguration;
import org.nd4j.linalg.api.memory.enums.AllocationPolicy;
import org.nd4j.linalg.api.memory.enums.LearningPolicy;
import org.nd4j.linalg.api.memory.enums.ResetPolicy;
import org.nd4j.linalg.api.ndarray.INDArray;
import org.nd4j.linalg.factory.Nd4j;
import org.slf4j.Logger;

/**
 * 
 * 这个例子展示了如何将内存工作空间与nd4j一起用于循环工作负载。
 * 背景:
 *
 * ND4J工作间是一个内存块,分配一次,然后在上面重复使用。基本上,如果使用循环工作负载,它为避免堆外内存的垃圾收集提供了一种方法。
 *请注意:工作间是可选的。如果你更喜欢使用原始的基于GC的内存管理器,那么你可以使用它而不会出现任何问题。
 *请注意:使用工作间时,你负责跟踪作用域等。你不应该访问附加到某些工作间之外的任何INDArray。结果将是不可预测的,直到JVM崩溃。
 *
 * @author raver119@gmail.com
 */
public class Nd4jEx15_Workspaces {
    private static final Logger log = org.slf4j.LoggerFactory.getLogger(Nd4jEx15_Workspaces.class);

    public static void main(String[] args) throws Exception {
       
        /**
         * 每个工作间都通过ID绑定到一个JVM线程。因此,不同线程中的相同ID将指向不同的实际工作区。
         * 每个工作区都是使用某些配置创建的,不同的工作区既可以共享相同的配置,也可以拥有自己的配置。
         */
       
        //我们创建了一个预先分配了10MB内存空间的配置
        WorkspaceConfiguration initialConfig = WorkspaceConfiguration.builder()
            .initialSize(10 * 1024L * 1024L)
            .policyAllocation(AllocationPolicy.STRICT)
            .policyLearning(LearningPolicy.NONE)
            .build();


        INDArray result = null;

        // 我们使用
        try(MemoryWorkspace ws = Nd4j.getWorkspaceManager().getAndActivateWorkspace(initialConfig, "SOME_ID")) {
           
            //现在,在此try块中创建的每个INDArray都将从此工作区池中分配
            INDArray array = Nd4j.rand(10, 10);

       
            //查看此数组是否连接到某个工作间的最简单方法。我们希望这里打印出TRUE。
            log.info("Array attached? {}", array.isAttached());

           
            //请注意,新的数组平均值也将附加到此工作间
            INDArray mean = array.mean(1);

         

            /**
             * 请注意:如果在工作间上执行了一些操作之后,你希望从中获得结果,那么应该利用它,或者分离
             */
            result = mean.detach();
        }

       
        //因为我们分离了数组,所以我们希望在这里输出false。所以,结果数组现在由GC管理。
        log.info("Array attached? {}", result.isAttached());



        /**
         * 
         * 工作间最初可以预先分配,如上图所示,或者可以随着时间的推移或在第一个循环之后学习其所需的大小。
         */

        WorkspaceConfiguration learningConfig = WorkspaceConfiguration.builder()
             //<--此选项禁用过度分配行为   
            .policyAllocation(AllocationPolicy.STRICT) 
             //<--此选项使工作间在第一个循环后学习
            .policyLearning(LearningPolicy.FIRST_LOOP)
            .build();

        for (int x = 0; x < 10; x++) {
            try (MemoryWorkspace ws = Nd4j.getWorkspaceManager().getAndActivateWorkspace(learningConfig, "OTHER_ID")) {
                INDArray array = Nd4j.create(100);

                /**
                 * 在第一次迭代时,工作间将所有配额作为独立的内存块,但在此次迭代完成后,工作间将被分配,以匹配所有
                 * 此次循环中要求的配额。所以,更多的迭代将一次次重复使用工作间内存。
                 */
            }
        }


        /**
         * 
         * 工作间可以嵌套。如果需要,INDArrays可以在它们之间迁移
         */

        try(MemoryWorkspace ws1 = Nd4j.getWorkspaceManager().getAndActivateWorkspace(initialConfig, "SOME_ID")) {
            INDArray array = Nd4j.create(10, 10).assign(1.0f);
            INDArray sumRes;

            try(MemoryWorkspace ws2 = Nd4j.getWorkspaceManager().getAndActivateWorkspace(initialConfig, "THIRD_ID")) {
                //请注意:只有当内存尚未关闭/重置时,我们才能从父工作间访问内存,而不会出现任何问题。
                INDArray res = array.sum(1);

              
                //数组在ws1处分配,而res在ws2中分配。但我们可以在需要时迁移它们。
                sumRes = res.leverageTo("SOME_ID");
            }

            // at this point sumRes contains valid data, allocated in current workspace. We expect 100 printed here.
            //此时,sumRes包含当前工作间中分配的有效数据。我们希望这里能打印100。
            log.info("Sum: {}", sumRes.sumNumber().floatValue());
        }


        /**
         * 
         * 如果出于某种原因需要用GC处理部分计算,则可以中断工作区流。
         */
        try(MemoryWorkspace ws1 = Nd4j.getWorkspaceManager().getAndActivateWorkspace(initialConfig, "SOME_ID")) {
            INDArray array1 = Nd4j.create(10, 10).assign(1.0f);
            INDArray array2;

            try(MemoryWorkspace ws = Nd4j.getWorkspaceManager().scopeOutOfWorkspaces()) {
               
                //此try块中分配的任何内容都将由GC管理
                array2 = Nd4j.create(10, 10).assign(2.0f);
            }


           
            //此时,sumRes包含当前工作间中分配的有效数据。我们希望这里能打印300。
            log.info("Sum: {}", array1.addi(array2).sumNumber().floatValue());
        }


        /**
         * 
         * 还可以构建充当循环缓冲区的工作间。
         */
        WorkspaceConfiguration circularConfig = WorkspaceConfiguration.builder()
            .initialSize(10 * 1024L * 1024L)
            .policyAllocation(AllocationPolicy.STRICT)
             // <--- 此选项将禁用工作间随时间的重新分配
            .policyLearning(LearningPolicy.NONE)   
             //<---此选项使工作间充当循环缓冲区,请注意。
            .policyReset(ResetPolicy.ENDOFBUFFER_REACHED) 
            .build();

        for (int x = 0; x < 10; x++) {
          
            //因为这个工作间是循环的,所以我们知道在缓冲区结束之前分配的所有指针都是可行的。
            try (MemoryWorkspace ws1 = Nd4j.getWorkspaceManager().getAndActivateWorkspace(circularConfig, "CIRCULAR_ID")) {
                INDArray array = Nd4j.create(100);
               //所以,只要确定缓冲区没有重置,就可以在任何地方使用这个数组。
               //换句话说:如果你负责流,它适合于生产者/消费者模式使用
            }
        }
    }
}



翻译:风一样的男子

image
上一篇下一篇

猜你喜欢

热点阅读