项目背景

教育学和心理学的研究表明,幼儿的阅读能力对认知能力的发展影响最大,尤其是0—6岁阶段的早期阅读能力,是影响幼儿未来学习能力和水平的关键。

可是如今,快餐式媒体信息的爆发,导致儿童的精神世界日益匮乏。很多六七岁的儿童只知道流行动画片里的人物,每天刷短视频、玩游戏,与书中精彩纷呈世界的距离却越来越遥远。对智能手机、平板电脑的过度依赖不仅严重影响儿童的视力,更扼杀了他们的精神世界。因而,越来越多的家长选择回归传统的教育模式,以书籍作为培养儿童阅读能力的主要途径。

然而,不论是纸质书籍还是电子产品,都存在着许多问题。第一,纸质书籍仅有图画和文字,缺少声音的辅助,且由于识字不多,学龄前儿童难以独立阅读。而家长们往往并没有太多时间陪同儿童阅读书本,无法带领其领略书中那精彩纷呈的世界。第二,对于儿童而言,电子产品中的有声媒体(如动画片)虽更易接受,但其显示效果与书籍差异较大,长时间注视背光液晶屏的会严重影响儿童的视力健康,不利于儿童良好阅读习惯的培养。此外,现有的电子书产品缺少针对儿童开发的图画、文字与声音同步显示功能,亦无法根据学龄前儿童的个人喜好为其推荐个性化图书,且大多数产品的外型不适合儿童使用。

如图,针对于市面上目前存在的各种可供儿童阅读的用具的缺点,我们需要一种既能够为儿童提供视觉、听觉等多感官阅读体验,激发儿童阅读兴趣,还能够根据儿童阅读兴趣进行个性化推荐,培养儿童阅读能力,更能够保护儿童健康视力的阅读途径。

技术方案

1. 技术方向

为更好地了解儿童的阅读兴趣,并根据儿童阅读习惯计算并推荐适合儿童阅读的书籍,培养儿童的阅读能力。本作品采用人工智能推荐算法。推荐算法使用工业界广泛应用、推荐效果十分优秀的DSSM双塔模型

2. 技术平台及方案

  • 技术平台

本作品基于百度飞桨平台进行人工智能推荐算法开发,在飞桨平台中构建基于深度学习的推荐算法

  • 技术方案

①控制电路介绍

②屏幕显示

屏幕上上使用电子墨水屏模块,6英寸,分辨率为1448×1072,使用IT8951作为控制器,使用SPI接口进行控制。具有功耗低、视角宽、阳光直射下仍可清晰显示等优点。

③音频

采用WM8960低功耗立体声编解码器,通过I2C接口控制,I2S接口传输音频。板载标准3.5mm耳机接口,可通过外接耳机播放音乐,同时也可通过双通道喇叭接口外接喇叭播放。采用多线程控制保证视频音频同步播放。

④按键电路

使用按键中断完成翻页、换书、音量控制等功能的实现,对按键上拉输入树莓派,按下按键时候检测到下降沿,经过延时防抖后接入按键中断。

⑤云技术

本作品采用云技术,能够不断更新书库资源。此外,当儿童阅读书籍时,其阅读信息传输至云端服务器,云端部署有推荐算法,对数据进行训练生成个性化推荐模型,并将该用户个性化推荐结果传输至树莓派,从而完成个性化阅读书籍的推荐。

3. 数据获取及处理途径

通过构建user和item两个独立的子网络,将训练好的两个“塔”中的user embedding 和item embedding各自缓存到内存数据库中。线上预测的时候只需要在内存中进行相似度运算即可。

在我们的书籍推荐算法中,数据集主要分为三个文件,分别为用户数据文件书籍数据文件评分数据文件。用户数据文件的数据格式为用户序号、性别、年龄。
书籍数据文件中数据格式为书籍序号、书籍标题、书籍种类。评分数据文件中数据格式为用户序号、书籍序号、用户评分。

通过以下过程得到各特征之间的相似度:

①分别将用户、书籍的多个特征数据转换成特征向量。

②对这些特征向量,使用全连接层进一步提取特征。

③将用户、书籍多个数据的特征向量融合成一个向量表示,方便进行相似度计算。

④计算特征之间的相似度。

根据用户的阅读历史记录、收藏等,能够将这些用户原始数据传输至云服务器,云服务器使用上述推荐算法进行训练,得到用户的阅读特征,并在我们现有书库中进行特征匹配,为用户进行个性化推荐。根据推荐结果将相关图书传输至用户使用端。

创新亮点

1. 互联网+个性化推荐

我们的作品基于大数据、云计算等先进技术。在未来我们的书库计划设立近万本图书,并且根据儿童对于不同类别的书观看的时间进行处理,迅速判断儿童喜欢什么样类别的书籍,并且根据其喜爱类别推荐下一本书籍,让其真正喜爱上阅读。

2. 高稳定性阅读环境

我们的作品使用了C语言进行开发,采用树莓派作为整体的开发环境,使用3d打印技术完成了作品外壳,令其具有较高的稳定性,适合长时间的观看。

3. 原生态纸张显示效果

与传统阅读器不同,我们的作品使用了墨水屏,相较于传统屏幕,墨水屏显示效果接近传统纸张。这能够让儿童更加适应传统的纸质书籍,也能够切实有效地保护儿童的眼睛。

4. 按键式操作布局—更适宜儿童

根据学龄前儿童不易操作电子产品的特点,我们初步没有采用触屏方案,相对的,我们采用了按键进行控制。一方面,按键相对于触屏来说更为简单易用,另一方面,按键也能让家长更方便的控制儿童使用本作品的时间。

5. 多感官阅读—提供更优质的阅读

与市面上的其他产品不同,我们的阅读文件采用了插画+文字+声音的形式,相较于文字,一幅幅精美的原创插画更能够起儿童的兴趣。耳边是温柔的故事,眼中是精美的图画。配合着文字,一幅幅生动的画卷徐徐展开。我们希望能在孩子们的心中树立起对于书本的美好印象,让他们真正的爱上读书。

配套代码

1. 数据处理

数据集主要分为三个文件,分别为 user.dat、book.dat、ratings.dat文件

  • 用户数据文件user.dat中的数据格式为:UserID::Gender::Age,分别代表其用户序号、性别、年龄

  • 书籍数据文件book.dat中数据格式为:BookID::BookTitle::BookCat,分别代表书籍序号、书籍标题、书籍种类

  • 评分数据文件ratings.dat中数据格式为:UserID::BookID::Rating,分别代表用户序号、书籍序号、用户评分

