|
| 1 | +# Licensed to the Apache Software Foundation (ASF) under one |
| 2 | +# or more contributor license agreements. See the NOTICE file |
| 3 | +# distributed with this work for additional information |
| 4 | +# regarding copyright ownership. The ASF licenses this file |
| 5 | +# to you under the Apache License, Version 2.0 (the |
| 6 | +# "License"); you may not use this file except in compliance |
| 7 | +# with the License. You may obtain a copy of the License at |
| 8 | +# |
| 9 | +# http://www.apache.org/licenses/LICENSE-2.0 |
| 10 | +# |
| 11 | +# Unless required by applicable law or agreed to in writing, |
| 12 | +# software distributed under the License is distributed on an |
| 13 | +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| 14 | +# KIND, either express or implied. See the License for the |
| 15 | +# specific language governing permissions and limitations |
| 16 | +# under the License. |
| 17 | + |
| 18 | +# pylint: skip-file |
| 19 | +from __future__ import absolute_import |
| 20 | +from __future__ import division |
| 21 | + |
| 22 | +import mxnet as mx |
| 23 | +from mxnet import gluon, autograd, np |
| 24 | +from mxnet.test_utils import use_np |
| 25 | + |
| 26 | + |
| 27 | +def test_create_np_param(): |
| 28 | + M, K, N = 10, 9, 20 |
| 29 | + |
| 30 | + def check_block_params(x, TestBlock, hybridize, expected_type): |
| 31 | + net = TestBlock() |
| 32 | + net.initialize() |
| 33 | + if hybridize: |
| 34 | + net.hybridize() |
| 35 | + net(x) |
| 36 | + params = net.collect_params() |
| 37 | + for k, v in params.items(): |
| 38 | + assert type(v.data()) is expected_type |
| 39 | + |
| 40 | + class TestBlock1(gluon.HybridBlock): |
| 41 | + def __init__(self): |
| 42 | + super(TestBlock1, self).__init__() |
| 43 | + with self.name_scope(): |
| 44 | + self.w = self.params.get('w', shape=(K, N), allow_deferred_init=True) |
| 45 | + |
| 46 | + def hybrid_forward(self, F, x, w): |
| 47 | + return F.dot(x, w) |
| 48 | + |
| 49 | + @use_np |
| 50 | + class TestBlock2(gluon.HybridBlock): |
| 51 | + def __init__(self): |
| 52 | + super(TestBlock2, self).__init__() |
| 53 | + with self.name_scope(): |
| 54 | + self.w = self.params.get('w', shape=(K, N), allow_deferred_init=True) |
| 55 | + |
| 56 | + def hybrid_forward(self, F, x, w): |
| 57 | + return F.np.dot(x, w) |
| 58 | + |
| 59 | + x = mx.nd.random.uniform(shape=(M, K)) |
| 60 | + check_block_params(x, TestBlock1, False, mx.nd.NDArray) |
| 61 | + check_block_params(x, TestBlock1, True, mx.nd.NDArray) |
| 62 | + check_block_params(x.as_np_ndarray(), TestBlock2, False, np.ndarray) |
| 63 | + check_block_params(x.as_np_ndarray(), TestBlock2, True, np.ndarray) |
| 64 | + |
| 65 | + |
| 66 | +@use_np |
| 67 | +def test_optimizer_with_np_ndarrays(): |
| 68 | + class LinearRegression(gluon.HybridBlock): |
| 69 | + def __init__(self, num_input_dim=0, num_hidden_dim=100, num_output_dim=10): |
| 70 | + super(LinearRegression, self).__init__() |
| 71 | + with self.name_scope(): |
| 72 | + self.w1 = self.params.get('w1', shape=(num_input_dim, num_hidden_dim), |
| 73 | + allow_deferred_init=True) |
| 74 | + self.w2 = self.params.get('w2', shape=(num_hidden_dim, num_output_dim), |
| 75 | + allow_deferred_init=True) |
| 76 | + |
| 77 | + def hybrid_forward(self, F, x, w1, w2): |
| 78 | + h = x.dot(w1) # equivalent to F.np.dot(x, w1) |
| 79 | + h_relu = F.npx.relu(h) # equivalent to F.relu(h) but generating np.ndarray |
| 80 | + y_pred = h_relu.dot(w2) # equivalent to F.np.dot(h_relu, w2) |
| 81 | + return y_pred |
| 82 | + |
| 83 | + class TotalLoss(gluon.HybridBlock): |
| 84 | + def hybrid_forward(self, F, pred, label): |
| 85 | + return ((pred - label) ** 2).sum() # equivalent to F.np.sum(F.np.square(pred - label)) |
| 86 | + |
| 87 | + regressor = LinearRegression() |
| 88 | + regressor.initialize(mx.init.Uniform()) |
| 89 | + regressor.hybridize() |
| 90 | + |
| 91 | + # Create random input and output data |
| 92 | + x = np.random.uniform(size=(64, 1000)) # x is of type mxnet.numpy.ndarray |
| 93 | + regressor(x) |
| 94 | + y = np.random.uniform(size=(64, 10)) # y is of type mxnet.numpy.ndarray |
| 95 | + |
| 96 | + total_loss = TotalLoss() |
| 97 | + total_loss.hybridize() |
| 98 | + |
| 99 | + trainer = gluon.Trainer(regressor.collect_params(), |
| 100 | + 'sgd', |
| 101 | + {'learning_rate': 1e-3, 'momentum': 0.9}) |
| 102 | + |
| 103 | + for t in range(2): |
| 104 | + with autograd.record(): |
| 105 | + output = regressor(x) # output is a type of np.ndarray because np.dot is the last op in the network |
| 106 | + loss = total_loss(output, y) # loss is a scalar np.ndarray |
| 107 | + loss.backward() |
| 108 | + trainer.step(1) |
| 109 | + |
| 110 | + |
| 111 | +if __name__ == '__main__': |
| 112 | + import nose |
| 113 | + nose.runmodule() |
0 commit comments