Skip to content

Commit 1d3d6f5

Browse files
authored
[date-conversion-attention] Add client-side inference and visualization (#226)
See screenshot: ![image](https://user-images.githubusercontent.com/16824702/52235038-045bba00-2891-11e9-9f86-92ee5ed2f291.png)
1 parent 21ee908 commit 1d3d6f5

File tree

9 files changed

+5043
-87
lines changed

9 files changed

+5043
-87
lines changed

date-conversion-attention/date_format.js

+53-1
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,11 @@ export function dateTupleToMMSlashDDSlashYYYY(dateTuple) {
8888
return `${monthStr}/${dayStr}/${dateTuple[0]}`;
8989
}
9090

91+
/** Date format such as 1/20/2019. */
92+
export function dateTupleToMSlashDSlashYYYY(dateTuple) {
93+
return `${dateTuple[1]}/${dateTuple[2]}/${dateTuple[0]}`;
94+
}
95+
9196
/** Date format such as 01/20/19. */
9297
export function dateTupleToMMSlashDDSlashYY(dateTuple) {
9398
const monthStr = toTwoDigitString(dateTuple[1]);
@@ -96,6 +101,12 @@ export function dateTupleToMMSlashDDSlashYY(dateTuple) {
96101
return `${monthStr}/${dayStr}/${yearStr}`;
97102
}
98103

104+
/** Date format such as 1/20/19. */
105+
export function dateTupleToMSlashDSlashYY(dateTuple) {
106+
const yearStr = `${dateTuple[0]}`.slice(2);
107+
return `${dateTuple[1]}/${dateTuple[2]}/${yearStr}`;
108+
}
109+
99110
/** Date format such as 012019. */
100111
export function dateTupleToMMDDYY(dateTuple) {
101112
const monthStr = toTwoDigitString(dateTuple[1]);
@@ -141,28 +152,47 @@ export function dateTupleToDDDashMMDashYYYY(dateTuple) {
141152
return `${dayStr}-${monthStr}-${dateTuple[0]}`;
142153
}
143154

155+
/** Date format such as 20-1-2019. */
156+
export function dateTupleToDDashMDashYYYY(dateTuple) {
157+
return `${dateTuple[2]}-${dateTuple[1]}-${dateTuple[0]}`;
158+
}
159+
144160
/** Date format such as 20.01.2019. */
145161
export function dateTupleToDDDotMMDotYYYY(dateTuple) {
146162
const monthStr = toTwoDigitString(dateTuple[1]);
147163
const dayStr = toTwoDigitString(dateTuple[2]);
148164
return `${dayStr}.${monthStr}.${dateTuple[0]}`;
149165
}
150166

167+
/** Date format such as 20.1.2019. */
168+
export function dateTupleToDDotMDotYYYY(dateTuple) {
169+
return `${dateTuple[2]}.${dateTuple[1]}.${dateTuple[0]}`;
170+
}
171+
151172
/** Date format such as 2019.01.20. */
152173
export function dateTupleToYYYYDotMMDotDD(dateTuple) {
153174
const monthStr = toTwoDigitString(dateTuple[1]);
154175
const dayStr = toTwoDigitString(dateTuple[2]);
155176
return `${dateTuple[0]}.${monthStr}.${dayStr}`;
156177
}
157178

179+
/** Date format such as 2019.1.20. */
180+
export function dateTupleToYYYYDotMDotD(dateTuple) {
181+
return `${dateTuple[0]}.${dateTuple[1]}.${dateTuple[2]}`;
182+
}
158183

159-
/** Date format such as 20190120 */
184+
/** Date format such as 20190120. */
160185
export function dateTupleToYYYYMMDD(dateTuple) {
161186
const monthStr = toTwoDigitString(dateTuple[1]);
162187
const dayStr = toTwoDigitString(dateTuple[2]);
163188
return `${dateTuple[0]}${monthStr}${dayStr}`;
164189
}
165190

191+
/** Date format such as 2019-1-20. */
192+
export function dateTupleToYYYYDashMDashD(dateTuple) {
193+
return `${dateTuple[0]}-${dateTuple[1]}-${dateTuple[2]}`;
194+
}
195+
166196
/**
167197
* Date format such as 2019-01-20
168198
* (i.e., the ISO format and the conversion target).
@@ -173,6 +203,28 @@ export function dateTupleToYYYYDashMMDashDD(dateTuple) {
173203
return `${dateTuple[0]}-${monthStr}-${dayStr}`;
174204
}
175205

206+
export const INPUT_FNS = [
207+
dateTupleToDDMMMYYYY,
208+
dateTupleToMMDDYY,
209+
dateTupleToMMSlashDDSlashYY,
210+
dateTupleToMMSlashDDSlashYYYY,
211+
dateTupleToMSlashDSlashYYYY,
212+
dateTupleToDDDashMMDashYYYY,
213+
dateTupleToDDashMDashYYYY,
214+
dateTupleToMMMSpaceDDSpaceYY,
215+
dateTupleToMSlashDSlashYY,
216+
dateTupleToMMMSpaceDDSpaceYYYY,
217+
dateTupleToMMMSpaceDDCommaSpaceYY,
218+
dateTupleToMMMSpaceDDCommaSpaceYYYY,
219+
dateTupleToDDDotMMDotYYYY,
220+
dateTupleToDDotMDotYYYY,
221+
dateTupleToYYYYDotMMDotDD,
222+
dateTupleToYYYYDotMDotD,
223+
dateTupleToYYYYMMDD,
224+
dateTupleToYYYYDashMDashD,
225+
dateTupleToYYYYDashMMDashDD
226+
]; // TODO(cais): Add more formats if necessary.
227+
176228
/**
177229
* Encode a number of input date strings as a `tf.Tensor`.
178230
*

date-conversion-attention/date_format_test.js

+48
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,14 @@ describe('Date formats', () => {
5050
}
5151
});
5252

53+
it('M/D/YYYY', () => {
54+
for (let i = 0; i < 10; ++i) {
55+
const str = dateFormat.dateTupleToMSlashDSlashYYYY(
56+
dateFormat.generateRandomDateTuple());
57+
expect(str).toMatch(/^\d{1,2}\/\d{1,2}\/[1-2]\d\d\d$/);
58+
}
59+
});
60+
5361
it('MM/DD/YY', () => {
5462
for (let i = 0; i < 10; ++i) {
5563
const str = dateFormat.dateTupleToMMSlashDDSlashYY(
@@ -58,6 +66,14 @@ describe('Date formats', () => {
5866
}
5967
});
6068

69+
it('M/D/YY', () => {
70+
for (let i = 0; i < 10; ++i) {
71+
const str = dateFormat.dateTupleToMSlashDSlashYY(
72+
dateFormat.generateRandomDateTuple());
73+
expect(str).toMatch(/^\d{1,2}\/\d{1,2}\/\d\d$/);
74+
}
75+
});
76+
6177
it('MMDDYY', () => {
6278
for (let i = 0; i < 10; ++i) {
6379
const str = dateFormat.dateTupleToMMDDYY(
@@ -110,6 +126,14 @@ describe('Date formats', () => {
110126
}
111127
});
112128

129+
it('M-D-YYYY', () => {
130+
for (let i = 0; i < 10; ++i) {
131+
const str = dateFormat.dateTupleToDDashMDashYYYY(
132+
dateFormat.generateRandomDateTuple());
133+
expect(str).toMatch(/^\d{1,2}-\d{1,2}-[1-2]\d\d\d$/);
134+
}
135+
});
136+
113137
it('YYYY.MM.DD', () => {
114138
for (let i = 0; i < 10; ++i) {
115139
const str = dateFormat.dateTupleToYYYYDotMMDotDD(
@@ -118,6 +142,14 @@ describe('Date formats', () => {
118142
}
119143
});
120144

145+
it('YYYY.M.D', () => {
146+
for (let i = 0; i < 10; ++i) {
147+
const str = dateFormat.dateTupleToYYYYDotMMDotDD(
148+
dateFormat.generateRandomDateTuple());
149+
expect(str).toMatch(/^[1-2]\d\d\d\.\d{1,2}\.\d{1,2}$/);
150+
}
151+
});
152+
121153
it('DD.MM.YYYY', () => {
122154
for (let i = 0; i < 10; ++i) {
123155
const str = dateFormat.dateTupleToDDDotMMDotYYYY(
@@ -126,6 +158,14 @@ describe('Date formats', () => {
126158
}
127159
});
128160

161+
it('D.M.YYYY', () => {
162+
for (let i = 0; i < 10; ++i) {
163+
const str = dateFormat.dateTupleToDDotMDotYYYY(
164+
dateFormat.generateRandomDateTuple());
165+
expect(str).toMatch(/^\d{1,2}\.\d{1,2}\.[1-2]\d\d\d$/);
166+
}
167+
});
168+
129169
it('YYYYMMDD', () => {
130170
for (let i = 0; i < 10; ++i) {
131171
const str = dateFormat.dateTupleToYYYYMMDD(
@@ -134,6 +174,14 @@ describe('Date formats', () => {
134174
}
135175
});
136176

177+
it('YYYY-M-D', () => {
178+
for (let i = 0; i < 10; ++i) {
179+
const str = dateFormat.dateTupleToYYYYDashMDashD(
180+
dateFormat.generateRandomDateTuple());
181+
expect(str).toMatch(/^[1-2]\d\d\d-\d{1,2}-\d{1,2}$/);
182+
}
183+
});
184+
137185
it('YYYY-MM-DD', () => {
138186
for (let i = 0; i < 10; ++i) {
139187
const str = dateFormat.dateTupleToYYYYDashMMDashDD(

date-conversion-attention/index.html

+177
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
<!--
2+
Copyright 2018 Google LLC. All Rights Reserved.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
==============================================================================
16+
-->
17+
18+
<!doctype html>
19+
20+
<head>
21+
<meta charset="UTF-8">
22+
<meta name="viewport" content="width=device-width, initial-scale=1">
23+
<link rel="stylesheet" href="../shared/tfjs-examples.css" />
24+
<title>TensorFlow.js: Date Conversion Through Attention</title>
25+
</head>
26+
<style>
27+
.horizontal-sections {
28+
display: inline-block;
29+
vertical-align: top;
30+
}
31+
.date-label {
32+
font-size: 18px;
33+
font-family: monospace;
34+
padding: 5px;
35+
width: 300px;
36+
display: block;
37+
}
38+
.hint {
39+
font-size: 12px;
40+
font-family: monospace;
41+
}
42+
.dates {
43+
font-size: 24px;
44+
font-family: monospace;
45+
}
46+
.date-input-output-section {
47+
display: inline-block;
48+
}
49+
.attention-section {
50+
margin-top: 8px;
51+
}
52+
#attention-heatmap {
53+
width: 600px;
54+
height: 360px;
55+
border: 2px solid lightblue
56+
}
57+
#date-format-table {
58+
font-size: 15px;
59+
font-family: monospace;
60+
text-align: left;
61+
}
62+
li {
63+
padding-top: 1px;
64+
padding-bottom: 2px;
65+
text-decoration: underline;
66+
color: blue;
67+
}
68+
#random-date {
69+
margin-top: 10px;
70+
padding-top: 5px;
71+
padding-bottom: 5px;
72+
}
73+
.benchmark {
74+
color: gray;
75+
}
76+
</style>
77+
78+
<body>
79+
<div class='tfjs-example-container centered-container'>
80+
<section class='title-area'>
81+
<h1>TensorFlow.js: Date String Conversion</h1>
82+
<p class='subtitle'>Solving a Sequence-to-Sequence Task Using LSTM and Attention</p>
83+
</section>
84+
<section>
85+
<p class='section-head'>Description</p>
86+
<p>
87+
This example demonstrates the inference stage of using a sequence-to-sequence
88+
model to convert a myriad of common date formats into the
89+
<a href="https://en.wikipedia.org/wiki/ISO_8601#Calendar_dates" target="_blank">
90+
ISO 8601 date format
91+
</a>
92+
(i.e., YYYY-MM-DD). The list below shows examples of the supported input date
93+
formats.
94+
</p>
95+
96+
<p>
97+
The model is based on
98+
<a href="https://js.tensorflow.org/api/latest/#layers.lstm" target="_blank">LSTM</a>
99+
and the
100+
<a href="https://medium.com/syncedreview/a-brief-overview-of-attention-mechanism-13c578ba9129" target="_blank">
101+
attention mechanism
102+
</a>.
103+
</p>
104+
105+
<p>
106+
The training uses
107+
<a href="https://github.com/tensorflow/tfjs-node">tfjs-node</a>
108+
and runs in the backend Node.js environment. The training script
109+
can be found
110+
<a href="https://github.com/tensorflow/tfjs-examples/tree/master/date-conversion-attention/train.js">
111+
here
112+
</a>.
113+
</p>
114+
</section>
115+
<section>
116+
<p class='section-head'>Status</p>
117+
<p>
118+
<span id="status"></span>
119+
</p>
120+
</section>
121+
<section>
122+
<p class='section-head'>Support Date Formats</p>
123+
<p>
124+
<div id="date-format-table">
125+
<div>Examples for supported formats (click to try):</div>
126+
<ul>
127+
<li><span class="input-date-example">23Jan2015</span></li>
128+
<li><span class="input-date-example">012315</span></li>
129+
<li><span class="input-date-example">01/23/15</span></li>
130+
<li><span class="input-date-example">1/23/15</span></li>
131+
<li><span class="input-date-example">01/23/2015</span></li>
132+
<li><span class="input-date-example">1/23/2015</span></li>
133+
<li><span class="input-date-example">23-01-2015</span></li>
134+
<li><span class="input-date-example">23-1-2015</span></li>
135+
<li><span class="input-date-example">JAN 23, 15</span></li>
136+
<li><span class="input-date-example">Jan 23, 2015</span></li>
137+
<li><span class="input-date-example">23.01.2015</span></li>
138+
<li><span class="input-date-example">23.1.2015</span></li>
139+
<li><span class="input-date-example">2015.01.23</span></li>
140+
<li><span class="input-date-example">2015.1.23</span></li>
141+
<li><span class="input-date-example">20150123</span></li>
142+
<li><span class="input-date-example">2015/01/23</span></li>
143+
<li><span class="input-date-example">2015-01-23</span></li>
144+
<li><span class="input-date-example">2015-1-23</span></li>
145+
</ul>
146+
</table>
147+
</p>
148+
</section>
149+
150+
<div class="horizontal-sections">
151+
<div class="horizontal-sections">
152+
<div class="date-input-output-section">
153+
<div class="date-label">Input date string:</div>
154+
<input type="text" class="dates" id="input-date-string" value="JAN 20, 2001"></input>
155+
</div>
156+
157+
<div class="hint">Press Enter to Refresh Conversion</div>
158+
<button id="random-date">Random</button>
159+
</div>
160+
161+
<div class="horizontal-sections">
162+
<div class="date-input-output-section">
163+
<div class="date-label">Output date string:</div>
164+
<input type="text" class="dates" id="output-date-string" disabled="true"></input>
165+
</div>
166+
167+
<div class="attention-section">
168+
<div class="date-label">Attention matrix:</div>
169+
<div id="attention-heatmap"></div>
170+
</div>
171+
</div>
172+
</div>
173+
</div>
174+
175+
</body>
176+
177+
<script src="index.js"></script>

0 commit comments

Comments
 (0)