<jupyter_start><jupyter_text>一个简单的根据0基础入门的示例中的识别手写数字改写而成的黄斑定位程序。**由于丢失了成绩为0.00923的checkpoint，我尽可能还原了之前的一些内容，当前代码成绩为0.0084，因为每次运行结果都有随机性，所以不保证可以得到相同结果，可以尝试多次运行来刷评分**思路：虽然图片的大小不一，但是可以将看作中心点在xy轴的百分比位置，如目标点在最中间则认为横纵分别为0.5。最后再将小数还原为整数即可得到真实图片上的像素点坐标。本程序没有实现异步读取，直接做了最基础的读数据，运行。最后会在./work/Fovea_Localization_Results.csv中保存测试结果。 **首先是获取数据**<jupyter_code># 下载数据
import urllib 
import requests   
import os
url = 'https://bj.bcebos.com/v1/dataset-bj/%E5%8C%BB%E7%96%97%E6%AF%94%E8%B5%9B/%E5%B8%B8%E8%A7%84%E8%B5%9B%EF%BC%9APALM%E7%9C%BC%E5%BA%95%E5%BD%A9%E7%85%A7%E4%B8%AD%E9%BB%84%E6%96%91%E4%B8%AD%E5%A4%AE%E5%87%B9%E5%AE%9A%E4%BD%8D.zip'  

if not os.path.exists('./work/Train_and_test.zip'):
    print("Downloading start!")
    urllib.request.urlretrieve(url, "./work/Train_and_test.zip")  
    print("Downloading end!")
else:
    print("Already Downloading")
# 解压数据
! unzip ./work/Train_and_test.zip -d ./work<jupyter_output>Archive:  ./work/Train_and_test.zip
replace ./work/常规赛：PALM眼底彩照中黄斑中央凹定位/License-PALM_0425.pdf? [y]es, [n]o, [A]ll, [N]one, [r]ename: ^C<jupyter_text>**定义需要用到的函数和类**包括:get_train_image		读取训练图片，缩放图片到指定大小get_test_image		读取测试图片，缩放图片到指定大小Mymodel				定义CNN网络train				对网络进行训练test				对网络进行测试并且写入.csv<jupyter_code>import paddle
import paddle.nn.functional as F
import os
import numpy as np
from paddle.nn import Conv2D, MaxPool2D, Linear
import pandas as pd
from PIL import Image

def get_train_image(image_size):
    pd.set_option('mode.chained_assignment', None)
    # 读xlsx
    df = pd.read_excel('./work/常规赛：PALM眼底彩照中黄斑中央凹定位/Train/Fovea_Location_train.xlsx')
    # 定义变量用于保存图片的原始大小和修改后的中心点坐标
    df['ori_width'] = 0
    df['ori_height'] = 0
    df['changed_x'] = 0.0
    df['changed_y'] = 0.0
    im_list = []
    for i in range(len(df)):  # df[df.columns[0]]:
        if i % 50 == 0:
            print(str(i / len(df) * 100) + '% finished')
        im = Image.open('./work/常规赛：PALM眼底彩照中黄斑中央凹定位/Train/fundus_image/' + df[df.columns[0]][i])
        df['ori_width'][i] = np.array(im).shape[1]  # 列对应横向宽度，行对应纵向宽度
        df['ori_height'][i] = np.array(im).shape[0]
        df['changed_x'][i] = df['Fovea_X'][i]/np.array(im).shape[1]
        df['changed_y'][i] = df['Fovea_Y'][i]/np.array(im).shape[0]
        #转化为灰度图并缩小，保存在列表中
        im = im.convert('L')
        im = im.resize((image_size, image_size), Image.ANTIALIAS)
        im = np.array(im).reshape(1, -1).astype(np.float32)
        im_list.append(im.tolist()[0])
    print(str(1 * 100) + '% finished')
    im_record = np.array(im_list)
    df2 = pd.DataFrame(im_record)
    pd.set_option('mode.chained_assignment', "raise")
    # return train_infor, train_input
    # 返回图片的标签信息和图片向量
    return df, df2