import paddle
from paddle.nn import Linear, Embedding, Conv2D
import paddle.nn.functional as F
import math
import random
import numpy as np
from PIL import Image
import mathclass BookLen(object):def __init__(self, use_poster):self.use_poster = use_poster# 声明每个数据文件的路径usr_info_path = "./work/user.dat"if use_poster:rating_path = "./work/new_rating.txt"else:rating_path = "./work/ratings.dat"book_info_path = "./work/book.dat"self.poster_path = "./work/posters/"# 得到书籍数据self.book_info, self.book_cat, self.book_title = self.get_book_info(book_info_path)# 记录书籍的最大IDself.max_book_cat = np.max([self.book_cat[k] for k in self.book_cat])self.max_book_tit = np.max([self.book_title[k] for k in self.book_title])self.max_book_id = np.max(list(map(int, self.book_info.keys())))# 记录用户数据的最大IDself.max_usr_id = 0self.max_usr_age = 0self.max_usr_job = 0# 得到用户数据self.usr_info = self.get_usr_info(usr_info_path)# 得到评分数据self.rating_info = self.get_rating_info(rating_path)# 构建数据集self.dataset = self.get_dataset(usr_info=self.usr_info,rating_info=self.rating_info,book_info=self.book_info)# 划分数据集,获得数据加载器self.train_dataset = self.dataset[:int(len(self.dataset)*0.9)]self.valid_dataset = self.dataset[int(len(self.dataset)*0.9):]print("##Total dataset instances: ", len(self.dataset))print("##BookLens dataset information: \nusr num: {}\n""book num: {}".format(len(self.usr_info),len(self.book_info)))# 得到书籍数据def get_book_info(self, path):# 打开文件,读取所有数据到data中with open(path, 'r') as f:data = f.readlines()# 建立三个字典,分别用户存放书籍所有信息,书籍的名字信息、类别信息book_info, book_titles, book_cat = {}, {}, {}# 对书籍名字、类别中不同的文字计数t_count, c_count = 1, 1count_tit = {}# 按行读取数据并处理for item in data:item = item.strip().split("::")v_id = item[0]v_title = item[1]cats = item[2].split('|')# titles = v_title.split()# 统计书籍名字的汉字,并给每个汉字一个序号,放在book_titles中for t in v_title:if t not in book_titles:book_titles[t] = t_countt_count += 1# 统计书籍类别单词,并给每个单词一个序号,放在book_cat中for cat in cats:if cat not in book_cat:book_cat[cat] = c_countc_count += 1# 补0使书籍名称对应的列表长度为12v_tit = [book_titles[k] for k in v_title]while len(v_tit)<12:v_tit.append(0)# 补0使电影种类对应的列表长度为3v_cat = [book_cat[k] for k in cats]while len(v_cat)<3:v_cat.append(0)# 保存电影数据到book_info中book_info[v_id] = {'book_id': int(v_id),'title': v_tit,'category': v_cat}return book_info, book_cat, book_titlesdef get_usr_info(self, path):# 性别转换函数,M-0, F-1def gender2num(gender):return 1 if gender == 'F' else 0# 打开文件,读取所有行到data中with open(path, 'r') as f:data = f.readlines()# 建立用户信息的字典use_info = {}max_usr_id = 0#按行索引数据for item in data:# 去除每一行中和数据无关的部分item = item.strip().split("::")usr_id = item[0]# 将字符数据转成数字并保存在字典中use_info[usr_id] = {'usr_id': int(usr_id),'gender': gender2num(item[1]),'age': int(item[2])}self.max_usr_id = max(self.max_usr_id, int(usr_id))self.max_usr_age = max(self.max_usr_age, int(item[2]))# self.max_usr_job = max(self.max_usr_job, int(item[3]))return use_info# 得到评分数据def get_rating_info(self, path):# 读取文件里的数据with open(path, 'r') as f:data = f.readlines()# 将数据保存在字典中并返回rating_info = {}for item in data:item = item.strip().split("::")usr_id,book_id,score = item[0],item[1],item[2]if usr_id not in rating_info.keys():rating_info[usr_id] = {book_id:float(score)}else:rating_info[usr_id][book_id] = float(score)return rating_info# 构建数据集def get_dataset(self, usr_info, rating_info, book_info):trainset = []for usr_id in rating_info.keys():usr_ratings = rating_info[usr_id]for book_id in usr_ratings:trainset.append({'usr_info': usr_info[usr_id],'book_info': book_info[book_id],'scores': usr_ratings[book_id]})return trainsetdef load_data(self, dataset=None, mode='train'):use_poster = False# 定义数据迭代Batch大小BATCHSIZE = 10data_length = len(dataset)index_list = list(range(data_length))# 定义数据迭代加载器def data_generator():# 训练模式下,打乱训练数据if mode == 'train':random.shuffle(index_list)# 声明每个特征的列表usr_id_list,usr_gender_list,usr_age_list = [], [], []book_id_list,book_tit_list,book_cat_list,book_poster_list = [], [], [], []score_list = []# 索引遍历输入数据集for idx, i in enumerate(index_list):# 获得特征数据保存到对应特征列表中usr_id_list.append(dataset[i]['usr_info']['usr_id'])usr_gender_list.append(dataset[i]['usr_info']['gender'])usr_age_list.append(dataset[i]['usr_info']['age'])book_id_list.append(dataset[i]['book_info']['book_id'])book_tit_list.append(dataset[i]['book_info']['title'])book_cat_list.append(dataset[i]['book_info']['category'])book_id = dataset[i]['book_info']['book_id']if use_poster:# 不使用图像特征时,不读取图像数据,加快数据读取速度poster = Image.open(self.poster_path+'book_id{}.jpg'.format(str(mov_id[0])))poster = poster.resize([64, 64])if len(poster.size) <= 2:poster = poster.convert("RGB")mov_poster_list.append(np.array(poster))score_list.append(int(dataset[i]['scores']))# 如果读取的数据量达到当前的batch大小,就返回当前批次if len(usr_id_list)==BATCHSIZE:# 转换列表数据为数组形式,reshape到固定形状usr_id_arr = np.array(usr_id_list)usr_gender_arr = np.array(usr_gender_list)usr_age_arr = np.array(usr_age_list)book_id_arr = np.array(book_id_list)book_cat_arr = np.reshape(np.array(book_cat_list), [BATCHSIZE, 3]).astype(np.int64)book_tit_arr = np.reshape(np.array(book_tit_list), [BATCHSIZE, 1, 12]).astype(np.int64)if use_poster:book_poster_arr = np.reshape(np.array(mov_poster_list)/127.5 - 1, [BATCHSIZE, 3, 64, 64]).astype(np.float32)else:mov_poster_arr = np.array([0.])scores_arr = np.reshape(np.array(score_list), [-1, 1]).astype(np.float32)# 放回当前批次数据yield [usr_id_arr, usr_gender_arr, usr_age_arr], \[book_id_arr, book_cat_arr, book_tit_arr], scores_arr# 清空数据usr_id_list, usr_gender_list, usr_age_list = [], [], []book_id_list, book_tit_list, book_cat_list, score_list = [], [], [], []book_poster_list = []return data_generator

