- [实操](#%E5%AE%9E%E6%93%8D)
- [1. 本地开发和调试](#1.%20%E6%9C%AC%E5%9C%B0%E5%BC%80%E5%8F%91%E5%92%8C%E8%B0%83%E8%AF%95)
- [2. 在 Azure GPU 虚拟机上部署和训练](#2.%20%E5%9C%A8%20Azure%20GPU%20%E8%99%9A%E6%8B%9F%E6%9C%BA%E4%B8%8A%E9%83%A8%E7%BD%B2%E5%92%8C%E8%AE%AD%E7%BB%83)
- [3. 模型测试和后续工作](#3.%20%E6%A8%A1%E5%9E%8B%E6%B5%8B%E8%AF%95%E5%92%8C%E5%90%8E%E7%BB%AD%E5%B7%A5%E4%BD%9C)
- [4. 小贴士](#4.%20%E5%B0%8F%E8%B4%B4%E5%A3%AB)
- [理论](#%E7%90%86%E8%AE%BA)
- [Assignment 概览](#Assignment%20%E6%A6%82%E8%A7%88)
- [Part 1: Neural Machine Translation with RNNs (45 分)](#Part%201:%20Neural%20Machine%20Translation%20with%20RNNs%20(45%20%E5%88%86))
- [(a) (2 分) 在 `utils.py` 里实现 `pad_sents` 函数](#(a)%20(2%20%E5%88%86)%20%E5%9C%A8%20%60utils.py%60%20%E9%87%8C%E5%AE%9E%E7%8E%B0%20%60pad_sents%60%20%E5%87%BD%E6%95%B0)
- [(b) (3 分) 在 `model_embeddings.py` 里实现 `__init__` 函数](#(b)%20(3%20%E5%88%86)%20%E5%9C%A8%20%60model_embeddings.py%60%20%E9%87%8C%E5%AE%9E%E7%8E%B0%20%60__init__%60%20%E5%87%BD%E6%95%B0)
- [(c) (4 分) 在 `nmt_model.py` 的 `__init__` 中初始化各层](#(c)%20(4%20%E5%88%86)%20%E5%9C%A8%20%60nmt_model.py%60%20%E7%9A%84%20%60__init__%60%20%E4%B8%AD%E5%88%9D%E5%A7%8B%E5%8C%96%E5%90%84%E5%B1%82)
- [(d) (8 分) 在 `nmt_model.py` 中实现 `encode()` 函数](#(d)%20(8%20%E5%88%86)%20%E5%9C%A8%20%60nmt_model.py%60%20%E4%B8%AD%E5%AE%9E%E7%8E%B0%20%60encode()%60%20%E5%87%BD%E6%95%B0)
- [(e) (8 分) 在 `nmt_model.py` 中实现 `decode()` 函数](#(e)%20(8%20%E5%88%86)%20%E5%9C%A8%20%60nmt_model.py%60%20%E4%B8%AD%E5%AE%9E%E7%8E%B0%20%60decode()%60%20%E5%87%BD%E6%95%B0)
- [(f) (10 分) 在 `nmt_model.py` 中实现 `step()` 函数](#(f)%20(10%20%E5%88%86)%20%E5%9C%A8%20%60nmt_model.py%60%20%E4%B8%AD%E5%AE%9E%E7%8E%B0%20%60step()%60%20%E5%87%BD%E6%95%B0)
- [(g) (3 分) (书面问题)关于 `generate_sent_masks()` 生成的 `enc_masks`](#(g)%20(3%20%E5%88%86)%20%EF%BC%88%E4%B9%A6%E9%9D%A2%E9%97%AE%E9%A2%98%EF%BC%89%E5%85%B3%E4%BA%8E%20%60generate_sent_masks()%60%20%E7%94%9F%E6%88%90%E7%9A%84%20%60enc_masks%60)
- [(i) (4 分) 训练完成后,测试并报告 BLEU 分数](#(i)%20(4%20%E5%88%86)%20%E8%AE%AD%E7%BB%83%E5%AE%8C%E6%88%90%E5%90%8E%EF%BC%8C%E6%B5%8B%E8%AF%95%E5%B9%B6%E6%8A%A5%E5%91%8A%20BLEU%20%E5%88%86%E6%95%B0)
- [(j) (3 分) (书面问题)比较 dot-product、multiplicative、additive attention 的优劣](#(j)%20(3%20%E5%88%86)%20%EF%BC%88%E4%B9%A6%E9%9D%A2%E9%97%AE%E9%A2%98%EF%BC%89%E6%AF%94%E8%BE%83%20dot-product%E3%80%81multiplicative%E3%80%81additive%20attention%20%E7%9A%84%E4%BC%98%E5%8A%A3)
- [Part 2: Analyzing NMT Systems (30 分)](#Part%202:%20Analyzing%20NMT%20Systems%20(30%20%E5%88%86))
- [(a) (12 分) 给定 6 个**已知翻译错误**的例子](#(a)%20(12%20%E5%88%86)%20%E7%BB%99%E5%AE%9A%206%20%E4%B8%AA**%E5%B7%B2%E7%9F%A5%E7%BF%BB%E8%AF%91%E9%94%99%E8%AF%AF**%E7%9A%84%E4%BE%8B%E5%AD%90)
- [(b) (4 分) 观察你自己模型在 test set 上的输出](#(b)%20(4%20%E5%88%86)%20%E8%A7%82%E5%AF%9F%E4%BD%A0%E8%87%AA%E5%B7%B1%E6%A8%A1%E5%9E%8B%E5%9C%A8%20test%20set%20%E4%B8%8A%E7%9A%84%E8%BE%93%E5%87%BA)
- [(c) (14 分) 手动计算 BLEU 的题目](#(c)%20(14%20%E5%88%86)%20%E6%89%8B%E5%8A%A8%E8%AE%A1%E7%AE%97%20BLEU%20%E7%9A%84%E9%A2%98%E7%9B%AE)
- [最终提交](#%E6%9C%80%E7%BB%88%E6%8F%90%E4%BA%A4)
## 实操
### 1. 本地开发和调试
**(1) 设置本地虚拟环境**
- 确保你已经安装了 Anaconda(或 Miniconda)。
- 在项目根目录下执行下面的命令来创建并激活本地虚拟环境:
```bash
conda env create --file local_env.yml
conda activate <your_env_name> # 替换 <your_env_name> 为 env.yml 中指定的环境名称
```
**(2) 生成词汇表**
- 在终端中运行下面的命令来生成所需的词汇表文件:
```bash
sh run.sh vocab
```
该命令会根据数据预处理,生成训练和测试过程中需要用到的词汇表。
**(3) 本地调试训练代码**
- 为了避免在 GPU 上浪费宝贵的时间,先在本地运行简化版的训练脚本。运行:
```bash
sh run.sh train_local
```
- 观察程序运行至少到 iter 10 或 iter 20,确保代码能够顺利执行且不会崩溃。如果在这一阶段发现问题,可以及时调试修改。
---
### 2. 在 Azure GPU 虚拟机上部署和训练
**(4) 准备并上传代码到 Azure VM**
- 按照 CS224n Azure Guide 和 "Managing Code Deployment to a VM" 指南配置你的 Azure 虚拟机(确保分配了 GPU 资源)。
- 使用 `scp` 或其它文件传输工具将你本地测试通过的代码上传到 VM 上。
**(5) 安装 GPU 版依赖**
- 在 VM 上进入你的项目目录,运行以下命令安装 GPU 环境所需的依赖包:
```bash
pip install -r gpu_requirements.txt
```
**(6) 利用 tmux 运行长时间训练任务**
- 为防止 SSH 连接断开导致训练中断,建议使用 tmux。首先创建一个 tmux 会话:
```bash
tmux new -s nmt
```
- 在 tmux 会话内,启动正式的训练(大约需要 4 小时):
```bash
sh run.sh train
```
- 如果需要临时退出 tmux 会话而不终止任务,可以按下 `Ctrl+B` 后再按 `D`(或者直接输入 `tmux detach`)。
**(7) 监控训练进程**
- 你可以随时通过下面的命令重新连接到该会话以查看训练日志:
```bash
tmux attach -t nmt
```
---
### 3. 模型测试和后续工作
**(8) 测试模型**
- 当训练完成后(约 4 小时后),在同一个 tmux 会话或新的终端中运行:
```bash
sh run.sh test
```
- 该命令会加载训练好的模型,对测试数据进行翻译,并计算 BLEU 分数。翻译结果一般会保存在 `outputs/test_outputs.txt` 文件中。
**(9) 分析和撰写报告**
- 根据测试结果,查阅输出文件,回答 Assignment #4 中关于 NMT 系统分析的书面题目。
- 确保代码部分和书面答案部分都按照要求打包提交到 GradeScope。
---
### 4. 小贴士
- **本地开发先行**:在正式上传到 VM 前,务必在本地充分调试代码,确保基本功能(如 pad_sents、encode、decode、step 等函数)正确实现。
- **合理管理资源**:在不使用 VM 时及时关闭以节省 GPU 使用时间和费用。
- **参考文档**:如果遇到任何问题,建议查阅 CS224n 提供的 Azure Guide、Practical Guide to VMs,以及课程网站上提供的相关文档。
按照以上步骤,你就可以一步步地跑起 Assignment #4 了。祝你训练顺利,取得好成绩!
## 理论
### Assignment 概览
本次作业分为两大部分:
1. **Neural Machine Translation with RNNs (45 分)**
以**西语 → 英语**的翻译为例,使用 **双向 LSTM Encoder + 单向 LSTM Decoder**,以及 **multiplicative attention** 来实现一个 Seq2Seq 的 NMT 系统。
- 你需要**在代码中实现**各个模块(embedding、encode、decode、attention 等),并进行训练和测试,最终得到一个 BLEU 分数。
- 其中还包含两个**简短的书面分析问题**((g) 关于 mask 的作用,(j) 关于不同 attention 机制的优劣)。
2. **Analyzing NMT Systems (30 分)**
主要是**书面分析题**,包括:
- 给出已有模型输出的翻译错误,并说明**错误类型**、**原因**以及**改进方法**;
- 手动计算 BLEU 分数,比较不同参考译文数量时 BLEU 分数的差异,以及讨论 BLEU 指标 vs. 人工评测的优缺点。
这两部分**相互独立**:如果你在第一部分遇到瓶颈,仍然可以先做第二部分的**written**分析题。
---
### Part 1: Neural Machine Translation with RNNs (45 分)
在此部分,你需要主要在 **`nmt_model.py`** 和 **`model_embeddings.py`**(以及一些辅助文件,如 `utils.py`)里完成对应的函数。完成后,在你的代码环境里跑 `sh run.sh train_local` 或者在 Azure VM 上跑 `sh run.sh train` 进行训练(大约需 4 小时 GPU 时间)。
#### (a) (2 分) 在 `utils.py` 里实现 `pad_sents` 函数
- **功能**:对一个 batch 中的句子进行补齐(padding),保证它们有相同长度,方便后续张量运算。
- 你只需在 `pad_sents` TODO 处完成并返回补齐后的结果。
#### (b) (3 分) 在 `model_embeddings.py` 里实现 `__init__` 函数
- **功能**:分别创建**源语言(source)**和**目标语言(target)**的嵌入层 (Embedding layer)。
- 作业要求**不直接使用** `nn.Embedding` 的高层封装,而是要自己写或至少自己初始化相关参数。
#### (c) (4 分) 在 `nmt_model.py` 的 `__init__` 中初始化各层
- **功能**:
- 建立 NMT 模型需要的层(**LSTM、投影层、dropout**等)
- 调用 `ModelEmbeddings` 来创建 embeddings
- 这些层会在后面的 `encode()`、`decode()`、`step()` 等函数里被调用。
#### (d) (8 分) 在 `nmt_model.py` 中实现 `encode()` 函数
- **功能**:
1. 把补齐后的源语句转换为张量 X;
2. 送入双向 LSTM(Bi-LSTM),得到 encoder hidden states hench_{enc};
3. 线性映射 encoder 最后的 hidden state/cell state 用于初始化 decoder 的 hdec0h_{dec}^0 和 cdec0c_{dec}^0;
- 可以用 `python sanity_check.py 1d` 做一个初步测试。
#### (e) (8 分) 在 `nmt_model.py` 中实现 `decode()` 函数
- **功能**:
1. 把目标语言词向量(以及前一步的输出向量)拼接,形成 decoder 的输入;
2. 多步(time step)调用 `step()` 函数,直到处理完目标句所有 token;
3. 收集 decoder 的输出,用来计算预测分布等。
- 可以用 `python sanity_check.py 1e` 做初步测试。
#### (f) (10 分) 在 `nmt_model.py` 中实现 `step()` 函数
- **功能**:
1. Decoder LSTM 单步更新 (h_t, c_t)
2. 计算对所有 encoder hidden states 的 attention 分数 e_t,并做 softmax 得到 attention 分布 α_t
3. 根据 α_t 做加权求和得到 context 向量 a_t
4. 将 a_t 和 h_t 拼接、通过一个线性 + tanh + dropout 得到 combined output o_t
5. 用 `o_t` 最终预测一个词分布
- 可以用 `python sanity_check.py 1f` 做初步测试。
#### (g) (3 分) (书面问题)关于 `generate_sent_masks()` 生成的 `enc_masks`
- 题目让你用**三四句话**说明:
1. mask 在 attention 计算中起到什么作用?
2. 为什么在计算注意力分数时,必须这样用 mask 去屏蔽 padding token?
- **mask 的作用**:在 attention 计算中,mask 用于屏蔽输入中那些仅用于填充、没有实际语义信息的位置,确保模型在计算注意力分布时只关注有效的词汇。
- **屏蔽 padding token 的必要性**:因为 padding token 并不携带实际信息,如果不屏蔽,这些位置可能会获得不合理的注意力得分,导致 softmax 后分配非零的概率,从而干扰上下文向量的计算和后续预测。因此,通过将 padding token 对应的注意力得分置为负无穷,保证它们在 softmax 后的概率为 0,使模型只聚焦于真正有用的输入信息。
#### (i) (4 分) 训练完成后,测试并报告 BLEU 分数
- **做法**:
1. 在 Azure VM 上完整训练(`sh run.sh train`),大约 4 小时;
2. 训练完后执行 `sh run.sh test` 计算 BLEU;
3. 在报告中**写出最终的 BLEU**,需要**大于 21**;
- 这部分也记得写在**Written**报告中。
#### (j) (3 分) (书面问题)比较 dot-product、multiplicative、additive attention 的优劣
- **要求**:
1. 说出 dot-product 相比 multiplicative 的优点和缺点(各 1 点);
2. 说出 additive 相比 multiplicative 的优点和缺点(各 1 点)。
把这些回答写在**Written**报告里。
---
### Part 2: Analyzing NMT Systems (30 分)
这一部分**完全是书面分析题**。重点是观察某些翻译错误、分析原因和改进思路,以及手动计算 BLEU。
#### (a) (12 分) 给定 6 个**已知翻译错误**的例子
- 对每个例子:
1. **指出** NMT 翻译出现了什么错误;
2. **可能的原因**(模型不足 or 特定语言现象)是什么;
3. **提出一个改进方案**(可以是模型结构、超参数调整、更多训练数据、改 attention 等)。
#### (b) (4 分) 观察你自己模型在 test set 上的输出
- 你在 part 1 训练后,生成的翻译保存在 `outputs/test_outputs.txt`。
- 需要**找出 2 处翻译错误**(并且和 part (a) 里给出的例子类型不同),对每个错误:
1. 写下**源句**(在 `test.es`)、**参考译文**(在 `test.en`)、**模型译文**;
2. 分析错误类型、可能原因、改进方案。
#### (c) (14 分) 手动计算 BLEU 的题目
- 让你根据给出的公式(Modified n-gram precision, brevity penalty 等)对 1 个句子进行 BLEU 计算;
- 分别在有两个参考译文 vs. 只有一个参考译文时,对比两个候选翻译 c1、c2 的 BLEU 分数;
- 问你是否同意 BLEU 的判断、为什么单一参考翻译有局限、BLEU 相比人工评测的优缺点等:
1. (i) (5 分) **同时有两条参考译文** r1,r2r_1, r_2,计算 c1、c2 的 BLEU;谁得分更高,是否符合直觉?
2. (ii) (5 分) **只剩下一条**参考译文r1r_1,再次算 c1、c2 的 BLEU;结果如何,对比之前有何变化?
3. (iii) (2 分) **为何仅有单一参考**对 NMT 评价可能存在问题?
4. (iv) (2 分) BLEU vs 人工评测:**列举 2 个优点和 2 个缺点**。
将这些**详细计算过程与答案**写在**Written**报告里。
---
### 最终提交
作业需要**两次**提交到 GradeScope:
1. **Assignment 4[coding]**
- 在你的 Azure VM 上执行 `collect_submission.sh`,会打包出 `assignment4.zip`;
- 下载到本地后上传到 Gradescope。
- 里面应该包含你写的**`nmt_model.py`、`model_embeddings.py`、`utils.py`** 等代码。
2. **Assignment 4[written]**
- 把**所有文字分析回答**(包括 Part 1(g), Part 1(j), Part 2(a)(b)(c))整理成一个 PDF(或学校要求的排版),上传到相应的 Written 作业入口。
- 在 Gradescope 上"**tag 对应页面**"时,记得把每个题目对应到 PDF 中正确的页码,否则可能被扣分。
完成以上流程,你就完成了 CS224n Assignment BLEU 分数并顺利完成作业!