"
- ],
- "application/javascript": [
- "download(\"download_67f1ab5e-e69e-4dc1-88b1-3762c7f37775\", \"visualizations_bundle.zip\", 358296)"
- ]
- },
- "metadata": {}
- }
- ],
- "source": [
- "# Bundle and download artifacts + visualizations to commit to the repo\n",
- "import shutil\n",
- "from google.colab import files\n",
- "\n",
- "shutil.make_archive('artifacts_bundle', 'zip', 'artifacts')\n",
- "shutil.make_archive('visualizations_bundle', 'zip', 'visualizations')\n",
- "\n",
- "files.download('artifacts_bundle.zip')\n",
- "files.download('visualizations_bundle.zip')"
- ],
- "id": "aGDUlZJxJBLN"
- },
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "ZbLgn6G7JBLN"
- },
- "source": [
- "## 7. Hand-off to Next Member\n",
- "\n",
- "**What you receive (in `artifacts/`):**\n",
- "\n",
- "| File | Shape / Type | Purpose |\n",
- "|---|---|---|\n",
- "| `features.npy` | `(N, 20) float32` | One row per video — input X for the classifier |\n",
- "| `labels.npy` | `(N,) int64` | Class index 0–99 — target y |\n",
- "| `video_ids.json` | list of N strings | Same order as the npy files; lets you trace any row back to its source video |\n",
- "| `splits.json` | `{train, val, test}` → video_id lists | Use these for train/test split — don't shuffle randomly, the WLASL splits are designed to keep signers separate |\n",
- "| `feature_schema.json` | metadata | Documents what each feature dimension means |\n",
- "\n",
- "**Your starter snippet (Step 8):**\n",
- "\n",
- "```python\n",
- "import json, numpy as np\n",
- "from sklearn.svm import SVC\n",
- "from sklearn.preprocessing import StandardScaler\n",
- "\n",
- "X = np.load('artifacts/features.npy')\n",
- "y = np.load('artifacts/labels.npy')\n",
- "with open('artifacts/video_ids.json') as f: ids = json.load(f)\n",
- "with open('artifacts/splits.json') as f: splits = json.load(f)\n",
- "\n",
- "id_to_row = {v: i for i, v in enumerate(ids)}\n",
- "tr = [id_to_row[v] for v in splits['train'] if v in id_to_row]\n",
- "te = [id_to_row[v] for v in splits['test'] if v in id_to_row]\n",
- "\n",
- "scaler = StandardScaler().fit(X[tr])\n",
- "model = SVC(kernel='rbf').fit(scaler.transform(X[tr]), y[tr])\n",
- "print('test acc:', model.score(scaler.transform(X[te]), y[te]))\n",
- "```\n",
- "\n",
- "**Important:** Standardize before SVM. The 4 stats columns (indices 16–19) are on a different scale than the histograms (which sum to 1)."
- ],
- "id": "ZbLgn6G7JBLN"
- },
- {
- "cell_type": "code",
- "source": [],
- "metadata": {
- "id": "d-2T4xE6RBZa"
- },
- "id": "d-2T4xE6RBZa",
- "execution_count": null,
- "outputs": []
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "Python 3",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "name": "python",
- "version": "3.10"
- },
- "colab": {
- "provenance": [],
- "include_colab_link": true
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
\ No newline at end of file
diff --git a/app.py b/app.py
new file mode 100644
index 0000000..ebc5e82
--- /dev/null
+++ b/app.py
@@ -0,0 +1,219 @@
+from flask import Flask, render_template_string, Response, jsonify
+import os
+import cv2
+import torch
+import numpy as np
+from collections import deque
+import yaml
+import json
+from src.extract_features import extract_flow_features
+from src.train_simple import LightweightNN
+import threading
+import mediapipe as mp
+
+app = Flask(__name__)
+
+# Global variables to hold the latest prediction
+latest_prediction = "Waiting for frames..."
+prediction_lock = threading.Lock()
+prediction_history = deque(maxlen=5)
+
+
+def get_model_and_scaler():
+ with open("configs/top10.yaml", "r") as f:
+ config = yaml.safe_load(f)
+
+ num_classes = config["dataset"]["top_k"]
+ device = torch.device(
+ "mps"
+ if torch.backends.mps.is_available()
+ else ("cuda" if torch.cuda.is_available() else "cpu")
+ )
+
+ model = LightweightNN(input_dim=1920, num_classes=num_classes).to(device)
+ model.load_state_dict(torch.load("results/lightweight_nn.pt", map_location=device))
+ model.eval()
+
+ mean = np.load("data/features/scaler_mean.npy")
+ std = np.load("data/features/scaler_std.npy")
+
+ with open("data/features/class_map.json", "r") as f:
+ class_map = json.load(f)
+
+ inv_class_map_orig = {v: int(k) for k, v in class_map.items()}
+ wlasl_text_map = {}
+ if os.path.exists("wlasl_class_list.txt"):
+ with open("wlasl_class_list.txt", "r") as f:
+ for line in f:
+ parts = line.strip().split("\t")
+ if len(parts) == 2:
+ wlasl_text_map[int(parts[0])] = parts[1]
+
+ inv_class_map = {}
+ for model_id, orig_id in inv_class_map_orig.items():
+ inv_class_map[model_id] = wlasl_text_map.get(orig_id, f"Sign ID {orig_id}")
+
+ return model, mean, std, inv_class_map, device, config["dataset"]["num_frames"]
+
+
+def generate_frames():
+ global latest_prediction
+ model, mean, std, inv_class_map, device, num_frames = get_model_and_scaler()
+ buffer = deque(maxlen=num_frames)
+
+ # Use cv2.CAP_AVFOUNDATION for Mac to explicitly request permissions sometimes works better
+ cap = cv2.VideoCapture(0)
+
+ mp_hands = mp.solutions.hands
+ mp_drawing = mp.solutions.drawing_utils
+ hands = mp_hands.Hands(
+ static_image_mode=False,
+ max_num_hands=2,
+ min_detection_confidence=0.5,
+ min_tracking_confidence=0.5
+ )
+
+ while True:
+ success, frame = cap.read()
+ if not success:
+ break
+
+ frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
+
+ # Draw MediaPipe hand landmarks
+ results = hands.process(frame_rgb)
+ if results.multi_hand_landmarks:
+ for hand_landmarks in results.multi_hand_landmarks:
+ mp_drawing.draw_landmarks(
+ frame,
+ hand_landmarks,
+ mp_hands.HAND_CONNECTIONS,
+ mp_drawing.DrawingSpec(color=(0,255,0), thickness=2, circle_radius=2),
+ mp_drawing.DrawingSpec(color=(0,0,255), thickness=2, circle_radius=2)
+ )
+
+ frame_resized = cv2.resize(frame_rgb, (128, 128))
+ buffer.append(frame_resized)
+
+ if len(buffer) == num_frames:
+ frames_list = list(buffer)
+ features = extract_flow_features(frames_list, grid_size=8)
+
+ motion_energy = np.max(np.abs(features))
+
+ if motion_energy < 0.3:
+ with prediction_lock:
+ latest_prediction = "Waiting for sign..."
+ prediction_history.clear()
+ else:
+ features_scaled = (features - mean) / std
+
+ x_tensor = (
+ torch.tensor(features_scaled, dtype=torch.float32).unsqueeze(0).to(device)
+ )
+
+ with torch.no_grad():
+ outputs = model(x_tensor)
+ probs = torch.softmax(outputs, dim=1)
+ top_prob, top_idx = torch.max(probs, dim=1)
+
+ class_id = top_idx.item()
+ prob = top_prob.item()
+
+ class_text = inv_class_map.get(class_id, f"Class {class_id}")
+ print(f"Motion Energy: {motion_energy:.2f} | Prob: {prob*100:.1f}% | Top Class: {class_text}")
+
+ if prob > 0.65:
+ prediction_history.append(class_text)
+ else:
+ prediction_history.append("Waiting for sign...")
+
+ # If the same class is predicted at least 3 times in the last 5 frames
+ if len(prediction_history) == 5 and prediction_history.count(class_text) >= 3 and prob > 0.65:
+ with prediction_lock:
+ latest_prediction = f"{class_text.upper()} ({prob*100:.1f}%)"
+ elif len(prediction_history) > 0 and prediction_history.count("Waiting for sign...") >= 3:
+ with prediction_lock:
+ latest_prediction = "Waiting for sign..."
+
+ # Draw on frame as well
+ cv2.putText(
+ frame,
+ latest_prediction,
+ (10, 40),
+ cv2.FONT_HERSHEY_SIMPLEX,
+ 1,
+ (0, 255, 0),
+ 2,
+ )
+
+ ret, buffer_img = cv2.imencode(".jpg", frame)
+ frame_bytes = buffer_img.tobytes()
+
+ yield (
+ b"--frame\r\n" b"Content-Type: image/jpeg\r\n\r\n" + frame_bytes + b"\r\n"
+ )
+
+
+HTML_TEMPLATE = """
+
+
+
+ ASL Recognition - Realtime Demo
+
+
+
+ Real-Time ASL Recognition
+ Using Lightweight NN & Farneback Optical Flow
+
+
+
 }})
+
+
+
+ Waiting for frames...
+
+
+
+
+
+"""
+
+
+@app.route("/")
+def index():
+ from flask import url_for
+
+ return render_template_string(HTML_TEMPLATE)
+
+
+@app.route("/video_feed")
+def video_feed():
+ return Response(
+ generate_frames(), mimetype="multipart/x-mixed-replace; boundary=frame"
+ )
+
+
+@app.route("/get_prediction")
+def get_prediction():
+ with prediction_lock:
+ return jsonify({"prediction": latest_prediction})
+
+
+if __name__ == "__main__":
+ print("Starting Web Server. Open http://localhost:5001 in your browser.")
+ app.run(host="0.0.0.0", port=5001, debug=False, threaded=True)
diff --git a/artifacts/feature_schema.json b/artifacts/feature_schema.json
deleted file mode 100644
index d2bbb98..0000000
--- a/artifacts/feature_schema.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "feature_dim": 20,
- "layout": "8 HOOF angle bins + 8 magnitude histogram bins + [mean_mag, std_mag, max_mag, mean_ang]",
- "flow_method": "Farneback dense optical flow (cv2.calcOpticalFlowFarneback)",
- "flow_resize_wh": [
- 160,
- 120
- ],
- "angle_bins": 8,
- "mag_bins": 8,
- "aggregation": "mean across all consecutive frame pairs in the video",
- "num_classes": 100,
- "num_videos": 1013
-}
\ No newline at end of file
diff --git a/artifacts/features.npy b/artifacts/features.npy
deleted file mode 100644
index 639c7f5..0000000
Binary files a/artifacts/features.npy and /dev/null differ
diff --git a/artifacts/labels.npy b/artifacts/labels.npy
deleted file mode 100644
index 14fca36..0000000
Binary files a/artifacts/labels.npy and /dev/null differ
diff --git a/artifacts/splits.json b/artifacts/splits.json
deleted file mode 100644
index 7d2f68d..0000000
--- a/artifacts/splits.json
+++ /dev/null
@@ -1,1021 +0,0 @@
-{
- "train": [
- "10893",
- "10892",
- "10895",
- "10894",
- "51064",
- "51061",
- "51060",
- "66779",
- "66778",
- "65278",
- "43180",
- "06365",
- "57291",
- "56839",
- "56838",
- "56837",
- "06334",
- "06337",
- "06331",
- "06333",
- "06332",
- "11768",
- "11769",
- "11767",
- "64292",
- "64291",
- "65504",
- "65507",
- "65503",
- "45443",
- "05734",
- "05730",
- "05731",
- "05732",
- "05733",
- "05229",
- "17720",
- "17721",
- "17722",
- "17723",
- "14624",
- "14625",
- "26973",
- "26972",
- "26975",
- "26976",
- "65029",
- "63208",
- "14680",
- "63204",
- "63207",
- "63200",
- "63202",
- "63203",
- "51063",
- "62246",
- "62245",
- "62248",
- "08437",
- "07074",
- "07070",
- "26719",
- "26713",
- "26712",
- "26715",
- "26714",
- "26717",
- "07961",
- "65889",
- "28214",
- "28210",
- "28211",
- "65084",
- "65085",
- "66532",
- "66769",
- "05243",
- "65263",
- "02003",
- "39006",
- "69343",
- "49174",
- "49175",
- "42843",
- "49178",
- "05740",
- "05743",
- "05742",
- "05749",
- "10158",
- "36946",
- "13199",
- "14894",
- "14893",
- "45273",
- "62259",
- "62250",
- "62251",
- "07068",
- "07069",
- "40847",
- "31755",
- "31756",
- "31753",
- "31752",
- "66575",
- "06486",
- "66799",
- "66798",
- "05644",
- "65216",
- "35458",
- "35452",
- "35453",
- "35456",
- "65187",
- "35455",
- "32250",
- "32254",
- "32257",
- "65677",
- "01387",
- "56852",
- "24955",
- "24954",
- "24956",
- "65328",
- "55365",
- "55362",
- "10166",
- "14882",
- "14884",
- "14885",
- "14886",
- "45263",
- "45261",
- "45264",
- "45265",
- "09850",
- "10147",
- "10148",
- "26739",
- "66146",
- "66147",
- "42832",
- "42830",
- "42831",
- "42836",
- "66098",
- "66099",
- "06832",
- "06833",
- "06834",
- "06835",
- "06839",
- "65996",
- "51056",
- "51057",
- "51058",
- "51059",
- "35467",
- "65200",
- "65192",
- "32248",
- "32249",
- "65440",
- "56841",
- "65445",
- "56844",
- "24947",
- "56848",
- "69325",
- "24943",
- "24940",
- "24941",
- "38990",
- "38995",
- "38997",
- "38999",
- "57647",
- "57641",
- "26971",
- "14627",
- "63679",
- "63673",
- "26974",
- "14622",
- "14623",
- "27216",
- "42956",
- "42959",
- "42958",
- "48114",
- "14676",
- "09848",
- "09849",
- "14671",
- "57935",
- "57934",
- "57937",
- "57936",
- "57939",
- "63205",
- "08424",
- "15038",
- "15032",
- "15033",
- "15034",
- "15035",
- "08935",
- "08937",
- "08936",
- "08938",
- "50044",
- "50046",
- "50040",
- "24961",
- "13647",
- "13646",
- "13642",
- "13640",
- "57634",
- "13648",
- "57630",
- "57631",
- "24973",
- "08431",
- "06371",
- "21891",
- "27221",
- "69206",
- "21871",
- "21870",
- "21878",
- "63668",
- "63666",
- "63667",
- "63665",
- "43167",
- "43169",
- "43168",
- "49183",
- "49181",
- "38544",
- "49188",
- "64300",
- "63799",
- "63792",
- "63793",
- "63790",
- "63791",
- "48106",
- "48107",
- "48109",
- "63242",
- "58499",
- "58498",
- "22130",
- "58361",
- "58360",
- "58363",
- "58362",
- "58366",
- "31767",
- "14681",
- "65299",
- "65298",
- "07963",
- "07962",
- "07960",
- "07966",
- "11330",
- "08924",
- "08920",
- "08921",
- "50039",
- "50038",
- "50037",
- "56842",
- "66183",
- "56846",
- "24638",
- "65043",
- "32260",
- "32261",
- "17709",
- "65824",
- "19258",
- "19259",
- "06363",
- "21883",
- "27217",
- "27215",
- "27214",
- "10149",
- "21869",
- "45436",
- "45434",
- "45433",
- "24962",
- "43174",
- "43170",
- "43173",
- "17085",
- "17084",
- "17087",
- "17086",
- "09869",
- "12316",
- "12317",
- "12314",
- "12313",
- "12311",
- "12318",
- "12319",
- "40130",
- "26980",
- "63227",
- "63225",
- "65539",
- "66592",
- "08917",
- "08916",
- "08919",
- "66441",
- "13161",
- "63672",
- "65145",
- "65144",
- "69534",
- "28115",
- "28116",
- "28111",
- "28110",
- "24640",
- "19261",
- "19260",
- "19264",
- "19269",
- "11780",
- "06359",
- "27208",
- "27206",
- "27207",
- "32946",
- "17090",
- "17091",
- "42961",
- "42966",
- "42967",
- "64212",
- "64213",
- "64218",
- "64219",
- "55366",
- "12327",
- "12328",
- "55364",
- "40121",
- "40129",
- "03005",
- "03000",
- "03001",
- "03002",
- "03003",
- "03008",
- "18329",
- "18325",
- "18324",
- "62170",
- "62175",
- "37886",
- "37883",
- "37881",
- "11313",
- "11310",
- "28107",
- "24651",
- "14675",
- "28108",
- "28109",
- "14674",
- "06343",
- "32158",
- "32155",
- "49600",
- "49602",
- "13333",
- "13337",
- "05638",
- "64224",
- "05634",
- "05637",
- "05636",
- "05631",
- "05630",
- "05633",
- "05632",
- "13202",
- "13201",
- "13200",
- "13209",
- "13208",
- "12338",
- "36929",
- "33285",
- "40119",
- "40117",
- "40116",
- "40115",
- "18335",
- "62168",
- "62169",
- "62163",
- "62164",
- "37894",
- "40836",
- "66008",
- "66007",
- "11309",
- "66469",
- "65162",
- "65161",
- "65167",
- "01987",
- "01988",
- "32945",
- "32947",
- "24660",
- "32949",
- "35523",
- "69241",
- "32163",
- "32160",
- "21945",
- "21941",
- "21943",
- "13326",
- "13327",
- "13323",
- "13328",
- "13329",
- "13213",
- "13216",
- "13217",
- "22967",
- "22960",
- "36930",
- "36931",
- "36932",
- "36933",
- "36936",
- "36937",
- "53268",
- "56556",
- "56557",
- "10157",
- "24648",
- "62159",
- "05629",
- "30832",
- "30831",
- "30835",
- "30834",
- "09967",
- "09966",
- "09960",
- "09963",
- "40841",
- "65363",
- "65362",
- "23769",
- "23768",
- "23766",
- "66010",
- "66014",
- "13695",
- "13697",
- "13699",
- "01991",
- "01992",
- "34738",
- "34734",
- "34736",
- "34737",
- "43179",
- "34732",
- "34733",
- "32954",
- "62970",
- "32959",
- "65009",
- "28125",
- "25321",
- "25323",
- "25322",
- "25325",
- "25324",
- "25326",
- "25329",
- "62979",
- "35511",
- "35517",
- "35516",
- "35518",
- "13630",
- "23782",
- "69290",
- "69298",
- "21950",
- "21951",
- "53279",
- "57286",
- "53273",
- "53270",
- "53271",
- "53275",
- "00624",
- "00623",
- "22953",
- "22952",
- "00629",
- "00628",
- "22955",
- "62966",
- "62964",
- "62968",
- "57953",
- "20979",
- "20978",
- "01388",
- "01385",
- "01384",
- "01383",
- "66640",
- "66644",
- "09970",
- "66246",
- "66804",
- "23771",
- "23774",
- "08955",
- "34742",
- "34746",
- "25339",
- "35509",
- "56563",
- "51223",
- "51221",
- "51226",
- "51225",
- "69282",
- "69283",
- "69281",
- "50045",
- "65721",
- "65635",
- "65434",
- "65439",
- "63806",
- "00632",
- "00633",
- "00631",
- "06478",
- "00639",
- "57940",
- "57942",
- "57947",
- "57949",
- "06471",
- "42969",
- "13168",
- "13160",
- "13167",
- "51235",
- "51231",
- "40834",
- "51232",
- "40837",
- "09949",
- "07389",
- "66816",
- "66818",
- "08942",
- "08944",
- "42829",
- "05238",
- "05728",
- "05231",
- "05233",
- "66038",
- "65601",
- "06472",
- "06473",
- "22120",
- "22121",
- "06477",
- "06474",
- "51236",
- "56579",
- "64090",
- "64091",
- "65731",
- "64088",
- "64087",
- "64086",
- "64085",
- "64084",
- "37884",
- "17711",
- "17710",
- "17712",
- "34831",
- "34830",
- "13157",
- "13156",
- "13158",
- "20992",
- "33267",
- "33266",
- "33269",
- "63236",
- "63231",
- "63232",
- "30840",
- "09954",
- "09956",
- "09953",
- "66531",
- "66820",
- "65540",
- "26741",
- "07394",
- "07397",
- "07390",
- "07391",
- "07392",
- "07393",
- "07399",
- "22116",
- "22115",
- "55363",
- "55361",
- "55368",
- "55369",
- "32953",
- "65449",
- "32321",
- "32322",
- "32324",
- "32326",
- "32955",
- "57638",
- "57635",
- "57632",
- "57633",
- "17019",
- "17013",
- "17017",
- "17014",
- "17015",
- "34823",
- "34824",
- "34825",
- "34826",
- "34827",
- "38524",
- "38527",
- "38529",
- "20986",
- "20987",
- "20982",
- "20983",
- "20980",
- "20981",
- "33274",
- "33273",
- "35512",
- "63228",
- "41037",
- "41032",
- "41030",
- "35454",
- "66296",
- "66297",
- "58503",
- "58508",
- "66637",
- "66638",
- "66639",
- "66742",
- "66743",
- "48105",
- "56558",
- "69430",
- "13702",
- "65242",
- "34839",
- "65241",
- "32338",
- "32333",
- "32337",
- "13636",
- "13632",
- "13631",
- "65450",
- "57276",
- "57277",
- "57287",
- "57284",
- "57283",
- "66355",
- "65408",
- "65409",
- "65403",
- "11770",
- "11773",
- "17026",
- "64288",
- "64284",
- "64281",
- "64280",
- "64283",
- "49595",
- "49596",
- "49597",
- "49598",
- "49599",
- "34832",
- "17733",
- "05729",
- "05230",
- "05234",
- "38534",
- "38532",
- "38530",
- "14633",
- "63214",
- "41025",
- "41026",
- "41028",
- "41029",
- "66606",
- "66351",
- "65890",
- "28205",
- "28204",
- "28202"
- ],
- "val": [
- "69422",
- "10898",
- "51067",
- "69395",
- "69396",
- "06330",
- "30849",
- "17724",
- "62244",
- "15043",
- "65086",
- "69413",
- "69411",
- "39000",
- "69345",
- "49176",
- "06476",
- "31751",
- "69402",
- "32255",
- "69359",
- "24952",
- "05750",
- "14887",
- "45262",
- "45267",
- "09851",
- "09854",
- "40835",
- "48124",
- "32263",
- "42833",
- "66097",
- "50052",
- "65843",
- "56840",
- "24946",
- "38994",
- "69213",
- "63788",
- "14672",
- "57933",
- "08426",
- "40840",
- "15037",
- "13641",
- "21874",
- "21872",
- "63669",
- "43166",
- "49182",
- "63795",
- "48108",
- "58497",
- "08929",
- "69524",
- "24639",
- "19257",
- "69238",
- "69233",
- "69236",
- "45438",
- "45435",
- "69307",
- "69302",
- "17083",
- "42977",
- "12315",
- "12312",
- "58370",
- "07973",
- "66591",
- "08918",
- "66112",
- "69531",
- "69533",
- "28112",
- "24641",
- "69316",
- "42962",
- "64211",
- "12326",
- "18323",
- "37882",
- "02999",
- "65792",
- "32156",
- "32154",
- "49606",
- "13203",
- "40118",
- "65163",
- "32948",
- "10904",
- "65342",
- "65341",
- "21942",
- "21949",
- "53269",
- "10151",
- "62158",
- "30833",
- "66015",
- "13696",
- "13197",
- "13698",
- "69274",
- "53274",
- "00627",
- "00626",
- "62965",
- "14903",
- "23775",
- "23776",
- "25330",
- "65294",
- "51220",
- "51227",
- "51224",
- "57948",
- "69511",
- "01398",
- "01391",
- "07388",
- "05232",
- "69455",
- "57629",
- "57628",
- "13155",
- "33268",
- "63230",
- "09955",
- "09957",
- "07398",
- "22114",
- "22113",
- "51081",
- "32320",
- "32323",
- "32325",
- "57639",
- "17016",
- "33270",
- "63229",
- "07099",
- "13703",
- "13634",
- "13633",
- "69546",
- "69364",
- "57285",
- "57282",
- "69368",
- "05239",
- "65402",
- "64287",
- "62988",
- "17734",
- "38533",
- "41027",
- "58365",
- "66607",
- "63237",
- "65891",
- "28203"
- ],
- "test": [
- "51068",
- "51066",
- "69370",
- "06335",
- "64293",
- "65506",
- "05739",
- "14685",
- "63201",
- "62247",
- "65884",
- "49173",
- "05741",
- "13198",
- "13196",
- "31750",
- "32253",
- "57278",
- "69439",
- "14888",
- "14883",
- "48126",
- "31749",
- "32246",
- "56843",
- "38991",
- "63789",
- "14673",
- "08425",
- "08429",
- "50041",
- "65300",
- "21890",
- "63664",
- "69269",
- "08925",
- "24636",
- "06360",
- "27213",
- "24960",
- "57640",
- "64209",
- "08915",
- "66111",
- "69225",
- "27209",
- "65761",
- "17097",
- "42960",
- "64210",
- "12320",
- "11311",
- "48115",
- "69252",
- "69257",
- "32157",
- "13334",
- "33286",
- "62160",
- "01986",
- "32167",
- "21944",
- "13325",
- "69431",
- "69433",
- "62975",
- "24649",
- "10159",
- "23767",
- "32950",
- "35513",
- "43171",
- "00625",
- "22954",
- "62967",
- "01386",
- "00634",
- "57941",
- "57943",
- "55375",
- "51233",
- "17713",
- "09950",
- "22117",
- "69440",
- "13710",
- "07400",
- "65415",
- "64097",
- "38525",
- "63226",
- "58502",
- "13635",
- "69389",
- "11772",
- "17020",
- "62987",
- "05727",
- "06845",
- "28201"
- ]
-}
\ No newline at end of file
diff --git a/artifacts/video_ids.json b/artifacts/video_ids.json
deleted file mode 100644
index 5fe7f1a..0000000
--- a/artifacts/video_ids.json
+++ /dev/null
@@ -1,1015 +0,0 @@
-[
- "69422",
- "10898",
- "10893",
- "10892",
- "10895",
- "10894",
- "51068",
- "51064",
- "51067",
- "51066",
- "51061",
- "51060",
- "66779",
- "66778",
- "65278",
- "43180",
- "06365",
- "69395",
- "69396",
- "57291",
- "69370",
- "56839",
- "56838",
- "56837",
- "06335",
- "06334",
- "06337",
- "06331",
- "06330",
- "06333",
- "06332",
- "11768",
- "11769",
- "11767",
- "30849",
- "64292",
- "64293",
- "64291",
- "65504",
- "65507",
- "65506",
- "65503",
- "45443",
- "05734",
- "05730",
- "05731",
- "05732",
- "05733",
- "05739",
- "05229",
- "17724",
- "17720",
- "17721",
- "17722",
- "17723",
- "14624",
- "14625",
- "26973",
- "26972",
- "26975",
- "26976",
- "14685",
- "65029",
- "63208",
- "14680",
- "63204",
- "63207",
- "63200",
- "63201",
- "63202",
- "63203",
- "51063",
- "62247",
- "62246",
- "62245",
- "62244",
- "62248",
- "08437",
- "07074",
- "07070",
- "26719",
- "26713",
- "26712",
- "26715",
- "26714",
- "26717",
- "07961",
- "65889",
- "65884",
- "15043",
- "28214",
- "28210",
- "28211",
- "65084",
- "65085",
- "65086",
- "66532",
- "69413",
- "69411",
- "66769",
- "05243",
- "65263",
- "02003",
- "39006",
- "39000",
- "69343",
- "69345",
- "49173",
- "49176",
- "49174",
- "49175",
- "42843",
- "49178",
- "05741",
- "05740",
- "05743",
- "05742",
- "05749",
- "10158",
- "36946",
- "13199",
- "13198",
- "14894",
- "14893",
- "13196",
- "45273",
- "06476",
- "62259",
- "62250",
- "62251",
- "07068",
- "07069",
- "40847",
- "31755",
- "31756",
- "31751",
- "31750",
- "31753",
- "31752",
- "66575",
- "06486",
- "69402",
- "66799",
- "66798",
- "05644",
- "65216",
- "35458",
- "35452",
- "35453",
- "35456",
- "65187",
- "35455",
- "32250",
- "32253",
- "32255",
- "32254",
- "32257",
- "65677",
- "01387",
- "56852",
- "69359",
- "57278",
- "24955",
- "24954",
- "24956",
- "65328",
- "24952",
- "55365",
- "55362",
- "69439",
- "05750",
- "10166",
- "14888",
- "14882",
- "14883",
- "14884",
- "14885",
- "14886",
- "14887",
- "45262",
- "45263",
- "45261",
- "45267",
- "45264",
- "45265",
- "09851",
- "09850",
- "09854",
- "40835",
- "48126",
- "48124",
- "10147",
- "10148",
- "26739",
- "32263",
- "31749",
- "66146",
- "66147",
- "42832",
- "42833",
- "42830",
- "42831",
- "66097",
- "42836",
- "66098",
- "66099",
- "06832",
- "06833",
- "06834",
- "06835",
- "06839",
- "65996",
- "51056",
- "51057",
- "51058",
- "51059",
- "50052",
- "35467",
- "65200",
- "65192",
- "32246",
- "32248",
- "32249",
- "65843",
- "65440",
- "56843",
- "56840",
- "56841",
- "65445",
- "56844",
- "24946",
- "24947",
- "56848",
- "69325",
- "24943",
- "24940",
- "24941",
- "38990",
- "38991",
- "38994",
- "38995",
- "38997",
- "38999",
- "57647",
- "57641",
- "69213",
- "26971",
- "14627",
- "63679",
- "63673",
- "26974",
- "14622",
- "14623",
- "27216",
- "63789",
- "63788",
- "42956",
- "42959",
- "42958",
- "48114",
- "14676",
- "09848",
- "09849",
- "14673",
- "14672",
- "14671",
- "57935",
- "57934",
- "57937",
- "57936",
- "57933",
- "57939",
- "63205",
- "08426",
- "08425",
- "08424",
- "40840",
- "08429",
- "15038",
- "15032",
- "15033",
- "15037",
- "15034",
- "15035",
- "08935",
- "08937",
- "08936",
- "08938",
- "50044",
- "50046",
- "50040",
- "50041",
- "24961",
- "13647",
- "13646",
- "13642",
- "13641",
- "13640",
- "57634",
- "13648",
- "57630",
- "57631",
- "65300",
- "24973",
- "08431",
- "06371",
- "21891",
- "21890",
- "27221",
- "69206",
- "21874",
- "21871",
- "21870",
- "21872",
- "21878",
- "63668",
- "63669",
- "63666",
- "63667",
- "63664",
- "63665",
- "43167",
- "43166",
- "43169",
- "43168",
- "49183",
- "49182",
- "49181",
- "38544",
- "49188",
- "64300",
- "63799",
- "63792",
- "63793",
- "63790",
- "63791",
- "63795",
- "48106",
- "48107",
- "48108",
- "48109",
- "63242",
- "58499",
- "58498",
- "22130",
- "58361",
- "58360",
- "58363",
- "58362",
- "58497",
- "58366",
- "69269",
- "31767",
- "14681",
- "65299",
- "65298",
- "07963",
- "07962",
- "07960",
- "07966",
- "11330",
- "08924",
- "08925",
- "08920",
- "08921",
- "08929",
- "50039",
- "50038",
- "50037",
- "56842",
- "66183",
- "56846",
- "69524",
- "24638",
- "24639",
- "65043",
- "32260",
- "32261",
- "24636",
- "17709",
- "65824",
- "19257",
- "19258",
- "19259",
- "06363",
- "06360",
- "21883",
- "27213",
- "69238",
- "27217",
- "27215",
- "27214",
- "69233",
- "69236",
- "10149",
- "21869",
- "45438",
- "45436",
- "45435",
- "45434",
- "45433",
- "69307",
- "24960",
- "69302",
- "24962",
- "43174",
- "43170",
- "43173",
- "17083",
- "17085",
- "17084",
- "17087",
- "17086",
- "42977",
- "09869",
- "57640",
- "64209",
- "12316",
- "12317",
- "12314",
- "12315",
- "12312",
- "12313",
- "12311",
- "12318",
- "12319",
- "58370",
- "40130",
- "26980",
- "63227",
- "07973",
- "63225",
- "65539",
- "66592",
- "66591",
- "08917",
- "08916",
- "08915",
- "08919",
- "08918",
- "66441",
- "13161",
- "66112",
- "66111",
- "63672",
- "65145",
- "65144",
- "69531",
- "69533",
- "69534",
- "28115",
- "28116",
- "28111",
- "28110",
- "28112",
- "24641",
- "24640",
- "19261",
- "19260",
- "19264",
- "19269",
- "11780",
- "06359",
- "69225",
- "27208",
- "27209",
- "27206",
- "27207",
- "65761",
- "32946",
- "69316",
- "17090",
- "17091",
- "17097",
- "42960",
- "42961",
- "42962",
- "42966",
- "42967",
- "64212",
- "64213",
- "64210",
- "64211",
- "64218",
- "64219",
- "55366",
- "12320",
- "12327",
- "12326",
- "12328",
- "55364",
- "40121",
- "40129",
- "03005",
- "03000",
- "03001",
- "03002",
- "03003",
- "03008",
- "18329",
- "18323",
- "18325",
- "18324",
- "62170",
- "62175",
- "37886",
- "37883",
- "37882",
- "37881",
- "02999",
- "11313",
- "11311",
- "11310",
- "48115",
- "28107",
- "24651",
- "14675",
- "28108",
- "28109",
- "14674",
- "06343",
- "69252",
- "69257",
- "65792",
- "32158",
- "32156",
- "32157",
- "32154",
- "32155",
- "49606",
- "49600",
- "49602",
- "13333",
- "13337",
- "13334",
- "05638",
- "64224",
- "05634",
- "05637",
- "05636",
- "05631",
- "05630",
- "05633",
- "05632",
- "13203",
- "13202",
- "13201",
- "13200",
- "13209",
- "13208",
- "12338",
- "36929",
- "33285",
- "33286",
- "40119",
- "40118",
- "40117",
- "40116",
- "40115",
- "18335",
- "62168",
- "62169",
- "62163",
- "62160",
- "62164",
- "37894",
- "40836",
- "66008",
- "66007",
- "11309",
- "66469",
- "65163",
- "65162",
- "65161",
- "65167",
- "01987",
- "01986",
- "01988",
- "32945",
- "32947",
- "24660",
- "32949",
- "32948",
- "35523",
- "69241",
- "32167",
- "32163",
- "32160",
- "10904",
- "65342",
- "65341",
- "21945",
- "21944",
- "21941",
- "21943",
- "21942",
- "21949",
- "13325",
- "13326",
- "13327",
- "13323",
- "13328",
- "13329",
- "53269",
- "69431",
- "69433",
- "13213",
- "13216",
- "13217",
- "22967",
- "22960",
- "62975",
- "36930",
- "36931",
- "36932",
- "36933",
- "36936",
- "36937",
- "53268",
- "10151",
- "56556",
- "56557",
- "10157",
- "24649",
- "24648",
- "10159",
- "62159",
- "62158",
- "05629",
- "30833",
- "30832",
- "30831",
- "30835",
- "30834",
- "09967",
- "09966",
- "09960",
- "09963",
- "40841",
- "65363",
- "65362",
- "23769",
- "23768",
- "23767",
- "23766",
- "66010",
- "66014",
- "66015",
- "13695",
- "13696",
- "13697",
- "13197",
- "13698",
- "13699",
- "01991",
- "01992",
- "34738",
- "34734",
- "34736",
- "34737",
- "43179",
- "34732",
- "34733",
- "32950",
- "32954",
- "62970",
- "32959",
- "65009",
- "28125",
- "25321",
- "25323",
- "25322",
- "25325",
- "25324",
- "25326",
- "25329",
- "35513",
- "62979",
- "35511",
- "35517",
- "35516",
- "35518",
- "13630",
- "23782",
- "69274",
- "69290",
- "69298",
- "21950",
- "21951",
- "53279",
- "57286",
- "53273",
- "53270",
- "53271",
- "43171",
- "53274",
- "53275",
- "00625",
- "00624",
- "00627",
- "00626",
- "00623",
- "22953",
- "22952",
- "00629",
- "00628",
- "22955",
- "22954",
- "62966",
- "62967",
- "62964",
- "62965",
- "62968",
- "14903",
- "57953",
- "20979",
- "20978",
- "01388",
- "01385",
- "01384",
- "01386",
- "01383",
- "66640",
- "66644",
- "09970",
- "66246",
- "66804",
- "23771",
- "23774",
- "23775",
- "23776",
- "08955",
- "34742",
- "34746",
- "25330",
- "25339",
- "35509",
- "56563",
- "65294",
- "51223",
- "51221",
- "51220",
- "51227",
- "51226",
- "51225",
- "51224",
- "69282",
- "69283",
- "69281",
- "50045",
- "65721",
- "65635",
- "65434",
- "65439",
- "63806",
- "00634",
- "00632",
- "00633",
- "00631",
- "06478",
- "00639",
- "57940",
- "57941",
- "57942",
- "57943",
- "57947",
- "57948",
- "57949",
- "06471",
- "42969",
- "13168",
- "13160",
- "13167",
- "51235",
- "69511",
- "51231",
- "40834",
- "51232",
- "01398",
- "40837",
- "01391",
- "09949",
- "07389",
- "07388",
- "66816",
- "66818",
- "08942",
- "08944",
- "42829",
- "05238",
- "05728",
- "05231",
- "05233",
- "05232",
- "66038",
- "55375",
- "65601",
- "06472",
- "06473",
- "22120",
- "22121",
- "06477",
- "06474",
- "51236",
- "51233",
- "56579",
- "64090",
- "69455",
- "64091",
- "65731",
- "57629",
- "57628",
- "64088",
- "64087",
- "64086",
- "64085",
- "64084",
- "37884",
- "17711",
- "17710",
- "17713",
- "17712",
- "34831",
- "34830",
- "13157",
- "13156",
- "13155",
- "13158",
- "20992",
- "33267",
- "33266",
- "33269",
- "33268",
- "63236",
- "63231",
- "63230",
- "63232",
- "30840",
- "09954",
- "09955",
- "09956",
- "09957",
- "09950",
- "09953",
- "66531",
- "66820",
- "65540",
- "26741",
- "07394",
- "07397",
- "07390",
- "07391",
- "07392",
- "07393",
- "07398",
- "07399",
- "22117",
- "22116",
- "22115",
- "22114",
- "22113",
- "55363",
- "55361",
- "55368",
- "55369",
- "69440",
- "13710",
- "07400",
- "51081",
- "32953",
- "65449",
- "32321",
- "32320",
- "32323",
- "32322",
- "32325",
- "32324",
- "32326",
- "32955",
- "65415",
- "57638",
- "57639",
- "57635",
- "57632",
- "57633",
- "64097",
- "17019",
- "17013",
- "17016",
- "17017",
- "17014",
- "17015",
- "34823",
- "34824",
- "34825",
- "34826",
- "34827",
- "38525",
- "38524",
- "38527",
- "38529",
- "20986",
- "20987",
- "20982",
- "20983",
- "20980",
- "20981",
- "33274",
- "33270",
- "33273",
- "63226",
- "35512",
- "63228",
- "63229",
- "41037",
- "41032",
- "41030",
- "35454",
- "66296",
- "66297",
- "07099",
- "58503",
- "58502",
- "58508",
- "66637",
- "66638",
- "66639",
- "66742",
- "66743",
- "48105",
- "56558",
- "69430",
- "13702",
- "13703",
- "65242",
- "34839",
- "65241",
- "32338",
- "32333",
- "32337",
- "13636",
- "13634",
- "13635",
- "13632",
- "13633",
- "69389",
- "13631",
- "65450",
- "57276",
- "57277",
- "69546",
- "57287",
- "69364",
- "57285",
- "57284",
- "57283",
- "57282",
- "69368",
- "66355",
- "65408",
- "65409",
- "05239",
- "65402",
- "65403",
- "11770",
- "11773",
- "11772",
- "17026",
- "64288",
- "17020",
- "64284",
- "64287",
- "64281",
- "64280",
- "64283",
- "49595",
- "49596",
- "49597",
- "49598",
- "49599",
- "34832",
- "17733",
- "05729",
- "62988",
- "17734",
- "05230",
- "62987",
- "05727",
- "05234",
- "38534",
- "38532",
- "38533",
- "38530",
- "14633",
- "63214",
- "41025",
- "41026",
- "41027",
- "41028",
- "41029",
- "06845",
- "58365",
- "66607",
- "66606",
- "66351",
- "63237",
- "65891",
- "65890",
- "28205",
- "28204",
- "28201",
- "28203",
- "28202"
-]
\ No newline at end of file
diff --git a/configs/top10.yaml b/configs/top10.yaml
new file mode 100644
index 0000000..ad925c4
--- /dev/null
+++ b/configs/top10.yaml
@@ -0,0 +1,28 @@
+dataset:
+ json_path: data/nslt_100.json
+ frames_dir: data/frames
+ missing_txt: data/missing.txt
+ top_k: 20
+ num_frames: 16
+ image_size: 224
+
+model:
+ rgb_backbone: resnet18
+ flow_hidden_dim: 128
+ landmark_hidden_dim: 128
+ fusion_hidden_dim: 256
+ num_classes: 10
+ dropout: 0.5
+
+training:
+ batch_size: 16
+ epochs: 20
+ lr: 0.001
+ weight_decay: 0.01
+ early_stop_patience: 5
+
+paths:
+ rgb_only_ckpt: results/rgb_only.pt
+ flow_only_ckpt: results/flow_only.pt
+ landmark_only_ckpt: results/landmark_only.pt
+ fusion_ckpt: results/fusion.pt
diff --git a/data/features/X_test.npy b/data/features/X_test.npy
new file mode 100644
index 0000000..5b85140
Binary files /dev/null and b/data/features/X_test.npy differ
diff --git a/data/features/X_train.npy b/data/features/X_train.npy
new file mode 100644
index 0000000..3629e7e
Binary files /dev/null and b/data/features/X_train.npy differ
diff --git a/data/features/X_val.npy b/data/features/X_val.npy
new file mode 100644
index 0000000..ed1201e
Binary files /dev/null and b/data/features/X_val.npy differ
diff --git a/data/features/class_map.json b/data/features/class_map.json
new file mode 100644
index 0000000..e12b1a0
--- /dev/null
+++ b/data/features/class_map.json
@@ -0,0 +1 @@
+{"0": 0, "1": 1, "2": 2, "3": 3, "5": 4, "4": 5, "7": 6, "6": 7, "8": 8, "9": 9, "10": 10, "17": 11, "15": 12, "12": 13, "13": 14, "14": 15, "11": 16, "16": 17, "27": 18, "24": 19}
\ No newline at end of file
diff --git a/data/features/scaler_mean.npy b/data/features/scaler_mean.npy
new file mode 100644
index 0000000..77a4e87
Binary files /dev/null and b/data/features/scaler_mean.npy differ
diff --git a/data/features/scaler_std.npy b/data/features/scaler_std.npy
new file mode 100644
index 0000000..e8d384d
Binary files /dev/null and b/data/features/scaler_std.npy differ
diff --git a/data/features/y_test.npy b/data/features/y_test.npy
new file mode 100644
index 0000000..3090066
Binary files /dev/null and b/data/features/y_test.npy differ
diff --git a/data/features/y_train.npy b/data/features/y_train.npy
new file mode 100644
index 0000000..ddccd75
Binary files /dev/null and b/data/features/y_train.npy differ
diff --git a/data/features/y_val.npy b/data/features/y_val.npy
new file mode 100644
index 0000000..ce9711f
Binary files /dev/null and b/data/features/y_val.npy differ
diff --git a/run_pipeline.sh b/run_pipeline.sh
new file mode 100755
index 0000000..1625102
--- /dev/null
+++ b/run_pipeline.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+echo "1. Extracting Farneback Optical Flow features..."
+python -m src.extract_features
+
+echo "2. Training Lightweight NN on Flow Features..."
+python -m src.model
+
+echo "Pipeline complete. You can now run the realtime demo:"
+echo "python -m src.realtime_demo"
diff --git a/src/data_utils.py b/src/data_utils.py
new file mode 100644
index 0000000..1558ab9
--- /dev/null
+++ b/src/data_utils.py
@@ -0,0 +1,135 @@
+import os
+import json
+import glob
+from collections import Counter
+import torch
+from torch.utils.data import Dataset, DataLoader
+import cv2
+import numpy as np
+
+# We'll import these to compute features on the fly and cache them
+from src.optical_flow import extract_flow_sequence
+from src.hand_landmarks import HandLandmarkExtractor
+
+def get_top_k_classes(json_path, k=10):
+ with open(json_path, 'r') as f:
+ data = json.load(f)
+ class_counts = Counter()
+ for video_id, info in data.items():
+ class_id = info['action'][0]
+ class_counts[class_id] += 1
+ top_k = class_counts.most_common(k)
+ return [c[0] for c in top_k]
+
+def get_data_splits(json_path, top_k_classes, missing_txt_path=None):
+ with open(json_path, 'r') as f:
+ data = json.load(f)
+ missing_videos = set()
+ if missing_txt_path and os.path.exists(missing_txt_path):
+ with open(missing_txt_path, 'r') as f:
+ missing_videos = set([line.strip() for line in f.readlines()])
+ splits = {'train': [], 'val': [], 'test': []}
+ class_map = {orig_class: idx for idx, orig_class in enumerate(top_k_classes)}
+ for video_id, info in data.items():
+ if video_id in missing_videos:
+ continue
+ class_id = info['action'][0]
+ if class_id in top_k_classes:
+ subset = info['subset']
+ if subset in splits:
+ splits[subset].append({'video_id': video_id, 'class_id': class_map[class_id]})
+ return splits, class_map
+
+class ASLDataset(Dataset):
+ def __init__(self, data_list, frames_dir, num_frames=16, transform=None):
+ self.data_list = data_list
+ self.frames_dir = frames_dir
+ self.num_frames = num_frames
+ self.transform = transform
+ self.cache_dir = os.path.join(os.path.dirname(frames_dir), 'cache')
+ os.makedirs(self.cache_dir, exist_ok=True)
+ self.lm_extractor = HandLandmarkExtractor()
+
+ def __len__(self):
+ return len(self.data_list)
+
+ def _load_frames(self, video_id):
+ video_dir = os.path.join(self.frames_dir, video_id)
+ if not os.path.exists(video_dir):
+ return None
+ frame_files = sorted(glob.glob(os.path.join(video_dir, '*.jpg')) + glob.glob(os.path.join(video_dir, '*.png')))
+ if not frame_files:
+ return None
+ indices = np.linspace(0, len(frame_files) - 1, self.num_frames, dtype=int)
+ frames = []
+ for idx in indices:
+ frame = cv2.imread(frame_files[idx])
+ if frame is not None:
+ frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
+ frame = cv2.resize(frame, (224, 224))
+ if self.transform:
+ frame = self.transform(frame)
+ frames.append(frame)
+ if not frames:
+ return None
+ while len(frames) < self.num_frames:
+ frames.append(frames[-1])
+ return np.array(frames)
+
+ def __getitem__(self, idx):
+ item = self.data_list[idx]
+ video_id = item['video_id']
+ label = item['class_id']
+
+ # Paths for cached features
+ flow_path = os.path.join(self.cache_dir, f"{video_id}_flow.pt")
+ lm_path = os.path.join(self.cache_dir, f"{video_id}_lm.pt")
+ rgb_path = os.path.join(self.cache_dir, f"{video_id}_rgb.pt")
+
+ if os.path.exists(flow_path) and os.path.exists(lm_path) and os.path.exists(rgb_path):
+ rgb = torch.load(rgb_path)
+ flow = torch.load(flow_path)
+ lm = torch.load(lm_path)
+ return rgb, flow, lm, label, video_id
+
+ frames_np = self._load_frames(video_id)
+ if frames_np is None:
+ rgb = torch.zeros((self.num_frames, 3, 224, 224))
+ flow = torch.zeros((self.num_frames-1, 2, 224, 224))
+ lm = torch.zeros((self.num_frames, 126))
+ return rgb, flow, lm, label, video_id
+
+ # Compute RGB tensor
+ rgb = torch.from_numpy(frames_np).float() / 255.0
+ rgb = rgb.permute(0, 3, 1, 2) # (T, C, H, W)
+
+ # Compute Flow
+ flow = extract_flow_sequence(rgb)
+
+ # Compute Landmarks
+ lm = self.lm_extractor.extract_sequence(rgb)
+
+ # Cache
+ torch.save(rgb, rgb_path)
+ torch.save(flow, flow_path)
+ torch.save(lm, lm_path)
+
+ return rgb, flow, lm, label, video_id
+
+def get_dataloaders(config, transform=None):
+ json_path = config['dataset']['json_path']
+ frames_dir = config['dataset']['frames_dir']
+ missing_txt = config['dataset'].get('missing_txt', None)
+ top_k = config['dataset']['top_k']
+ num_frames = config['dataset']['num_frames']
+ batch_size = config['training']['batch_size']
+
+ top_k_classes = get_top_k_classes(json_path, k=top_k)
+ splits, class_map = get_data_splits(json_path, top_k_classes, missing_txt)
+
+ dataloaders = {}
+ for subset in ['train', 'val', 'test']:
+ dataset = ASLDataset(splits[subset], frames_dir, num_frames=num_frames, transform=transform)
+ shuffle = (subset == 'train')
+ dataloaders[subset] = DataLoader(dataset, batch_size=batch_size, shuffle=shuffle, num_workers=0)
+ return dataloaders, class_map
diff --git a/src/extract_features.py b/src/extract_features.py
new file mode 100644
index 0000000..63d70e2
--- /dev/null
+++ b/src/extract_features.py
@@ -0,0 +1,161 @@
+import os
+import cv2
+import json
+import yaml
+import glob
+import numpy as np
+from collections import Counter
+from tqdm import tqdm
+from src.hand_landmarks import HandLandmarkExtractor
+
+
+def extract_combined_features(frames, extractor, grid_size=8):
+ """
+ Extracts both Farneback Optical Flow and MediaPipe hand landmarks per frame.
+ Since optical flow needs 2 frames, it returns T-1 frames.
+ frames: list of numpy arrays (H, W, 3) in RGB
+ Returns: 2D numpy array of size (len(frames)-1, 126 + 128)
+ """
+ seq_features = []
+
+ # 1. Get MediaPipe landmarks for all frames
+ all_landmarks = []
+ for frame in frames:
+ landmarks = extractor.extract_from_frame(frame)
+ all_landmarks.append(landmarks)
+
+ # 2. Get Farneback flow
+ prev_gray = cv2.cvtColor(frames[0], cv2.COLOR_RGB2GRAY)
+ h, w = prev_gray.shape
+ cell_h = h // grid_size
+ cell_w = w // grid_size
+
+ for i in range(1, len(frames)):
+ curr_gray = cv2.cvtColor(frames[i], cv2.COLOR_RGB2GRAY)
+ flow = cv2.calcOpticalFlowFarneback(
+ prev_gray, curr_gray, None, 0.5, 3, 15, 3, 5, 1.2, 0
+ )
+
+ # Grid-based mean pooling
+ flow_features = []
+ for r in range(grid_size):
+ for c in range(grid_size):
+ cell_flow = flow[
+ r * cell_h : (r + 1) * cell_h, c * cell_w : (c + 1) * cell_w
+ ]
+ mean_u = np.mean(cell_flow[..., 0])
+ mean_v = np.mean(cell_flow[..., 1])
+ flow_features.extend([mean_u, mean_v])
+
+ prev_gray = curr_gray
+
+ # Combine Flow (128) + Landmarks (126) for this frame step
+ # We use the landmarks of the *current* frame (index i)
+ combined = np.concatenate([flow_features, all_landmarks[i]])
+ seq_features.append(combined)
+
+ return np.array(seq_features, dtype=np.float32)
+
+
+def augment_sequence(seq):
+ """
+ Adds small random Gaussian noise to simulate slightly different movements/positions.
+ """
+ noise = np.random.normal(0, 0.02, seq.shape).astype(np.float32)
+ return seq + noise
+
+
+def main():
+ with open("configs/top10.yaml", "r") as f:
+ config = yaml.safe_load(f)
+
+ json_path = config["dataset"]["json_path"]
+ frames_dir = config["dataset"]["frames_dir"]
+ missing_txt = config["dataset"].get("missing_txt", None)
+ top_k = config["dataset"]["top_k"]
+ num_frames = config["dataset"]["num_frames"]
+
+ with open(json_path, "r") as f:
+ data = json.load(f)
+
+ class_counts = Counter()
+ for vid, info in data.items():
+ class_counts[info["action"][0]] += 1
+
+ top_classes = [c[0] for c in class_counts.most_common(top_k)]
+ class_map = {orig_class: idx for idx, orig_class in enumerate(top_classes)}
+
+ missing_videos = set()
+ if missing_txt and os.path.exists(missing_txt):
+ with open(missing_txt, "r") as f:
+ missing_videos = set([line.strip() for line in f.readlines()])
+
+ X_dict = {"train": [], "val": [], "test": []}
+ y_dict = {"train": [], "val": [], "test": []}
+
+ video_list = [
+ (vid, info)
+ for vid, info in data.items()
+ if vid not in missing_videos and info["action"][0] in top_classes
+ ]
+
+ print(f"Extracting features for {len(video_list)} videos...")
+
+ extractor = HandLandmarkExtractor()
+
+ for vid, info in tqdm(video_list):
+ subset = info["subset"]
+ class_id = class_map[info["action"][0]]
+
+ video_dir = os.path.join(frames_dir, vid)
+ if not os.path.exists(video_dir):
+ continue
+
+ frame_files = sorted(
+ glob.glob(os.path.join(video_dir, "*.jpg"))
+ + glob.glob(os.path.join(video_dir, "*.png"))
+ )
+ if not frame_files:
+ continue
+
+ indices = np.linspace(0, len(frame_files) - 1, num_frames, dtype=int)
+ frames = []
+ for idx in indices:
+ frame = cv2.imread(frame_files[idx])
+ if frame is not None:
+ frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
+ frame = cv2.resize(frame, (128, 128)) # Ensure constant size for flow
+ frames.append(frame)
+
+ if not frames:
+ continue
+
+ while len(frames) < num_frames:
+ frames.append(frames[-1])
+
+ seq_features = extract_combined_features(frames, extractor, grid_size=8)
+
+ if subset in X_dict:
+ # Original
+ X_dict[subset].append(seq_features)
+ y_dict[subset].append(class_id)
+
+ # Augment training data to reduce overfitting
+ if subset == "train":
+ for _ in range(3): # 3 augmented copies
+ X_dict[subset].append(augment_sequence(seq_features))
+ y_dict[subset].append(class_id)
+
+ os.makedirs("data/features", exist_ok=True)
+ for subset in ["train", "val", "test"]:
+ np.save(f"data/features/X_{subset}.npy", np.array(X_dict[subset]))
+ np.save(f"data/features/y_{subset}.npy", np.array(y_dict[subset]))
+
+ with open("data/features/class_map.json", "w") as f:
+ json.dump(class_map, f)
+
+ print("Feature extraction complete.")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/src/hand_landmarks.py b/src/hand_landmarks.py
new file mode 100644
index 0000000..0a960b2
--- /dev/null
+++ b/src/hand_landmarks.py
@@ -0,0 +1,64 @@
+import mediapipe as mp
+import numpy as np
+import torch
+
+class HandLandmarkExtractor:
+ def __init__(self):
+ self.mp_hands = mp.solutions.hands
+ # We need static_image_mode=True if we extract frame by frame independently
+ self.hands = self.mp_hands.Hands(
+ static_image_mode=False,
+ max_num_hands=2,
+ min_detection_confidence=0.5,
+ min_tracking_confidence=0.5
+ )
+
+ def extract_from_frame(self, frame):
+ """
+ Extracts hand landmarks from a single RGB frame.
+ Args:
+ frame: numpy array (H, W, 3) in RGB
+ Returns:
+ landmarks: numpy array of shape (42, 3) - 21 points per hand (x,y,z)
+ """
+ results = self.hands.process(frame)
+
+ # Initialize with zeros for 2 hands, 21 landmarks, 3 coordinates
+ landmarks = np.zeros((2, 21, 3), dtype=np.float32)
+
+ if results.multi_hand_landmarks and results.multi_handedness:
+ for hand_idx, hand_landmarks in enumerate(results.multi_hand_landmarks):
+ # Ensure we only process up to 2 hands
+ if hand_idx >= 2:
+ break
+
+ wrist_x = hand_landmarks.landmark[0].x
+ wrist_y = hand_landmarks.landmark[0].y
+ wrist_z = hand_landmarks.landmark[0].z
+
+ for i, lm in enumerate(hand_landmarks.landmark):
+ landmarks[hand_idx, i, 0] = lm.x - wrist_x
+ landmarks[hand_idx, i, 1] = lm.y - wrist_y
+ landmarks[hand_idx, i, 2] = lm.z - wrist_z
+
+ # Flatten to (42*3,) or just return as (42, 3) -> flattening later
+ return landmarks.reshape(-1)
+
+ def extract_sequence(self, frames):
+ """
+ Extract landmarks from sequence of frames.
+ Args:
+ frames: torch Tensor (T, C, H, W)
+ Returns:
+ seq_landmarks: torch Tensor (T, 42*3)
+ """
+ # Convert to numpy (T, H, W, C), uint8
+ frames_np = (frames.permute(0, 2, 3, 1).numpy() * 255).astype(np.uint8)
+ T = frames_np.shape[0]
+
+ seq_lms = []
+ for t in range(T):
+ lms = self.extract_from_frame(frames_np[t])
+ seq_lms.append(lms)
+
+ return torch.from_numpy(np.array(seq_lms)).float()
diff --git a/src/model.py b/src/model.py
new file mode 100644
index 0000000..1034f6c
--- /dev/null
+++ b/src/model.py
@@ -0,0 +1,169 @@
+import numpy as np
+from sklearn.svm import SVC, LinearSVC
+from sklearn.ensemble import RandomForestClassifier
+from sklearn.neural_network import MLPClassifier
+from sklearn.metrics import accuracy_score
+from sklearn.preprocessing import StandardScaler
+from sklearn.decomposition import PCA
+import torch
+import torch.nn as nn
+from torch.utils.data import DataLoader, TensorDataset
+
+
+class SimpleLSTM(nn.Module):
+ def __init__(self, input_dim=254, hidden_dim=16, num_classes=10):
+ super().__init__()
+ self.lstm = nn.LSTM(input_dim, hidden_dim, num_layers=1, batch_first=True)
+ self.dropout = nn.Dropout(0.7) # Extremely strong dropout
+ self.fc = nn.Linear(hidden_dim, num_classes)
+
+ def forward(self, x):
+ # x: (B, T, D)
+ out, (hn, cn) = self.lstm(x)
+ # use the last hidden state with dropout
+ out = self.dropout(hn[-1])
+ out = self.fc(out)
+ return out
+
+
+def train_lstm(X_train, y_train, X_val, y_val, epochs=200, lr=0.005, weight_decay=1e-2):
+ num_classes = len(np.unique(y_train))
+ model = SimpleLSTM(hidden_dim=16, num_classes=num_classes)
+ criterion = nn.CrossEntropyLoss()
+ # Add Strong L2 Regularization (weight_decay)
+ optimizer = torch.optim.Adam(model.parameters(), lr=lr, weight_decay=weight_decay)
+
+ # Convert to PyTorch tensors
+ X_train_t = torch.tensor(X_train, dtype=torch.float32)
+ y_train_t = torch.tensor(y_train, dtype=torch.long)
+ X_val_t = torch.tensor(X_val, dtype=torch.float32)
+ y_val_t = torch.tensor(y_val, dtype=torch.long)
+
+ dataset = TensorDataset(X_train_t, y_train_t)
+ dataloader = DataLoader(dataset, batch_size=32, shuffle=True)
+
+ best_val_acc = 0.0
+ best_model_state = None
+ patience = 10
+ epochs_no_improve = 0
+
+ for epoch in range(epochs):
+ model.train()
+ for batch_x, batch_y in dataloader:
+ optimizer.zero_grad()
+ outputs = model(batch_x)
+ loss = criterion(outputs, batch_y)
+ loss.backward()
+ optimizer.step()
+
+ # Early Stopping Check
+ model.eval()
+ with torch.no_grad():
+ val_preds = model(X_val_t).argmax(dim=1).numpy()
+ val_acc = accuracy_score(y_val, val_preds)
+
+ if val_acc > best_val_acc:
+ best_val_acc = val_acc
+ best_model_state = model.state_dict()
+ epochs_no_improve = 0
+ else:
+ epochs_no_improve += 1
+
+ if epochs_no_improve >= patience:
+ break
+
+ # Load best model
+ if best_model_state is not None:
+ model.load_state_dict(best_model_state)
+
+ model.eval()
+ with torch.no_grad():
+ train_preds = model(X_train_t).argmax(dim=1).numpy()
+ val_preds = model(X_val_t).argmax(dim=1).numpy()
+
+ train_acc = accuracy_score(y_train, train_preds)
+ val_acc = accuracy_score(y_val, val_preds)
+
+ print("PyTorch LSTM (Ultra-Regularized + Early Stopping)")
+ print(f" Train Acc: {train_acc:.4f}")
+ print(f" Val Acc: {val_acc:.4f}")
+ print("-" * 40)
+
+
+def load_data():
+ X_train = np.load("data/features/X_train.npy")
+ y_train = np.load("data/features/y_train.npy")
+ X_val = np.load("data/features/X_val.npy")
+ y_val = np.load("data/features/y_val.npy")
+ return X_train, y_train, X_val, y_val
+
+
+def evaluate(model, name, X_train, y_train, X_val, y_val):
+ model.fit(X_train, y_train)
+
+ train_acc = accuracy_score(y_train, model.predict(X_train))
+ val_acc = accuracy_score(y_val, model.predict(X_val))
+
+ print(f"{name}")
+ print(f" Train Acc: {train_acc:.4f}")
+ print(f" Val Acc: {val_acc:.4f}")
+ print("-" * 40)
+
+
+def main():
+ X_train, y_train, X_val, y_val = load_data()
+
+ print("Comparing models...\n")
+
+ # Train LSTM directly on 3D data: (N, T, 126)
+ train_lstm(X_train, y_train, X_val, y_val, epochs=100)
+
+ # Flatten for sklearn models
+ N_train, T, F = X_train.shape
+ N_val = X_val.shape[0]
+ X_train_flat = X_train.reshape(N_train, T * F)
+ X_val_flat = X_val.reshape(N_val, T * F)
+
+ # Normalize
+ scaler = StandardScaler()
+ X_train_flat = scaler.fit_transform(X_train_flat)
+ X_val_flat = scaler.transform(X_val_flat)
+
+ # PCA (CRUCIAL)
+ pca = PCA(n_components=0.99, random_state=42)
+ X_train_flat = pca.fit_transform(X_train_flat)
+ X_val_flat = pca.transform(X_val_flat)
+
+ # 1. Linear SVM
+ evaluate(LinearSVC(C=1e-5, max_iter=5000), "Linear SVM", X_train_flat, y_train, X_val_flat, y_val)
+
+ # 2. RBF SVM (regularized)
+ evaluate(
+ SVC(kernel="rbf", C=0.01, gamma="scale"), "RBF SVM", X_train_flat, y_train, X_val_flat, y_val
+ )
+
+ # 3. Random Forest
+ evaluate(
+ RandomForestClassifier(n_estimators=100, max_depth=2, min_samples_leaf=20, random_state=42),
+ "Random Forest",
+ X_train_flat,
+ y_train,
+ X_val_flat,
+ y_val,
+ )
+
+ # 4. MLP (sklearn)
+ evaluate(
+ MLPClassifier(
+ hidden_layer_sizes=(16,), max_iter=500, alpha=20.0, early_stopping=True, validation_fraction=0.15, n_iter_no_change=5, random_state=42
+ ),
+ "MLP (sklearn)",
+ X_train_flat,
+ y_train,
+ X_val_flat,
+ y_val,
+ )
+
+
+if __name__ == "__main__":
+ main()
diff --git a/src/optical_flow.py b/src/optical_flow.py
new file mode 100644
index 0000000..1b371f2
--- /dev/null
+++ b/src/optical_flow.py
@@ -0,0 +1,58 @@
+import cv2
+import numpy as np
+import torch
+import os
+
+def compute_dense_optical_flow(prev_frame, next_frame):
+ """
+ Computes Farneback dense optical flow.
+ Args:
+ prev_frame: numpy array (H, W, C) or (H, W)
+ next_frame: numpy array (H, W, C) or (H, W)
+ Returns:
+ flow: numpy array (H, W, 2)
+ """
+ if len(prev_frame.shape) == 3:
+ prev_gray = cv2.cvtColor(prev_frame, cv2.COLOR_RGB2GRAY)
+ else:
+ prev_gray = prev_frame
+
+ if len(next_frame.shape) == 3:
+ next_gray = cv2.cvtColor(next_frame, cv2.COLOR_RGB2GRAY)
+ else:
+ next_gray = next_frame
+
+ # Convert to 8-bit if necessary
+ if prev_gray.dtype != np.uint8:
+ prev_gray = (prev_gray * 255).astype(np.uint8)
+ if next_gray.dtype != np.uint8:
+ next_gray = (next_gray * 255).astype(np.uint8)
+
+ flow = cv2.calcOpticalFlowFarneback(
+ prev_gray, next_gray, None,
+ pyr_scale=0.5, levels=3, winsize=15,
+ iterations=3, poly_n=5, poly_sigma=1.2, flags=0
+ )
+ return flow
+
+def extract_flow_sequence(frames):
+ """
+ Extracts flow sequence from a sequence of frames.
+ Args:
+ frames: torch Tensor (T, C, H, W)
+ Returns:
+ flow_sequence: torch Tensor (T-1, 2, H, W)
+ """
+ # Convert back to numpy (T, H, W, C) for OpenCV
+ frames_np = frames.permute(0, 2, 3, 1).numpy()
+ T = frames_np.shape[0]
+
+ flow_seq = []
+ for t in range(T - 1):
+ flow = compute_dense_optical_flow(frames_np[t], frames_np[t+1])
+ flow_seq.append(flow)
+
+ # Convert to tensor (T-1, 2, H, W)
+ flow_seq = torch.from_numpy(np.array(flow_seq)).permute(0, 3, 1, 2)
+ return flow_seq
+
diff --git a/visualizations/flow_class07_vid66779.png b/visualizations/flow_class07_vid66779.png
deleted file mode 100644
index 2e1209a..0000000
Binary files a/visualizations/flow_class07_vid66779.png and /dev/null differ
diff --git a/visualizations/flow_class27_vid69422.png b/visualizations/flow_class27_vid69422.png
deleted file mode 100644
index 83e911a..0000000
Binary files a/visualizations/flow_class27_vid69422.png and /dev/null differ
diff --git a/visualizations/flow_class46_vid51068.png b/visualizations/flow_class46_vid51068.png
deleted file mode 100644
index 39e7a98..0000000
Binary files a/visualizations/flow_class46_vid51068.png and /dev/null differ
diff --git a/visualizations/flow_class82_vid10898.png b/visualizations/flow_class82_vid10898.png
deleted file mode 100644
index ca9e047..0000000
Binary files a/visualizations/flow_class82_vid10898.png and /dev/null differ
diff --git a/wlasl_class_list.txt b/wlasl_class_list.txt
new file mode 100644
index 0000000..76b1630
--- /dev/null
+++ b/wlasl_class_list.txt
@@ -0,0 +1,2000 @@
+0 book
+1 drink
+2 computer
+3 before
+4 chair
+5 go
+6 clothes
+7 who
+8 candy
+9 cousin
+10 deaf
+11 fine
+12 help
+13 no
+14 thin
+15 walk
+16 year
+17 yes
+18 all
+19 black
+20 cool
+21 finish
+22 hot
+23 like
+24 many
+25 mother
+26 now
+27 orange
+28 table
+29 thanksgiving
+30 what
+31 woman
+32 bed
+33 blue
+34 bowling
+35 can
+36 dog
+37 family
+38 fish
+39 graduate
+40 hat
+41 hearing
+42 kiss
+43 language
+44 later
+45 man
+46 shirt
+47 study
+48 tall
+49 white
+50 wrong
+51 accident
+52 apple
+53 bird
+54 change
+55 color
+56 corn
+57 cow
+58 dance
+59 dark
+60 doctor
+61 eat
+62 enjoy
+63 forget
+64 give
+65 last
+66 meet
+67 pink
+68 pizza
+69 play
+70 school
+71 secretary
+72 short
+73 time
+74 want
+75 work
+76 africa
+77 basketball
+78 birthday
+79 brown
+80 but
+81 cheat
+82 city
+83 cook
+84 decide
+85 full
+86 how
+87 jacket
+88 letter
+89 medicine
+90 need
+91 paint
+92 paper
+93 pull
+94 purple
+95 right
+96 same
+97 son
+98 tell
+99 thursday
+100 visit
+101 wait
+102 water
+103 wife
+104 yellow
+105 backpack
+106 bar
+107 brother
+108 cat
+109 check
+110 class
+111 cry
+112 different
+113 door
+114 green
+115 hair
+116 have
+117 headache
+118 inform
+119 knife
+120 laugh
+121 learn
+122 movie
+123 rabbit
+124 read
+125 red
+126 room
+127 run
+128 show
+129 sick
+130 snow
+131 take
+132 tea
+133 teacher
+134 week
+135 why
+136 with
+137 write
+138 yesterday
+139 again
+140 bad
+141 ball
+142 bathroom
+143 blanket
+144 buy
+145 call
+146 coffee
+147 cold
+148 college
+149 copy
+150 cute
+151 daughter
+152 example
+153 far
+154 first
+155 friend
+156 good
+157 happy
+158 home
+159 know
+160 late
+161 leave
+162 list
+163 losear
+164 name
+165 old
+166 person
+167 police
+168 problem
+169 remember
+170 share
+171 soon
+172 stay
+173 sunday
+174 test
+175 tired
+176 trade
+177 travel
+178 window
+179 you
+180 about
+181 approve
+182 arrive
+183 balance
+184 banana
+185 beard
+186 because
+187 boy
+188 business
+189 careful
+190 center
+191 chat
+192 children
+193 christmas
+194 clock
+195 close
+196 convince
+197 country
+198 crash
+199 day
+200 discuss
+201 dress
+202 drive
+203 drop
+204 fat
+205 feel
+206 football
+207 future
+208 game
+209 girl
+210 government
+211 hear
+212 here
+213 hope
+214 house
+215 husband
+216 interest
+217 join
+218 light
+219 live
+220 make
+221 mean
+222 more
+223 most
+224 music
+225 new
+226 none
+227 office
+228 order
+229 pants
+230 party
+231 past
+232 pencil
+233 plan
+234 please
+235 practice
+236 president
+237 restaurant
+238 ride
+239 russia
+240 salt
+241 sandwich
+242 sign
+243 since
+244 small
+245 some
+246 south
+247 student
+248 teach
+249 theory
+250 tomato
+251 train
+252 ugly
+253 war
+254 where
+255 your
+256 always
+257 animal
+258 argue
+259 baby
+260 back
+261 bake
+262 bath
+263 behind
+264 bring
+265 catch
+266 cereal
+267 champion
+268 cheese
+269 cough
+270 crazy
+271 delay
+272 delicious
+273 disappear
+274 divorce
+275 draw
+276 east
+277 easy
+278 egg
+279 environment
+280 father
+281 fault
+282 flower
+283 friendly
+284 glasses
+285 halloween
+286 hard
+287 heart
+288 hour
+289 humble
+290 hurry
+291 improve
+292 internet
+293 jump
+294 kill
+295 law
+296 match
+297 meat
+298 milk
+299 money
+300 month
+301 moon
+302 move
+303 near
+304 nephew
+305 nice
+306 niece
+307 noon
+308 north
+309 not
+310 nurse
+311 off
+312 ok
+313 patient
+314 pay
+315 perspective
+316 potato
+317 sad
+318 saturday
+319 save
+320 scissors
+321 secret
+322 shoes
+323 shop
+324 silly
+325 sister
+326 sleep
+327 sorry
+328 straight
+329 sweet
+330 talk
+331 temperature
+332 tent
+333 thank you
+334 think
+335 throw
+336 today
+337 traffic
+338 understand
+339 use
+340 voice
+341 vomit
+342 vote
+343 wednesday
+344 west
+345 wet
+346 when
+347 which
+348 win
+349 word
+350 afternoon
+351 age
+352 alone
+353 appointment
+354 australia
+355 avoid
+356 balloon
+357 basement
+358 bear
+359 believe
+360 better
+361 blind
+362 bored
+363 bowl
+364 box
+365 bracelet
+366 bread
+367 cafeteria
+368 car
+369 chicken
+370 child
+371 choose
+372 church
+373 cookie
+374 cup
+375 cut
+376 decorate
+377 deep
+378 deer
+379 dentist
+380 dirty
+381 dive
+382 down
+383 dry
+384 ear
+385 earn
+386 earring
+387 elephant
+388 english
+389 escape
+390 expensive
+391 explain
+392 fast
+393 fight
+394 find
+395 fishing
+396 floor
+397 fly
+398 follow
+399 from
+400 get
+401 happen
+402 hello
+403 hit
+404 hospital
+405 idea
+406 important
+407 investigate
+408 japan
+409 jealous
+410 king
+411 kitchen
+412 large
+413 last year
+414 lemon
+415 lettuce
+416 marry
+417 meeting
+418 minute
+419 mirror
+420 miss
+421 monkey
+422 morning
+423 motorcycle
+424 necklace
+425 never
+426 newspaper
+427 night
+428 onion
+429 people
+430 pepper
+431 phone
+432 picture
+433 plus
+434 point
+435 poor
+436 possible
+437 quiet
+438 rain
+439 ready
+440 research
+441 scared
+442 science
+443 score
+444 sentence
+445 shape
+446 sit
+447 slow
+448 snake
+449 soap
+450 soda
+451 speech
+452 star
+453 stink
+454 struggle
+455 stubborn
+456 sunset
+457 surgery
+458 there
+459 tiger
+460 toast
+461 toilet
+462 tomorrow
+463 town
+464 transfer
+465 tree
+466 truck
+467 uncle
+468 vacation
+469 weather
+470 weekend
+471 accept
+472 adult
+473 after
+474 ago
+475 allow
+476 america
+477 angel
+478 answer
+479 any
+480 area
+481 art
+482 asl
+483 aunt
+484 awful
+485 awkward
+486 bacon
+487 bark
+488 bedroom
+489 beer
+490 belt
+491 big
+492 bitter
+493 both
+494 cake
+495 california
+496 canada
+497 carrot
+498 cause
+499 challenge
+500 cheap
+501 chocolate
+502 clean
+503 cloud
+504 compare
+505 complex
+506 contact
+507 continue
+508 corner
+509 correct
+510 curse
+511 dead
+512 demand
+513 depend
+514 desert
+515 desk
+516 develop
+517 dictionary
+518 doll
+519 duty
+520 easter
+521 egypt
+522 elevator
+523 email
+524 end
+525 enter
+526 europe
+527 event
+528 exchange
+529 experience
+530 face
+531 fail
+532 feed
+533 few
+534 flag
+535 food
+536 for
+537 form
+538 freeze
+539 friday
+540 front
+541 giraffe
+542 god
+543 grammar
+544 grandfather
+545 great
+546 greece
+547 guess
+548 guitar
+549 hammer
+550 helicopter
+551 high
+552 history
+553 hungry
+554 hurt
+555 introduce
+556 invest
+557 lazy
+558 library
+559 lie
+560 lobster
+561 love
+562 lucky
+563 magazine
+564 measure
+565 microwave
+566 my
+567 neighbor
+568 number
+569 one
+570 outside
+571 peach
+572 pig
+573 polite
+574 postpone
+575 power
+576 present
+577 price
+578 prison
+579 push
+580 raccoon
+581 really
+582 reason
+583 religion
+584 respect
+585 rule
+586 salad
+587 schedule
+588 sell
+589 serious
+590 shower
+591 single
+592 smart
+593 smile
+594 soft
+595 sound
+596 soup
+597 spain
+598 spray
+599 squirrel
+600 stomach
+601 story
+602 strange
+603 street
+604 stress
+605 strict
+606 strong
+607 sugar
+608 summer
+609 suspect
+610 sweetheart
+611 tease
+612 that
+613 themselves
+614 therapy
+615 thirsty
+616 ticket
+617 top
+618 tuesday
+619 turkey
+620 university
+621 until
+622 watch
+623 weak
+624 wedding
+625 will
+626 wind
+627 world
+628 worry
+629 wow
+630 young
+631 add
+632 airplane
+633 already
+634 also
+635 analyze
+636 and
+637 angry
+638 appear
+639 arm
+640 army
+641 arrest
+642 asia
+643 ask
+644 attitude
+645 attract
+646 bald
+647 barely
+648 baseball
+649 beg
+650 benefit
+651 bite
+652 blame
+653 boat
+654 body
+655 borrow
+656 boss
+657 bother
+658 bottle
+659 bottom
+660 brag
+661 build
+662 bus
+663 butter
+664 calm
+665 cancel
+666 candle
+667 cards
+668 choice
+669 comb
+670 comfortable
+671 conflict
+672 cover
+673 deodorant
+674 dessert
+675 destroy
+676 diamond
+677 dollar
+678 drawer
+679 dream
+680 drunk
+681 duck
+682 during
+683 eagle
+684 early
+685 equal
+686 every
+687 excited
+688 exercise
+689 experiment
+690 expert
+691 fact
+692 fear
+693 feedback
+694 fold
+695 forest
+696 france
+697 frog
+698 funny
+699 garage
+700 goal
+701 golf
+702 gone
+703 gossip
+704 grandmother
+705 grapes
+706 group
+707 guilty
+708 hamburger
+709 hate
+710 head
+711 her
+712 horse
+713 ignore
+714 impossible
+715 in
+716 independent
+717 inside
+718 insurance
+719 island
+720 lecture
+721 lesson
+722 limit
+723 lion
+724 listen
+725 march
+726 math
+727 maybe
+728 mechanic
+729 mom
+730 mouse
+731 much
+732 muscle
+733 museum
+734 must
+735 mustache
+736 negative
+737 nervous
+738 neutral
+739 nose
+740 often
+741 operate
+742 opinion
+743 other
+744 pass
+745 pillow
+746 prepare
+747 pretty
+748 priest
+749 program
+750 promise
+751 put
+752 queen
+753 quit
+754 radio
+755 rat
+756 reject
+757 require
+758 rest
+759 retire
+760 rise
+761 river
+762 rough
+763 see
+764 seem
+765 send
+766 sew
+767 sheep
+768 shine
+769 shock
+770 should
+771 silent
+772 skinny
+773 skirt
+774 sky
+775 sour
+776 special
+777 spirit
+778 staff
+779 stand
+780 steal
+781 stop
+782 stupid
+783 summon
+784 sunrise
+785 swallow
+786 television
+787 to
+788 together
+789 translate
+790 triangle
+791 turtle
+792 underwear
+793 up
+794 upset
+795 violin
+796 volunteer
+797 warm
+798 warn
+799 wash
+800 wine
+801 witness
+802 wood
+803 zero
+804 across
+805 actor
+806 agree
+807 alarm
+808 allergy
+809 almost
+810 announce
+811 apartment
+812 attention
+813 audience
+814 august
+815 autumn
+816 away
+817 beautiful
+818 become
+819 below
+820 best
+821 bet
+822 bicycle
+823 biology
+824 boyfriend
+825 break
+826 bridge
+827 brush
+828 building
+829 busy
+830 camera
+831 camp
+832 caption
+833 care
+834 carry
+835 celebrate
+836 certificate
+837 chain
+838 chance
+839 character
+840 chase
+841 classroom
+842 clear
+843 climb
+844 command
+845 community
+846 complain
+847 compromise
+848 contribute
+849 cop
+850 cost
+851 couch
+852 cracker
+853 curious
+854 curriculum
+855 dad
+856 deny
+857 describe
+858 diaper
+859 diarrhea
+860 disagree
+861 dissolve
+862 divide
+863 dolphin
+864 double
+865 doubt
+866 dumb
+867 earth
+868 earthquake
+869 eight
+870 embarrass
+871 emotion
+872 encourage
+873 energy
+874 enough
+875 evaluate
+876 evidence
+877 exact
+878 exaggerate
+879 expect
+880 fancy
+881 favorite
+882 finally
+883 fox
+884 french
+885 fruit
+886 function
+887 gather
+888 germany
+889 gloves
+890 goat
+891 goodbye
+892 grow
+893 gum
+894 half
+895 hawaii
+896 herself
+897 highway
+898 homework
+899 honor
+900 ice cream
+901 if
+902 increase
+903 india
+904 information
+905 interpret
+906 interview
+907 invite
+908 israel
+909 jesus
+910 keep
+911 keyboard
+912 land
+913 lawyer
+914 lead
+915 lesbian
+916 line
+917 lock
+918 loud
+919 lousy
+920 lunch
+921 machine
+922 mad
+923 memorize
+924 minus
+925 monday
+926 mountain
+927 mouth
+928 mushroom
+929 napkin
+930 neck
+931 next
+932 ocean
+933 open
+934 overwhelm
+935 owe
+936 page
+937 pain
+938 parade
+939 parents
+940 perfect
+941 period
+942 philosophy
+943 photographer
+944 place
+945 policy
+946 popular
+947 pray
+948 predict
+949 presentation
+950 print
+951 printer
+952 private
+953 procrastinate
+954 project
+955 protect
+956 prove
+957 provide
+958 psychology
+959 punish
+960 puzzled
+961 question
+962 quick
+963 rainbow
+964 rake
+965 rehearse
+966 remove
+967 revenge
+968 review
+969 rich
+970 roof
+971 rooster
+972 rude
+973 say
+974 scientist
+975 scotland
+976 screwdriver
+977 second
+978 senate
+979 separate
+980 service
+981 shrimp
+982 shy
+983 side
+984 situation
+985 slave
+986 soccer
+987 socks
+988 solid
+989 sometimes
+990 spider
+991 spin
+992 square
+993 stairs
+994 stare
+995 start
+996 store
+997 straw
+998 structure
+999 suggest
+1000 sun
+1001 support
+1002 suppose
+1003 sure
+1004 surprise
+1005 sweater
+1006 swim
+1007 symbol
+1008 taste
+1009 team
+1010 telephone
+1011 tennis
+1012 their
+1013 then
+1014 thermometer
+1015 thing
+1016 third
+1017 thousand
+1018 three
+1019 tie
+1020 topic
+1021 touch
+1022 tournament
+1023 try
+1024 two
+1025 type
+1026 umbrella
+1027 vegetable
+1028 vocabulary
+1029 waste
+1030 we
+1031 wear
+1032 weekly
+1033 welcome
+1034 winter
+1035 without
+1036 wolf
+1037 worm
+1038 wristwatch
+1039 yourself
+1040 above
+1041 accomplish
+1042 adopt
+1043 advantage
+1044 alphabet
+1045 anniversary
+1046 another
+1047 appropriate
+1048 arrogant
+1049 artist
+1050 background
+1051 bee
+1052 behavior
+1053 bell
+1054 birth
+1055 bless
+1056 blood
+1057 boots
+1058 brave
+1059 breathe
+1060 bright
+1061 bull
+1062 butterfly
+1063 card
+1064 category
+1065 catholic
+1066 cent
+1067 chemistry
+1068 cherry
+1069 china
+1070 chop
+1071 christian
+1072 cigarette
+1073 clever
+1074 clown
+1075 coach
+1076 coat
+1077 cochlear implant
+1078 coconut
+1079 common
+1080 commute
+1081 control
+1082 count
+1083 culture
+1084 daily
+1085 defend
+1086 degree
+1087 demonstrate
+1088 department
+1089 die
+1090 dig
+1091 dinner
+1092 dinosaur
+1093 diploma
+1094 director
+1095 disconnect
+1096 discover
+1097 don't want
+1098 drum
+1099 each
+1100 educate
+1101 electrician
+1102 empty
+1103 england
+1104 establish
+1105 excuse
+1106 eyeglasses
+1107 faculty
+1108 fall in love
+1109 famous
+1110 farm
+1111 fence
+1112 fix
+1113 flexible
+1114 flirt
+1115 flood
+1116 fork
+1117 four
+1118 fun
+1119 funeral
+1120 furniture
+1121 gallaudet
+1122 general
+1123 ghost
+1124 give up
+1125 glass
+1126 gorilla
+1127 gray
+1128 guide
+1129 habit
+1130 health
+1131 hearing aid
+1132 heaven
+1133 heavy
+1134 helmet
+1135 hide
+1136 high school
+1137 hockey
+1138 hold
+1139 honest
+1140 hug
+1141 hunt
+1142 image
+1143 influence
+1144 interesting
+1145 interpreter
+1146 iran
+1147 italy
+1148 jewish
+1149 judge
+1150 key
+1151 label
+1152 leaf
+1153 left
+1154 lend
+1155 less
+1156 linguistics
+1157 lonely
+1158 long
+1159 magic
+1160 mainstream
+1161 major
+1162 manager
+1163 maximum
+1164 me
+1165 mexico
+1166 middle
+1167 mind
+1168 misunderstand
+1169 monster
+1170 multiply
+1171 myself
+1172 nothing
+1173 october
+1174 odd
+1175 offer
+1176 on
+1177 only
+1178 opposite
+1179 out
+1180 overlook
+1181 path
+1182 percent
+1183 physics
+1184 piano
+1185 pick
+1186 pie
+1187 plate
+1188 pocket
+1189 popcorn
+1190 positive
+1191 pregnant
+1192 prevent
+1193 proof
+1194 pumpkin
+1195 purpose
+1196 race
+1197 realize
+1198 recognize
+1199 refuse
+1200 relationship
+1201 repeat
+1202 replace
+1203 report
+1204 represent
+1205 request
+1206 responsibility
+1207 result
+1208 reveal
+1209 ring
+1210 rob
+1211 rock
+1212 role
+1213 rope
+1214 rush
+1215 salute
+1216 satisfy
+1217 search
+1218 selfish
+1219 sensitive
+1220 serve
+1221 seven
+1222 shampoo
+1223 she
+1224 shelf
+1225 shopping
+1226 sign language
+1227 similar
+1228 sing
+1229 six
+1230 skeleton
+1231 sketch
+1232 skill
+1233 sleepy
+1234 slip
+1235 smell
+1236 sneeze
+1237 snob
+1238 specific
+1239 stamp
+1240 steel
+1241 strawberry
+1242 subtract
+1243 subway
+1244 suffer
+1245 surface
+1246 sweep
+1247 swing
+1248 switzerland
+1249 tale
+1250 tan
+1251 teeth
+1252 terrible
+1253 thankful
+1254 they
+1255 through
+1256 tiptoe
+1257 title
+1258 tooth
+1259 toothbrush
+1260 total
+1261 tough
+1262 tradition
+1263 trophy
+1264 trouble
+1265 true
+1266 trust
+1267 under
+1268 verb
+1269 wall
+1270 watermelon
+1271 way
+1272 weird
+1273 while
+1274 wide
+1275 willing
+1276 wish
+1277 wonderful
+1278 workshop
+1279 worse
+1280 wrench
+1281 a
+1282 a lot
+1283 abdomen
+1284 able
+1285 accountant
+1286 action
+1287 active
+1288 activity
+1289 address
+1290 affect
+1291 afraid
+1292 against
+1293 agenda
+1294 ahead
+1295 aim
+1296 alcohol
+1297 algebra
+1298 all day
+1299 amazing
+1300 angle
+1301 apart
+1302 apostrophe
+1303 appetite
+1304 appreciate
+1305 april
+1306 archery
+1307 around
+1308 article
+1309 assistant
+1310 attend
+1311 auction
+1312 authority
+1313 average
+1314 awake
+1315 b
+1316 babysitter
+1317 battle
+1318 beginning
+1319 belief
+1320 bible
+1321 bike
+1322 blend
+1323 bone
+1324 bra
+1325 brief
+1326 broke
+1327 bug
+1328 bully
+1329 button
+1330 cabbage
+1331 cabinet
+1332 calculate
+1333 calculator
+1334 calculus
+1335 camping
+1336 canoe
+1337 careless
+1338 ceiling
+1339 cemetery
+1340 chapter
+1341 choir
+1342 circle
+1343 come
+1344 come here
+1345 company
+1346 complete
+1347 concept
+1348 concern
+1349 confront
+1350 confused
+1351 congress
+1352 connect
+1353 conquer
+1354 constitution
+1355 contract
+1356 court
+1357 crab
+1358 cross
+1359 cruel
+1360 crush
+1361 date
+1362 december
+1363 decrease
+1364 deduct
+1365 defeat
+1366 deposit
+1367 depressed
+1368 detach
+1369 determine
+1370 diabetes
+1371 dime
+1372 dirt
+1373 disgust
+1374 dismiss
+1375 dizzy
+1376 document
+1377 dorm
+1378 dormitory
+1379 downstairs
+1380 economy
+1381 education
+1382 effort
+1383 eighteen
+1384 engage
+1385 engagement
+1386 engineer
+1387 envelope
+1388 erase
+1389 eternity
+1390 evening
+1391 everyday
+1392 expand
+1393 eye
+1394 eyes
+1395 fake
+1396 farmer
+1397 february
+1398 federal
+1399 final
+1400 florida
+1401 flute
+1402 forbid
+1403 forever
+1404 fourth
+1405 free
+1406 french fries
+1407 gamble
+1408 gas
+1409 gasoline
+1410 generation
+1411 geography
+1412 german
+1413 girlfriend
+1414 gold
+1415 grandma
+1416 grass
+1417 grow up
+1418 gun
+1419 haircut
+1420 hard of hearing
+1421 hippopotamus
+1422 his
+1423 honey
+1424 hurricane
+1425 identify
+1426 include
+1427 infection
+1428 innocent
+1429 insect
+1430 instead
+1431 institute
+1432 international
+1433 interrupt
+1434 involve
+1435 jail
+1436 january
+1437 joke
+1438 june
+1439 kangaroo
+1440 karate
+1441 kick
+1442 kneel
+1443 knock
+1444 laptop
+1445 lift
+1446 lightning
+1447 lip
+1448 lipstick
+1449 local
+1450 manage
+1451 mature
+1452 member
+1453 message
+1454 metal
+1455 microphone
+1456 mix
+1457 monthly
+1458 motor
+1459 nation
+1460 network
+1461 nickel
+1462 nineteen
+1463 normal
+1464 november
+1465 nut
+1466 octopus
+1467 once
+1468 organize
+1469 over
+1470 owl
+1471 p
+1472 parachute
+1473 paragraph
+1474 parallel
+1475 pay attention
+1476 peace
+1477 peanut butter
+1478 perfume
+1479 personality
+1480 pet
+1481 philadelphia
+1482 physician
+1483 piece
+1484 pity
+1485 plant
+1486 plenty
+1487 pneumonia
+1488 politics
+1489 position
+1490 pound
+1491 pour
+1492 praise
+1493 preach
+1494 preacher
+1495 prefer
+1496 pressure
+1497 principal
+1498 priority
+1499 professional
+1500 professor
+1501 promote
+1502 prostitute
+1503 proud
+1504 quote
+1505 receive
+1506 recent
+1507 reduce
+1508 refer
+1509 referee
+1510 relate
+1511 relax
+1512 remote control
+1513 rent
+1514 reputation
+1515 resign
+1516 responsible
+1517 ridiculous
+1518 road
+1519 robot
+1520 rubber
+1521 safe
+1522 sauce
+1523 sausage
+1524 scold
+1525 senior
+1526 september
+1527 several
+1528 shame
+1529 shave
+1530 shoot
+1531 shoulder
+1532 silver
+1533 simple
+1534 siren
+1535 size
+1536 skate
+1537 skin
+1538 skunk
+1539 slice
+1540 smooth
+1541 snack
+1542 snowman
+1543 society
+1544 someone
+1545 song
+1546 sore throat
+1547 south america
+1548 spanish
+1549 speak
+1550 speed
+1551 spell
+1552 spoon
+1553 spring
+1554 standard
+1555 statistics
+1556 sticky
+1557 still
+1558 stretch
+1559 surgeon
+1560 sweden
+1561 swimsuit
+1562 sympathy
+1563 take turns
+1564 take up
+1565 technology
+1566 temple
+1567 tender
+1568 thailand
+1569 theater
+1570 them
+1571 theme
+1572 thick
+1573 this
+1574 throat
+1575 tissue
+1576 tongue
+1577 tonight
+1578 tornado
+1579 tower
+1580 tranquil
+1581 transform
+1582 tutor
+1583 twin
+1584 united states
+1585 value
+1586 visitor
+1587 waiter
+1588 wake up
+1589 wallet
+1590 wander
+1591 wash face
+1592 weight
+1593 whale
+1594 whatever
+1595 within
+1596 wonder
+1597 worker
+1598 worthless
+1599 wrap
+1600 accent
+1601 act
+1602 adapt
+1603 adjective
+1604 adjust
+1605 admire
+1606 admit
+1607 advanced
+1608 adverb
+1609 agreement
+1610 aid
+1611 alligator
+1612 amputate
+1613 anatomy
+1614 annoy
+1615 anyway
+1616 approach
+1617 arizona
+1618 assist
+1619 assume
+1620 attorney
+1621 audiologist
+1622 audiology
+1623 austria
+1624 author
+1625 available
+1626 award
+1627 aware
+1628 bank
+1629 baptize
+1630 basic
+1631 battery
+1632 berry
+1633 beside
+1634 between
+1635 binoculars
+1636 blow
+1637 boast
+1638 boil
+1639 bookshelf
+1640 bookstore
+1641 boxing
+1642 braid
+1643 brain
+1644 breakdown
+1645 breakfast
+1646 breeze
+1647 bribe
+1648 brochure
+1649 buffalo
+1650 burp
+1651 bush
+1652 bye
+1653 camel
+1654 candidate
+1655 cannot
+1656 captain
+1657 carnival
+1658 caterpillar
+1659 cheerleader
+1660 chemical
+1661 chicago
+1662 choke
+1663 christ
+1664 click
+1665 closet
+1666 clueless
+1667 clumsy
+1668 collect
+1669 comma
+1670 comment
+1671 commit
+1672 committee
+1673 common sense
+1674 compete
+1675 concentrate
+1676 congratulations
+1677 consider
+1678 construct
+1679 consume
+1680 contest
+1681 conversation
+1682 convert
+1683 cooperate
+1684 counsel
+1685 counselor
+1686 crave
+1687 create
+1688 crocodile
+1689 crown
+1690 cuba
+1691 curtain
+1692 customer
+1693 d
+1694 damage
+1695 dancer
+1696 danger
+1697 dangerous
+1698 dawn
+1699 death
+1700 debate
+1701 debt
+1702 deliver
+1703 democrat
+1704 descend
+1705 design
+1706 detective
+1707 devil
+1708 dice
+1709 difficult
+1710 dining room
+1711 discipline
+1712 discount
+1713 disgusted
+1714 disturb
+1715 division
+1716 done
+1717 drag
+1718 dragon
+1719 drama
+1720 drug
+1721 due
+1722 dull
+1723 dusk
+1724 dvd
+1725 dye
+1726 e
+1727 either
+1728 electricity
+1729 elementary
+1730 else
+1731 emergency
+1732 engine
+1733 enormous
+1734 eraser
+1735 every monday
+1736 every tuesday
+1737 everything
+1738 except
+1739 exhibit
+1740 explode
+1741 express
+1742 f
+1743 fairy
+1744 familiar
+1745 festival
+1746 finance
+1747 fingerspell
+1748 fire
+1749 firefighter
+1750 five
+1751 flatter
+1752 fool
+1753 forgive
+1754 former
+1755 freeway
+1756 from now on
+1757 g
+1758 gang
+1759 gay
+1760 geometry
+1761 get up
+1762 gift
+1763 grab
+1764 graduation
+1765 grateful
+1766 grey
+1767 gymnastics
+1768 h
+1769 hang up
+1770 hanukkah
+1771 heap
+1772 heart attack
+1773 hill
+1774 holy
+1775 hop
+1776 host
+1777 hot dog
+1778 human
+1779 i
+1780 ill
+1781 illegal
+1782 impact
+1783 individual
+1784 inspect
+1785 inspire
+1786 intersection
+1787 ireland
+1788 iron
+1789 j
+1790 jewelry
+1791 journey
+1792 joy
+1793 july
+1794 k
+1795 kid
+1796 kindergarten
+1797 lady
+1798 lamp
+1799 last week
+1800 laundry
+1801 leader
+1802 league
+1803 leak
+1804 legal
+1805 let
+1806 liability
+1807 librarian
+1808 license
+1809 little bit
+1810 loan
+1811 look at
+1812 look for
+1813 lord
+1814 m
+1815 meaning
+1816 melody
+1817 melt
+1818 mention
+1819 microscope
+1820 midnight
+1821 military
+1822 mine
+1823 mistake
+1824 mock
+1825 moose
+1826 mosquito
+1827 motivate
+1828 murder
+1829 n
+1830 narrow
+1831 necessary
+1832 negotiate
+1833 new york
+1834 nine
+1835 northwest
+1836 not yet
+1837 notice
+1838 numerous
+1839 nun
+1840 o
+1841 objective
+1842 obsess
+1843 obtain
+1844 occur
+1845 odor
+1846 olympics
+1847 or
+1848 oral
+1849 our
+1850 overcome
+1851 pack
+1852 painter
+1853 part
+1854 pause
+1855 peaceful
+1856 pear
+1857 peel
+1858 penalty
+1859 pennsylvania
+1860 penny
+1861 permit
+1862 phrase
+1863 pickle
+1864 pilot
+1865 player
+1866 polar bear
+1867 policeman
+1868 poop
+1869 post
+1870 potential
+1871 poverty
+1872 precious
+1873 precipitation
+1874 precise
+1875 preschool
+1876 pride
+1877 prince
+1878 princess
+1879 principle
+1880 process
+1881 profit
+1882 progress
+1883 propaganda
+1884 proper
+1885 psychologist
+1886 public
+1887 publish
+1888 purchase
+1889 pure
+1890 pursue
+1891 put off
+1892 q
+1893 quality
+1894 quarrel
+1895 quarter
+1896 r
+1897 rage
+1898 rather
+1899 real
+1900 recliner
+1901 recommend
+1902 recover
+1903 regular
+1904 release
+1905 relief
+1906 rely
+1907 reply
+1908 rescue
+1909 resist
+1910 restroom
+1911 retreat
+1912 roar
+1913 robber
+1914 roommate
+1915 rose
+1916 ruin
+1917 s
+1918 salary
+1919 saw
+1920 scan
+1921 scream
+1922 sculpture
+1923 sea
+1924 seldom
+1925 sequence
+1926 settle
+1927 shout
+1928 shovel
+1929 sin
+1930 singer
+1931 sixteen
+1932 ski
+1933 skip
+1934 smoking
+1935 sofa
+1936 soldier
+1937 solve
+1938 someday
+1939 something
+1940 somewhere
+1941 soul
+1942 spill
+1943 spit
+1944 spread
+1945 sprint
+1946 squeeze
+1947 stadium
+1948 stepfather
+1949 sting
+1950 stir
+1951 stitch
+1952 stuck
+1953 sue
+1954 sunshine
+1955 superman
+1956 surrender
+1957 suspend
+1958 swimming
+1959 t
+1960 talent
+1961 telescope
+1962 tempt
+1963 ten
+1964 tend
+1965 testify
+1966 texas
+1967 text
+1968 than
+1969 therefore
+1970 thrill
+1971 tobacco
+1972 toilet paper
+1973 tolerate
+1974 torture
+1975 towel
+1976 trip
+1977 truth
+1978 turn
+1979 tv
+1980 u
+1981 unique
+1982 upstairs
+1983 v
+1984 vacant
+1985 vague
+1986 valley
+1987 vampire
+1988 very
+1989 vice president
+1990 viewpoint
+1991 visualize
+1992 vlog
+1993 volleyball
+1994 w
+1995 washington
+1996 waterfall
+1997 weigh
+1998 wheelchair
+1999 whistle