2. 模型设计

神经网络模型的设计包含如下步骤:

  • 分别将用户、书籍的多个特征数据转换成特征向量。

  • 对这些特征向量,使用全连接层或者卷积层进一步提取特征。

  • 将用户、书籍多个数据的特征向量融合成一个向量表示,方便进行相似度计算。

  • 计算特征之间的相似度。

class Model(paddle.nn.Layer):def __init__(self, use_poster, use_book_title, use_book_cat, use_age_job,fc_sizes):super(Model, self).__init__()# 将传入的name信息和bool型参数添加到模型类中self.use_book_poster = use_posterself.use_book_title = use_book_titleself.use_usr_age_job = use_age_jobself.use_book_cat = use_book_catself.fc_sizes=fc_sizes# 获取数据集的信息,并构建训练和验证集的数据迭代器Dataset = BookLen(self.use_book_poster)self.Dataset = Datasetself.trainset = self.Dataset.train_datasetself.valset = self.Dataset.valid_datasetself.train_loader = self.Dataset.load_data(dataset=self.trainset, mode='train')self.valid_loader = self.Dataset.load_data(dataset=self.valset, mode='valid')usr_embedding_dim=32gender_embeding_dim=16age_embedding_dim=16# job_embedding_dim=16book_embedding_dim=16category_embedding_dim=16title_embedding_dim=32""" define network layer for embedding usr info """USR_ID_NUM = Dataset.max_usr_id + 1# 对用户ID做映射,并紧接着一个Linear层self.usr_emb = Embedding(num_embeddings=USR_ID_NUM, embedding_dim=usr_embedding_dim, sparse=False)self.usr_fc = Linear(in_features=usr_embedding_dim, out_features=32)# 对用户性别信息做映射,并紧接着一个Linear层USR_GENDER_DICT_SIZE = 2self.usr_gender_emb = Embedding(num_embeddings=USR_GENDER_DICT_SIZE, embedding_dim=gender_embeding_dim)self.usr_gender_fc = Linear(in_features=gender_embeding_dim, out_features=16)# 对用户年龄信息做映射,并紧接着一个Linear层USR_AGE_DICT_SIZE = Dataset.max_usr_age + 1self.usr_age_emb = Embedding(num_embeddings=USR_AGE_DICT_SIZE, embedding_dim=age_embedding_dim)self.usr_age_fc = Linear(in_features=age_embedding_dim, out_features=16)# # 对用户职业信息做映射,并紧接着一个Linear层# USR_JOB_DICT_SIZE = Dataset.max_usr_job + 1# self.usr_job_emb = Embedding(num_embeddings=USR_JOB_DICT_SIZE, embedding_dim=job_embedding_dim)# self.usr_job_fc = Linear(in_features=job_embedding_dim, out_features=16)# 新建一个Linear层,用于整合用户数据信息self.usr_combined = Linear(in_features=64, out_features=200)""" define network layer for embedding usr info """# 对书籍ID信息做映射,并紧接着一个Linear层BOOK_DICT_SIZE = Dataset.max_book_id + 1self.book_emb = Embedding(num_embeddings=BOOK_DICT_SIZE, embedding_dim=book_embedding_dim)self.book_fc = Linear(in_features=book_embedding_dim, out_features=32)# 对书籍类别做映射CATEGORY_DICT_SIZE = len(Dataset.book_cat) + 1self.book_cat_emb = Embedding(num_embeddings=CATEGORY_DICT_SIZE, embedding_dim=category_embedding_dim, sparse=False)self.book_cat_fc = Linear(in_features=category_embedding_dim, out_features=32)# 对书籍名称做映射BOOK_TITLE_DICT_SIZE = len(Dataset.book_title) + 1self.book_title_emb = Embedding(num_embeddings=BOOK_TITLE_DICT_SIZE, embedding_dim=title_embedding_dim, sparse=False)self.book_title_conv = Conv2D(in_channels=1, out_channels=1, kernel_size=(3, 1), stride=(2,1), padding=0)self.book_title_conv2 = Conv2D(in_channels=1, out_channels=1, kernel_size=(3, 1), stride=1, padding=0)# 新建一个Linear层,用于整合书籍特征self.book_concat_embed = Linear(in_features=96, out_features=200)user_sizes = [200] + self.fc_sizesacts = ["relu" for _ in range(len(self.fc_sizes))]self._user_layers = []for i in range(len(self.fc_sizes)):linear = paddle.nn.Linear(in_features=user_sizes[i],out_features=user_sizes[i + 1],weight_attr=paddle.ParamAttr(initializer=paddle.nn.initializer.Normal(std=1.0 / math.sqrt(user_sizes[i]))))self.add_sublayer('linear_user_%d' % i, linear)self._user_layers.append(linear)if acts[i] == 'relu':act = paddle.nn.ReLU()self.add_sublayer('user_act_%d' % i, act)self._user_layers.append(act)#书籍特征和用户特征使用了不同的全连接层,不共享参数book_sizes = [200] + self.fc_sizesacts = ["relu" for _ in range(len(self.fc_sizes))]self._book_layers = []for i in range(len(self.fc_sizes)):linear = paddle.nn.Linear(in_features=book_sizes[i],out_features=book_sizes[i + 1],weight_attr=paddle.ParamAttr(initializer=paddle.nn.initializer.Normal(std=1.0 / math.sqrt(book_sizes[i]))))self.add_sublayer('linear_book_%d' % i, linear)self._book_layers.append(linear)if acts[i] == 'relu':act = paddle.nn.ReLU()self.add_sublayer('book_act_%d' % i, act)self._book_layers.append(act)# 定义计算用户特征的前向运算过程def get_usr_feat(self, usr_var):""" get usr features"""# 获取到用户数据usr_id, usr_gender, usr_age = usr_var# 将用户的ID数据经过embedding和Linear计算,得到的特征保存在feats_collect中feats_collect = []usr_id = self.usr_emb(usr_id)usr_id = self.usr_fc(usr_id)usr_id = F.relu(usr_id)feats_collect.append(usr_id)# 计算用户的性别特征,并保存在feats_collect中usr_gender = self.usr_gender_emb(usr_gender)usr_gender = self.usr_gender_fc(usr_gender)usr_gender = F.relu(usr_gender)feats_collect.append(usr_gender)# 选择是否使用用户的年龄-职业特征if self.use_usr_age_job:# 计算用户的年龄特征,并保存在feats_collect中usr_age = self.usr_age_emb(usr_age)usr_age = self.usr_age_fc(usr_age)usr_age = F.relu(usr_age)feats_collect.append(usr_age)# # 计算用户的职业特征,并保存在feats_collect中# usr_job = self.usr_job_emb(usr_job)# usr_job = self.usr_job_fc(usr_job)# usr_job = F.relu(usr_job)# feats_collect.append(usr_job)# 将用户的特征级联,并通过Linear层得到最终的用户特征usr_feat = paddle.concat(feats_collect, axis=1)user_features = F.tanh(self.usr_combined(usr_feat))#通过3层全链接层,获得用于计算相似度的用户特征和书籍特征for n_layer in self._user_layers:user_features = n_layer(user_features)return user_features# 定义书籍特征的前向计算过程def get_book_feat(self, book_var):""" get book features"""# 获得书籍数据book_id, book_cat, book_title = book_varfeats_collect = []# 获得batchsize的大小batch_size = book_id.shape[0]# 计算书籍ID的特征,并存在feats_collect中book_id = self.book_emb(book_id)book_id = self.book_fc(book_id)book_id = F.relu(book_id)feats_collect.append(book_id)# 如果使用书籍的种类数据,计算书籍种类特征的映射if self.use_book_cat:# 计算书籍种类的特征映射,对多个种类的特征求和得到最终特征book_cat = self.book_cat_emb(book_cat)book_cat = paddle.sum(book_cat, axis=1, keepdim=False)book_cat = self.book_cat_fc(book_cat)feats_collect.append(book_cat)if self.use_book_title:# 计算书籍名字的特征映射,对特征映射使用卷积计算最终的特征book_title = self.book_title_emb(book_title)book_title = F.relu(self.book_title_conv2(F.relu(self.book_title_conv(book_title))))book_title = paddle.sum(book_title, axis=2, keepdim=False)book_title = F.relu(book_title)book_title = paddle.reshape(book_title, [batch_size, -1])feats_collect.append(book_title)# 使用一个全连接层,整合所有书籍特征,映射为一个200维的特征向量book_feat = paddle.concat(feats_collect, axis=1)book_features = F.tanh(self.book_concat_embed(book_feat))for n_layer in self._book_layers:book_features = n_layer(book_features)return book_features# 定义个性化推荐算法的前向计算def forward(self, usr_var, book_var):# 计算用户特征和书籍特征user_features = self.get_usr_feat(usr_var)book_features = self.get_book_feat(book_var)# 根据计算的特征计算相似度sim = F.common.cosine_similarity(user_features, book_features).reshape([-1, 1])#使用余弦相似度算子,计算用户和书籍的相似程度# sim = F.cosine_similarity(user_features, book_features, axis=1).reshape([-1, 1])# 将相似度扩大范围到和书籍评分相同数据范围res = paddle.scale(sim, scale=5)return user_features, book_features, res