def get_test_image(image_size):
    # read the test_infor
    mylist=[]
    im_list = []
    for i in range(400):
        if i % 50 == 0:
            print(str(i / 400 * 100) + '% finished')
        target_pic_name='T' + ('%04d' % (i+1)) + '.jpg'
        # 无法直接从csv中读取，所以手动生成向量
        tmplist=[target_pic_name,0.0,0.0,0,0,0.0,0.0]
        im = Image.open('./work/常规赛：PALM眼底彩照中黄斑中央凹定位/PALM-Testing400-Images/' + target_pic_name)
        tmplist[3] = np.array(im).shape[1]  # 列对应横向宽度，行对应纵向宽度
        tmplist[4] = np.array(im).shape[0]
        im = im.convert('L')
        im = im.resize((image_size, image_size), Image.ANTIALIAS)
        im = np.array(im).reshape(1, -1).astype(np.float32)
        im_list.append(im.tolist()[0])

        mylist.append(tmplist)
    print(str(1 * 100) + '% finished')
    test_df = pd.DataFrame.from_records(mylist, columns=['FileName', 'Fovea_X', 'Fovea_Y', 'ori_width', 'ori_height', 'changed_x', 'changed_y'])
    im_record = np.array(im_list)
    df_test_input = pd.DataFrame(im_record)
    pd.set_option('mode.chained_assignment', "raise")
    # return test_infor, test_input
    return test_df, df_test_input

#定义模型，本模型参考了https://www.paddlepaddle.org.cn/tutorials/projectdetail/2182025
class Mymodel(paddle.nn.Layer):
    def __init__(self):
        super(Mymodel, self).__init__()
        global image_size
        # 定义卷积层，输出特征通道out_channels设置为20，卷积核的大小kernel_size为5，卷积步长stride=1，padding=2
        self.conv1 = Conv2D(in_channels=1, out_channels=20, kernel_size=5, stride=1, padding=2)
        # 定义池化层，池化核的大小kernel_size为2，池化步长为2
        self.max_pool1 = MaxPool2D(kernel_size=2, stride=2)
        # 定义卷积层，输出特征通道out_channels设置为20，卷积核的大小kernel_size为5，卷积步长stride=1，padding=2
        self.conv2 = Conv2D(in_channels=20, out_channels=20, kernel_size=5, stride=1, padding=2)
        # 定义池化层，池化核的大小kernel_size为2，池化步长为2
        self.max_pool2 = MaxPool2D(kernel_size=2, stride=2)
        # 定义全连接层，输出维度是2
        # 计算维度
        tmp=np.zeros([image_size,image_size], dtype='float32', order='C')
        tmp = np.array(tmp).reshape(1, 1, image_size, image_size).astype(np.float32)
        tmp=paddle.to_tensor(tmp)
        tmp1 = self.conv1(tmp)
        tmp2 = self.max_pool1(tmp1)
        tmp3 = self.conv2(tmp2)
        tmp4 = self.max_pool2(tmp3)
        liner_input_num=1
        for i in range(len(tmp4.shape)):
            liner_input_num*=tmp4.shape[i]
        self.fc = Linear(in_features=liner_input_num, out_features=5000)
        self.fc2 = Linear(in_features=5000, out_features=1000)
        self.fc3 = Linear(in_features=1000, out_features=2)

    # 定义网络前向计算过程，卷积后紧接着使用池化层，最后使用全连接层计算最终输出
    def forward(self, inputs):
         x = self.conv1(inputs)
         x = F.relu(x)
         x = self.max_pool1(x)
         x = self.conv2(x)
         x = F.relu(x)
         x = self.max_pool2(x)
         x = paddle.reshape(x, [x.shape[0], -1])
         x = self.fc(x)
         x = F.relu6(x)
         x =self.fc2(x)
         x = F.tanh(x)
         x =self.fc3(x)
         return x

