@@ -1950,6 +1950,137 @@ fn simple_eval_(
19501950 ) ;
19511951 }
19521952 }
1953+ "RNN" => {
1954+ // activation_alpha and activation_beta don't apply to (Tanh, Tanh) so ignoring them is okay
1955+ let activations_default = vec ! [ "Tanh" . to_string( ) , "Tanh" . to_string( ) ] ;
1956+ let activations = get_attr_opt_owned :: < Vec < String > > ( node, "activations" ) ?
1957+ . unwrap_or ( activations_default. clone ( ) ) ;
1958+ let clip = get_attr_opt :: < f32 > ( node, "clip" ) ?. copied ( ) ;
1959+ if clip. is_some ( ) {
1960+ bail ! ( "RNN does not currently support clip attribute" ) ;
1961+ }
1962+ let direction = get_attr_opt ( node, "direction" ) ?. unwrap_or ( "forward" ) ;
1963+ if direction != "forward" {
1964+ bail ! ( "RNN currently only supports direction == \" forward\" " ) ;
1965+ }
1966+ let num_directions = if direction == "bidirectional" { 2 } else { 1 } ;
1967+ let hidden_size: i64 = get_attr ( node, "hidden_size" ) . copied ( ) ?;
1968+
1969+ // The shape format of inputs X, initial_h and outputs Y, Y_h.
1970+ // If 0, the following shapes are expected:
1971+ // X.shape = [seq_length, batch_size, input_size],
1972+ // Y.shape = [seq_length, num_directions, batch_size, hidden_size],
1973+ // initial_h.shape = Y_h.shape = [num_directions, batch_size, hidden_size].
1974+ // If 1, the following shapes are expected:
1975+ // X.shape = [batch_size, seq_length, input_size],
1976+ // Y.shape = [batch_size, seq_length, num_directions, hidden_size],
1977+ // initial_h.shape = Y_h.shape = [batch_size, num_directions, hidden_size].
1978+ let layout = get_attr_opt ( node, "layout" ) ?. copied ( ) . unwrap_or ( 0 ) ;
1979+ if layout != 0 {
1980+ bail ! ( "RNN currently only supports layout == 0" ) ;
1981+ }
1982+
1983+ // The input sequences packed (and potentially padded) into one 3-D tensor
1984+ // with the shape of `[seq_length, batch_size, input_size]`.
1985+ let x = get ( & node. input [ 0 ] ) ?;
1986+ // XXX: depends on layout
1987+ let ( seq_length, batch_size, _) = x. dims3 ( ) ?;
1988+ // The weight tensor for the input gate.
1989+ // Concatenation of `Wi` and `WBi` (if bidirectional).
1990+ // The tensor has shape `[num_directions, hidden_size, input_size]`.
1991+ let w = get ( & node. input [ 1 ] ) ?;
1992+ // The recurrence weight tensor.
1993+ // Concatenation of `Ri` and `RBi` (if bidirectional).
1994+ // This tensor has shape `[num_directions, hidden_size, hidden_size]`.
1995+ let r = get ( & node. input [ 2 ] ) ?;
1996+
1997+ // The bias tensor for input gate.
1998+ // Concatenation of `[Wbi, Rbi]` and `[WBbi, RBbi]` (if bidirectional).
1999+ // This tensor has shape `[num_directions, 2*hidden_size]`.
2000+ // Optional: If not specified - assumed to be 0.
2001+ let b_default: Tensor ;
2002+ let b = match get_opt ( 3 ) {
2003+ Some ( n) => n?,
2004+ None => {
2005+ b_default = Tensor :: zeros (
2006+ ( num_directions, 2 * hidden_size as usize ) ,
2007+ DType :: F32 ,
2008+ x. device ( ) ,
2009+ ) ?;
2010+ & b_default
2011+ }
2012+ } ;
2013+
2014+ // Optional tensor specifying lengths of the sequences in a batch.
2015+ // If not specified - assumed all sequences in the batch to have length `seq_length`.
2016+ // It has shape `[batch_size]`.
2017+ let seq_lens_default: Tensor ;
2018+ let seq_lens = match get_opt ( 4 ) {
2019+ Some ( n) => n?,
2020+ None => {
2021+ seq_lens_default =
2022+ Tensor :: full ( seq_length as i64 , ( batch_size, ) , x. device ( ) ) ?;
2023+ & seq_lens_default
2024+ }
2025+ } ;
2026+ let seq_lens_is_default =
2027+ ( seq_lens. to_vec1 :: < i64 > ( ) ?. iter ( ) ) . all ( |e| * e as usize == seq_length) ;
2028+ if !seq_lens_is_default {
2029+ bail ! ( "RNN currently does not support variable-length sequences. All sequences must use the full sequence length of {}" , seq_length) ;
2030+ }
2031+
2032+ // Optional initial value of the hidden. If not specified - assumed to be 0.
2033+ // It has shape `[num_directions, batch_size, hidden_size]`.
2034+ let initial_h_default: Tensor ;
2035+ let initial_h = match get_opt ( 5 ) {
2036+ Some ( n) => n?,
2037+ _ => {
2038+ initial_h_default = Tensor :: zeros (
2039+ ( num_directions, batch_size, hidden_size as usize ) ,
2040+ DType :: F32 ,
2041+ x. device ( ) ,
2042+ ) ?;
2043+ & initial_h_default
2044+ }
2045+ } ;
2046+
2047+ fn choose_activation ( activation : & str , x : & Tensor ) -> Result < Tensor > {
2048+ match activation {
2049+ "Tanh" => x. tanh ( ) ,
2050+ _ => bail ! ( "unsupported activation {activation}" ) ,
2051+ }
2052+ }
2053+
2054+ // these all have [num_directions, ...] shapes
2055+ let w = w. get ( 0 ) ?;
2056+ let r = r. get ( 0 ) ?;
2057+ let b = b. get ( 0 ) ?;
2058+ let idx_wb = Tensor :: arange ( 0 , hidden_size, x. device ( ) ) ?;
2059+ let idx_rb = Tensor :: arange ( hidden_size, 2 * hidden_size, x. device ( ) ) ?;
2060+ let wb = b. index_select ( & idx_wb, 0 ) ?;
2061+ let rb = b. index_select ( & idx_rb, 0 ) ?;
2062+ let mut h_t = initial_h. get ( 0 ) ?;
2063+ let mut h_list: Vec < Tensor > = vec ! [ ] ;
2064+ for i in 0 ..seq_length {
2065+ let xs = x. get ( i) ?;
2066+ let h = xs
2067+ . matmul ( & w. t ( ) ?) ?
2068+ . add ( & h_t. matmul ( & r. t ( ) ?) ?) ?
2069+ . add ( & wb. unsqueeze ( 0 ) ?) ?
2070+ . add ( & rb. unsqueeze ( 0 ) ?) ?;
2071+ let h = choose_activation ( & activations[ 0 ] , & h) ?;
2072+ h_list. push ( h. to_owned ( ) ) ;
2073+ h_t = h;
2074+ }
2075+ let h = Tensor :: stack ( & h_list, 0 ) ?;
2076+ let h =
2077+ h. reshape ( ( seq_length, num_directions, batch_size, hidden_size as usize ) ) ?;
2078+ values. insert ( node. output [ 0 ] . clone ( ) , h) ;
2079+ values. insert (
2080+ node. output [ 1 ] . clone ( ) ,
2081+ h_t. reshape ( ( num_directions, batch_size, hidden_size as usize ) ) ?,
2082+ ) ;
2083+ }
19532084 // https://onnx.ai/onnx/operators/onnx__Xor.html
19542085 "Xor" => {
19552086 // Since we don't have a `DType::Bool` yet, this ensures that we are working with `0`(False) & `1`(True)
@@ -1966,6 +2097,11 @@ fn simple_eval_(
19662097 let output = input. sign ( ) ?;
19672098 values. insert ( node. output [ 0 ] . clone ( ) , output) ;
19682099 }
2100+ "HardSwish" => {
2101+ let input = get ( & node. input [ 0 ] ) ?;
2102+ let hard_sigmoid = candle_nn:: ops:: hard_sigmoid ( & input) ?;
2103+ let output = input * hard_sigmoid;
2104+ values. insert ( node. output [ 0 ] . clone ( ) , output?) ;
19692105 "Resize" => {
19702106 let input = get ( & node. input [ 0 ] ) ?;
19712107
@@ -2234,6 +2370,7 @@ fn simple_eval_(
22342370 values. insert ( node. output [ 0 ] . clone ( ) , output) ;
22352371 }
22362372 op_type => bail ! ( "unsupported op_type {op_type} for op {node:?}" ) ,
2373+
22372374 }
22382375 }
22392376 graph
0 commit comments