3. 模型训练

def train(model):# 配置训练参数lr = 0.001Epoches = 100#开启GPUuse_gpu = Falsepaddle.set_device('gpu:0') if use_gpu else paddle.set_device('cpu')# 启动训练model.train()# 获得数据读取器data_loader = model.train_loader# 使用adam优化器,学习率使用0.01opt = paddle.optimizer.Adam(learning_rate=lr, parameters=model.parameters())for epoch in range(0, Epoches):for idx, data in enumerate(data_loader()):# 获得数据,并转为tensor格式usr, book, score = datausr_v = [paddle.to_tensor(var) for var in usr]book_v = [paddle.to_tensor(var) for var in book]scores_label = paddle.to_tensor(score)# 计算出算法的前向计算结果_, _, scores_predict = model(usr_v, book_v)# 计算lossloss = F.square_error_cost(scores_predict, scores_label)avg_loss = paddle.mean(loss)if idx % 1000 == 0:print("epoch: {}, batch_id: {}, loss is: {}".format(epoch, idx, avg_loss.numpy()))# 损失函数下降,并清除梯度avg_loss.backward()opt.step()opt.clear_grad()# 每10个epoch 保存一次模型if epoch % 10 == 0:paddle.save(model.state_dict(), './checkpoint/epoch'+str(epoch)+'.pdparams')# 启动训练
fc_sizes=[128, 64, 32]
use_poster, use_book_title, use_book_cat, use_age_job = False, True, True, True
model = Model(use_poster, use_book_title, use_book_cat, use_age_job, fc_sizes)
train(model)
##Total dataset instances:  622
##BookLens dataset information:
usr num: 120
book num: 292
epoch: 0, batch_id: 0, loss is: [4.17028]
epoch: 1, batch_id: 0, loss is: [1.9047146]
epoch: 2, batch_id: 0, loss is: [0.7461074]
epoch: 3, batch_id: 0, loss is: [1.5499896]
epoch: 4, batch_id: 0, loss is: [1.5756546]
epoch: 5, batch_id: 0, loss is: [1.5339775]
epoch: 6, batch_id: 0, loss is: [0.48119536]
epoch: 7, batch_id: 0, loss is: [2.130187]
epoch: 8, batch_id: 0, loss is: [0.7817024]
epoch: 9, batch_id: 0, loss is: [0.46116963]
epoch: 10, batch_id: 0, loss is: [0.83575314]
epoch: 11, batch_id: 0, loss is: [0.21608064]
epoch: 12, batch_id: 0, loss is: [0.3550441]
epoch: 13, batch_id: 0, loss is: [0.18410006]
epoch: 14, batch_id: 0, loss is: [0.32895657]
epoch: 15, batch_id: 0, loss is: [0.22927241]
epoch: 16, batch_id: 0, loss is: [0.17777193]
epoch: 17, batch_id: 0, loss is: [0.42232656]
epoch: 18, batch_id: 0, loss is: [0.26365492]
epoch: 19, batch_id: 0, loss is: [0.11804922]
epoch: 20, batch_id: 0, loss is: [0.15374365]
epoch: 21, batch_id: 0, loss is: [0.07359996]
epoch: 22, batch_id: 0, loss is: [0.15296113]
epoch: 23, batch_id: 0, loss is: [0.07737824]
epoch: 24, batch_id: 0, loss is: [0.08948071]
epoch: 25, batch_id: 0, loss is: [0.0607689]
epoch: 26, batch_id: 0, loss is: [0.1715309]
epoch: 27, batch_id: 0, loss is: [0.1659071]
epoch: 28, batch_id: 0, loss is: [0.08382701]
epoch: 29, batch_id: 0, loss is: [0.03567206]
epoch: 30, batch_id: 0, loss is: [0.13538584]
epoch: 31, batch_id: 0, loss is: [0.06940095]
epoch: 32, batch_id: 0, loss is: [0.09211605]
epoch: 33, batch_id: 0, loss is: [0.07237571]
epoch: 34, batch_id: 0, loss is: [0.02138581]
epoch: 35, batch_id: 0, loss is: [0.02448878]
epoch: 36, batch_id: 0, loss is: [0.12813365]
epoch: 37, batch_id: 0, loss is: [0.15136755]
epoch: 38, batch_id: 0, loss is: [0.0616869]
epoch: 39, batch_id: 0, loss is: [0.06575496]
epoch: 40, batch_id: 0, loss is: [0.07189639]
epoch: 41, batch_id: 0, loss is: [0.04775456]
epoch: 42, batch_id: 0, loss is: [0.01638624]
epoch: 43, batch_id: 0, loss is: [0.03363843]
epoch: 44, batch_id: 0, loss is: [0.02819246]
epoch: 45, batch_id: 0, loss is: [0.02556055]
epoch: 46, batch_id: 0, loss is: [0.0485466]
epoch: 47, batch_id: 0, loss is: [0.14426994]
epoch: 48, batch_id: 0, loss is: [0.00691183]
epoch: 49, batch_id: 0, loss is: [0.07448427]
epoch: 50, batch_id: 0, loss is: [0.06333739]
epoch: 51, batch_id: 0, loss is: [0.05606419]
epoch: 52, batch_id: 0, loss is: [0.02504155]
epoch: 53, batch_id: 0, loss is: [0.06804784]
epoch: 54, batch_id: 0, loss is: [0.06871384]
epoch: 55, batch_id: 0, loss is: [0.07204606]
epoch: 56, batch_id: 0, loss is: [0.0304878]
epoch: 57, batch_id: 0, loss is: [0.0189317]
epoch: 58, batch_id: 0, loss is: [0.03077856]
epoch: 59, batch_id: 0, loss is: [0.07299428]
epoch: 60, batch_id: 0, loss is: [0.05836454]
epoch: 61, batch_id: 0, loss is: [0.06750873]
epoch: 62, batch_id: 0, loss is: [0.06627946]
epoch: 63, batch_id: 0, loss is: [0.02012284]
epoch: 64, batch_id: 0, loss is: [0.04086507]
epoch: 65, batch_id: 0, loss is: [0.01258313]
epoch: 66, batch_id: 0, loss is: [0.02361046]
epoch: 67, batch_id: 0, loss is: [0.02590574]
epoch: 68, batch_id: 0, loss is: [0.05788648]
epoch: 69, batch_id: 0, loss is: [0.13692534]
epoch: 70, batch_id: 0, loss is: [0.04251902]
epoch: 71, batch_id: 0, loss is: [0.02980524]
epoch: 72, batch_id: 0, loss is: [0.03573945]
epoch: 73, batch_id: 0, loss is: [0.04036443]
epoch: 74, batch_id: 0, loss is: [0.02487365]
epoch: 75, batch_id: 0, loss is: [0.16449247]
epoch: 76, batch_id: 0, loss is: [0.01489545]
epoch: 77, batch_id: 0, loss is: [0.03338253]
epoch: 78, batch_id: 0, loss is: [0.03407313]
epoch: 79, batch_id: 0, loss is: [0.02788509]
epoch: 80, batch_id: 0, loss is: [0.01425998]
epoch: 81, batch_id: 0, loss is: [0.05642505]
epoch: 82, batch_id: 0, loss is: [0.0104793]
epoch: 83, batch_id: 0, loss is: [0.01036843]
epoch: 84, batch_id: 0, loss is: [0.0570774]
epoch: 85, batch_id: 0, loss is: [0.0096895]
epoch: 86, batch_id: 0, loss is: [0.02637998]
epoch: 87, batch_id: 0, loss is: [0.01522477]
epoch: 88, batch_id: 0, loss is: [0.03692281]
epoch: 89, batch_id: 0, loss is: [0.04502665]
epoch: 90, batch_id: 0, loss is: [0.0479662]
epoch: 91, batch_id: 0, loss is: [0.08084913]
epoch: 92, batch_id: 0, loss is: [0.01147039]
epoch: 93, batch_id: 0, loss is: [0.02813186]
epoch: 94, batch_id: 0, loss is: [0.03969964]
epoch: 95, batch_id: 0, loss is: [0.01681328]
epoch: 96, batch_id: 0, loss is: [0.03814338]
epoch: 97, batch_id: 0, loss is: [0.03696106]
epoch: 98, batch_id: 0, loss is: [0.03102725]
epoch: 99, batch_id: 0, loss is: [0.02521455]

