scope.md 4.6 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
```cpp
class Variable {
private:
  Variable() = default;
  friend class Scope;
};

using VariablePtr = std::weak_ptr<Variable>;

class Scope {
Y
Yu Yang 已提交
79
private:
Y
Yu Yang 已提交
80 81
  Scope(const std::shared_ptr<Scope>& parent = nullptr);

Y
Yu Yang 已提交
82 83 84
public:
  static std::shared_ptr<Scope> Create(const std::shared_ptr<Scope>& parent = nullptr);

Y
Yu Yang 已提交
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
  // 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.

Y
Yu Yang 已提交
108 109
Also, as the parent scope is a `shared_ptr`, we can only `Create()` a scope shared pointer. We cannot construct a scope variable, because it cannot be passed to other scope as `parent` pointer.

Y
Yu Yang 已提交
110 111 112
## 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.