ND4j大矩陣做相識度計算實現1:N計算

現在很多做人臉識別的技術都是基於C++,python;但是java也是有自己的深度學習的庫,Deeplearning4j就是java自己的深度學習庫,ND4j就是dp4j裏面專門做向量計算的庫,現在就用ND4j實現1:N矩陣計算功能:

pom:

       <dependency>
            <groupId>org.nd4j</groupId>
            <artifactId>nd4j-native</artifactId>
            <version>${dp4j-version}</version>
        </dependency>

1:N計算的核心就是,用矩陣和一個大矩陣做內積乘法

業務功能:就是用一張人臉的特徵和數據庫裏面有的特徵做內積乘法,快速在數據庫裏面找到這張人臉對應的人;

現實方法:

由於每次都在數據庫裏面去查詢特徵數據會消耗時間,所以我把特徵數據初始化加載到內存裏面來維護;做完內積計算以後需要找到相識度最大的對應的那條數據,opencv裏面有一個sortIndex函數可以將數組的值排序以後返回對應的索引地址,java可以自己實現一個排序;

將查出來的特徵值進行緩存:

@Component
public class NDCache {


    public static List<BasisFeature> basisFeatures = Lists.newArrayList();

    public static INDArray zeros = null;

    public static void load(List<BasisFeature> features){
        basisFeatures = features;
        List<INDArray> INDArrays = features.stream().map(basisFeature -> Nd4j.create(basisFeature.getBasis())).collect(Collectors.toList());
         zeros = Nd4j.vstack(INDArrays);
    }

}

實現矩陣計算,更新矩陣:

@Slf4j
@Service
public class NDService {

    @Autowired
    private MongoTemplate mongoTemplate;

    private static double forecastValues = 0.65D;

    private INDArray creArry(List<Double> features) {
        INDArray array = Nd4j.create(features.size(), 1);
        features.forEach(item -> array.putRow(features.indexOf(item), Nd4j.create(new double[]{item})));
        return array;
    }

    public BasisFeature comparRes(List<Double> features){
        INDArray resArr =  NDCache.zeros.mmul(creArry(features));
        Point[] points = Point.sortPoint(resArr.toDoubleVector());
        Point point = points[0];
        if (point.getValue() < forecastValues){
            return  null;
        }
        log.info("1比N第一位結果:"+point);
        return NDCache.basisFeatures.get(point.getIndex());
    }

    public void updateArr(BasisFeature basisFeature){
        for (int i=0;i<NDCache.basisFeatures.size();i++){
            BasisFeature feature = NDCache.basisFeatures.get(i);
            if (feature.getObjectId().equals(basisFeature.getObjectId())){
                NDCache.basisFeatures.set(i,basisFeature);
                NDCache.zeros.put(i,Nd4j.create(basisFeature.getBasis()));
                log.info("矩陣更新:"+NDCache.zeros.length());
            }
        }
    }

    public void loadNDarr(){
        Query query = new Query();
    
        List<BasisFeature> features = mongoTemplate.find(query,BasisFeature.class);
        NDCache.basisFeatures = features;
        List<INDArray> INDArrays = features.stream().map(basisFeature -> Nd4j.create(basisFeature.getBasis())).collect(Collectors.toList());
        NDCache.zeros = Nd4j.vstack(INDArrays);
        log.info("初始化矩陣大小:"+NDCache.zeros.length()+":數據源大小:"+features.size());
    }

    public void add(BasisFeature ... basisFeatures){
        if (ObjectUtils.isEmpty(NDCache.zeros)){
            loadNDarr();
        }else {
            List<INDArray> indArrays = Lists.newArrayList(NDCache.zeros);
            Arrays.asList(basisFeatures).stream().forEach(basisFeature -> indArrays.add(Nd4j.create(basisFeature.getBasis())));
            NDCache.zeros = Nd4j.vstack(indArrays);
            log.info("矩陣擴張:"+NDCache.zeros.length());
        }
    }

}

自定義sortIndex:

public class SortComprator implements Comparator {

    @Override
    public int compare(Object arg0, Object arg1) {
        Point t1=(Point)arg0;
        Point t2=(Point)arg1;
        return t2.getValue().compareTo(t1.getValue());
    }

}

整個計算流程只是把其他語言的實現方法實現了一遍,但是java在計算方便的速度也是很快的,一百萬的矩陣差不多也就141ms,

這個只是基於cpu的計算,當然nd4j也是可以基於cuda的GPU計算的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章