4. 模型评估

#使用验证集评估
from math import sqrt
def evaluation(model, params_file_path):model_state_dict = paddle.load(params_file_path)model.load_dict(model_state_dict)model.eval()acc_set = []avg_loss_set = []squaredError=[]for idx, data in enumerate(model.valid_loader()):usr, book, score_label = datausr_v = [paddle.to_tensor(var) for var in usr]book_v = [paddle.to_tensor(var) for var in book]_, _, scores_predict = model(usr_v, book_v)pred_scores = scores_predict.numpy()avg_loss_set.append(np.mean(np.abs(pred_scores - score_label)))squaredError.extend(np.abs(pred_scores - score_label)**2)diff = np.abs(pred_scores - score_label)diff[diff>0.5] = 1acc = 1 - np.mean(diff)acc_set.append(acc)RMSE=sqrt(np.sum(squaredError) / len(squaredError))return np.mean(acc_set), np.mean(avg_loss_set),RMSEparam_path = "./checkpoint/epoch"
for i in range(10, 100, 10):acc, mae,RMSE = evaluation(model, param_path+str(i)+'.pdparams')print("ACC:", acc, "MAE:", mae,'RMSE:',RMSE)
ACC: 0.17182029287020364 MAE: 1.1997116 RMSE: 1.475322158028782
ACC: 0.19211931029955545 MAE: 1.2133589 RMSE: 1.507057456814861
ACC: 0.17072982589403787 MAE: 1.2733771 RMSE: 1.5482858511081008
ACC: 0.16275082031885782 MAE: 1.2313476 RMSE: 1.5054256225173135
ACC: 0.16929025451342264 MAE: 1.2491957 RMSE: 1.5280627237331459
ACC: 0.18736409147580466 MAE: 1.2148415 RMSE: 1.4847097347358071
ACC: 0.21810143192609152 MAE: 1.1934332 RMSE: 1.476677805655484
ACC: 0.20665311813354492 MAE: 1.2063422 RMSE: 1.4829182647727908
ACC: 0.19917185107866922 MAE: 1.2284497 RMSE: 1.5081138718140858

