-
Notifications
You must be signed in to change notification settings - Fork 541
Expand file tree
/
Copy pathGradientTape.cs
More file actions
161 lines (138 loc) · 5.16 KB
/
Copy pathGradientTape.cs
File metadata and controls
161 lines (138 loc) · 5.16 KB
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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
using System;
using System.Collections.Generic;
using System.Linq;
using static Tensorflow.Binding;
namespace Tensorflow.Gradients
{
/// <summary>
/// Gradient Tape Set
/// Record operations for automatic differentiation.
///
/// Operations are recorded if they are executed within this context manager and
/// at least one of their inputs is being "watched".
///
/// Trainable variables (created by `tf.Variable` or `tf.compat.v1.get_variable`,
/// where `trainable=True` is default in both cases) are automatically watched.
/// Tensors can be manually watched by invoking the `watch` method on this context
/// manager.
/// </summary>
public class GradientTape : IDisposable
{
int _nextTapeId;
ITape _tape => _tapeSet.Peek();
Stack<ITape> _tapeSet;
public GradientTape()
{
_tapeSet = new Stack<ITape>();
}
/// <summary>
/// New tape onto the tape stack.
/// </summary>
public ITape PushTape(bool persistent = false,
bool watch_accessed_variables = true)
{
// Enters a context inside which operations are recorded on this tape.
if (tf.Context.executing_eagerly())
tf.Context.ensure_initialized();
var tape = new Tape(persistent, watch_accessed_variables);
tape.SetTapeId(_nextTapeId++);
_tapeSet.Push(tape);
return tape;
}
public void PushTape(ITape tape)
{
// Enters a context inside which operations are recorded on this tape.
if (tf.Context.executing_eagerly())
tf.Context.ensure_initialized();
_tapeSet.Push(tape);
}
ITape PopTape()
{
_tape.StopRecord();
return _tapeSet.Pop();
}
/// <summary>
/// Marks this tensor to be watched by the given tape.
/// </summary>
/// <param name="x"></param>
public void watch(Tensor x)
{
if (!_tapeSet.Any())
return;
_tape.Watch(x);
}
/// <summary>
/// Computes the gradient using operations recorded in context of this tape.
/// </summary>
/// <param name="target"></param>
/// <param name="source"></param>
/// <returns></returns>
public Tensor gradient(Tensor target, Tensor source, List<Tensor> output_gradients = null,
string unconnected_gradients = null)
{
if(_tape is null)
{
throw new RuntimeError("A non-persistent GradientTape can only be used to " +
"compute one set of gradients (or jacobians).");
}
ITape tape = stop_recording();
var results = tf.Runner.TFE_TapeGradient(tape,
new[] { target },
new[] { source },
output_gradients,
new[] { source },
unconnected_gradients);
return results[0];
}
public Tensor gradient(Tensor target, ResourceVariable source, List<Tensor> output_gradients = null,
string unconnected_gradients = null)
{
var results = gradient(target, new List<IVariableV1> { source }, output_gradients, unconnected_gradients);
return results[0];
}
public (Tensor, Tensor) gradient(Tensor target, (ResourceVariable, ResourceVariable) sources, List<Tensor> output_gradients = null,
string unconnected_gradients = null)
{
var results = gradient(target, new List<IVariableV1> { sources.Item1, sources.Item2 }, output_gradients, unconnected_gradients);
return (results[0], results[1]);
}
public Tensor[] gradient(Tensor target, IEnumerable<IVariableV1> sources, List<Tensor> output_gradients = null,
string unconnected_gradients = null)
{
if (_tape is null)
{
throw new RuntimeError("A non-persistent GradientTape can only be used to " +
"compute one set of gradients (or jacobians).");
}
var tape = stop_recording();
var results = tf.Runner.TFE_TapeGradient(tape,
new[] { target },
sources.Select(x => x.Handle).ToArray(),
output_gradients,
sources.Select(x => x.Handle).ToArray(),
unconnected_gradients);
if (!tape.Persistent)
{
// Keep track of watched variables before setting tape to None
// _watched_variables = _tape.WatchedVariables();
}
return results;
}
/// <summary>
/// Temporarily stops recording operations on this tape.
/// </summary>
public ITape stop_recording()
{
var tape = _tape;
if (!tape.Persistent)
tape = PopTape();
return tape;
}
public Stack<ITape> GetTapeSet()
=> _tapeSet;
public void Dispose()
{
_tapeSet.Clear();
}
}
}