# 验证码破解技术四部曲之使用卷积神经网络（四）

## 训练

### 构建网络

``````void construct_net(network<sequential>& nn) {
// connection table [Y.Lecun, 1998 Table.1]
#define O true
#define X false
static const bool tbl[] = {
O, X, X, X, O, O, O, X, X, O, O, O, O, X, O, O,
O, O, X, X, X, O, O, O, X, X, O, O, O, O, X, O,
O, O, O, X, X, X, O, O, O, X, X, O, X, O, O, O,
X, O, O, O, X, X, O, O, O, O, X, X, O, X, O, O,
X, X, O, O, O, X, X, O, O, O, O, X, O, O, X, O,
X, X, X, O, O, O, X, X, O, O, O, O, X, O, O, O
};
#undef O
#undef X

// construct nets
nn << convolutional_layer<tan_h>(32, 32, 5, 1, 6)  // C1, 1@32x32-in, 6@28x28-out
<< average_pooling_layer<tan_h>(28, 28, 6, 2)   // S2, 6@28x28-in, 6@14x14-out
<< convolutional_layer<tan_h>(14, 14, 5, 6, 16,
connection_table(tbl, 6, 16))              // C3, 6@14x14-in, 16@10x10-in
<< average_pooling_layer<tan_h>(10, 10, 16, 2)  // S4, 16@10x10-in, 16@5x5-out
<< convolutional_layer<tan_h>(5, 5, 5, 16, 120) // C5, 16@5x5-in, 120@1x1-out
<< fully_connected_layer<tan_h>(120, 14);       // F6, 120-in, 14-out
}``````

（注：这里只能修改F6层的参数而不能修改C1层的参数，修改C1参数会影响到其他层的输入。）

### 加载数据集

``````std::string label_strs[14] = {
"3", "C", "D", "E", "F", "H", "J", "K", "L", "M", "N", "W", "X", "Y"
};
std::vector<vec_t> &train_images,
std::vector<label_t> &test_labels,
std::vector<vec_t> &test_images)
{
for (int i = 0; i < 14; ++i){
std::vector<std::string> images;

fs::directory_iterator end_iter;
fs::path path("./training_set/"+label_strs[i]);
for (fs::directory_iterator iter(path); iter != end_iter; ++iter){
if (fs::extension(*iter)==".png"){
images.push_back(iter->path().string());
}
}

//train_set.size() : test_set.size() = 4:1
int flag = 0;
std::vector<std::string>::iterator itr = images.begin();
for (;itr != images.end(); ++itr){
vec_t data;
convert_image(*itr, -1.0, 1.0, 32, 32, data);
if (flag <= 4){
train_labels.push_back(i);
train_images.push_back(data);
}else{
test_labels.push_back(i);
test_images.push_back(data);
flag = 0;
}
flag++;
}
}
}``````

### 参数设置

``````int minibatch_size = 100;             //每批量的数量
int num_epochs = 50;                  //迭代次数

// optimizer.alpha *= std::sqrt(minibatch_size); 使用默认的学习速率``````

### 保存结果

``````// save networks
std::ofstream ofs("weibo.cn-nn-weights");
ofs << nn;``````

## 识别

``````int recognize(const std::string& dictionary, cv::Mat &img) {
network<sequential> nn;

construct_net(nn);

ifstream ifs(dictionary.c_str());
ifs >> nn;

// convert cvMat to vec_t
vec_t data;
convert_mat(img, -1.0, 1.0, 32, 32, data);

// recognize
auto res = nn.predict(data);
vector<pair<double, int> > scores;

for (int i = 0; i < 14; i++)
scores.emplace_back(rescale<tan_h>(res[i]), i);

// sort and get the result
sort(scores.begin(), scores.end(), greater<pair<double, int>>());
return scores[0].second;
}``````

583 声望40 粉丝

0 条评论