1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
//------------------------------------------------------------------------------
// LAGraph_dnn: sparse deep neural network
//------------------------------------------------------------------------------
// LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved.
// SPDX-License-Identifier: BSD-2-Clause
//
// For additional details (including references to third party source code and
// other files) see the LICENSE file or contact permission@sei.cmu.edu. See
// Contributors.txt for a full list of contributors. Created, in part, with
// funding and support from the U.S. Government (see Acknowledgments.txt file).
// DM22-0790
// Contributed by Timothy A. Davis, Texas A&M University
//------------------------------------------------------------------------------
// LAGraph_dnn: sparse deep neural network.
// Based on inferenceReLUvec.m by Jeremy Kepner, MIT.
// Performs ReLU inference using input feature vectors Y0.
// See http://graphchallenge.org/ for a description of the algorithm.
// On input, Y0 is the initial feature vectors, of size nfeatures-by-nneurons.
// This format uses the graph convention that A(i,j) is the edge (i,j).
// Each row of Y0 is a single feature.
// W is an array of size nlayers of sparse matrices. Each W[layer] matrix has
// the same size: nneurons-by-nneurons. W[layer] represents the DNN weights
// for that layer.
// The Bias[layer] matrices are diagonal, and the same size as W[layer].
// All matrices should have type GrB_FP32; the method will be very slow
// otherwise.
// On output, Y is the computed result, of the same size as Y0.
#define LG_FREE_ALL \
{ \
GrB_free (&Y) ; \
}
#include "LG_internal.h"
#include "LAGraphX.h"
//****************************************************************************
GrB_Info LAGraph_dnn // returns GrB_SUCCESS if successful
(
// output
GrB_Matrix *Yhandle, // Y, created on output
// input: not modified
GrB_Matrix *W, // W [0..nlayers-1], each nneurons-by-nneurons
GrB_Matrix *Bias, // Bias [0..nlayers-1], diagonal nneurons-by-nneurons
int nlayers, // # of layers
GrB_Matrix Y0 // input features: nfeatures-by-nneurons
)
{
GrB_Info info ;
char *msg = NULL ;
//--------------------------------------------------------------------------
// check inputs
//--------------------------------------------------------------------------
if (Yhandle == NULL || W == NULL || Bias == NULL || Y0 == NULL)
{
return (GrB_NULL_POINTER) ;
}
//--------------------------------------------------------------------------
// create the output matrix Y
//--------------------------------------------------------------------------
GrB_Matrix Y = NULL ;
(*Yhandle) = NULL ;
GrB_Index nfeatures, nneurons ;
GRB_TRY (GrB_Matrix_nrows (&nfeatures, Y0)) ;
GRB_TRY (GrB_Matrix_ncols (&nneurons, Y0)) ;
GRB_TRY (GrB_Matrix_new (&Y, GrB_FP32, nfeatures, nneurons)) ;
//--------------------------------------------------------------------------
// propagate the features through the neuron layers
//--------------------------------------------------------------------------
for (int layer = 0 ; layer < nlayers ; layer++)
{
// Y = Y * W [layer], using the conventional PLUS_TIMES semiring
GRB_TRY (GrB_mxm (Y, NULL, NULL, GrB_PLUS_TIMES_SEMIRING_FP32,
((layer == 0) ? Y0 : Y), W [layer], NULL)) ;
// Y = Y * Bias [layer], using the MIN_PLUS semiring. This computes
// Y(i,j) += Bias [layer] (j,j) for each entry Y(i,j). It does not
// introduce any new entries in Y. The MIN monoid is not actually used
// since Bias [layer] is a diagonal matrix. The prior version used
// a PLUS_PLUS semiring, which also works but is not a GrB built-in.
GRB_TRY (GrB_mxm (Y, NULL, NULL, GrB_MIN_PLUS_SEMIRING_FP32, Y,
Bias [layer], NULL)) ;
// delete entries from Y: keep only those entries greater than zero
GRB_TRY (GrB_select (Y, NULL, NULL, GrB_VALUEGT_FP32, Y, (float) 0,
NULL));
// threshold maximum values: Y = min (Y, 32)
GRB_TRY (GrB_apply (Y, NULL, NULL, GrB_MIN_FP32, Y, (float) 32, NULL)) ;
}
//--------------------------------------------------------------------------
// return result
//--------------------------------------------------------------------------
(*Yhandle) = Y ;
return (GrB_SUCCESS) ;
}