# 定义训练
def train(model, train_infor, train_input, image_size,m_ite):
    # 将数据转化为四维矩阵格式，并归一到0-1
    train_im = paddle.to_tensor(train_input.values.astype('float32')/255)
    train_im = paddle.reshape(train_im,[train_im.shape[0], 1, image_size, image_size])
    train_lab = train_infor[['changed_x','changed_y']]
    train_lab = paddle.to_tensor(train_lab.values.astype('float32'))

    # 定义学习器
    opt = paddle.optimizer.Adam(learning_rate=0.001, weight_decay=paddle.regularizer.L2Decay(coeff=1e-5),
                                parameters=model.parameters())

    print('init train!')
    
    # 训练
    for i in range(m_ite):
        print(i)
        predicts = model(train_im)
        loss = F.square_error_cost(predicts, train_lab)
        avg_loss = paddle.mean(loss)

        avg_loss.backward()
        opt.step()
        opt.clear_grad()
        print("now los is {}".format(avg_loss.numpy()))

#定义测试
def test(model, test_infor, test_input ,image_size):
    print('test_start')
    # param_dict = paddle.load('./PALM')
    # model.load_dict(param_dict)
    
    model.eval()
    test_im = paddle.to_tensor(test_input.values.astype('float32')/255)
    test_im = paddle.reshape(test_im,[test_im.shape[0], 1, image_size, image_size])
    predicts = model(test_im)
    predicts = predicts.numpy()

    pd.set_option('mode.chained_assignment', None)

    #将预测的点还原为图片上的坐标
    for i in range(400):
        test_infor['changed_x'][i]=predicts[i][0]
        test_infor['changed_y'][i]=predicts[i][1]
        test_infor['Fovea_X'][i] = predicts[i][0]*test_infor['ori_width'][i]
        test_infor['Fovea_Y'][i] = predicts[i][1]*test_infor['ori_height'][i]
    pd.set_option('mode.chained_assignment', 'raise')
    
    #写文件
    final_df=test_infor[['FileName','Fovea_X','Fovea_Y']]
    final_df.to_csv('./work/Fovea_Localization_Results.csv', index=None)<jupyter_output><empty_output><jupyter_text>**正式进行训练和测试**<jupyter_code># 定义缩放的大小，训练迭代次数，模型保存目录
global image_size
image_size = 96
m_ite=500
model_save_dir='./work/mymodel'
last_model_dir='./work/mymodel'
#获得训练数据
print("get_train_image!")
train_infor, train_input=get_train_image(image_size)
print("train infor gotten!")
#构造模型开始训练
model = Mymodel()
print("model created")
train(model,train_infor, train_input, image_size, m_ite)
print("train finish")
paddle.save(model.state_dict(), model_save_dir)
print("model saved")
#开始测试
model = Mymodel()
print("model created")
param_dict = paddle.load(last_model_dir)
model.load_dict(param_dict)
print("get_test_image!")
test_infor, test_input=get_test_image(image_size)
print("test infor gotten!")
test(model, test_infor, test_input ,image_size)<jupyter_output>model created
get_test_image!
0.0% finished
12.5% finished
25.0% finished
37.5% finished
50.0% finished
62.5% finished
75.0% finished
87.5% finished
100% finished
test infor gotten!
test_start
{'fraction_non_alphanumeric': 0.1459025787965616, 'fraction_numerical': 0.03507163323782235, 'mean_word_length': 3.458865610628513, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 11, 'https://': 2, 'lorem ipsum': 0, 'www.': 1, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 5, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '3', 'dir': 'jupyter-structured-clean-dedup', 'id': '291417', 'license': 'Apache-2.0', 'n_tokens_mistral': 4102, 'n_tokens_neox': 4105, 'n_words': 459, 'path': 'PALM.ipynb', 'repo_name': 'Liyulingyue/Paddle-PALM-locate-2021-7', 'size': '8725'}