scope.md 4.3 KB
Newer Older
Y
Yu Yang 已提交
1
# What is a scope.
Q
qiaolongfei 已提交
2

Y
Yu Yang 已提交
3
## Overview
Q
qiaolongfei 已提交
4

Y
Yu Yang 已提交
5
预期使用场景。
Q
qiaolongfei 已提交
6

Y
Yu Yang 已提交
7 8 9
引出Scope的两个属性。
    1. Scope是Variable的Container
    2. Scope可以共享
Y
Yu Yang 已提交
10

Q
qiaolongfei 已提交
11
## Scope is a Container of Variables.
Y
Yu Yang 已提交
12

Q
qiaolongfei 已提交
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
    * Scope contains Variables as it's data member.
    * Scope contains methods that are used to manage Variables, such as Create/Get/Delete.
    * every variable only belong to one certain Scope.
    * Scope should destruct all Variables within it when itself is destructed.
    * Variable can only be created by Scope.
    * Variable can only be got from Scope.

    * Scope do not contains Operators and have no information to run them.

```cpp
class Scope {
 public:
  Variable* CreateVariable(const std::string& name);
  const Variable* GetVariable(const std::string& name) const;
  bool DeleteVariable(const std::string& name);

 private:
    std::unordered_map<std::string, std::shared_ptr<Vairable>> variable_map_;
};
```
Y
Yu Yang 已提交
33

Q
qiaolongfei 已提交
34

Y
Yu Yang 已提交
35 36
## Parent scope and local scope

Y
Yu Yang 已提交
37
Just like [scope](https://en.wikipedia.org/wiki/Scope_(computer_science)) in programming languages, `Scope` in the neural network can also be a local scope. There are two attributes about local scope.
Y
Yu Yang 已提交
38

Y
Yu Yang 已提交
39
1.  We can create local variables in a local scope. When that local scope are destroyed, all local variables should also be destroyed.
Y
Yu Yang 已提交
40
2.  Variables in a parent scope can be retrieved from local scopes of that parent scope, i.e., when user get a variable from a scope, it will try to search this variable in current scope. If there is no such variable in the local scope, `scope` will keep searching from its parent, until the variable is found or there is no parent.
Y
Yu Yang 已提交
41 42 43 44 45 46

```cpp
class Scope {
public:
  Scope(const std::shared_ptr<Scope>& scope): parent_(scope) {}

Y
Yu Yang 已提交
47
  Variable* GetVar(const std::string& name) const {
Y
Yu Yang 已提交
48 49 50 51 52 53 54 55 56 57 58 59 60 61
    Variable* var = GetVarLocally(name);
    if (var != nullptr) {
      return var;
    } else if (parent_ != nullptr) {
      return parent_->Get(name);
    } else {
      return nullptr;
    }
  }

private:
  std::shared_ptr<Scope> parent_ {nullptr};
};
```
Y
Yu Yang 已提交
62

Y
Yu Yang 已提交
63
In `Scope` class, there is a private data member called `parent_`. `parent_` is a smart pointer to its parent scope. When user `Get` a variable by its `name`, the `name` will be searched inside the current scope. If the variable cannot be found locally and parent scope is not a `nullptr`, the variable will be searched inside that parent scope. `parent_` pointer's default value is `nullptr`. It means that the scope is a global scope when `parent_` is nullptr.
Y
Yu Yang 已提交
64

Y
Yu Yang 已提交
65
A local scope is very useful when we implement Recurrent Neural Network. Each timestep of an RNN should be a `Net`. Each `Net` of timestep (`StepNet` for short) should use an independent local scope. Just like variables in a while loop is inside a local scope in programming languages. By using a single `StepNet` and changing local scope, we can implement an RNN easily.
Y
Yu Yang 已提交
66

Y
Yu Yang 已提交
67
# Interface Design
Y
Yu Yang 已提交
68

Y
Yu Yang 已提交
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
```cpp
class Variable {
private:
  Variable() = default;
  friend class Scope;
};

using VariablePtr = std::weak_ptr<Variable>;

class Scope {
public:
  Scope(const std::shared_ptr<Scope>& parent = nullptr);

  // return nullptr if not found.
  VariablePtr GetVariable(const std::string& name) const;

  // return Error if already contains same name variable.
  Error CreateVariable(const std::string& name);

private:
  std::shared_ptr<Scope> parent_;
  std::unordered_map<std::string, std::shared_ptr<Scope>> attrs_;
};
```
## Only scope can create a variable

To ensure `only scope can create a variable`, we should mark `Variable`'s constructor as a private member function, and Scope is a friend class of Variable. And then only `CreateVariable` can construct `Variable`.

## When scope destroyed, all variables inside this scope should be destroyed together

The `VariablePtr` is a `weak_ptr`. `Net` and `Op` can only get a Variable from `Scope`, but cannot hold it. When scope is destroyed, all `VariablePtr`s belong to this Scope will be changed to `nullptr`.

## Sharing a parent scope

Local scope contains a `parent_` pointer. It is a linked-list for scopes. Using a `shared_ptr` because when a local scope is using, its parents cannot be destroyed.

## Orthogonal interface

`GetVariable` will return `nullptr` when `name` is not found. It can be used as `Contains` method. `CreateVariable` will return a `Error` when there is a name conflict locally. Combine `GetVariable` and `CreateVariable`, we can implement `CreateOrGetVariable` easily.