-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathreplayMemory.ts
More file actions
112 lines (100 loc) · 2.78 KB
/
Copy pathreplayMemory.ts
File metadata and controls
112 lines (100 loc) · 2.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
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
108
109
110
111
import * as tf from '@tensorflow/tfjs-node'
//import * as tf from '@tensorflow/tfjs';
/** Replay buffer for DQN training. */
export class ReplayMemory {
maxLen;
buffer;
sBuffer;
index;
length;
bufferIndices_;
initialNegativeReward;
bufferFull;
constructor(maxLen) {
this.maxLen = maxLen;
this.buffer = [];
this.bufferFull = false;
for (let i = 0; i < maxLen; ++i) {
this.buffer.push(null);
}
this.index = 0;
this.length = 0;
this.initialNegativeReward = 0;
this.bufferIndices_ = [];
for (let i = 0; i < maxLen; ++i) {
this.bufferIndices_.push(i);
}
}
/**
* Append an item to the replay buffer.
*
* @param {any} item The item to append.
*/
append(item) {
if (!item) {
throw new Error("undefined item appended to replayMemory")
}
this.buffer[this.index] = item;
if (this.index == 0 && !this.bufferFull) {
this.buffer[this.index][3] = this.initialNegativeReward
}
this.length = Math.min(this.length + 1, this.maxLen);
if (this.index == this.maxLen - 1) {
this.bufferFull = true
}
this.index = (this.index + 1) % this.maxLen;
return this.bufferFull
}
/**
* Randomly sample a batch of items from the replay buffer.
*
* The sampling is done *without* replacement.
*
* @param {number} batchSize Size of the batch.
* @return {Array<any>} Sampled items.
*/
sample(batchSize) {
if (batchSize > this.maxLen) {
throw new Error(
`batchSize (${batchSize}) exceeds buffer length (${this.maxLen})`);
}
if (!this.bufferFull) {
throw new Error(`trying to sample before buffer is filled. Current index at: ${this.index}`)
}
tf.util.shuffle(this.bufferIndices_);
const preOut = []
const out = [];
/*To learn from more meaningful moves we chose moves with higher rewards with greater probablity
*/
// preselect a Set (preOut) of Size 1% of Buffer Size
for (let i = 0; i < this.maxLen * 0.01 * batchSize; ++i) {
let item = this.buffer[this.bufferIndices_[i]]
if (item) {
preOut.push(item);
}else {
throw new Error(`null item in batch at ${this.bufferIndices_[i]}`)
}
}
//Sort preselection so that highest reward is in front
preOut.sort((i1,i2) => {return (i2[2]+i2[3]) - (i1[2] + i1[3])})
//return batchsize elements of sorted preseclection
return preOut.slice(0,batchSize);
}
addNegativeReward(reward) {
if (this.index == 0) {
this.initialNegativeReward += reward
} else {
this.buffer[this.index - 1][3] += reward
}
}
addFinalState(state) {
if (this.index > 0) {
this.buffer[this.index - 1][6] = state;
}
}
setDone() {
if (this.index > 0) {
this.buffer[this.index - 1][4] = true;
}
}
}