def __init__( self, layers: List[int], activations: List[str], use_batch_norm: bool = False, action_dim: int = 0, ) -> None: """ Dueling Q-Network Architecture: https://arxiv.org/abs/1511.06581 :param layers: List of layer dimensions :param activations: List of layer activations :param use_batch_norm: bool indicating whether to apply batch normalization :param action_dim: if !=0 use parametric dueling DQN, else standard dueling DQN """ super().__init__() self.layers: nn.ModuleList = nn.ModuleList() self.batch_norm_ops: nn.ModuleList = nn.ModuleList() self.activations = activations self.use_batch_norm = use_batch_norm assert len(layers) >= 3, "Invalid layer schema {} for network".format( layers) assert ( len(layers) == len(activations) + 1), "Invalid activation schema {} for network".format(activations) assert (layers[-2] % 2 == 0), """Last shared layer in dueling architecture should be divisible by 2.""" self.state_dim = layers[0] self.action_dim = action_dim for i, layer in enumerate(layers[1:-1]): self.layers.append(nn.Linear(layers[i], layer)) self.batch_norm_ops.append(nn.BatchNorm1d(layers[i])) gaussian_fill_w_gain(self.layers[i].weight, self.activations[i], layers[i]) init.constant_(self.layers[i].bias, 0) self.parametric_action = action_dim > 0 # Split last layer into a value & advantage stream self.advantage = nn.Sequential( # type: ignore nn.Linear(int(layers[-2] + action_dim), int(layers[-2] / 2)), nn.ReLU(), # type: ignore nn.Linear(int(layers[-2] / 2), layers[-1]), ) self.value = nn.Sequential( # type: ignore nn.Linear(int(layers[-2]), int(layers[-2] / 2)), nn.ReLU(), # type: ignore nn.Linear(int(layers[-2] / 2), 1), ) self._name = "unnamed"
def __init__(self, layers, activations, use_batch_norm=False, action_dim=0) -> None: """ Dueling Q-Network Architecture: https://arxiv.org/abs/1511.06581 :param layers: List of layer dimensions :param activations: List of layer activations :param use_batch_norm: bool indicating whether to apply batch normalization :param action_dim: if !=0 use parametric dueling DQN, else standard dueling DQN """ super(DuelingQNetwork, self).__init__() self.layers: nn.ModuleList = nn.ModuleList() self.batch_norm_ops: nn.ModuleList = nn.ModuleList() self.activations = activations self.use_batch_norm = use_batch_norm assert len(layers) >= 3, "Invalid layer schema {} for network".format(layers) assert ( len(layers) == len(activations) + 1 ), "Invalid activation schema {} for network".format(activations) assert ( layers[-2] % 2 == 0 ), """Last shared layer in dueling architecture should be divisible by 2.""" for i, layer in enumerate(layers[1:-1]): self.layers.append(nn.Linear(layers[i], layer)) self.batch_norm_ops.append(nn.BatchNorm1d(layers[i])) gaussian_fill_w_gain(self.layers[i].weight, self.activations[i], layers[i]) init.constant_(self.layers[i].bias, 0) self.parametric_action = action_dim > 0 # Split last layer into a value & advantage stream self.advantage = nn.Sequential( nn.Linear(int(layers[-2] + action_dim), int(layers[-2] / 2)), nn.ReLU(), nn.Linear(int(layers[-2] / 2), layers[-1]), ) self.value = nn.Sequential( nn.Linear(int(layers[-2]), int(layers[-2] / 2)), nn.ReLU(), nn.Linear(int(layers[-2] / 2), 1), ) self._name = "unnamed"