5. 推荐范例

import pickle
# 定义根据用户兴趣推荐电影
def recommend_book_for_usr(usr_id, top_k, pick_num, usr_feat_dir, book_feat_dir, book_info_path):assert pick_num <= top_k# 读取电影和用户的特征usr_feats = pickle.load(open(usr_feat_dir, 'rb'))book_feats = pickle.load(open(book_feat_dir, 'rb'))usr_feat = usr_feats[str(usr_id)]cos_sims = []# with dygraph.guard():paddle.disable_static()# 索引电影特征,计算和输入用户ID的特征的相似度for idx, key in enumerate(book_feats.keys()):book_feat = book_feats[key]usr_feat = paddle.to_tensor(usr_feat)book_feat = paddle.to_tensor(book_feat)# 计算余弦相似度sim = paddle.nn.functional.common.cosine_similarity(usr_feat, book_feat)cos_sims.append(sim.numpy()[0])# 对相似度排序index = np.argsort(cos_sims)[-top_k:]book_info = {}# 读取电影文件里的数据,根据电影ID索引到电影信息with open(book_info_path, 'r') as f:data = f.readlines()for item in data:item = item.strip().split("::")book_info[str(item[0])] = itemprint("当前的用户是:")print("usr_id:", usr_id)print("推荐可能喜欢的电影是:")res = []# 加入随机选择因素,确保每次推荐的都不一样while len(res) < pick_num:val = np.random.choice(len(index), 1)[0]idx = index[val]book_id = list(book_feats.keys())[idx]if book_id not in res:res.append(book_id)for id in res:print("book_id:", id, book_info[str(id)])book_data_path = "./work/book.dat"
top_k, pick_num = 10, 6
usr_id = 2
recommend_book_for_usr(usr_id, top_k, pick_num, './work/usr_feat.pkl', './work/book_feat.pkl', book_data_path)
当前的用户是:
usr_id: 2
推荐可能喜欢的电影是:
book_id: 160 ['160', '神们自己', '科幻']
book_id: 181 ['181', '红星照耀中国', '历史']
book_id: 184 ['184', '覆雨翻云', '武侠']
book_id: 26 ['26', '铁剑红颜', '武侠']
book_id: 182 ['182', '明日杀机', '科幻']
book_id: 108 ['108', '快乐王子', '王尔德童话']

问题分析

通过对现有市场及产品的细致观察与分析,我们团队的成员总结并发现了诸多问题,以下列举四个主要问题:

1. 市面上的电子产品多半采用LCD作为显示媒介

