Java 如何有效地更新EnumeratedDistribution实例中的概率? 问题摘要

Java 如何有效地更新EnumeratedDistribution实例中的概率? 问题摘要,java,android,distribution,q-learning,Java,Android,Distribution,Q Learning,是否有任何方法可以在不创建全新实例的情况下更新类的现有实例中的概率 背景 我正在尝试使用android手机实现一个简化的Q-learning风格的演示。我需要通过学习过程中的每个循环更新每个项目的概率。目前,我无法从我的EnumeratedIntegraterDistribution实例中找到任何可以让我重置|更新|修改这些概率的方法。因此,我能看到的唯一方法是在每个循环中创建EnumeratedIntegraterDistribution的新实例。请记住,这些循环中的每一个都只有20毫秒长,我

是否有任何方法可以在不创建全新实例的情况下更新类的现有实例中的概率

背景 我正在尝试使用android手机实现一个简化的Q-learning风格的演示。我需要通过学习过程中的每个循环更新每个项目的概率。目前,我无法从我的
EnumeratedIntegraterDistribution
实例中找到任何可以让我重置|更新|修改这些概率的方法。因此,我能看到的唯一方法是在每个循环中创建EnumeratedIntegraterDistribution的新实例。请记住,这些循环中的每一个都只有20毫秒长,我的理解是,与创建一个实例并更新现有实例中的值相比,这将是非常低效的内存。是否没有标准的集合式方法来更新这些概率?如果没有,是否有建议的解决方法(即使用不同的类、创建自己的类、重写某些内容以使其可访问等)

接下来的问题是这个问题是否是一个没有实际意义的问题。通过尝试避免每个循环都使用这个新实例,编译后的代码实际上会提高/降低效率吗?(我没有足够的知识知道编译器将如何处理这些事情)

代码 下面是一个简单的例子:

package com.example.mypackage.learning;  
  
import android.app.Activity;  
import android.os.Bundle;  
import org.apache.commons.math3.distribution.EnumeratedIntegerDistribution;  
  
  
public class Qlearning extends Activity {  
  
    private int selectedAction;  
    private int[] actions = {0, 1, 2};  
    private double[] weights = {1.0, 1.0, 1.0};  
    private double[] qValues = {1.0, 1.0, 1.0};  
    private double qValuesSum;  
    EnumeratedIntegerDistribution enumeratedIntegerDistribution = new EnumeratedIntegerDistribution(actions, weights);  
    private final double alpha = 0.001;  
    int action;  
    double reward;  
  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        while(true){  
            action = determineAction();  
            reward = determineReward();  
            learn(action, reward);  
        }  
    }  
      
    public void learn(int action, double reward) {  
        qValues[selectedAction] = (alpha * reward) + ((1.0 - alpha) * qValues[selectedAction]);  
        qValuesSum = 0;  
        for (int i = 0; i < qValues.length; i++){  
            qValuesSum += Math.exp(qValues[i]);  
        }  
        weights[selectedAction] = Math.exp(qValues[selectedAction]) / qValuesSum;  
        // *** This seems inefficient ***  
        EnumeratedIntegerDistribution enumeratedIntegerDistribution = new EnumeratedIntegerDistribution(actions, weights);  
    }  
}

不幸的是,无法更新现有的EnumeratedIntegerDistribution。我过去也遇到过类似的问题,每次需要更新机会时,我都会重新创建实例

我不会太担心内存分配,因为这些都是短期对象。这些都是你不应该担心的微观优化

在我的项目中,我使用接口实现了一种更简洁的方法来创建这些
EnumeratedDistribution
类的实例

这不是直接的答案,但可能会指引你走向正确的方向

public class DistributedProbabilityGeneratorBuilder<T extends DistributedProbabilityGeneratorBuilder.ProbableItem> {

    private static final DistributedProbabilityGenerator EMPTY = () -> {
        throw new UnsupportedOperationException("Not supported");
    };

    private final Map<Integer, T> distribution = new HashMap<>();

    private DistributedProbabilityGeneratorBuilder() {
    }

    public static <T extends ProbableItem> DistributedProbabilityGeneratorBuilder<T> newBuilder() {
        return new DistributedProbabilityGeneratorBuilder<>();
    }

    public DistributedProbabilityGenerator build() {
        return build(ProbableItem::getChances);
    }

    /**
     * Returns a new instance of probability generator at every call.
     * @param chanceChangeFunction - Function to modify existing chances
     */
    public DistributedProbabilityGenerator build(Function<T, Double> chanceChangeFunction) {
        if (distribution.isEmpty()) {
            return EMPTY;
        } else {
            return new NonEmptyProbabilityGenerator(createPairList(chanceChangeFunction));
        }
    }

    private List<Pair<Integer, Double>> createPairList(Function<T, Double> chanceChangeFunction) {
        return distribution.entrySet().stream()
                .map(entry -> Pair.create(entry.getKey(), chanceChangeFunction.apply(entry.getValue())))
                .collect(Collectors.toList());
    }

    public DistributedProbabilityGeneratorBuilder<T> add(int id, T item) {
        if (distribution.containsKey(id)) {
            throw new IllegalArgumentException("Id " + id + " already present.");
        }

        this.distribution.put(id, item);
        return this;
    }

    public interface ProbableItem {

        double getChances();
    }

    public interface DistributedProbabilityGenerator {

        int generateId();
    }

    public static class NonEmptyProbabilityGenerator implements DistributedProbabilityGenerator {

        private final EnumeratedDistribution<Integer> enumeratedDistribution;

        NonEmptyProbabilityGenerator(List<Pair<Integer, Double>> pairs) {
            this.enumeratedDistribution = new EnumeratedDistribution<>(pairs);
        }

        @Override
        public int generateId() {
            return enumeratedDistribution.sample();
        }
    }

    public static ProbableItem ofDouble(double chances) {
        return () -> chances;
    }
}

同样,这不是对您问题的直接回答,而是指向如何更好地使用这些类的指针。

不,我不认为soI最终创建了自己的类来解决这个问题,但我希望找到更成熟的东西(构造函数、错误处理、类型限制等)如果没有更好的答案,我会在这里发布我的基本课程。也许Java没有任何好的Q-learning或强化学习库?@topher217您还拥有您编写的实现吗?@Ishaan,我刚刚更新了我的问题,包括一年后我能够找到的内容:D。。。没有承诺,但希望它能给你一些对你有用的提示。@topher217太棒了,谢谢!
DistributedProbabilityGenerator distributedProbabilityGenerator = DistributedProbabilityGeneratorBuilder.newBuilder()
                .add(0, ofDouble(10))
                .add(1, ofDouble(45))
                .add(2, ofDouble(45))
                .build();

int generatedObjectId = distributedProbabilityGenerator.generateId();