Skip to content
This repository was archived by the owner on Jul 1, 2023. It is now read-only.

Commit 141f449

Browse files
committed
Add @Freezable property wrapper.
`@Freezable` wraps differentiable values and provides toggleable trainability via the `isFrozen` property and `freeze`/`unfreeze` mutating methods. When `isFrozen` is true, accesses to `value` have a derivative of zero.
1 parent 1aceb2d commit 141f449

File tree

1 file changed

+76
-0
lines changed

1 file changed

+76
-0
lines changed
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// Copyright 2019 The TensorFlow Authors. All Rights Reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
import XCTest
16+
@testable import TensorFlow
17+
18+
final class FreezableTests: XCTestCase {
19+
func testFreezableParameters() {
20+
// A dense layer with freezable properties.
21+
struct FreezableDense : Layer {
22+
@Freezable var weight: Tensor<Float>
23+
@Freezable var bias: Tensor<Float>
24+
25+
init(weight: Tensor<Float>, bias: Tensor<Float>) {
26+
// Require scalar weight and bias for simplicity.
27+
precondition(weight.isScalar)
28+
precondition(bias.isScalar)
29+
self.weight = weight
30+
self.bias = bias
31+
}
32+
33+
@differentiable
34+
func callAsFunction(_ input: Tensor<Float>) -> Tensor<Float> {
35+
return input * weight + bias
36+
}
37+
}
38+
39+
var dense = FreezableDense(weight: Tensor(2), bias: Tensor(3))
40+
let x = Tensor<Float>(4)
41+
do {
42+
let (value, gradient) = valueWithGradient(at: dense, x) { dense, x in dense(x) }
43+
XCTAssertEqual(Tensor(11), value)
44+
// The gradient of `dense.weight` should be non-zero.
45+
XCTAssertEqual(FreezableDense.TangentVector(_weight: Tensor(4), _bias: Tensor(1)),
46+
gradient.0)
47+
XCTAssertEqual(Tensor(2), gradient.1)
48+
}
49+
50+
// Freeze derivatives for `dense.weight`.
51+
dense.$weight.freeze()
52+
do {
53+
let (value, gradient) = valueWithGradient(at: dense, x) { dense, x in dense(x) }
54+
// The gradient of `dense.weight` should now be zero.
55+
XCTAssertEqual(Tensor(11), value)
56+
XCTAssertEqual(FreezableDense.TangentVector(_weight: Tensor(0), _bias: Tensor(1)),
57+
gradient.0)
58+
XCTAssertEqual(Tensor(2), gradient.1)
59+
}
60+
61+
// Unfreeze derivatives for `dense.weight`.
62+
dense.$weight.unfreeze()
63+
do {
64+
let (value, gradient) = valueWithGradient(at: dense, x) { dense, x in dense(x) }
65+
XCTAssertEqual(Tensor(11), value)
66+
// The gradient of `dense.weight` should now be non-zero.
67+
XCTAssertEqual(FreezableDense.TangentVector(_weight: Tensor(4), _bias: Tensor(1)),
68+
gradient.0)
69+
XCTAssertEqual(Tensor(2), gradient.1)
70+
}
71+
}
72+
73+
static var allTests = [
74+
("testFreezableParameters", testFreezableParameters),
75+
]
76+
}

0 commit comments

Comments
 (0)