LCD 的构造是在两片平行的玻璃基板当中放置液晶盒,下基板玻璃上设置TFT(薄膜晶体管),上基板玻璃上设置彩色滤光片,通过TFT上的信号与电压改变来控制液晶分子的转动方向,从而达到控制每个像素点偏振光出射与否而达到显示目的。LCD的特性就决定了其想要显示画面就必须拥有屏幕背光。这就使得在长时间使用这些设备的时候孩子的视力会被严重的损伤。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7J21dShu-1669557832329)(https://ai-studio-static-online.cdn.bcebos.com/8364a8eae91b4af8bfd3390214d486a6698351250e52499bbe0e424a2d81e3f3)]

2. 多媒体设备与书籍相差较大

学龄前儿童尚未形成自己对世界独立的认知。家长希望借助多媒体设备来培养孩子的阅读习惯,但最终很可能事与愿违,不但没有培养起孩子的阅读兴趣,反而加强了孩子对多媒体设备的依赖。

  • 多媒体设备在形态上与传统书籍相差较大,长期使用后,儿童易形成这些设备的肌肉记忆,导致其可能无法对传统书籍产生兴趣。

  • 多媒体设备的显示效果与繁多的功能更易加重儿童对其的依赖性。尤其随着近年来短视频平台的兴起,越来越多的儿童沉迷其中,往往数个小时无法脱身。久而久之,儿童与书籍之间的距离越来越远,从而难以养成阅读书籍的良好习惯。

3. 现有的儿童教育电子产品存在诸多问题

儿童早期阅读习惯的养成,与其对阅读的兴趣程度有着密不可分的关系。而良好的阅读环境与阅读体验,能极大地刺激儿童对阅读的兴趣。传统书籍虽然更利于儿童专注于阅读,不受多媒体设备中纷繁杂多的软件影响,但长久地注视于书籍的文墨,易造成儿童眼睛的疲劳,更易使儿童产生乏味感,从而渐渐失去对阅读的兴趣。因而,我们不仅应关注儿童的视觉体验,也要注重如听觉等方面的体验。随着时代的进步,越来越多的儿童早教产品涌入市场,而不少产品仍存在诸多问题,我们以早教市场常见的点读机、故事机、投影仪为例。

  • 点读机

点读机将儿童的视觉、触觉与听觉结合,使儿童能够多方位感知学习书籍中的内容。而点读机对文字的显示仍依赖于传统书籍,以书籍为媒介,为儿童提供文字知识的学习。这样的学习方式虽然为儿童带来了听觉效果,但在视觉上的呈现效果与传统书籍并无差别,这就导致其仅适用于拥有一定识字阅读基础的儿童,在受众人群上受到了不小的限制。此外,能够适用于某一款点读机的书籍往往是有限的,这与点读机识字效果的实现路径有着莫大的关系。这就导致儿童能从某一款点读机配套的书籍中学到的知识少之又少,想要学习更多的知识,又需要重新更换点读机的款式,这显然是不现实的。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PYLZurJD-1669557832329)(https://ai-studio-static-online.cdn.bcebos.com/38571fac86b44ab2aeb5959796bebbd2099ba7d86e484dd99dd7ca2bf50e10b4)]

  • 故事机

故事机着手于儿童的听觉体验效果,其受众人群较广,且一般体型较小,便于携带。但其定位往往仅作为一款能够讲故事的产品,缺乏对儿童视觉及触觉等方面的培养,因而不利于儿童阅读兴趣的产生及阅读习惯的养成。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aAMHvYWG-1669557832330)(https://ai-studio-static-online.cdn.bcebos.com/c3f9d22b89664306b95a11245c1174e92720b8bd96fe49a6a2efc902211c4dd4)]

  • 投影仪

投影仪的体验效果较好,一款好的投影仪能够为儿童带来身历其境的体验。但投影仪体型较大,不宜携带,这就导致其对使用场景要求较高,其往往仅能被安置在一个地方。此外,投影仪的操作过程较为繁琐,无法达到随时随地便捷使用的效果,对于年龄较小的儿童也仅能够在家长的陪护下使用投影仪,从而易导致儿童形成对其使用流程的厌烦。再者,缺乏了触觉方面的体验,不易培养儿童的自主动手能力,亦不利于其良好阅读习惯的形成。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KxeMqdjX-1669557832331)(https://ai-studio-static-online.cdn.bcebos.com/eb2e98cb6fb944d7893ca81bab81a89891f1946a959941b09d93050f1c896555)]

**4. 现有的儿童电子书产品无法根据儿童的个人喜好推荐图

现有的儿童电子书产品中的书籍种类及数量虽然多,但儿童在面临书籍选择的时候,往往要花费大量的时间去挑选出自己感兴趣的书籍。此外,年龄较小的儿童面对当今电子书产品中的书籍还不具备自主选择的能力,因而无法从中获得良好的阅读体验,更无法激起自身的阅读兴趣

创作思路

面对创作时所要解决的种种问题,我们的团队进行了数次讨论,每个人都提出了自己的想法与见解,每个环节我们都采用举手投票的方式进行选择。由于在创作时面临的问题与对应的解决思路较多,这里仅针对于上述四个主要问题进行说明。

1. 对于屏幕显示媒介,我们摒弃了传统的LCD及OLED,选择采用基于电子墨水显示技术的墨水屏

墨水屏是由两片基板组成,上面涂有一种由无数微小透明颗粒组成的电子墨水,颗粒由带正、负电的许多黑色和白色粒子密封于内部液态微胶囊内形成,不同颜色的带电粒子会因施加电场的不同,而朝不同的方向运动,在显示屏表面呈现出黑或白的效果。这样,在墨水屏的表面就可以显示出如同印物的黑白图案和文字,看起来与纸张极为类似,在阳光下没有传统液晶显示的反光现象。同时只有画素颜色变化时(例如从黑转到白)才耗电,关电源后显示屏上画面仍可保留。

得益于墨水屏优良的性能以及显示技术,我们的产品不仅拥有极佳的护眼效果,同时还兼备了功率低、耗电慢、续航好的特点。墨水屏能够尽最大可能还原纸质书籍的体验,更有利于儿童阅读习惯的养成。并且,相较于传统LCD或者OLED屏幕,墨水屏本身并不发光,切实保护了儿童的视力健康。也正是得益于墨水屏本身不需要额外的背光模块,我们产品的单次充电使用时长得到了极大的保证,儿童随时都能够使用我们的产品,感受阅读带来的快乐。

2. 对于产品外形及阅读环境,我们选择采用更贴近于书籍的外形与极简的阅读环境

我们的产品在大小上选择了介于如今市场上多数手机与平板二者的尺寸之间,大小及厚度更接近于传统书籍。

此外,为了避免诸如手机、平板中各式各样软件的干扰,我们在设计时始终坚持不添加多余的功能,尽可能设计出更适于儿童阅读的背景及功能,以“纯净”的阅读环境,为儿童提供更舒心、更便捷的阅读体验。

3. 对于当前市面上存在的儿童早教电子产品的诸多问题,我们选择在保证阅读器体型及便携性的同时,为儿童提供多种感官方面的体验效果

以第2个问题中的创作思路为基础,我们的阅读器体型适中,且便于携带,儿童随时随地都能够进行阅读。此外,墨水屏为儿童提供了护眼的视觉体验,双音响为儿童提供了立体的听觉体验,便捷操作的按键布局也为儿童提供了良好的触觉体验。在简易便捷的阅读环境的支持下,儿童能够更快地投入到阅读的氛围当中,多重感官的体验更潜移默化地培养了儿童的阅读兴趣,锻炼了儿童的自主阅读能力。

4. 对于多数儿童缺乏自主选择能力,保证图书选择的高效性及准确性,我们选择采用如今快速发展的云计算、大数据推荐算法等先进技术

我们的书库计划于未来设立近万本图书,对于儿童读物九大类别:生活认知、人际交往、品德品格、科普百科、生命教育、想象幻想、人文艺术、学习工具、益智游戏进行全方面覆盖,根据儿童对于不同类别书籍的观看时间进行计算,迅速判断出儿童感兴趣的书籍类别,从而为其推荐下一本书籍,更有利于对儿童阅读兴趣的维持,提高锻练其阅读能力的效率。具体云计算及推荐算法的实现路径,可以参考技术方案中的相关介绍。

应用前景

借助于“小书虫”儿童阅读器便携的特点,广大儿童可以在任何适于阅读的环境下打开阅读器进行阅读,如:在教室、图书馆、书桌前等等,避免了携带传统纸质版书籍的种种不便。

“小书虫”儿童阅读器能够多元化培养儿童在视觉、听觉、触觉方面的能力,更有效地激发儿童幼年时期的阅读兴趣,提高儿童的阅读水平,解决了传统纸质书籍单一培养识字阅读能力的问题。

此外,“小书虫”儿童阅读器是一款针对于儿童开发的阅读器,相较于智能手机及平板电脑,其阅读环境更纯净,操作性更简便,免去了众多复杂且不适于儿童使用的功能及软件。在提高儿童阅读效率的同时,在墨水护眼屏的加持下,更能有效保护儿童视力免受传统屏幕光线的侵害。

另一方面,凭借着人工智能推荐算法的核心技术,“小书虫”儿童阅读器更是解决了许多儿童“找书难”的问题——每当儿童阅读完一本书后,系统会根据儿童自身喜好快速推荐其他同类型的书籍,从而更有效地激发儿童的阅读兴趣。

“小书虫”儿童阅读器所具有的种种优点,在未来会有很大的发展空间,并拥有以下的潜在合作对象。

1. 学前教育机构

注重学前幼儿阅读素养养成的教育企业机构,格外注重儿童阅读媒介的选择。越来越多的教育企业机构将电子阅读器引入儿童的阅读过程中,致力于打造一个更生动、更便利、更有趣的阅读环境。而很多时候却面临着儿童阅读器的选择问题。现如今大多阅读器无法在提供多感官阅读训练的同时保护好儿童的视力,更无法针对性地提供个性化阅读建议。因而,学前教育机构将会是将来重要的合作对象。

2. 学校

为响应国家“全民阅读”的号召,很多学校将“阅读课”纳入日常的教学日常当中。然而,大多情况下,学校及教室并不了解儿童的阅读习惯及兴趣,无法有效督促学生投入到阅读的环境中。且由于担心学生分心,不专注于阅读及学习,大多学校禁止学生携带手机进入校园。面临形式单一的传统纸质书籍,许多学生无法集中注意力静心阅读,从而无法真正实现“阅读课”的目的与功效。因此,学校也会是将来的重要合作对象。

总结

通过以上的介绍,相信大家已经对“小书虫”儿童电子阅读器有了详细的了解:“小书虫”是一款针对性地面向学龄前儿童开发的电子阅读器,其基于云上人工智能推荐系统,通过对儿童阅读书籍种类的识别采集,总结出儿童的阅读兴趣及习惯,为儿童提供个性化阅读方案,并在儿童阅读完当前书籍时,自动为儿童推荐其可能感兴趣的书籍,从而持续性培养儿童的阅读能力。此外,本作品将电子纸显示技术与有声画书相结合,可以在培养儿童阅读习惯的同时,保护其视力免受传统LCD或OLED显示屏长时间照射的危害,减轻儿童的阅读负担,更有效地激发儿童阅读兴趣、锻练儿童阅读能力。

在未来,不论是学前教育辅导还是对儿童的阅读兴趣培养,“小书虫”儿童电子阅读器都有着极其广阔的应用前景。我们期待其在不久的将来,其能够面向广大儿童,改变儿童阅读领域的现状,真正让儿童发自内心地喜爱上阅读,领略阅读的无限魅力,更能够为我国儿童的视力健康带来改善。

此文章为搬运
原项目链接

基于飞桨的“小书虫”儿童电子阅读器相关推荐

  1. 赛桨PaddleScience v1.0 Beta:基于飞桨核心框架的科学计算通用求解器

    近年来,关于AI for Science的主题被广泛讨论,重点领域包含使用AI方法加速设计并发现新材料,助力高能物理及天文领域的新问题探索,以及加速智慧工业实时设备数据与模型的"数字孪生&q ...

  2. 搭建基于飞桨的OCR工具库,总模型仅8.6M的超轻量级中文OCR,单模型支持中英文数字组合识别、竖排文本识别、长文本识别的PaddleOCR

    介绍 基于飞桨的OCR工具库,包含总模型仅8.6M的超轻量级中文OCR,单模型支持中英文数字组合识别.竖排文本识别.长文本识别.同时支持多种文本检测.文本识别的训练算法. 相关链接 PaddleOCR ...

  3. 基于飞桨 DeepLabV3+实现人体肾组织图像中肾小球识别

    基于飞桨 DeepLabV3+实现人体肾组织图像中肾小球识别 一.项目背景 估计显示,地球上有超过70亿人,银河系中有3000亿颗恒星.相比之下,成年人体内含有37万亿个细胞.确定这些细胞之间的功能和 ...

  4. 基于飞桨实现高精度岩相自动分析,助力油气田勘探开发设计

    1. 概述 1.1 行业背景与痛点 岩相分析是以岩石薄片的微观描述和分类为基础的研究工作,也是沉积和成岩研究的一项重要技术,对于油气勘探开发的工程实践具有基础性指导地位.通过薄片分析矿物的比例.分布. ...

  5. 基于飞桨图像分类套件PaddleClas的柠檬分类竞赛实战

    前情提要   通过之前教程中的学习,相信大家对于如何搭建一个分类网络已经清晰了.那么我们不禁会想,有没有更快速的尝试模型及技巧的方法呢?因为我们在上一次课程中使用的代码都需要自己进行开发,自己写需要很 ...

  6. 强烈推荐 | 基于飞桨的五大目标检测模型实战详解

    机器视觉领域的核心问题之一就是目标检测(object detection),它的任务是找出图像当中所有感兴趣的目标(物体),确定其位置和大小.对于人类来说,目标检测是一个非常简单的任务.然而,计算机能 ...

  7. 基于飞桨的小样本学习工具包助你举一反三

    王雅晴,PaddleFSL负责人.飞桨高级开发者技术专家(高级PPDE).2019年博士毕业于香港科技大学计算机科学及工程学系.通过百度公司AIDU计划加入百度研究院商业智能实验室,现任资深研发工程师 ...

  8. 基于飞桨的稻米加工品质监测系统

    基于飞桨的稻米加工品质监测系统 本项目拟解决目前农业中普遍存在的稻米过度加工问题,通过开发基于PaddlePaddle的密集粘连小目标的图像分割与目标检测算法,量化各环节稻米的加工指标,进而实现产线工 ...

  9. 基于飞桨复现语义分割网络HRNet,实现瓷砖缺陷检测

    点击左上方蓝字关注我们 [飞桨开发者说]路星奎,沈阳化工大学信息工程学院研究生在读,PPDE飞桨开发者技术专家,研究方向为图像分类.目标检测.图像分割等 内容简介 本项目讲述了HRNet网络结构,并尝 ...

最新文章

  1. 3D目标检测论文阅读摘要
  2. The Memory Managerment of the Computer
  3. python提升计算速度的方法
  4. java 级联下拉列表_java 下拉框级联(年月日级联)
  5. html5学习笔记(audio)
  6. 正则表达式特别需要注意的点:“空“字符的匹配
  7. LeetCode-3. 无重复字符的最长子串
  8. Office文档在线预览接口服务器
  9. com.jogamp.opengl.GLException: J3D-Renderer-1: createImpl ARB n/a but required, profile > GL2 reques
  10. 基本排序算法:Python实现
  11. 《挖掘管理价值:企业软件项目管理实战》一1.3 软件项目管理模型
  12. 热传导方程有限差分法实现matlab,热传导方程有限差分法的MATLAB实现-史策
  13. unity3d 怎么生成网页版_unity3D u3D网页游戏制作游戏优势
  14. Spring boot 整合WebSocket
  15. CTF密码学之Base64,Base32,Base16
  16. 计算机网络二进制计算题
  17. 学习笔记 Tianmao 篇 recyclerView 辅助的RecycleAdapterImpl类(适配自定义home三型)
  18. 在网址前加神秘字母,让你打开新世界(z)
  19. 车载导航蓝牙知识介绍
  20. uniapp开发app中配置高德地图定位流程

热门文章

  1. 格拉斯哥团队用 GaAs 制造“电子皮肤”
  2. python transpose函数_Python Numpy.transpose函数可视化解释
  3. Linux之文件压缩gzip,bzip,tar等
  4. docker安装镜像很慢,小白也能看明白
  5. rtmp服务器搭建-windows
  6. 安卓硬编音视频数据推送到rtmp服务器
  7. Win10任务栏卡死怎么办?这3个方法快收藏!
  8. 日语二级考试题型与分值分配
  9. mysql 登录失败18456_SQL 2008 windows登录失败,错误18456, 更正
  10. 修改Maven镜像仓库为阿里云Maven仓库,下载如有神