diff --git a/.vitepress/components/Confetti.vue b/.vitepress/components/Confetti.vue new file mode 100644 index 0000000..ab08d7b --- /dev/null +++ b/.vitepress/components/Confetti.vue @@ -0,0 +1,65 @@ + + + diff --git a/.vitepress/components/CustomNotFound.vue b/.vitepress/components/CustomNotFound.vue new file mode 100644 index 0000000..04d5cf6 --- /dev/null +++ b/.vitepress/components/CustomNotFound.vue @@ -0,0 +1,111 @@ + + + + + \ No newline at end of file diff --git a/.vitepress/components/MineBlock.vue b/.vitepress/components/MineBlock.vue new file mode 100644 index 0000000..65a0276 --- /dev/null +++ b/.vitepress/components/MineBlock.vue @@ -0,0 +1,73 @@ + + + + + \ No newline at end of file diff --git a/.vitepress/components/sweep.vue b/.vitepress/components/sweep.vue new file mode 100644 index 0000000..8ca4915 --- /dev/null +++ b/.vitepress/components/sweep.vue @@ -0,0 +1,161 @@ + + + + + \ No newline at end of file diff --git a/.vitepress/composables/logic.js b/.vitepress/composables/logic.js new file mode 100644 index 0000000..b9a56b6 --- /dev/null +++ b/.vitepress/composables/logic.js @@ -0,0 +1,210 @@ +import { ref } from 'vue'; + +const directions = [ + [1, 1], + [1, 0], + [1, -1], + [0, -1], + [-1, -1], + [-1, 0], + [-1, 1], + [0, 1], +]; + +export class GamePlay { + state = ref(); + + constructor(width, height, mines) { + this.width = width; + this.height = height; + this.mines = mines; + this.reset(); + } + + get board() { + return this.state.value.board; + } + + get blocks() { + return this.state.value.board.flat(); + } + + reset(width = this.width, height = this.height, mines = this.mines) { + this.width = width; + this.height = height; + this.mines = mines; + + this.state.value = { + startMS: +Date.now(), + endMS: undefined, // 确保结束时间戳被重置 + mineGenerated: false, + status: 'play', + board: Array.from({ length: this.height }, (_, y) => + Array.from({ length: this.width }, (_, x) => ({ + x, + y, + mine: false, // 初始化 mine 属性 + flagged: false, // 初始化 flagged 属性 + adjacentMines: 0, + revealed: false, + }), + ), + ), + }; + } + + randomRange(min, max) { + return Math.random() * (max - min) + min; + } + + randomInt(min, max) { + return Math.round(this.randomRange(min, max)); + } + + generateMines(state, initial) { + const placeRandom = () => { + const x = this.randomInt(0, this.width - 1); + const y = this.randomInt(0, this.height - 1); + const block = state[y][x]; + if (Math.abs(initial.x - block.x) <= 1 && Math.abs(initial.y - block.y) <= 1) + return false; + if (block.mine) + return false; + block.mine = true; + return true; + }; + Array.from({ length: this.mines }, () => null) + .forEach(() => { + let placed = false; + let attempts = 0; + const maxAttempts = 1000; + while (!placed) { + if (attempts++ > maxAttempts) { + this.reset(); + break; + } + placed = placeRandom(); + } + }); + this.updateNumbers(); + } + + updateNumbers() { + this.board.forEach((raw) => { + raw.forEach((block) => { + if (block.mine) + return; + this.getSiblings(block) + .forEach((b) => { + if (b.mine) + block.adjacentMines += 1; + }); + }); + }); + } + + expendZero(block) { + if (block.adjacentMines) + return; + + this.getSiblings(block) + .forEach((s) => { + if (!s.revealed) { + s.revealed = true; + this.expendZero(s); + } + }); + } + + onRightClick(block) { + if (this.state.value.status !== 'play') + return; + + if (block.revealed) + return; + block.flagged = !block.flagged; + } + + onClick(block) { + if (this.state.value.status !== 'play') + return; + + if (!this.state.value.mineGenerated) { + this.generateMines(this.board, block); + this.state.value.mineGenerated = true; + } + + block.revealed = true; + if (block.mine) { + this.onGameOver('lost'); + return; + } + + this.expendZero(block); + } + + getSiblings(block) { + return directions.map(([dx, dy]) => { + const x2 = block.x + dx; + const y2 = block.y + dy; + if (x2 < 0 || x2 >= this.width || y2 < 0 || y2 >= this.height) + return undefined; + return this.board[y2][x2]; + }) + .filter(Boolean); + } + + showAllMines() { + this.board.flat().forEach((i) => { + if (i.mine) + i.revealed = true; + }); + } + + checkGameState() { + if (!this.state.value.mineGenerated) + return; + const blocks = this.board.flat(); + + if (blocks.every(block => block.revealed || block.flagged || block.mine)) { + if (blocks.some(block => block.flagged && !block.mine)) + this.onGameOver('lost'); + else + this.onGameOver('won'); + } + } + + autoExpand(block) { + const siblings = this.getSiblings(block); + const flags = siblings.reduce((a, b) => a + (b.flagged ? 1 : 0), 0); + const notRevealed = siblings.reduce((a, b) => a + (!b.revealed && !b.flagged ? 1 : 0), 0); + if (flags === block.adjacentMines) { + siblings.forEach((i) => { + if (i.revealed || i.flagged) + return; + i.revealed = true; + this.expendZero(i); + if (i.mine) + this.onGameOver('lost'); + }); + } + const missingFlags = block.adjacentMines - flags; + if (notRevealed === missingFlags) { + siblings.forEach((i) => { + if (!i.revealed && !i.flagged) + i.flagged = true; + }); + } + } + + onGameOver(status) { + this.state.value.status = status; + this.state.value.endMS = +Date.now(); + if (status === 'lost') { + this.showAllMines(); + setTimeout(() => { + alert('lost'); + }, 10); + } + } +} diff --git a/.vitepress/config.js b/.vitepress/config.js index ad3891e..811b2d2 100644 --- a/.vitepress/config.js +++ b/.vitepress/config.js @@ -1,15 +1,11 @@ // import { defineConfig } from 'vitepress' -import { withMermaid } from "vitepress-plugin-mermaid"; +import { withMermaid } from "vitepress-plugin-mermaid-xyxsw"; import mathjax3 from 'markdown-it-mathjax3'; import { main_sidebar, chapter2, chapter3, chapter4, chapter5, chapter6, chapter7, chapter8, chapter9 } from './sidebar.js'; import { nav } from './nav.js'; import PanguPlugin from 'markdown-it-pangu' -import { createWriteStream } from 'node:fs' -import { resolve } from 'node:path' -import { SitemapStream } from 'sitemap' import { fileURLToPath, URL } from 'node:url' - -const links = [] +import VueMacros from 'unplugin-vue-macros/vite' const customElements = [ 'mjx-container', @@ -107,6 +103,7 @@ export default withMermaid({ title: "HDU-CS-WIKI", description: "HDU 计算机科学讲义", lastUpdated: true, + cleanUrls: true, head: [['script', { async: "async", src: 'https://umami.hdu-cs.wiki/script.js', "data-website-id": "3f11687a-faae-463a-b863-6127a8c28301", "data-domains": "wiki.xyxsw.site,hdu-cs.wiki" }]], themeConfig: { // https://vitepress.dev/reference/default-theme-config @@ -146,6 +143,7 @@ export default withMermaid({ externalLinkIcon: true, }, markdown: { + lineNumbers: true, config: (md) => { md.use(mathjax3); md.use(PanguPlugin); @@ -157,32 +155,21 @@ export default withMermaid({ isCustomElement: (tag) => customElements.includes(tag), }, }, + }, - transformHtml: (_, id, { pageData }) => { - if (!/[\\/]404\.html$/.test(id)) - links.push({ - // you might need to change this if not using clean urls mode - url: pageData.relativePath.replace(/((^|\/)index)?\.md$/, '$2'), - lastmod: pageData.lastUpdated - }) - }, - buildEnd: async ({ outDir }) => { - const sitemap = new SitemapStream({ - hostname: 'https://hdu-cs.wiki/' - }) - const writeStream = createWriteStream(resolve(outDir, 'sitemap.xml')) - sitemap.pipe(writeStream) - links.forEach((link) => sitemap.write(link)) - sitemap.end() - await new Promise((r) => writeStream.on('finish', r)) + sitemap: { + hostname: 'https://hdu-cs.wiki' }, vite: { + plugins: [ + VueMacros(), + ], resolve: { alias: [ { - find: /^.*\/VPSwitchAppearance\.vue$/, + find: /^.*\/NotFound\.vue$/, replacement: fileURLToPath( - new URL('./components/CustomSwitchAppearance.vue', import.meta.url) + new URL('./components/CustomNotFound.vue', import.meta.url) ) } ] diff --git a/.vitepress/sidebar.js b/.vitepress/sidebar.js index 262279d..249165e 100644 --- a/.vitepress/sidebar.js +++ b/.vitepress/sidebar.js @@ -12,19 +12,20 @@ export function main_sidebar() { text: '1.杭电生存指南(最重要模块)', collapsed: true, items: [ - { text: '1.1人文社科的重要性(韩健夫老师寄语)', link: '/1.杭电生存指南/1.1人文社科的重要性(韩健夫老师寄语)' }, - { text: '1.2竞赛指北', link: '/1.杭电生存指南/1.2竞赛指北' }, - { text: '1.3导师选择', link: '/1.杭电生存指南/1.3导师选择' }, - { text: '1.4小心项目陷阱', link: '/1.杭电生存指南/1.4小心项目陷阱' }, - { text: '1.5小组作业避雷指南', link: '/1.杭电生存指南/1.5小组作业避雷指南' }, - { text: '1.6正确解读GPA', link: '/1.杭电生存指南/1.6正确解读GPA' }, - { text: '1.7杭电出国自救指南', link: '/1.杭电生存指南/1.7杭电出国自救指南' }, - { text: '1.8转专业二三事', link: '/1.杭电生存指南/1.8转专业二三事' }, - { text: '1.9问题专题:好想进入实验室', link: '/1.杭电生存指南/1.9问题专题:好想进入实验室' }, - { text: '1.10如何读论文', link: '/1.杭电生存指南/1.10如何读论文' }, - { text: '1.11陷入虚无主义?进来看看吧', link: '/1.杭电生存指南/1.11陷入虚无主义?进来看看吧' }, - { text: '1.12选课原则与抢课技巧', link: '/1.杭电生存指南/1.12选课原则与抢课技巧' }, - { text: '1.13数学学习篇', link: '/1.杭电生存指南/1.13数学学习篇'}, + { text: '1.1 人文社科的重要性(韩健夫老师寄语)', link: '/1.杭电生存指南/1.1人文社科的重要性(韩健夫老师寄语)' }, + { text: '1.2 竞赛指北', link: '/1.杭电生存指南/1.2竞赛指北' }, + { text: '1.3 导师选择', link: '/1.杭电生存指南/1.3导师选择' }, + { text: '1.4 小心项目陷阱', link: '/1.杭电生存指南/1.4小心项目陷阱' }, + { text: '1.5 小组作业避雷指南', link: '/1.杭电生存指南/1.5小组作业避雷指南' }, + { text: '1.6 正确解读GPA', link: '/1.杭电生存指南/1.6正确解读GPA' }, + { text: '1.7 杭电出国自救指南', link: '/1.杭电生存指南/1.7杭电出国自救指南' }, + { text: '1.8 转专业二三事', link: '/1.杭电生存指南/1.8转专业二三事' }, + { text: '1.9 问题专题:好想进入实验室', link: '/1.杭电生存指南/1.9问题专题:好想进入实验室' }, + { text: '1.10 如何读论文', link: '/1.杭电生存指南/1.10如何读论文' }, + { text: '1.11 陷入虚无主义?进来看看吧', link: '/1.杭电生存指南/1.11陷入虚无主义?进来看看吧' }, + { text: '1.12 选课原则与抢课技巧', link: '/1.杭电生存指南/1.12选课原则与抢课技巧' }, + { text: '1.13 数学学习篇', link: '/1.杭电生存指南/1.13数学学习篇' }, + { text: '1.14 杭电“失败”指南', link: '/1.杭电生存指南/1.14 杭电失败指南' }, ] }, { @@ -227,11 +228,11 @@ export function chapter3() { ] }, { - text: '3.6.5CS61A食用指南', + text: '3.6.5 CS61A 食用指南', collapsed: true, items: [ - { text: '3.6.5CS61A食用指南', link: '/3.编程思维体系构建/3.6.5CS61A食用指南' }, - { text: '3.6.5.1CS61A Sec1', link: '/3.编程思维体系构建/3.6.5.1CS61A Sec1' }, + { text: '3.6.5 CS61A 食用指南', link: '/3.编程思维体系构建/3.6.5CS61A食用指南' }, + { text: '3.6.5.1 CS61A Sec1', link: '/3.编程思维体系构建/3.6.5.1CS61A Sec1' }, ] } ] @@ -674,8 +675,15 @@ export function chapter9() { { text: '9.1 计网速通', link: '/9.计算机网络/9.1计网速通' }, { text: '9.2.1 物理层' }, { text: '9.2.2 链路层' }, - { text: '9.2.3 网络层' , link: '/9.计算机网络/9.2.3网络层'}, - { text: '9.2.3.1 IP 协议', link: '/9.计算机网络/9.2.3.1IP协议' }, + { + text: '9.2.3 网络层', + collapsed: true, + items: [ + { text: '9.2.3 网络层', link: '/9.计算机网络/9.2.3网络层' }, + { text: '9.2.3.1 IP 协议', link: '/9.计算机网络/9.2.3.1IP协议' }, + { text: '9.2.3.2 子网与无类域间路由', link: '/9.计算机网络/9.2.3.2子网与无类域间路由' } + ] + }, ] } ] diff --git a/.vitepress/theme/Layout.vue b/.vitepress/theme/Layout.vue new file mode 100644 index 0000000..a4567b2 --- /dev/null +++ b/.vitepress/theme/Layout.vue @@ -0,0 +1,70 @@ + + + + + \ No newline at end of file diff --git a/.vitepress/theme/font/NotoSansMono-Regular.ttf b/.vitepress/theme/font/NotoSansMono-Regular.ttf deleted file mode 100644 index b7615d8..0000000 Binary files a/.vitepress/theme/font/NotoSansMono-Regular.ttf and /dev/null differ diff --git a/.vitepress/theme/font/NotoSansSC-Bold.otf b/.vitepress/theme/font/NotoSansSC-Bold.otf deleted file mode 100644 index 172eb67..0000000 Binary files a/.vitepress/theme/font/NotoSansSC-Bold.otf and /dev/null differ diff --git a/.vitepress/theme/font/NotoSansSC-Regular.otf b/.vitepress/theme/font/NotoSansSC-Regular.otf deleted file mode 100644 index d350ffa..0000000 Binary files a/.vitepress/theme/font/NotoSansSC-Regular.otf and /dev/null differ diff --git a/.vitepress/theme/index.js b/.vitepress/theme/index.js index 7ddda1d..d09f77a 100644 --- a/.vitepress/theme/index.js +++ b/.vitepress/theme/index.js @@ -1,8 +1,8 @@ // https://vitepress.dev/guide/custom-theme import { h, watch } from 'vue' -import { inject } from '@vercel/analytics'; // import Theme from 'vitepress/theme' import DefaultTheme from 'vitepress/theme-without-fonts' +import Layout from './Layout.vue' import Download from '../../components/Download.vue' import Bilibili from '../../components/Bilibili.vue' import Parallax from '../../components/Parallax.vue' @@ -11,14 +11,9 @@ import './rainbow.css' let homePageStyle = undefined -inject() - export default { ...DefaultTheme, - Layout: () => { - return h(DefaultTheme.Layout, null, { - }) - }, + Layout: Layout, enhanceApp(ctx) { DefaultTheme.enhanceApp(ctx) ctx.app.component('Download', Download) @@ -29,7 +24,7 @@ export default { watch( () => ctx.router.route.data.relativePath, - () => updateHomePageStyle(location.pathname === '/' || location.pathname === '/contributors.html'), + () => updateHomePageStyle(location.pathname === '/' || location.pathname === '/contributors'), { immediate: true }, ) }, diff --git a/.vitepress/theme/style.css b/.vitepress/theme/style.css index 8f67acb..76ba62b 100644 --- a/.vitepress/theme/style.css +++ b/.vitepress/theme/style.css @@ -18,17 +18,31 @@ } .dark .vp-doc a,#loading, .dark .vp-doc a>code, .dark .VPNavBarMenuLink.VPNavBarMenuLink:hover, .dark .VPNavBarMenuLink.VPNavBarMenuLink.active, .dark .link.link:hover, .dark .link.link.active, .dark .edit-link-button.edit-link-button, .dark .pager-link .title { - color: var(--vp-c-brand-lighter); + color: var(--vp-c-brand-3); +} + +/** + * 这个版本可能有 bug,build 后字体变不了还为 consolas 可能是我自己配的有问题 可能是这个版本拉了 总之就加个临时的 + * -------------------------------------------------------------------------- */ +code { + font-family: 'Noto Sans Mono', sans-serif, monospace, consolas !important; + font-weight: 400 !important; + font-size: 14px !important; } :root { - --vp-c-brand: #0dadc4; - --vp-c-brand-light: #1A9CED; - --vp-c-brand-lighter: #1CA8FF; - --vp-c-brand-lightest: #5EB2E6; - --vp-c-brand-dark: #0B52BF; - --vp-c-brand-darker: #015F8F; - --vp-c-brand-dimm: rgba(100, 108, 255, 0.08); + --vp-c-brand-1: #0dadc4; + --vp-c-brand-2: #1A9CED; + --vp-c-brand-3: #1CA8FF; + --vp-c-brand-soft: #5EB2E6; + --vp-code-copy-copied-text-content: '复制成功'; + --vp-code-color: rgba(60, 60, 67); + --vp-custom-block-tip-bg: rgba(100, 108, 255, 0.16) !important; + --vp-badge-tip-bg: rgba(100, 108, 255, 0.16) !important; +} + +.dark { + --vp-code-color: rgba(255, 255, 245, 0.86); } :root { @@ -41,15 +55,15 @@ * -------------------------------------------------------------------------- */ :root { - --vp-button-brand-border: var(--vp-c-brand-light); + --vp-button-brand-border: transparent; --vp-button-brand-text: var(--vp-c-white); - --vp-button-brand-bg: var(--vp-c-brand); - --vp-button-brand-hover-border: var(--vp-c-brand-light); + --vp-button-brand-bg: var(--vp-c-brand-3); + --vp-button-brand-hover-border: transparent; --vp-button-brand-hover-text: var(--vp-c-white); - --vp-button-brand-hover-bg: var(--vp-c-brand-light); - --vp-button-brand-active-border: var(--vp-c-brand-light); + --vp-button-brand-hover-bg: var(--vp-c-brand-2); + --vp-button-brand-active-border: transparent; --vp-button-brand-active-text: var(--vp-c-white); - --vp-button-brand-active-bg: var(--vp-button-brand-bg); + --vp-button-brand-active-bg: var(--vp-c-brand-1); } /** @@ -91,15 +105,10 @@ * -------------------------------------------------------------------------- */ :root { - --vp-custom-block-tip-border: var(--vp-c-brand); - --vp-custom-block-tip-text: var(--vp-c-brand-darker); - --vp-custom-block-tip-bg: var(--vp-c-brand-dimm); -} - -.dark { - --vp-custom-block-tip-border: var(--vp-c-brand); - --vp-custom-block-tip-text: var(--vp-c-brand-lightest); - --vp-custom-block-tip-bg: var(--vp-c-brand-dimm); + --vp-custom-block-tip-border: transparent; + --vp-custom-block-tip-text: var(--vp-c-text-1); + --vp-custom-block-tip-bg: var(--vp-c-brand-soft); + --vp-custom-block-tip-code-bg: var(--vp-c-brand-soft); } /** @@ -107,7 +116,7 @@ * -------------------------------------------------------------------------- */ .DocSearch { - --docsearch-primary-color: var(--vp-c-brand) !important; + --docsearch-primary-color: var(--vp-c-brand-1) !important; } mjx-container { @@ -126,7 +135,6 @@ mjx-container { opacity: 1; } - :root { --vp-home-hero-name-color: transparent; --vp-home-hero-name-background: -webkit-linear-gradient( @@ -195,4 +203,12 @@ mjx-container { user-drag: none !important; -webkit-user-drag: none !important; -moz-user-drag: none !important; +} + +.custom-block.tip code { + background-color: rgba(100, 108, 255, 0.14); +} + +mjx-container > svg { + display: inline-block; } \ No newline at end of file diff --git a/1.杭电生存指南/1.14 杭电失败指南.md b/1.杭电生存指南/1.14 杭电失败指南.md new file mode 100644 index 0000000..39c162d --- /dev/null +++ b/1.杭电生存指南/1.14 杭电失败指南.md @@ -0,0 +1,183 @@ + +# 杭电“失败”指南 + +## 前言 + +> 淋过雨的人,也想为别人打伞 + +毕业很久了,但是回望我的大学生涯,充满了很多遗憾,吃过很多苦头,收获了很多教训,我偶尔会回想,如果当初我如何如何,现在会不会不那么“失败”一些。于是,在某个晚上,有了这篇指南。 + +谢谢学弟学妹能够抽出时间看这篇“失败”指南,这篇指南以个人角度讲述了一个 CS 学生在上大学的时候收获到的一些经验和教训,或许没那么适用,但是也许可以让学弟学妹的大学生活不会像我一样“失败”。 + +这篇文章尽可能少的讲故事,更多是实用主义的教训(杂谈篇除外)(里面有太多偏激的观点,说教色彩也很浓厚,仅供参考)。 + +如果这篇所谓的狗屁指南让你觉得 + +> 听过很多道理,依然过不好这一生 + +没关系,勇敢地去做自己热爱的事情就好。 + +## 杂谈篇 + +> 如果你是一个对 CS 充满热爱,怀抱一颗技术宅拯救世界的心,那你可以跳过此篇。(其他章节可以读读 (#^.^#)) +> 如果你像我一样,是一个明明从小热爱技术,但是有时候有些功利的矛盾人,又或者是大多数对大学充满迷茫,不知道该怎么办的人,或许可以继续看下去。 + +### 高考败犬:脱颖而出的心态修炼 + +我所在的学院每年都有或多或少一些学生,觉得自己是高考考差才来这里的,刚进来校的我也是这样。这种心态我非常能理解,但是问题是进来了以后,怎么在这所学校脱颖而出?(PS:前提是你想脱颖而出) + +1. 保持这份不甘心。太多同学在刚进大学的时候踌躇满志,最后四年以后可能也是泯然众人。当初的一份志气也被消磨在宿舍、游戏和无意义的社交中。为了让自己能够脱颖而出,首先要做的就是提醒自己,保持不甘心,保持自己的志气,不要甘心自己已经有的一切,永远觉得自己可以更强,更厉害。 + +2. 充满野心,渴望成为这个学校最顶尖的那批人。老实说,杭电是一所双非,在未来会对你(大部分人)在很多地方都有些隐性限制,但是,每一所大学最顶尖的那批人,都能够冲破这些束缚。直白些说,即使它是一所双非,但是它在很多领域都有超越一些 211 和 985 的资源和实力。很幸运,CS 领域就是其中之一。不用怀疑,它能够提供你所想要的一切。但是资源是有限的,所以如果你想成为很厉害很厉害的人,那么就一定要尽可能去抓住它能够给你的一切资源。 + +### 攫取者:永远向厉害的人去学习 + +那么,杭电究竟能够给大家什么资源呢?浓厚的竞赛氛围?浓厚的 CS 氛围?我个人觉得不全是。杭电之所以成为 CS 强校,是因为上述氛围吸引和聚拢了一堆充满理想,热爱技术的人儿。或许你可能只是一名还在迷茫期的新生,但是没关系,去主动靠近和接触他们,永远向比你厉害的人学习,不断提高自己的技能和认知水平。特别是认知。 + +之所以强调这一点,是因为技能是可以自己通过时间去磨炼的,但是认知的话,如果你根本不知道有"A",怎么可能去主动学习"A"呢?如果你不知道厉害的人他们平时在干什么,他们在学什么,在打什么比赛,研究什么先进或有趣的东西,你怎么可能去学习这些呢?我觉得进杭电的同学,其实"天赋"和"聪明程度"都差不多,关键在于信息差和执行力。(PS:hdu-cs-wiki 就是一种缩小信息差的工具) + +那么,怎么才能认识到这么多厉害的人,以及向他们学习呢?说白了,就是混进大佬的圈子。作为新生,一个打开局面的方法是,先选择一个方向去钻研学习,结识这个方向的大佬,成为这个方向的大佬,然后认识其他方向的大佬。 + +问题就转化成,我该选择哪个方向成为我的起点。 + +### 迷茫中的选择:科研/竞赛/开源/学业/技术/工作 + +> 犹豫就会败北,世界不是非此即彼,热爱才抵得过岁月漫长 + +作为新生,我曾一度非常非常非常迷茫,当时最大的问题是,该选择哪个方向发展,是 CTF?还是 ACM?还是刷绩点争取保研?还是专注我热爱的技术,做有影响力的开源? + +我犯过最大的教训有三个,一个是功利主义地拒绝了自己最热爱的方向,二是总在犹豫和后悔自己的选择,三是总觉得不同方向只能选择一个,无法兼顾。 + +TBD... + +## 科研篇 + +### 选择障碍:怎么选择研究方向 + +TBD... + +### 从 0 入门 AI:实践和理论的权衡 + +TBD... + +### 论文相关:从阅读一篇论文说起 + +TBD... + +### 论文相关:头疼的文献管理 + +TBD... + +### 论文相关:好记性不如烂笔头 + +TBD... + +### 经验谈:炼丹师的能力修炼 + +TBD... + +### 经验谈:合作交流及信息渠道 + +TBD... + +### 实践谈:提出 idea 到投稿的经验教训 + +TBD... + +## 竞赛篇 + +### 四大竞赛对个人成长的收益分析 + +TBD... + +## 开源和个人影响力 + +### 为什么要培养个人影响力 + +TBD... + +### 如何做人工智能方向的开源项目 + +TBD... + +## 技术篇 + +### 后悔药:如何选择技术发展方向 + +TBD... + +## 学业篇 + +### 如何兼顾学业绩点和专业技能培养 + +TBD... + +### 过时的个人谬论:如何聪明且高效地刷绩点 + +TBD... + +### 2023 年以后读研的必要性如何 + +TBD... + +### 保研经验分享 + +TBD... + +## 找工篇 + +### 后悔药:如何“面向找大厂工作”读大学 + +TBD... + +### 经验篇:高效准备基础知识和笔试考核 + +TBD... + +### 简历篇:如何做一份或许“优秀”的简历 + +TBD... + +### 经验谈:非技术因素在面试中的影响 + +之所以选择这个话题,一方面是因为这个东西很容易被大家忽略,另一方面这个也比较普适,无论做开发还是算法都可以参考。 + +#### 面试前 - 个人介绍 + +在面试前应该准备好自己的个人介绍,除了老生常态的基本信息外,我觉得需要做到既要突出自己的亮点,但是别太过,同时也要根据不同的面试去修改。 + +先给大家看一个例子: + +您好,我叫 xxx,是 xx 大学 xx 学院 xx 级学生。自从进入大学以来,我【省略一些内容】。在 xxx 地方实习期间做了 xxx 工作。在平时,xxxxx(主要讲自己的开源社区贡献、技术博客撰写、竞赛等) + +**第一就是要尽量介绍地比较“多面”**,不但要说自己在学校和实习中做了什么,还要说一些个人影响力的东西,比如开源社区贡献这一块。其实就是突出一些自己相对于其他候选人的亮点,相比于其他大部分人来说,你的特别在哪。 + +**第二就是要建立“投缘”机会**,在面试前,搜集到这场面试的部门和小组是做什么,甚至面试官是谁。【省略一些例子】。我想强调的关键是在自我介绍中,**突出自己和这个部门,这个组的 connection,寻找尽可能多的共同点和缘分点**。 + +#### 面试中 - 项目准备 + +在面试前,还应该准备好自己的项目梳理笔记。实际上,在面试过程中,如果没有提前梳理好自己的项目的逻辑的话,很难在面试现场讲清楚以及让面试官及时 get 到你想表达的点。 + +一般而言,对于在校期间做的一些项目或者开源项目自己都能比较好地梳理清楚,但是比较难的是在实习过程中,特别是一份复杂的业务实习中梳理自己的产出。我个人认为**面试官比较关注以下几个方面**:一就是业务背景,也就是咱们的业务是什么,大概的架构,发展到哪种阶段,目前的瓶颈等。二就是本人负责的模块是什么,创新点是什么,以及特别重要的是:”我为什么要做这件事!“,三就是这个模块最后的业务收益是多少,怎么去评判收益。可以参考这种逻辑去梳理。 + +#### 面试前 - 好记性不如烂笔头 + +上文主要讲了个人介绍和项目梳理,我建议大家把个人介绍和项目梳理都放在一个 note 里面,每次面试前半个小时到一个小时回顾下自己的 note,以及根据面试岗位和小组来修改下。这样的好处在于每次都回顾下自己的项目和介绍,面试过程中有参考,不会慌。等面试次数多了,你就会发现,其实**每场面试都是在重复介绍你 note 里面的内容**。 + +#### 面试中 - 换位思考很重要 + +**面试过程中的一大禁忌就是不考虑面试官的感受,一股脑介绍自己的项目**。一方面,面试官无法在短时间内吸收到你想表达的内容,另一方面,你一直噼里啪啦输出面试官听不懂的东西,面试官也会特别烦躁。 + +一个比较好的方式是:每次介绍完一段时,就停下来,反问面试官:您看您对这个项目的 xx 有什么疑问吗?比如说你介绍完项目背景后,就记得停下来,反问下,您看你对这个项目背景有什么疑问吗。 + +除了每次介绍完一段就停顿时,还有一个需要注意的点在于,不要梳理完项目以后,就完全按照项目梳理的内容去念,要注意观察面试官的反应,如果感觉他其实并不怎么感兴趣,就想办法赶紧结束。 + +#### 面试中 - 反问阶段 + +反问阶段是一个及时获取信息的好机会。不同面试阶段有不同的提问。一面基本是你的同事或者你的 mentor,这个时候可以专注问一些工作内容,工作氛围等比较实际的话题。对于三面来说,一般是大老板,这个时候你要抓住机会和他交流下一些比较 high-level 的东西,因为以后很少有机会去和这样 senior 的人交流。话题诸如:职业发展路径、发展前景、绩效考核、我会被分配到什么具体组。 + +如果在每场面试的时候,你想知道自己大概的表现,你可以反问阶段,非常非常非常委婉地提问:您看我这次面试还有什么可以提升的地方吗? + +## 结语 + +TBD... diff --git a/1.杭电生存指南/1.1人文社科的重要性(韩健夫老师寄语).md b/1.杭电生存指南/1.1人文社科的重要性(韩健夫老师寄语).md index 76ccdbe..4f10c06 100644 --- a/1.杭电生存指南/1.1人文社科的重要性(韩健夫老师寄语).md +++ b/1.杭电生存指南/1.1人文社科的重要性(韩健夫老师寄语).md @@ -4,20 +4,20 @@ 大学的真意是综合而全面的培养一个人。为什么大学有这样的职责?因为这是人最后的受教育阶段(研究生、博士生也是在大学里接受教育)。从接受教育开始到走向社会为止,这期间是人,变成一个人最为宝贵的阶段。 -大学是唯一可以与来自五湖四海、不同学科背景的人共处一个校园的时期,这里就应该是开放而需要激烈思想碰撞的地方。大学是专业的,但同时更是广博的,我们在黄金的年龄来到这里,就不要轻易的错过这样疯狂吸纳不同看法的机会。同样,大学是未来所有可能性的孵化器,请保持一颗尝试新事物的心,索取大学所能给予的任何一切,并让它成为提升自我的工具。 +**大学是唯一可以与来自五湖四海、不同学科背景的人共处一个校园的时期,这里就应该是开放而需要激烈思想碰撞的地方**。大学是专业的,但同时更是广博的,我们在黄金的年龄来到这里,就不要轻易的错过这样疯狂吸纳不同看法的机会。同样,大学是未来所有可能性的孵化器,请保持一颗尝试新事物的心,索取大学所能给予的任何一切,并让它成为提升自我的工具。 工具,我并不避讳这个词。只不过我并不想将这个词与人画等号。人非工具,而是使用工具的。我们的祖先经过数百万年的努力和尝试,才学会使用并创造工具,目的就是不再沦为工具,我们站在 21 世纪也不应该心甘情愿的将自己锻造成一个工具,这是返祖与退化的表现。 21 世纪是人类对高科技和超级想象力、创造力最渴求的百年。一个想法和主意胜过千万个重复的机械化劳动,虽然后者也能带来一定程度的好处,但这并不我们的目标。大学是否能迸发出惊人的创造力,在于学生和教师的思想与行为。而不同的学科交叉和碰撞会让创造力和科技的创新更大概率出现。 -听说乔布斯有对禅宗修习的经历,而他的工作可能并不与禅宗搭边。但他的成功却不能不说与他广泛的涉猎有关。工具是没有办法创造工具的,只有人才能创造。我们大学生应该去思考在大学四年如何想办法把自己锻造成真正的人。 +听说乔布斯有对禅宗修习的经历,而他的工作可能并不与禅宗搭边。但他的成功却不能不说与他广泛的涉猎有关。工具是没有办法创造工具的,只有人才能创造。**我们大学生应该去思考在大学四年如何想办法把自己锻造成真正的人。** -这个人不是做题的机器,不是刷题的工具,不是眼中只有考高分的单一生物,当然更不可能是成天浑浑噩噩、行尸走肉的颓丧者、躺平者。说到这里,可能会讲,难道不躺平去卷吗?并不是,我反对 “卷”,因为 “卷” 的含义是无意义的恶性竞争和没有实际突破的简单重复劳动,边际效益递减的不划算却无奈的选择。“卷” 不等于 “勤奋” 、 “创造” 和 “想要变得更强” ,将之画等号我认为是当前观念中一个很大的误区。我们需要大学生有自己的思考和创造力,需要大学生是一个综合全面发展的人。只有这样大学才有活力、希望,社会才有动力,国家才有未来。 +这个人不是做题的机器,不是刷题的工具,不是眼中只有考高分的单一生物,当然更不可能是成天浑浑噩噩、行尸走肉的颓丧者、躺平者。说到这里,可能会讲,难道不躺平去卷吗?并不是,我反对 “卷”,**因为 “卷” 的含义是无意义的恶性竞争和没有实际突破的简单重复劳动,边际效益递减的不划算却无奈的选择。**“卷” 不等于 “勤奋” 、 “创造” 和 “想要变得更强” ,将之画等号我认为是当前观念中一个很大的误区。**我们需要大学生有自己的思考和创造力,需要大学生是一个综合全面发展的人。**只有这样大学才有活力、希望,社会才有动力,国家才有未来。 我知道大学可能并不如你们想象的那般美好,有不负责的、划水上课的老师以及你看不惯的、瞧不起的种种行为,但这并不是自己选择放弃和抱怨的理由。因为,我相信大学还有认真负责的老师、有思想的学者以及有想法的同学,我们需要和自己钦佩、三观相符的人多接触,让自己成为你佩服的人的样子,而非因为种种不好的现象而选择全盘的否定、甚至自暴自弃。 - 要有自己的目标,年轻是实现自己目标最好的资本。为了这个目标,在大学里徜徉、像海绵一样吸纳如水般的知识和见识。博采众长而非简单功利。可能你今天听了不重要的课(相对于专业课),但只要是值得听的老师讲的有涵养的课,你就不算枉费时光。因为这样的经历并不会让你浪费时间,而会在未来的某刻显示出它的价值。 +** 要有自己的目标,年轻是实现自己目标最好的资本。**为了这个目标,在大学里徜徉、像海绵一样吸纳如水般的知识和见识。博采众长而非简单功利。可能你今天听了不重要的课(相对于专业课),但只要是值得听的老师讲的有涵养的课,你就不算枉费时光。因为这样的经历并不会让你浪费时间,而会在未来的某刻显示出它的价值。 -不要让自己的大脑空空,刷抖音、看游戏直播或者看无聊的视频或许是娱乐的方式,但这些是你可以在余生每天都可做的最没有技术含量的事,而且这些并不会让你大脑填入真正有价值的东西。去做只有大学时光才能做的事吧!丰富自己、创造自己、提升自己。多看一页经典的著作,这是人类上百年乃至上千年思想的精华。多认真的听一节有价值的课吧,这是老师积几十年的学识认真准备的盛宴。 +不要让自己的大脑空空,刷抖音、看游戏直播或者看无聊的视频或许是娱乐的方式,但这些是你可以在余生每天都可做的最没有技术含量的事,而且这些并不会让你大脑填入真正有价值的东西。**去做只有大学时光才能做的事吧!**丰富自己、创造自己、提升自己。多看一页经典的著作,这是人类上百年乃至上千年思想的精华。多认真的听一节有价值的课吧,这是老师积几十年的学识认真准备的盛宴。 可能你会说,大学没有好的课程,老师都在划水。如果你有这样的看法,我想说,可能是你了解的太少所致,多去了解一下一定有让你满意的老师。另外,为什么大学会出现这样不好的课程呢?因为老师不愿意好好上课。为什么老师不愿意好好教学呢?因为在功利化的指挥棒下,好好上课是性价比最低的行为。如此,你就知道大学只知道功利化、工具化的接受教育,而不培养人文素养的恶果了吧! diff --git a/1.杭电生存指南/1.2竞赛指北.md b/1.杭电生存指南/1.2竞赛指北.md index 53aa6ee..64e6cb0 100644 --- a/1.杭电生存指南/1.2竞赛指北.md +++ b/1.杭电生存指南/1.2竞赛指北.md @@ -43,7 +43,7 @@ 好处是本身就是落地项目,在论证项目可行性时具有很强的说服力,这类项目也相对来说会容易获奖。对于想要做实际落地项目的技术人员来说是不错的锻炼机会。 -坏处是甲方可能提出大量需求,技术人员需付出大量精力跟进,然而因为项目本身参与比赛而无法收取原定的外包费用,技术人员成为白菜大学生被白嫖(当然这个潜在可能性带来的坏处也因人而异,如果不在乎频繁改动需求 / 愿意做没有外包费用的无偿奉献,只想锻炼自己,那就无所谓)。 +坏处是甲方**可能**提出大量需求,技术人员需付出大量精力跟进,然而因为项目本身参与比赛而无法收取原定的外包费用,技术人员成为白菜大学生被白嫖(当然这个潜在可能性带来的坏处也因人而异,如果不在乎频繁改动需求 / 愿意做没有外包费用的无偿奉献,只想锻炼自己,那就无所谓)。 - 自立初创项目 @@ -81,7 +81,7 @@ CTF还有的缺点也是目前热门领域的通病:发展速度过快,后 更多可以参考计算安全章节 -[传送门](/6.%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%AE%89%E5%85%A8/6.%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%AE%89%E5%85%A8.html) +[传送门](/6.%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%AE%89%E5%85%A8/6.%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%AE%89%E5%85%A8) ## 数据科学竞赛 diff --git a/1.杭电生存指南/1.6正确解读GPA.md b/1.杭电生存指南/1.6正确解读GPA.md index 9df0525..770bfb5 100644 --- a/1.杭电生存指南/1.6正确解读GPA.md +++ b/1.杭电生存指南/1.6正确解读GPA.md @@ -10,11 +10,11 @@ GPA,一个酷似成绩的东西, 毕竟在高中,一份理想的成绩意味着一个光明的未来。 -但是我想说,在大学,请摆脱高中的绩点惯性。 +但是我想说,**在大学,请摆脱高中的绩点惯性**。 在大学,绩点其实只是一个获得资源的工具,高的绩点并不代表光明的未来,也不能够代表高超的学习能力和扎实的专业知识。同时我们要明白,与高中截然不同的是,大学是一个多目标优化问题,绩点只是优化问题的一个维度,而非所有。 -> author:晓宇 +> **author:晓宇** 所以本文会讲述 GPA 能够带来什么,什么是一个合理的对待 GPA 的态度,如果需要,如何获得一个较高的 GPA 。 @@ -90,7 +90,7 @@ B. 大一进来从来不太在意 GPA,大部分经历在研究 Github 项目 当你已经成为大学生的时候,GPA(成绩)不是和一个人的优秀的呈正相关的,这不过是一个通往一些资源的途径,同样的,也有很多资源可以不用 GPA,可以靠个人硬实力去争取,例如实习,例如科研助理云云。只是说,如果你不知道干啥,先认真学好专业课知识,是一个保有收益的事情,但当有其他选择的时候可以权衡,但也不可走另外一个极端,则完全不在乎 GPA,在职业规划并不清晰的时候不要自废道路。 -最后想说的是,一个获得资源的玩具罢了,不值得让你常沉苦海,永失真道。 +最后想说的是,一个获得资源的玩具罢了,不值得让你**常沉苦海,永失真道**。 ## GPA 补充内容: diff --git a/1.杭电生存指南/1.8转专业二三事.md b/1.杭电生存指南/1.8转专业二三事.md index 32bd68c..ed6b3a4 100644 --- a/1.杭电生存指南/1.8转专业二三事.md +++ b/1.杭电生存指南/1.8转专业二三事.md @@ -4,11 +4,11 @@ 相信转专业的人里,不少是慕 HDU 的强势理工科热门专业来的。但是在转专业之前,你需要先确认以下几点。 -1. 你是跟风听你家七大姑八大姨说这个专业好,才想转来这个专业的吗? -2. 你确定你所向往的和这个专业所学的相关吗?有没有比这个专业更贴切的选择? -3. 你确定你能良好适应(至少不反感)这个专业所学的专业课吗? +1. 你是**跟风**听你家七大姑八大姨说这个专业好,才想转来这个专业的吗? +2. 你确定你**所向往的**和这个专业所学的**相关**吗?有没有比这个专业更贴切的选择? +3. 你确定你能良好适应(**至少不反感**)这个专业所学的专业课吗? -以上的问题,如果有觉得不确定的,也没关系,你至少有一学期在学校里探索。可以是问该学院的学长学姐的感受,可以是进研究相关专业知识的社团学习,也可以是自己研究。总之,不能转专业转得迷迷糊糊,因为虽然 HDU 转专业机制比较友好,但转专业机会只有一次,如果你转进去之后发现自己完全不适应,那也只能自认倒霉。 +以上的问题,如果有觉得不确定的,也没关系,你至少有一学期在学校里探索。可以是问该学院的学长学姐的感受,可以是进研究相关专业知识的社团学习,也可以是自己研究。总之,不能转专业转得迷迷糊糊,因为虽然 HDU 转专业机制比较友好,**但转专业机会只有一次**,如果你转进去之后发现自己完全不适应,那也只能自认倒霉。 像笔者本人最初其实想做游戏开发,本身也热爱绘画之类的艺术。当年只觉得游戏开发和计算机有关,一门心思转计算机,后来转成功之后才发现其实数媒的培养计划更贴合笔者想学的,而现在所在的计科学得更多的是计算机理论方面的知识,也跟游戏开发不搭边。 @@ -29,16 +29,16 @@ ::: -转专业填报截止时间一般是在期末考试结束前后,届时最多填两个意向专业。 +转专业填报截止时间一般是在期末考试结束前后,届时**最多填两个**意向专业。 -转专业公示时间一般在开学前后。在转专业结果公示一周内,可以申请放弃转专业,此时视作已用过一次转专业机会,不可再次转专业。所以如果是非某个专业不去,建议只填报一个意向专业,以防被第二个专业录取,失去转专业资格。 +转专业公示时间一般在开学前后。在转专业结果公示一周内,**可以申请放弃转专业**,此时视作已用过一次转专业机会,**不可再次转专业**。所以如果是非某个专业不去,建议只填报一个意向专业,以防被第二个专业录取,失去转专业资格。 ## 转专业后的选课 在转专业公示结束后,转专业才正式生效。在公示期期间,如果想提前选课,需要走特殊退改选;也可以等转专业生效后再正常选课。 -需要注意的是,你必须退掉原专业所有的课程。如果在选课结束后,你仍有未退的原专业课程,你必须含泪又交学费又上课,说不好还要考这个课的试。其中要特别注意原专业的短学期实践课,这个课程比较容易被忽视。 +需要注意的是,**你必须退掉原专业所有的课程**。如果在选课结束后,你仍有未退的原专业课程,你必须含泪又交学费又上课,说不好还要考这个课的试。其中要特别注意原专业的短学期实践课,这个课程比较容易被忽视。 -在排课时,请找到你转入专业的培养计划,根据培养计划的课程号进行选课(而不是课程名)。HDU 有些课程同名不同号,如果选择了同名不同号的课程,只能寻求课程替代(而且有概率不成功)。这种情况常见于你发现你原来专业的课程和转入专业的某课程名字一样,你懒得换了,殊不知这两个课程完全不是一个课程号,喜变纯纯冤种。 +在排课时,请找到你转入专业的培养计划,根据培养计划的**课程号**进行选课(而不是课程名)。HDU 有些课程同名不同号,如果选择了同名不同号的课程,只能寻求课程替代(而且有概率不成功)。这种情况常见于你发现你原来专业的课程和转入专业的某课程名字一样,你懒得换了,殊不知这两个课程完全不是一个课程号,喜变纯纯冤种。 另外,建议根据开课班级排课。有些课程虽然课程号相同,但可能开给不同学院。比如计算机学院的课程经常和卓越或计算机二专业的一些课程同号,如果你选了其他专业的开课班级的班,期末考试可能会不一样(如计科和卓越的电路与电子学课程号同号,但在 20 级是分开期末考试的)。建议看清开课班级再选课。 diff --git a/1.杭电生存指南/1.9问题专题:好想进入实验室.md b/1.杭电生存指南/1.9问题专题:好想进入实验室.md index 08a6c3d..fec7ab0 100644 --- a/1.杭电生存指南/1.9问题专题:好想进入实验室.md +++ b/1.杭电生存指南/1.9问题专题:好想进入实验室.md @@ -10,15 +10,15 @@ 概括一下:摒弃伸手,被动思维,能够主动争取各种机会,带着一个能够独当一面的能力进入实验室,与老师能够形成合作关系。 -能力上:目前计算机上的科研主要在两大方向,第一大方向是 AI(关于这件事情是不是畸形要后期在讨论)第二大方向是系统数据库, +**能力上:**目前计算机上的科研主要在两大方向,第一大方向是 AI(关于这件事情是不是畸形要后期在讨论)第二大方向是系统数据库, 对于数据库与系统,我目前还没有涉及 -领域的基础能力:这里要我力推我们的课题教程,有较好的 AI 路线图,尽管 AI 有非常多子方向,如 NLP,CV,多模态,CV 下面又有检测 语义分割,NLP 又有推荐系统等云云,但是无论如何他们的源头都是 MLP,MLP 的源头都是多维线性回归,都是基于统计学习理论体系下,都是使用 Pytorch,都要学习数学理论体系,所以是可以要有一套类似的培养体系的。视觉被推荐 cs231n NLP 被推荐 CS224n。 +**领域的基础能力:**这里要我力推我们的课题教程,有较好的 AI 路线图,尽管 AI 有非常多子方向,如 NLP,CV,多模态,CV 下面又有检测 语义分割,NLP 又有推荐系统等云云,但是无论如何他们的源头都是 MLP,MLP 的源头都是多维线性回归,都是基于统计学习理论体系下,都是使用 Pytorch,都要学习数学理论体系,所以是可以要有一套类似的培养体系的。视觉被推荐 cs231n NLP 被推荐 CS224n。 论文的阅读能力:在了解一个领域的时候,最开始会发现什么词都不懂,一篇文章无论是从语言上还是英文上都无法阅读,所以能否具备快速阅读并读懂一篇文章的能力也是非常重要的。 -如何寻找老师上: +**如何寻找老师上:** 学校内和学校外都可以寻求合作,在学校内, diff --git a/2.高效学习/2.1.3错误的提问姿态.md b/2.高效学习/2.1.3错误的提问姿态.md index af709df..672bf95 100644 --- a/2.高效学习/2.1.3错误的提问姿态.md +++ b/2.高效学习/2.1.3错误的提问姿态.md @@ -6,9 +6,11 @@ 然后你要慢慢询问他的问题,接着你要问各种问题各种检查然后去看,如果有十个人一百个人都这么问,你肯定会受不了的吧。 -事实上, 如果希望能提高得到回答的概率, 提问者应该学会如何更好地提问. 换句话说, 提问者应该去积极思考 "我可以主动做些什么来让对方更方便地帮助我诊断问题". +事实上,如果希望能提高得到回答的概率,提问者应该学会如何更好地提问。换句话说,提问者应该去积极思考 "我可以主动做些什么来让对方更方便地帮助我诊断问题". -如果你的提问方式非常不专业, 很可能没有人愿意关注你的问题, 因为这不仅让人觉得你随便提的问题没那么重要, 而且大家也不愿意花费大量的时间向你来回地咨询. +如果你的提问方式非常不专业,很可能没有人愿意关注你的问题,因为这不仅让人觉得你随便提的问题没那么重要,而且大家也不愿意花费大量的时间向你来回地咨询。 + + ## 解决 @@ -30,11 +32,37 @@ ![](https://cdn.xyxsw.site/boxcnhuhE7qBLHyJKaesHGC033b.png) -欢迎大家阅读 +### 关于截图 -[Stop-Ask-Questions-The-Stupid-Ways/README.md at master · tangx/Stop-Ask-Questions-The-Stupid-Ways](https://github.com/tangx/Stop-Ask-Questions-The-Stupid-Ways/blob/master/README.md) 别像弱智一样提问 +如果你在问问题的时候掏出一张手机拍电脑🤳🖥️的图片,那么大概率会让想要帮助你解决问题的学长血压升高然后放弃回答你的问题。 -[https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way/blob/main/README-zh_CN.md](https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way/blob/main/README-zh_CN.md) 提问的智慧 +除非遇到一些特殊情况(例如你的电脑进 BIOS 了),只能手机拍照,也请保证图片清晰便于识别。 + +![](static/02.jpg) + +在 wiki 的[2.2 优雅的使用工具](2.2优雅的使用工具.md),有推荐一些好用开源的截图工具 + +不过一般情况来说,Windows 的组合键`Win+Shift+S`截屏,在任意窗口按下这个组合键便可进入截屏模式,按住鼠标左键拖动框选区域即可截屏,使用`Ctrl+V`操作将截屏内容粘贴到想要保存的地方;如果已经登录了 QQ,那么 QQ 的截图快捷键默认是`Ctrl+Alt+A`,同样使用`Ctrl+V`粘贴截屏内容。 + +ps:QQ 有长截图的功能,妈妈再也不用担心我不会滚动捕捉了! + +记住这两个快捷键已经足够满足你对截图的 90% 的需求了 + +### 橡皮鸭 + +> 来自伯克利大学的学习建议 + +当遇到问题时,除了截图外,试着组织语言来解释你遇到困难的地方。 + +![](static/01.jpg) + +**这并不需要一个找到懂得如何解决问题的人 (或者甚至是一个人 —— 这种做法通常被称为橡皮鸭,因为你可以把一只橡皮鸭当作你的练习对象) ,因为主要目标是让你弄清楚你自己的想法,弄清楚你的理解和代码到底在哪里卡住了。这样你可以知道应该专注于哪一部分,以便更好地理解。** + +### 欢迎大家阅读 + +[Stop-Ask-Questions-The-Stupid-Ways](https://github.com/tangx/Stop-Ask-Questions-The-Stupid-Ways/blob/master/README.md) 别像弱智一样提问 + +[How-To-Ask-Questions-The-Smart-Way](https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way/blob/main/README-zh_CN.md) 提问的智慧 ## 关于如何搜索代码 @@ -56,11 +84,11 @@ cv.waitKey(0) 接下来,我会去搜索每行代码的作用:(以下是搜索后我做的注释) ```python -import cv2 as cv # 调opencv库 +import cv2 as cv # 调 opencv 库 img = cv.imread('lbxx.jpg',1) # 读取图片(“图片路径”) -img_1 = cv.cvtColor(img,cv.COLOR_BGR2GRAY) # 转换成灰度图(图片, 颜色模式) -cv.imshow('gray',img_1) # 展示图片(展示img_1为灰度图) -cv.imshow('colour',img) # 展示图片(展示img为彩色图) +img_1 = cv.cvtColor(img,cv.COLOR_BGR2GRAY) # 转换成灰度图(图片,颜色模式) +cv.imshow('gray',img_1) # 展示图片(展示 img_1 为灰度图) +cv.imshow('colour',img) # 展示图片(展示 img 为彩色图) cv.waitKey(0) # 保存展示窗口打开 ``` diff --git a/2.高效学习/2.2优雅的使用工具.md b/2.高效学习/2.2优雅的使用工具.md index 00650f5..6618b05 100644 --- a/2.高效学习/2.2优雅的使用工具.md +++ b/2.高效学习/2.2优雅的使用工具.md @@ -12,13 +12,17 @@ - [Everything](https://www.voidtools.com/zh-cn/downloads/) 电脑上的全局文件搜索 方便你找到不知道丢哪的文件 - [SpaceSniffer](http://www.uderzo.it/main_products/space_sniffer/download.html) 快速分析硬盘空间占用情况 解放储存,不解放大脑 +- [Snipaste](https://zh.snipaste.com/) 全局截图工具,按 F1 键截图,F3 键贴图,简单够用 +- [eSearch](https://esearch.vercel.app/) 全局截图工具,优化了文字识别功能,可个性化,支持全平台 +- [ShareX](https://esearch.vercel.app/) 全局截图工具,功能非常强大,高度可个性化,仅支持 Win +- [IDM](https://www.internetdownloadmanager.com/) :好用的多线程下载器(付费的),想要免费的话可以搜一下绿色版之类的。(推荐设置线程数为 CPU 核心数的 2 倍,比如 8 核心的 CPU 设置线程数为 16) - [XDM](https://github.com/subhra74/xdm) :IDM 的跨平台版本。 - [uTools](https://www.u.tools/) :自由组合插件集(最好用的是 Alt+Space 搜索功能)非常强大,比如安装 fileshare 可以在局域网共享超大文件,而且是跨平台的。 - [PowerToys](https://github.com/microsoft/PowerToys) :微软官方出品,包含诸多功能,解决 windows 下一些小痛点。 - [Connect to Work or Games from Anywhere | Parsec](https://parsec.app/) :串流小工具,简单来说你就是可以在手机上玩电脑了,远程操作,极致体验~~(也可以玩游戏)~~ - [VMware workstation](../3.%E7%BC%96%E7%A8%8B%E6%80%9D%E7%BB%B4%E4%BD%93%E7%B3%BB%E6%9E%84%E5%BB%BA/3.Y.1VMware%E7%9A%84%E5%AE%89%E8%A3%85%E4%B8%8E%E5%AE%89%E8%A3%85Ubuntu22.04%E7%B3%BB%E7%BB%9F.md):虚拟机就用它!但是最好自己找找盗版,正版要钱。 - [cloc](https://github.com/AlDanial/cloc): 统计代码行数(空白行,注释行,代码行)的小工具 -- mv & cp 命令显示进度条: 在复制大文件的时候非常友好,可以通过以下脚本安装(Linux系统) +- mv & cp 命令显示进度条:在复制大文件的时候非常友好,可以通过以下脚本安装(Linux 系统) ```bash #!/bin/bash @@ -50,9 +54,9 @@ rm coreutils-8.32 coreutils-8.32.tar.xz ## 笔记工具 -- [Typora](https://typora.io/) 付费的,~~你可以去并夕夕啊淘宝啊花个不多于 5 块钱的钱买盗版 😋~~,( 正版 $14.99 ),真的好用,感觉没有 Markdown 编辑器能好用过 Typora🤥。 +- [Typora](https://typora.io/) 付费的,~~你可以去并夕夕啊淘宝啊花个不多于 5 块钱的钱买盗版 😋~~,(正版 $14.99),真的好用,感觉没有 Markdown 编辑器能好用过 Typora🤥。 - [MarkText](https://github.com/marktext/marktext) 免费的,平替 Typora。 -- [MiaoYan](https://github.com/tw93/MiaoYan) 仅支持 apple ,界面挺清爽。 +- [MiaoYan](https://github.com/tw93/MiaoYan) 仅支持 apple,界面挺清爽。 - [思源笔记](https://b3log.org/siyuan/) 一个国产开源的笔记/知识库软件,优势是 本地化、双链、Markdown 语法,与 Obsidian 定位相似,但 Geek 成分和自定义空间相对更高 - [Zotero](https://www.zotero.org/):协助文献阅读还有写笔记,支持与平板同传(同时他是开源的,所以可以添加一些插件) @@ -67,8 +71,8 @@ rm coreutils-8.32 coreutils-8.32.tar.xz ## 浏览器插件 -- [沉浸式翻译](https://immersivetranslate.com/docs/installation/):中英文对照翻译,可以给你英文下面写一小行中文翻译(里面免费的 api 只有谷歌,必应,腾讯,不过够了,也可以自行配置其他 api ) -- (你真的不玩原神吗)来试试这款原神浏览器插件 [派蒙 paimon](https://github.com/daidr/paimon-webext) : 可以实时显示你的树脂,委托,派遣等情况提示。 +- [沉浸式翻译](https://immersivetranslate.com/docs/installation/):中英文对照翻译,可以给你英文下面写一小行中文翻译(里面免费的 api 只有谷歌,必应,腾讯,不过够了,也可以自行配置其他 api) +- (你真的不玩原神吗)来试试这款原神浏览器插件 [派蒙 paimon](https://github.com/daidr/paimon-webext) :可以实时显示你的树脂,委托,派遣等情况提示。 - [wappalyzer](https://www.wappalyzer.com/):如果你是个 web 仔,这个插件可以帮你检测网页所用的前后端技术栈。 - [FeHelper--Web 前端助手](https://github.com/zxlie/FeHelper):十几个小工具的集合,包括 base64 离线解码等。 - [darkreader](https://github.com/darkreader/darkreader):适应网页的暗色模式,夜深人静冲浪更爽 diff --git a/2.高效学习/static/01.jpg b/2.高效学习/static/01.jpg new file mode 100644 index 0000000..fe35ce9 Binary files /dev/null and b/2.高效学习/static/01.jpg differ diff --git a/2.高效学习/static/02.jpg b/2.高效学习/static/02.jpg new file mode 100644 index 0000000..7ed2142 Binary files /dev/null and b/2.高效学习/static/02.jpg differ diff --git a/3.编程思维体系构建/3.0 编程入门之道.md b/3.编程思维体系构建/3.0 编程入门之道.md index e84e8a2..145fe72 100644 --- a/3.编程思维体系构建/3.0 编程入门之道.md +++ b/3.编程思维体系构建/3.0 编程入门之道.md @@ -13,7 +13,7 @@ ### 这篇讲义讲什么 - 首先,如上文所述,如何轻松地利用本章乃至整个讲义 -- 在第一点的基础上,引申出我自己归纳的编程入门之“道” +- 在第一点的基础上,引申出我自己归纳的**编程入门之“道”** ### 请随意喷这篇讲义 @@ -28,7 +28,7 @@ 1. 这里的文章的最大的作用是帮你打开信息壁垒,告诉你编程的世界有哪些东西,可以去学什么。 2. 把讲义当成字典来用。很多文章并不是完全对新人友好的,你现在不需要看懂,甚至可能不需要看。你只要大概记下有这么个概念和工具,当下次要用到的时候,再查阅、再仔细学习就好。 -简单来说就是,抱着平和的心态,随便看看,知道这一章都讲了哪些东西,看完有个印象就好,然后常回家看看。 +简单来说就是,**抱着平和的心态,随便看看**,知道这一章都讲了哪些东西,看完有个印象就好,然后常回家看看。 技术细节本身永远都不是最重要的,重要的是思想和方法,如何快速掌握一门技术。 @@ -38,7 +38,7 @@ 这是我的第一个也是最重要的建议。 -无论是学一门语言,还是学一个工具:尽可能地先用最短的时间搞懂这个东西是做什么的,然后以最快的方式把它“run”起来。 +无论是学一门语言,还是学一个工具:**尽可能地先用最短的时间搞懂这个东西是做什么的,然后以最快的方式把它“run”起来。** 当你已经能跑起一个语言、一个工具的最简单的示例的时候,再去花时间慢慢了解背后的复杂的内容,再去拓展即可。先用起来,跑起来,带着问题去翻资料。 @@ -58,7 +58,7 @@ 那么该怎么学呢? -先简单地会一样东西的最核心的部分,再去找一个实际的编程场景、编程任务、项目。你会在完成这个项目中遇到各种各样的问题,无论是遗漏了知识点还是压根没思路,这时候不断地用搜索引擎来学习。( [2.3 高效的信息检索](../2.%E9%AB%98%E6%95%88%E5%AD%A6%E4%B9%A0/2.3%E9%AB%98%E6%95%88%E7%9A%84%E4%BF%A1%E6%81%AF%E6%A3%80%E7%B4%A2.md) +**先简单地会一样东西的最核心的部分,再去找一个实际的编程场景、编程任务、项目。你会在完成这个项目中遇到各种各样的问题,无论是遗漏了知识点还是压根没思路,这时候不断地用搜索引擎来学习。( **[2.3 高效的信息检索](../2.%E9%AB%98%E6%95%88%E5%AD%A6%E4%B9%A0/2.3%E9%AB%98%E6%95%88%E7%9A%84%E4%BF%A1%E6%81%AF%E6%A3%80%E7%B4%A2.md)**)** 举个例子:你想做一个小程序,来检测某电影院的电影预售。程序大概要做到不断刷新网页,一检测到这个电影预售了,就马上发短信给自己手机(或者直接帮你抢) @@ -85,7 +85,7 @@ 刚开始你可能什么都不会,什么地方都被阻塞,但当你把坑踩遍了。就发现,哎嘿,不好意思,这玩意我怎么又会! -所以让我们基于这个“任务驱动”,再看看本章的内容。这些内容大多看了就忘,因为细节非常多,而且并不一定能解决你手头上的问题。但这些文档,带你领进了新的领域的大门,让你的工具箱里多了一个可以解决问题的工具,以后用到了可以想起他们。并且,这些文章多是通俗的,且作者多是讲述了 ta 所认为的该语言/工具的最核心、最精华的部分,或者说第一次入门最需要学习的部分。 +**所以让我们基于这个“任务驱动”,再看看本章的内容。这些内容大多看了就忘,因为细节非常多,而且并不一定能解决你手头上的问题。但这些文档,带你领进了新的领域的大门,让你的工具箱里多了一个可以解决问题的工具,以后用到了可以想起他们。并且,这些文章多是通俗的,且作者多是讲述了 ta 所认为的该语言/工具的最核心、最精华的部分,或者说第一次入门最需要学习的部分。** ## 圈子 diff --git a/3.编程思维体系构建/3.1该使用哪个编辑器???.md b/3.编程思维体系构建/3.1该使用哪个编辑器???.md index 5600062..2a14a07 100644 --- a/3.编程思维体系构建/3.1该使用哪个编辑器???.md +++ b/3.编程思维体系构建/3.1该使用哪个编辑器???.md @@ -20,9 +20,9 @@ 当然在这里我们主要讲的是代码编辑器,一个好的编辑器可以节省开发时间,提高工作效率,它们都能提供非常方便易用的开发环境。你可以用它们来编写代码,查看源文件和文档等,简化你的工作。以下是一些常用的代码编辑器,每个不同的编辑器都有不尽相同的目标用户群体。 -- Visual Studio Code : 微软 VS 系列的新作品,适用于多平台的代码编辑器,其很好服从了轻量化 + 拓展的 Unix 思想,在整体快捷方便的同时具有极强的功能拓展空间,是值得首要推荐的编辑器。 -- Vim : Vim 是从 vi 发展出来的一个文本编辑器,在程序员中被广泛使用,运行在 Linux 环境下。 -- GNU Emacs : Emacs 是一个轻便、可扩展、免费的编辑器,它比其它的编辑器要更强大,是一个整合环境,或可称它为集成开发环境。它可以处理文字,图像,高亮语法,将代码更直观地展现给开发者。 +- *Visual Studio Code* : 微软 VS 系列的新作品,适用于多平台的代码编辑器,其很好服从了轻量化 + 拓展的 Unix 思想,在整体快捷方便的同时具有极强的功能拓展空间,是值得首要推荐的编辑器。 +- *Vim*: Vim 是从 vi 发展出来的一个文本编辑器,在程序员中被广泛使用,运行在 Linux 环境下。 +- *GNU Emacs* : Emacs 是一个轻便、可扩展、免费的编辑器,它比其它的编辑器要更强大,是一个整合环境,或可称它为集成开发环境。它可以处理文字,图像,高亮语法,将代码更直观地展现给开发者。 ### 什么是编译器 diff --git a/3.编程思维体系构建/3.2.1为什么要选择ACM——谈谈我与ACM.md b/3.编程思维体系构建/3.2.1为什么要选择ACM——谈谈我与ACM.md index 71047ad..cd02091 100644 --- a/3.编程思维体系构建/3.2.1为什么要选择ACM——谈谈我与ACM.md +++ b/3.编程思维体系构建/3.2.1为什么要选择ACM——谈谈我与ACM.md @@ -12,7 +12,7 @@ author:wenjing ## ACM 能为我带来什么? -显然,做为一名计算机专业的学生,编程是一项必须掌握的技能。再次引用 Niklaus Emil Wirth 的一句话:程序=算法 + 数据结构。例如在大一开设的程序设计基础中,我们需要重点学习链表这一数据结构,熟悉运用分支与循环结构(勉强也算算法吧)。然而,在 ACM 中,这是基础到不值一提的事物,宛如空气与水一般基础。你们是否想过,花了大量课时学习的这些知识,其实小学生也可以学会(看看远处的小学编程补习班吧,家人们)那做为大学生去学习这些知识,是否应当得到一些不止于考试内容的知识呢? +显然,做为一名计算机专业的学生,编程是一项必须掌握的技能。再次引用 Niklaus Emil Wirth 的一句话:**程序=算法 + 数据结构。**例如在大一开设的程序设计基础中,我们需要重点学习链表这一数据结构,熟悉运用分支与循环结构(勉强也算算法吧)。然而,在 ACM 中,这是基础到不值一提的事物,宛如空气与水一般基础。你们是否想过,花了大量课时学习的这些知识,其实小学生也可以学会(看看远处的小学编程补习班吧,家人们)那做为大学生去学习这些知识,是否应当得到一些不止于考试内容的知识呢? 我认为有两个方向,一是我们去学习一些更底层的逻辑与原理,此外就是学习如何更好的利用链表,实现一些别的数据结构做不到的事情,我认为 ACM 可以极大的提升我们对后者的理解。 diff --git a/3.编程思维体系构建/3.2.2手把手教你学算法——如何使用OJ(Online Judge).md b/3.编程思维体系构建/3.2.2手把手教你学算法——如何使用OJ(Online Judge).md index 57306b1..6c48141 100644 --- a/3.编程思维体系构建/3.2.2手把手教你学算法——如何使用OJ(Online Judge).md +++ b/3.编程思维体系构建/3.2.2手把手教你学算法——如何使用OJ(Online Judge).md @@ -119,7 +119,7 @@ Div.1、Div.2、Div.3、Div.4 数字越小难度越大。 这是一场笔者之前赛后补过的 Div.2,画面右下角分别为赛后公告和题解,右侧便是开启 VP 的按钮。 ![](https://cdn.xyxsw.site/wenjing10.png) -VP模拟赛时的好处就是在虚拟参赛中获得真实比赛才能积累的经验,比如这里笔者发现通过前三题后,我应该先去看看 F 题,因为做出来的人更多,我有更大的可能性做出来,ACM 中题目并不是 100% 按难度排序。 +*VP模拟赛时的好处就是在虚拟参赛中获得真实比赛才能积累的经验,比如这里笔者发现通过前三题后,我应该先去看看 F 题,因为做出来的人更多,我有更大的可能性做出来,ACM 中题目并不是 100% 按难度排序。* ![](https://cdn.xyxsw.site/wenjing11.png) diff --git a/3.编程思维体系构建/3.2算法杂谈.md b/3.编程思维体系构建/3.2算法杂谈.md index 9157afa..bc9d23e 100644 --- a/3.编程思维体系构建/3.2算法杂谈.md +++ b/3.编程思维体系构建/3.2算法杂谈.md @@ -12,7 +12,7 @@ ## 学了算法就相当于学好了计算机吗? -学好了算法当然不等于学好了计算机科学。计算机科学是一个非常庞大的知识体系,包括更为底层的计算机组成原理、编译原理等,更为表层的 AI,开发等,是一门综合性学科。总的来说,算法是计算机科学中较为重要的一部分,但远远不是全部。 +学好了算法当然不等于学好了计算机科学。计算机科学是一个非常庞大的知识体系,包括更为底层的计算机组成原理、编译原理等,更为表层的 AI,开发等,是一门综合性学科。总的来说,算法是计算机科学中较为重要的一部分,但**远远**不是全部。 ## 学算法就要用《算法导论》一类的书吗? @@ -32,6 +32,6 @@ ACM 是美国计算机协会(Association for Computing Machinery)的缩写 在我校,参加 ACM 社团(姑且叫做社团)并不代表能够参加有含金量的团体赛(ICPC、CCPC 等)。你需要先参加由我校教练刘春英老师组织的各种比赛,有资格进入集训队后,才有机会代表学校参加比赛(当然不限名额的个人赛想参加就参加)。 -进入集训队后采取末位淘汰制度(最后留下来的人在 20 人左右),最后留下来的人才有机会参加比赛。因此个人并不推荐 0 基础的同学对于 ACM 过于执着,有 0 基础的同学最后进入校队的例子,不过这通常意味着你一天至少得刷一道算法题。如果还是想尝试的同学,可以去洛谷 ([www.luogu.com.cn](http://www.luogu.com.cn))、Codeforces([www.codeforces.com](http://www.codeforces.com))、Atcoder([atcoder.jp](https://atcoder.jp/)) 等平台上注册账号,练习题目,参加这些网站定期组织的一些比赛。 +进入集训队后采取末位淘汰制度(最后留下来的人在 20 人左右),最后留下来的人才有机会参加比赛。**因此个人并不推荐 0 基础的同学对于 ACM 过于执着**,有 0 基础的同学最后进入校队的例子,不过这通常意味着你一天至少得刷一道算法题。如果还是想尝试的同学,可以去洛谷 ([www.luogu.com.cn](http://www.luogu.com.cn))、Codeforces([www.codeforces.com](http://www.codeforces.com))、Atcoder([atcoder.jp](https://atcoder.jp/)) 等平台上注册账号,练习题目,参加这些网站定期组织的一些比赛。 如果经过一段时间的练习能够在 Codefoces([www.codeforces.com](http://www.codeforces.com))上达到 1400 以上的 Rating,那么可以再观望观望参与 ACM。 diff --git a/3.编程思维体系构建/3.3如何选择编程语言.md b/3.编程思维体系构建/3.3如何选择编程语言.md index afe19df..a8f949d 100644 --- a/3.编程思维体系构建/3.3如何选择编程语言.md +++ b/3.编程思维体系构建/3.3如何选择编程语言.md @@ -22,9 +22,9 @@ C 语言其实是一门优秀的承上启下的语言,既具有高级语言的 但是其功能毕竟受限,有时候用起来会苦恼其操作受限以及各种奇奇怪怪的 bug 问题。 -如果为了增强自身的编程能力和计算机素养,培养解决问题的能力,C 语言的你的不二选择。在这里强烈推荐 jyy 老师的各类课程。([http://jyywiki.cn/](http://jyywiki.cn/) +**如果为了增强自身的编程能力和计算机素养,培养解决问题的能力,C 语言的你的不二选择。在这里强烈推荐 jyy 老师的各类课程。([http://jyywiki.cn/](http://jyywiki.cn/))** -我们的任务一部分会使用 C 语言,一方面培养大家编程能力,一方面辅助大家期末考试。 +**我们的任务一部分会使用 C 语言,一方面培养大家编程能力,一方面辅助大家期末考试。** ### C++ @@ -34,7 +34,7 @@ C 语言其实是一门优秀的承上启下的语言,既具有高级语言的 - 更高级的语言特征,可自定义数据类型 - 标准库 -C++ 既有 C 面向过程的特点,又拥有面向对象的特性,是一门系统级的语言。 +**C++ 既有 C 面向过程的特点,又拥有面向对象的特性,是一门系统级的语言。** 编译器、操作系统的开发,高性能服务器的开发,游戏引擎的开发,硬件编程,深度学习框架的开发......只要是和底层系统或者是与性能相关的事情,通常都会有 C++ 的一席之地。 @@ -46,7 +46,7 @@ Python 在图里是电锯,适合干比较“狂野”的任务,也是深度 使用缩进控制语句是此语言的特点。 -作为深度学习的主要使用语言,我们将以Python 为主。 +**作为深度学习的主要使用语言,我们将以****P****ython 为主。** ## JAVA @@ -54,7 +54,7 @@ Python 在图里是电锯,适合干比较“狂野”的任务,也是深度 他太老了,虽然不少框架都依托于 Java,但是不得不说,一些地方略有落后。 -频繁应用于Web 开发,安卓应用等等。 +**频繁应用于****W****eb 开发,安卓应用等等。** ![](https://cdn.xyxsw.site/boxcnPv2FcyQxGLjYHThSaJNwRf.jpeg) diff --git a/3.编程思维体系构建/3.4.1FAQ:常见问题.md b/3.编程思维体系构建/3.4.1FAQ:常见问题.md index 03b00ff..1872180 100644 --- a/3.编程思维体系构建/3.4.1FAQ:常见问题.md +++ b/3.编程思维体系构建/3.4.1FAQ:常见问题.md @@ -22,7 +22,7 @@ 更严重的是,他可能会透支学校的信誉。 -同时,先学好 C 语言对你有以下帮助: +**同时,先学好 C 语言对你有以下帮助:** 1. 掌握计算机底层知识:C 语言是一种高效的系统级语言,它的语法和数据结构设计直接映射到底层计算机硬件,通过学习 C 语言可以更深入地了解计算机底层运作原理,为理解更高级的编程语言和开发工具奠定基础。 2. 提高编程能力:C 语言的语法相对较为简单,但是它要求程序员手动管理内存,这需要编程者深入了解内存结构和指针的使用。通过学习 C 语言,可以锻炼编程能力,提高代码质量和效率。 @@ -65,7 +65,7 @@ NJU-ICS-PA 南京大学计算机系统基础 有且仅有大学有这样好的资源帮助你了 -## 坚持了好久还是搞不定,我想放弃了 +## **坚持了好久还是搞不定,我想放弃了** ![](https://cdn.xyxsw.site/boxcnuNXrb5zOppCZAlGQ19wuDk.jpg) diff --git a/3.编程思维体系构建/3.4.2用什么写 C 语言.md b/3.编程思维体系构建/3.4.2用什么写 C 语言.md index 0b145db..21ea037 100644 --- a/3.编程思维体系构建/3.4.2用什么写 C 语言.md +++ b/3.编程思维体系构建/3.4.2用什么写 C 语言.md @@ -12,7 +12,7 @@ Visual Studio(以下简称 VS)是 Windows 下最完美的 C/C++ 等语言的 什么是 IDE,什么是代码编辑器,什么是编译器等等细碎问题参考文档 [3.1 该使用哪个编辑器???](3.1%E8%AF%A5%E4%BD%BF%E7%94%A8%E5%93%AA%E4%B8%AA%E7%BC%96%E8%BE%91%E5%99%A8%EF%BC%9F%EF%BC%9F%EF%BC%9F.md) 看不懂的话直接无脑装 -### 下载 +### **下载** [https://visualstudio.microsoft.com/zh-hans/downloads/](https://visualstudio.microsoft.com/zh-hans/downloads/) @@ -60,7 +60,7 @@ VS 是项目制,你需要创建一个项目才能开始编写代码并运行 阅读完以后,就可以将代码全部删去,编写自己的代码了。 -注意控制台项目初始源文件后缀为.cpp 为 C++ 文件,如果编写 C 语言建议将后缀改为.c。.cpp 存在隐患:如果不小心使用了 C++ 的语法而非 C 存在的语法,编译器并不会报错,且 C 与 C++ 在某些特性存在区别。 +注意控制台项目初始源文件后缀为.cpp 为 C++ 文件,如果编写 C 语言**建议将后缀改为.c**。.cpp 存在隐患:如果不小心使用了 C++ 的语法而非 C 存在的语法,编译器并不会报错,且 C 与 C++ 在某些特性存在区别。 ### “运行”你的 C 语言代码 @@ -88,7 +88,7 @@ IDE 相比于代码编辑器,最强大的一点莫过于成熟的调试系统 ![](https://cdn.xyxsw.site/boxcnydHyaNPqUEVVWmbdGofX0d.png) -### 深色主题 +### **深色主题** 需要深色主题请在工具 - 主题里更改为深色 diff --git a/3.编程思维体系构建/3.4.3解决编程问题的普适性过程.md b/3.编程思维体系构建/3.4.3解决编程问题的普适性过程.md index cf3bd42..c2cc8d3 100644 --- a/3.编程思维体系构建/3.4.3解决编程问题的普适性过程.md +++ b/3.编程思维体系构建/3.4.3解决编程问题的普适性过程.md @@ -17,7 +17,7 @@ ## Work an Example Yourself -尝试设计算法的第一步是自己(手动)处理至少一个问题实例,为每个参数选择特定值。往往需要确定一个正确的示例,以及错误的示例。 +尝试设计算法的第一步是**自己(手动)处理至少一个问题实例,为每个参数选择特定值。**往往需要确定**一个正确的示例,以及错误的示例。** 如果你在这一步陷入困境,这通常意味着两件事中的一件。第一种情况是问题不明确,不清楚你应该做什么。在这种情况下,你必须在继续之前解决问题。如果你正在解决自己创造的问题,你可能需要更仔细地思考正确的答案应该是什么,并完善你对问题的定义。 @@ -25,15 +25,15 @@ ## Write Down What You Just Did -这一步中,必须思考解决问题所做的工作,并写下解决该特定实例的步骤。思考这一步骤的另一种方式是,写下一组清晰的指示,其他人可以按照这些指示来重现刚刚解决的特定问题实例的答案。如果在步骤 1 中执行了多个实例,那么也将重复步骤 2 多次,对步骤 1 中的每个实例重复一次。如果一条指令有点复杂,那没关系,只要指令稍后有明确的含义,我们将把这些复杂的步骤转化为它们自己的编程问题,这些问题将单独解决。 +这一步中,必须思考解决问题所做的工作,并写下**解决该特定实例的步骤。**思考这一步骤的另一种方式是,写下一组清晰的指示,**其他人可以按照这些指示来重现刚刚解决的特定问题实例的答案**。如果在步骤 1 中执行了多个实例,那么也将重复步骤 2 多次,对步骤 1 中的每个实例重复一次。如果一条指令有点复杂,那没关系,只要指令稍后有明确的含义,我们将把这些复杂的步骤转化为它们自己的编程问题,这些问题将单独解决。 ## Generalize Your Steps -将步骤 2 得到的具体步骤,抽象为一般性的结论。有时可能很难概括步骤。发生这种情况时,返回步骤 1 和 2 可能会有所帮助。做更多的问题实例将提供更多的信息供参考,更能帮助深入算法。这个过程通常被称为编写“伪代码”,以编程方式设计算法,而不使用特定的目标语言。几乎所有的程序员在编写任何实际代码之前都会使用这种方法来确保他们的算法是正确的。 +**将步骤 2 得到的具体步骤,抽象为一般性的结论。**有时可能很难概括步骤。发生这种情况时,返回步骤 1 和 2 可能会有所帮助。做更多的问题实例将提供更多的信息供参考,更能帮助深入算法。这个过程通常被称为编写“伪代码”,以编程方式设计算法,而不使用特定的目标语言。几乎所有的程序员在编写任何实际代码之前都会使用这种方法来确保他们的算法是正确的。 ## Test Your Algorithm -在步骤 3 之后,我们有了一个我们认为正确的算法。然而,我们完全有可能在这一路上搞砸了。步骤 4 的主要目的是确保我们的步骤在继续之前是正确的。为了实现这一点,我们使用不同于设计算法时使用的参数值来测试我们的算法。我们手动执行算法,并将其获得的答案与正确的答案进行比较。如果它们不同,那么我们知道我们的算法是错误的。我们使用的测试用例(参数值)越多,我们就越能确信我们的算法是正确的。不幸的是,通过测试无法确保我们的算法是正确的。要完全确定你的算法是正确的,唯一的方法就是正式证明它的正确性(使用数学证明),这超出了这个专门化的范围。 +在步骤 3 之后,我们有了一个我们认为正确的算法。然而,我们完全有可能在这一路上搞砸了。步骤 4 的主要目的是确保我们的步骤在继续之前是正确的。为了实现这一点,我们使用**不同于设计算法时使用的参数值**来测试我们的算法。我们手动执行算法,并将其获得的答案与正确的答案进行比较。如果它们不同,那么我们知道我们的算法是错误的。我们使用的测试用例(参数值)越多,我们就越能确信我们的算法是正确的。不幸的是,通过测试无法确保我们的算法是正确的。要完全确定你的算法是正确的,唯一的方法就是正式证明它的正确性(使用数学证明),这超出了这个专门化的范围。 确定好的测试用例是一项重要的技能,可以随着实践而提高。对于步骤 4 中的测试,您需要使用至少产生几个不同答案的情况进行测试(例如,如果您的算法有“是”或“否”答案,则应使用同时产生“是”和“否”的参数进行测试)。您还应该测试任何角落情况,其中行为可能与更一般的情况不同。每当您有条件决定(包括计算位置的限制)时,您应该在这些条件的边界附近测试潜在的角点情况。 @@ -47,7 +47,7 @@ 在黑盒测试中,测试人员只考虑功能的预期行为,而不考虑设计测试用例的任何实现细节。缺乏对实现细节的访问是这种测试方法的由来——函数的实现被视为测试人员无法查看的“黑盒子”。 -事实上我们无需执行步骤 1-5 就能够为假设问题设想好的测试用例。实际上,在开始解决问题之前,您可以针对问题提出一组黑盒测试。一些程序员提倡测试优先的开发方法。一个优点是,如果您在开始之前编写了一个全面的测试套件,那么在实现代码之后就不太可能在测试上有所疏漏。另一个优点是,通过提前考虑你的情况,你在开发和实现算法时能够降低错误率。 +事实上我们无需执行步骤 1-5 就能够为假设问题设想好的测试用例。实际上,在开始解决问题之前,您可以针对问题提出一组黑盒测试。一些程序员提倡**测试优先**的开发方法。一个优点是,如果您在开始之前编写了一个全面的测试套件,那么在实现代码之后就不太可能在测试上有所疏漏。另一个优点是,通过提前考虑你的情况,你在开发和实现算法时能够降低错误率。 - 选择测试用例的一些建议 diff --git a/3.编程思维体系构建/3.4.4C语言前置概念学习.md b/3.编程思维体系构建/3.4.4C语言前置概念学习.md index 735839f..90f0c33 100644 --- a/3.编程思维体系构建/3.4.4C语言前置概念学习.md +++ b/3.编程思维体系构建/3.4.4C语言前置概念学习.md @@ -1,6 +1,6 @@ # C 语言前置概念学习 -如何学习 C 语言?第一步:Throw away the textbook。也许你可以通过以下途径: +如何学习 C 语言?**第一步:Throw away the textbook。**也许你可以通过以下途径: 以下方式难度由易到难,但并不意味着收获由小到大: @@ -14,9 +14,9 @@ 4.Web:[CNote](https://github.com/coderit666/CNote)(例子密集,学习曲线平滑,覆盖面广且具有深度) -5.Book:教材替换用书——《C Primer Plus》!(基础且深入的恰到好处,有一定拓展,可能后面的章节有点难懂,是一本不可多得的好书,不要忽视课本习题及 Projects) +5.Book:**教材替换用书——《C Primer Plus》!**(基础且深入的恰到好处,有一定拓展,可能后面的章节有点难懂,是一本不可多得的好书,不要忽视课本习题及 Projects) -6.MOOC:[Introductory C Programming 专项课程](https://www.coursera.org/specializations/c-programming)(全英文,好处是涉及到计算机思维,包含许多常用 tools 的教学例如 git、make、emacs、gdb,视频讲解结合文档阅读,对于 C 的重要核心知识讲解透彻,难度颇高,建议用作提升) +6.MOOC:[Introductory C Programming 专项课程](https://www.coursera.org/specializations/c-programming)(**全英文**,好处是涉及到计算机思维,包含许多常用 tools 的教学例如 git、make、emacs、gdb,视频讲解结合文档阅读,对于 C 的重要核心知识讲解透彻,难度颇高,建议用作提升) 7.Web:[LinuxC 一站式编程](https://akaedu.github.io/book/)(难度大,枯燥硬核,收获多,基于 linux) @@ -38,4 +38,4 @@ ![](https://cdn.xyxsw.site/Hqzbbs6iYobnxWxz11Ocfa9gnHd.png) -### CS education is more than just “learning how to code”! +### **CS education is more than just “learning how to code”!** diff --git a/3.编程思维体系构建/3.4.5.1C语言自测标准——链表.md b/3.编程思维体系构建/3.4.5.1C语言自测标准——链表.md index 17ef4c0..91dffb7 100644 --- a/3.编程思维体系构建/3.4.5.1C语言自测标准——链表.md +++ b/3.编程思维体系构建/3.4.5.1C语言自测标准——链表.md @@ -54,9 +54,9 @@ typedef struct Node* Link; 例如,若链表无头结点,则对于在链表中第一个数据结点之前插入一个新结点,或者对链表中第一个数据结点做删除操作,都必须要当做特殊情况,进行特殊考虑;而若链表中设有头结点,以上两种特殊情况都可被视为普通情况,不需要特殊考虑,降低了问题实现的难度。 -链表有头结点,也不一定都是有利的。例如解决约瑟夫环问题,若链表有头结点,在一定程度上会阻碍算法的实现。 +**链表有头结点,也不一定都是有利的。例如解决约瑟夫环问题,若链表有头结点,在一定程度上会阻碍算法的实现。** -所以,对于一个链表来说,设置头指针是必要且必须的,但有没有头结点,则需要根据实际问题特殊分析。 +**所以,对于一个链表来说,设置头指针是必要且必须的,但有没有头结点,则需要根据实际问题特殊分析。** 首元结点:指的是链表开头第一个存有数据的结点。 @@ -329,7 +329,7 @@ int ListDelete(Link *L, int i, int* e) - 3 出列后,从 5 开始数 1,2 数 2,所以 2 出列; - 最后只剩下 5 自己,所以 5 胜出。 -那么,究竟要如何用链表实现约瑟夫环呢?如何让一个含 5 个元素的约瑟夫环,能从第 5 个元素出发,访问到第 2 个元素呢?上面所讲的链表操作显然是难以做到的,解决这个问题就需要用到循环链表。 +那么,究竟要如何用链表实现约瑟夫环呢?如何让一个含 5 个元素的约瑟夫环,能从第 5 个元素出发,访问到第 2 个元素呢?上面所讲的链表操作显然是难以做到的,解决这个问题就需要用到**循环链表**。 ## 循环链表 diff --git a/3.编程思维体系构建/3.4.6.1.开始冒险.md b/3.编程思维体系构建/3.4.6.1.开始冒险.md index a4f7828..96323ed 100644 --- a/3.编程思维体系构建/3.4.6.1.开始冒险.md +++ b/3.编程思维体系构建/3.4.6.1.开始冒险.md @@ -21,7 +21,7 @@ It is very dark in here. Bye! -尽管可能微不足道,但该程序确实展示 任何文本冒险中最重要的方面:描述性文本。一个好的故事是制作一款好的冒险游戏的要素之一。 +尽管可能微不足道,但该程序确实展示 *了*任何文本冒险中最重要的方面:描述性文本。一个好的故事是制作一款好的冒险游戏的要素之一。 ## 为什么要用英文? diff --git a/3.编程思维体系构建/3.4.6.10.增添属性.md b/3.编程思维体系构建/3.4.6.10.增添属性.md index 05e01da..beb9afc 100644 --- a/3.编程思维体系构建/3.4.6.10.增添属性.md +++ b/3.编程思维体系构建/3.4.6.10.增添属性.md @@ -12,7 +12,7 @@ 举个例子,一条林道可能隐藏着陷阱。虽然通道似乎从位置 A 通向位置 B,但实际上终点是位置 C,即掉进坑了。 -假设我们的洞口被警卫挡住了。玩家就过不去,我们可以简单地将通道的目的地更改为终点位置(或 NULL),但这会导致对诸如 go cave 和 look cave 这样的命令做出不正确的回应:“你在这里看不到任何洞穴。我们需要一个将通道的实际终点和虚假终点分开的单独属性。为此,我们将引入一个属性 prospect 来表示后者。 +假设我们的洞口被警卫挡住了。玩家就过不去,我们可以简单地将通道的*目的地*更改为终点位置(或 *NULL*),但这会导致对*诸如 go cave 和 look cave* 这样的命令做出不正确的回应:“你在这里看不到任何洞穴。我们需要一个将通道的实际终点和虚假终点分开的单独属性。为此,我们将引入一个属性 prospect 来表示后者。 1. 在许多冒险中,玩家以及游戏中的 NPC 在携带量方面受到限制。给每件物品一个重量,角色库存中所有物品的总重量不应超过该角色所能承载的最大重量。当然,我们也可以给一个物体一个非常高的重量,使它不可移动(一棵树,一座房子,一座山)。 2. RPG 式的冒险游戏需要角色的整个属性范围 ( 玩家与非玩家 ),例如 HP。HP 为零的对象要么死了,要么根本不是角色。 @@ -120,7 +120,7 @@ extern OBJECT objs[]; ::: warning 🤔 思考题:你能否自行实现上述伪代码? ::: -现在,我们已经可以使用新属性 (如果你完成了上面的思考题),details 用于新识别的命令外观``,textGo 在我们的命令 go 实现中替换固定文本“OK”。 +现在,我们已经可以使用新属性 (如果你完成了上面的思考题),**details** 用于新识别的命令*外观``*,**textGo** 在我们的命令 *go* 实现中替换固定文本*“OK*”。 ## location.c @@ -331,11 +331,11 @@ void executeInventory(void) ::: warning 🤔 思考题:仔细观察这段代码,看看与你写的有何不同? ::: -权重检查利用了新功能 weightOfContents,它将在misc.c中实现。在同一模块中,我们还对一些现有函数进行了修改,以支持最后几个属性。 +权重检查利用了新功能 *weightOfContents,*它将在*misc.c*中实现。在同一模块中,我们还对一些现有函数进行了修改,以支持最后几个属性。 -属性内容将替换固定文本“You see”。在列出玩家的库存时,原始文本已经有点奇怪了,但是现在函数listObjectsAtLocation用于显示任何可能对象的内容(请参阅上面的函数expertLook),我们真的需要一些更灵活的东西。 +属性内容将替换固定文本*“You see”。*在列出玩家的库存时,原始文本已经有点奇怪了,但是现在函数*listObjectsAtLocation*用于显示任何可能对象的内容(请参阅上面的函数*expertLook*),我们真的需要一些更灵活的东西。 -在函数 getPassage 中我们将属性目标替换为 prospect,并改进对所有命令(而不仅仅是 go and look)的响应,这些命令应用于位于“隐藏通道”另一端的位置。 +在函数 *getPassage* 中我们将属性*目标*替换为 prospect,并改进*对所有*命令(而不仅仅是 *go* and *look*)的响应,这些命令应用于位于“隐藏通道”另一端的位置。 ## misc.h @@ -462,8 +462,8 @@ function outputEdge(from, to, style) 注意: -- 尽量不要太担心浪费仅在某些类型的对象中使用的属性上的内存空间(例如,textGo仅用于通道),或者许多重复的字符串文本。 -- 为了演示属性 prospect 的使用,我们使洞穴无法访问。当您查看新地图时,这一点立即变得很明显。进入洞穴的箭头是虚线的,这意味着这是一个虚假的通道,但不是实际的通道。请放心,洞穴将在下一章重新开放。 +- 尽量不要太担心浪费仅在某些类型的对象中使用的属性上的内存空间(例如,*textGo*仅用于通道),或者许多重复的字符串文本。 +- 为了演示属性 prospect 的使用,我们使洞穴无法访问。当您查看新*地图时,*这一点立即变得很明显。进入洞穴的箭头是虚线的,这意味着这是一个虚假的通道,但不是实际的通道。请放心,洞穴将在下一章重新开放。 - 请注意,更详细的描述往往需要一个更大的字典(更多的对象,更多的标签)。例如,命令 look silver coin 现在返回 "该硬币的正面有一只鹰"。玩家通过输入一个命令 look eagle 来查看银币,但程序并不知道鹰是什么意思 (显然这样子是不行的)。 输出样例 diff --git a/3.编程思维体系构建/3.4.6.11.设置条件.md b/3.编程思维体系构建/3.4.6.11.设置条件.md index a1659e4..668a89c 100644 --- a/3.编程思维体系构建/3.4.6.11.设置条件.md +++ b/3.编程思维体系构建/3.4.6.11.设置条件.md @@ -13,7 +13,7 @@ 打开一个封闭的通道(在这里是进入洞穴)涉及到改变一些属性值: - 目的地从 NULL(空地点) 变为洞穴 -- textGo从 "警卫阻止你...... "改为 "你走进山洞" +- **textGo**从 "警卫阻止你...... "改为 "你走进山洞" - 在一些特殊情况下,描述和细节不需要改变。但对于一个门洞或栅栏,其中之一(或两者)通常会包含一些从 "开放 "到 "关闭 "的文字。 有许多方法来实现这一目标。在这里,我们将讨论一种简单、可维护和通用的方法。 @@ -22,7 +22,7 @@ 接下来,我们引入一个名为条件的新属性,它决定了某个对象是否存在。这两个通道将被赋予互斥的条件,因此在任何时候都只能有一个存在。 -每个条件将被实现为一个布尔函数:TRUE意味着该对象存在,FALSE意味着它不存在。 +每个条件将被实现为一个布尔函数:**TRUE**意味着该对象存在,**FALSE**意味着它不存在。 ```c bool intoCaveIsOpen(void) @@ -281,7 +281,7 @@ int listObjectsAtLocation(OBJECT *location) 注意: -1. 警卫不可能会死,所以可以说我们的条件函数中的HP是很无用的。当然,这很容易通过添加一个 kill 命令来解决,见第 20 章。 +1. 警卫不可能会死,所以可以说我们的条件函数中的**HP**是很无用的。当然,这很容易通过添加一个 kill 命令来解决,见第 20 章。 2. 这两个条件函数是互补的;它们有资格成为重复的代码。为了消除这一点,我们可能决定让一个函数调用另一个函数(用'!'操作符来否定结果)。一个匿名函数没有(稳定的)名字,但我们可以用它的对象来指代它。我们可以用 intoCaveBlocked 的条件函数代替。 3. 为了简单起见,条件函数没有参数。实际上,传递一个参数 OBJECT *obj 可能更好;这使得编写更多的通用条件函数成为可能,可以在多个对象中重复使用。 4. 在理论上,任何对象都可以成为 "条件"。在下一章,你可以看到一个类似的技术被应用于此。 diff --git a/3.编程思维体系构建/3.4.6.13.编写解析器.md b/3.编程思维体系构建/3.4.6.13.编写解析器.md index 03284bc..1e591b9 100644 --- a/3.编程思维体系构建/3.4.6.13.编写解析器.md +++ b/3.编程思维体系构建/3.4.6.13.编写解析器.md @@ -246,7 +246,7 @@ bool matchCommand(const char *src, const char *pattern) 我们调整各种命令的实现,以利用新的数组参数。 -## inventory.h +## **inventory.h** ```c extern bool executeGet(void); @@ -256,7 +256,7 @@ extern bool executeGive(void); extern bool executeInventory(void); ``` -## inventory.c +## **inventory.c** ```c #include diff --git a/3.编程思维体系构建/3.4.6.2.探索未知.md b/3.编程思维体系构建/3.4.6.2.探索未知.md index 0ddcb65..8c15503 100644 --- a/3.编程思维体系构建/3.4.6.2.探索未知.md +++ b/3.编程思维体系构建/3.4.6.2.探索未知.md @@ -1,6 +1,6 @@ # 2.探索未知 -::: tip 驾驭项目,而不是被项目驾驭 +::: tip **驾驭项目,而不是被项目驾驭** 你和一个项目的关系会经历 4 个阶段: @@ -35,9 +35,9 @@ ::: 下面的代码示例包含三个函数,每个步骤一个函数: -1. 函数getInput。 -2. 函数parseAndExecute。 -3. 函数main,负责重复调用其他两个函数。 +1. 函数*getInput*。 +2. 函数*parseAndExecute*。 +3. 函数*main*,负责重复调用其他两个函数。 ## main.c @@ -70,7 +70,7 @@ int main() ::: warning 🤔 思考题:static 是什么意思?我为什么要用他? ::: -## parsexec.h +## **parsexec.h** ```c extern bool parseAndExecute(char *input); @@ -86,7 +86,7 @@ extern 是干什么的?.h 文件又在干嘛? 在这里用指针是为了传参的时候可以传字符串哦 ::: -## parsexec.c +## **parsexec.c** ```c #include @@ -126,9 +126,9 @@ bool parseAndExecute(char *input) 你的编译器可能会给出警告 the unused variable‘noun’,这些不用担心,将会在下一章解决。 -返回false将导致主循环结束。 +返回*false*将导致主循环结束。 -::: warning RTFM&&STFW +::: warning **RTFM&&STFW** 搞懂 strtok 和 strcmp 的用法 ::: diff --git a/3.编程思维体系构建/3.4.6.3.指明地点.md b/3.编程思维体系构建/3.4.6.3.指明地点.md index 7d6b06b..e357152 100644 --- a/3.编程思维体系构建/3.4.6.3.指明地点.md +++ b/3.编程思维体系构建/3.4.6.3.指明地点.md @@ -99,7 +99,7 @@ bx = torch.cat((xs[0], bs[0], xs[1], bs[1], xs[2], bs[2], xs[3], bs[3], xs[4], b 这个故事折射出,大公司中程序员的编程习惯也许不比你好多少,他们也会写出 Copy-Paste 这种难以维护的代码。但反过来说,重视编码风格这些企业看中的能力,你从现在就可以开始培养。 ::: -传统上,文本冒险是由(许多)不同位置组成的虚拟世界。虽然这不是必需的(一些冒险发生在一个房间里!),但这是解释数据结构使用的好方法。 +*传统上,文本冒险是由(许多)不同位置组成的虚拟世界。虽然这不是必需的(一些冒险发生在一个房间里!),但这是解释**数据结构**使用的好方法。* 我们首先定义一个[结构](http://en.wikipedia.org/wiki/Struct_(C_programming_language))来表示一个位置。它包含两个简单的属性开始(稍后可能会有更多的属性)。 @@ -136,7 +136,7 @@ struct location locs[2] = { }; ``` -让我们把它付诸实践。在上一章(parsexec.c) 的代码示例中,我们更改了第 4、18 和 22 行)。 +让我们把它付诸实践。在上一章(*parsexec.c)* 的代码示例中,我们更改了第 4、18 和 22 行)。 ## parsexec.c @@ -237,9 +237,9 @@ void executeGo(const char *noun) } ``` -在 C 语言中,你可以使用单个语句来定义类型(结构位置),声明变量(locs)并用其初始值填充它。 +在 C 语言中,你可以使用单个语句来定义类型(*结构位置*),声明变量(*locs*)并用其初始值填充它。 -思考题:变量locs是[静态分配的](http://en.wikipedia.org/wiki/Static_memory_allocation),什么是静态分配? +思考题:变量*locs*是[静态分配的](http://en.wikipedia.org/wiki/Static_memory_allocation),什么是静态分配? 静态分配和动态分配有什么不同之处? diff --git a/3.编程思维体系构建/3.4.6.4.创建对象.md b/3.编程思维体系构建/3.4.6.4.创建对象.md index 3a7d1ab..635883c 100644 --- a/3.编程思维体系构建/3.4.6.4.创建对象.md +++ b/3.编程思维体系构建/3.4.6.4.创建对象.md @@ -1,17 +1,17 @@ # 4.创建对象 -在我们继续之前,我在这里使用的是[哲学意义上](https://en.wikipedia.org/wiki/Object_(philosophy))的“对象”一词。它与[面向对象编程](https://en.wikipedia.org/wiki/Object-oriented_programming)无关,也与JavaC#Python等编程语言中预定义的“对象”类型没有任何共同之处。下面,我将定义一个名为 object 的结构体。 +*在我们继续之前,我们在这里使用的是[哲学意义上](https://en.wikipedia.org/wiki/Object_(philosophy))的“对象”一词。它与[面向对象编程](https://en.wikipedia.org/wiki/Object-oriented_programming)无关,也与Java,C#和Python等编程语言中预定义的“对象”类型没有任何共同之处。下面,我将定义一个名为 object 的结构体。* -冒险游戏中的大多数谜题都围绕着物品。例子: +冒险游戏中的大多数谜题都围绕着**物品**。例子: - 必须找到一把钥匙,然后用来解锁某扇门。 - 必须杀死守卫或者诱骗守卫才能开启房间 所以,为了表示这个物品,我们可以使用如下[结构](http://en.wikipedia.org/wiki/Struct_(C_programming_language)): -- description: 对物品的描述 -- tag: 物品的类型 -- location: 物品所在的位置。这是对应上一章中定义的物品位置的指针。 +- **description: ****对物品的描述** +- **tag: ****物品的类型** +- **location: ****物品所在****的位置。这是****对应****上一章中定义的****物品****位置****的指针。** ```c struct object { @@ -87,30 +87,30 @@ for (obj = objs; obj < objs + 5; obj++) 那么,我们有合并这个物品(或地点)列表有什么好处呢?答案是这会让我们的代码变得更加简单,因为许多函数(如上面的函数通过这样的列表)只需要扫描单个列表就可以实现,而不是三个列表。有人可能会说没必要,因为每个命令仅适用于一种类型的对象: -- 命令 go 适用于位置对象。 -- 命令 get 应用于获得物品。 +- 命令 *go* 适用于位置对象。 +- 命令 *get* 应用于获得物品。 - 命令 kill 适应用于杀死人物。 但这种方法不太对劲,原因有三: -1. 某些命令适用于多种类型的对象,尤其是检查。 +1. 某些命令适用于多种类型的对象,尤其是*检查*。 2. 有时候会出现很没意思的交互方式,比如说你要吃掉守卫,他说不行。 3. 某些对象在游戏中可能具有多个角色。比如说队友系统,NPC 可以是你的物品也可以是对象 -将所有对象放在一个大列表中,很容易添加一个名为“type”的属性来构造对象,以帮助我们区分不同类型的对象。 +将所有对象放在一个大列表中,很容易添加一个名为“type”的属性来*构造对象*,以帮助我们区分不同类型的对象。 ::: warning 🤔 怎么做怎么遍历呢?先思考吧 ::: 但是,对象通常具有同样有效的其他特征: -- Locations:通过道路连接(将在后面介绍)。如果一个物体无法通过一条通道到达,那么它就不是一个位置。就是这么简单。 -- Items:玩家唯一可以捡起的物品;可以给他们整一个重量的属性 -- Actors:玩家唯一可以与之交谈,交易,战斗的对象;当然,前提是他们还活着!可以加一个 HP 属性 +- **Locations:通过****道路****连接(将在后面介绍)。如果一个物体无法通过一条通道到达,那么它就不是一个位置。就是这么简单。** +- **Items:玩家唯一可以捡起的物品;****可以给他们整一个重量的属性** +- **Actors:玩家唯一可以与之交谈,交易,战斗的对象;当然,前提是他们还活着!****可以加一个 HP 属性** 我们还要向数组中添加一个对象:玩家自己。 -在上一章中,有一个单独的变量 locationOfPlayer。我们将删除它,然后换上用户的位置属性取代他! +在上一章中,有一个单独的变量 *locationOfPlayer*。我们将删除它,然后换上用户的位置属性取代他! 例如,此语句会将玩家移入洞穴: @@ -163,7 +163,7 @@ OBJECT objs[] = { }; ``` -注意:要编译此模块,编译器必须支持 Constant folding。这排除了一些更原始的编译器,如 [Z88DK](http://en.wikipedia.org/wiki/Z88DK)。 +**注意:**要编译此模块,编译器*必须*支持 Constant folding。这排除了一些更原始的编译器,如 [Z88DK](http://en.wikipedia.org/wiki/Z88DK)。 以下模块将帮助我们找到与指定名词匹配的对象。 @@ -173,7 +173,7 @@ OBJECT objs[] = { extern OBJECT *getVisible(const char *intention, const char *noun); ``` -::: warning 🤔 指针?函数?希望你已经掌握这是什么了 +::: warning **🤔 指针?函数?希望你已经掌握这是什么了** ::: ## noun.c @@ -232,7 +232,7 @@ OBJECT *getVisible(const char *intention, const char *noun) } ``` -这是另一个辅助程序的函数。它打印存在于特定位置的对象(物品,NPC)的列表。它将用于函数 executeLook,在下一章中,我们将介绍另一个需要它的命令。 +这是另一个辅助程序的函数。它打印存在于特定位置的对象(物品,NPC)的列表。它将用于函数 *executeLook*,在下一章中,我们将介绍另一个需要它的命令。 ## misc.h @@ -268,7 +268,7 @@ int listObjectsAtLocation(OBJECT *location) } ``` -在 location.c 中,命令环顾四周的实现,并根据新的数据结构进行调整。旧的位置数组被删除,变量 locationOfPlayer 也是如此。 +在 *location.c* 中,命令环*顾四周的实现*,并根据新的数据结构进行调整。旧的位置数组被删除,变量 *locationOfPlayer* 也是如此。 ## location.h @@ -302,7 +302,7 @@ void executeLook(const char *noun) void executeGo(const char *noun) { -//消除了函数executeGo中的循环,代码更优雅了~ +//消除了函数*executeGo*中的循环,代码更优雅了~ OBJECT *obj = getVisible("where you want to go", noun); if (obj == NULL) { diff --git a/3.编程思维体系构建/3.4.6.5.捡起物品.md b/3.编程思维体系构建/3.4.6.5.捡起物品.md index a2ea2bb..a899ae7 100644 --- a/3.编程思维体系构建/3.4.6.5.捡起物品.md +++ b/3.编程思维体系构建/3.4.6.5.捡起物品.md @@ -24,7 +24,7 @@ | 玩家从演员那里收到物品 | ask | silver->location = player; | | 列出其他演员的库存 | examine | listObjectsAtLocation(guard); | -你可以尝试去使用这些命令(上面的前两个示例已经在上一章中实现了)。现在,我们将为玩家和非玩家角色介绍一些典型的物品栏操作(命令获取掉落给予询问物品栏)。 +你可以尝试去使用这些命令(上面的前两个示例已经在上一章中实现了)。现在,我们将为玩家和非玩家角色介绍一些典型的**物品栏**操作(命令*获取*、*掉落*、*给予*、*询问*和*物品栏*)。 ::: warning 🤔 思考题: 你能不能尝试自己实现一下上面的命令? @@ -32,7 +32,7 @@ 如果你可以在不参考下面内容的情况下就写出基本内容会有很大收获的 ::: -## parsexec.c +## **parsexec.c** ```c #include @@ -91,7 +91,7 @@ bool parseAndExecute(char *input) 新命令由以下模块实现。 -## inventory.h +## **inventory.h** ```c extern void executeGet(const char *noun); @@ -101,7 +101,7 @@ extern void executeGive(const char *noun); extern void executeInventory(void); ``` -## inventory.c +## **inventory.c** ```c #include @@ -160,7 +160,7 @@ void executeInventory(void) } ``` -注意:由于动词名词比较好弄,命令 askgive 只有一个参数:item。 +注意:由于动词名词比较好弄,命令 *ask* 和 *give* 只有一个参数:item。 ::: warning 🤔 思考题: 为什么我们要这样设计? @@ -168,7 +168,7 @@ void executeInventory(void) 你能否为这些命令多加几个参数? ::: -从本质上讲,get, drop, give and ask 这些命令除了将项目从一个地方移动到另一个地方之外,什么都不做。单个函数 move 对象可以对所有四个命令执行该操作。 +从本质上讲,*get*, *drop*, *give* and *ask 这些命令*除了将项目从一个地方移动到另一个地方之外,什么都不做。单个函数 *move 对象*可以对所有四个命令执行该操作。 ## move.h @@ -229,7 +229,7 @@ void moveObject(OBJECT *obj, OBJECT *to) ::: warning 🤔 思考题:识别一些我们拿不了的物品需要考虑什么因素? ::: -命令“get”使用函数getVisible将名词转换为 object,就像命令“go”一样;请参阅上一章。但是对于对玩家(或其他一些参与者)已经持有的对象进行drop, ask, give 等命令时,我们需要稍微不同的东西。我们将在 noun.c 中添加一个函数 getPossession。 +命令“get”使用函数*getVisible*将名词转换为 object,就像命令“go”一样;请参阅上一章。但是对于对玩家(或其他一些参与者)已经持有的对象进行*drop*, *ask*, *give 等*命令时,我们需要稍微不同的东西。我们将在 *noun.c* 中添加一个函数 *getPossession*。 ## noun.h @@ -318,9 +318,9 @@ OBJECT *getPossession(OBJECT *from, const char *verb, const char *noun) } ``` -注意:新函数(45-75 行) getPossessiongetObject 的装饰器(wrapper)(参见第 52 行),它要么返回匹配的对象,要么返回 NULL(如果没有合适的对象与名词匹配)。 +注意:新函数(45-75 行) *getPossession* 是 *getObject* 的装饰器(wrapper)(参见第 52 行),它要么返回匹配的对象,要么返回 NULL(如果没有合适的对象与名词匹配)。 -函数 actor 这里用于命令 giveask,但它也可能由其他命令调用。所以我们在misc.c中定义了它。 +函数 *actor 这里*用于命令 *give* 和 *ask*,但它也可能由其他命令调用。所以我们在*misc.c*中定义了它。 ## misc.h @@ -370,7 +370,7 @@ int listObjectsAtLocation(OBJECT *location) ::: warning 🤔 思考题:上面第四行中的函数 actorHere 返回的指针指向什么? ::: -在第 9 行中,有一个详尽的,硬编码的非玩家角色列表(到目前为止,只有一个:守卫)。 +在第 9 行中,有一个详尽的,硬编码的非玩家角色列表(到目前为止,只有一个:*守卫*)。 在第 10 章中,我们将开始使用属性作为区分角色与项目和其他非参与者对象的更优雅方式。 diff --git a/3.编程思维体系构建/3.4.6.6.绘制地图.md b/3.编程思维体系构建/3.4.6.6.绘制地图.md index 882e064..070cc33 100644 --- a/3.编程思维体系构建/3.4.6.6.绘制地图.md +++ b/3.编程思维体系构建/3.4.6.6.绘制地图.md @@ -1,17 +1,17 @@ # 6.绘制地图 -作为一个 RPG 游戏怎么能没有地图呢,是时候绘制地图了! +作为一个 RPG 游戏怎么能没有地图呢,*是时候绘制地图了!* -绘制地图的最佳工具始终是:一支铅笔和一张纸。基本地图由位置(矩形)组成,由道路(箭头)连接。我们已经在第 3 章中创建了位置,现在我们将开始添加道路。 +绘制地图的最佳工具始终是:一支铅笔和一张纸。基本地图由**位置**(矩形)组成,由道路(箭头)连接。我们已经在第 3 章中创建了位置,现在我们将开始添加道路。 在虚拟世界中,“道路”可能是连接两个位置的任何东西:一条路,一扇门,沙漠中。基本上,一段经文具有以下属性: - 起点(位置)。 - 目标(位置)。 - 叙述性描述,例如“森林小径”。 -- 在 go 命令中往哪里走的描述性标记 +- 在 *go* 命令中往哪里走的描述性标记 -考虑到这些属性,第 4 章中定义的结构对象就非常适合存储道路了。事实上,一个道路与一个项目或 NPC 并没有太大的不同,它作为“可见出口”存在于某个位置(该位置是起点)。它只是与某些命令的行为不同,特别是命令“go”:应用于道路,go将改变玩家的位置。 +考虑到这些属性,第 4 章中定义的结构对象就非常适合存储道路了。事实上,一个道路与一个项目或 NPC 并没有太大的不同,它作为“可见出口”存在于某个位置(该位置是起点)。它只是与某些命令的行为不同,特别是命令“go”:应用于道路,*go*将改变玩家的位置。 ```c struct object { @@ -24,9 +24,9 @@ struct object { 注意: -- 显然,目的地在大多数其他对象(物品,NPC)中都没有使用 +- 显然,*目的地*在大多数其他对象(物品,NPC)中都没有使用 - 通道总是朝一个方向运行;要双向连接两个位置,我们总是必须创建两个单独的通道。乍一看,这似乎很笨拙,但它确实给了我们很大的灵活性来完善命令“go”的行为 -- 在大地图上,你可能会发现手动创建所有通道很乏味。所以,我强烈建议你使用自定义工具生成地图中重复性更强的部分。这里不会介绍这一点,但您可能会在第 9 章中找到一些灵感,我们将在其中讨论自动胜场。 +- 在大地图上,你可能会发现手动创建所有通道很乏味。所以,我强烈建议你使用自定义工具*生成*地图中重复性更强的部分。这里不会介绍这一点,但您可能会在第 9 章中找到一些灵感,我们将在其中讨论自动胜场。 ::: warning 🤔 思考题:为什么创建两个通道可以使我们的程序更加灵活? ::: @@ -75,7 +75,7 @@ OBJECT objs[] = { }; ``` -我们将在 misc.c 中添加一个小的帮助函数,以确定两个给定位置之间是否存在通道。 +我们将在 *misc.c* 中添加一个小的帮助函数,以确定两个给定位置之间是否存在通道。 ## misc.h @@ -139,7 +139,7 @@ int listObjectsAtLocation(OBJECT *location) } ``` -我们将在命令“go”的实现中使用新功能getPassage来确定是否存在可以将玩家带到所需位置的通道。 +我们将在命令“go”的实现中使用新功能*getPassage*来确定是否存在可以将玩家带到所需位置的通道。 ## location.h @@ -201,7 +201,7 @@ void executeGo(const char *noun) } ``` -我们还将使用新功能getPassage来确定从玩家站立的位置是否可以看到某个位置。未通过通道连接到当前位置的位置不被视为可见。 +我们还将使用新功能*getPassage*来确定从玩家站立的位置是否可以看到某个位置。未通过通道连接到当前位置的位置不被视为可见。 ## noun.h diff --git a/3.编程思维体系构建/3.4.6.7.增大距离.md b/3.编程思维体系构建/3.4.6.7.增大距离.md index 361b834..08b99fb 100644 --- a/3.编程思维体系构建/3.4.6.7.增大距离.md +++ b/3.编程思维体系构建/3.4.6.7.增大距离.md @@ -1,23 +1,23 @@ # 7.增大距离 -一个典型的冒险包含许多谜题。众所周知,[Infocom](https://en.wikipedia.org/wiki/Infocom)的冒险很难完成。解决每个难题可能需要数周甚至数月的反复试验。 +*一个典型的冒险包含许多谜题。众所周知,[Infocom](https://en.wikipedia.org/wiki/Infocom)的冒险很难完成。解决每个难题可能需要数周甚至数月的反复试验。* -当玩家操纵角色失败后,如果只是返回“你不能这么操作”来回应玩家,会很 nt,很没意思 +*当玩家操纵角色失败后,如果只是返回“你不能这么操作”来回应玩家,会很 nt,很没意思。* -它忽略了电脑游戏的一个重要方面,而这也是生活本身的一部分:玩家必须从错误中吸取教训。 +*它忽略了电脑游戏的一个重要方面,而这也是生活本身的一部分:玩家必须从错误中吸取教训。* 当你的游戏反复输入东西都是,你不能这样做的时候,会显得很无聊的。 -冒险游戏至少应该做的是解释为什么玩家的命令无法完成:“你不能这样做,因为......”这有助于使虚拟世界更具说服力,故事更可信,游戏更有趣。 +*冒险游戏至少应该做的是解释为什么玩家的命令无法完成:“你不能这样做,因为......”这有助于使虚拟世界更具说服力,故事更可信,游戏更有趣。* -我们已经付出了相当大的努力让游戏解释为什么某些命令是无效的。只需看看名词.c,inventory.c,location.cmove.c中的许多printf调用。但随着游戏变得越来越复杂,这正成为一个相当大的负担。我们需要一种更结构化的方法来检测和处理错误情况。这就是我们在本章中将要讨论的内容。 +我们已经付出了相当大的努力让游戏解释**为什么**某些命令是无效的。只需看看*名词.c,inventory.c,location.c*,*move.c*中的许多*printf*调用。但随着游戏变得越来越复杂,这正成为一个相当大的负担。我们需要一种更结构化的方法来检测和处理错误情况。这就是我们在本章中将要讨论的内容。 大多数命令对一个或多个对象进行操作,例如: - 玩家拿起一件物品,然后把它交给另一个 NPC。 - 玩家沿着一条通道到另一个位置。 -首先要检查的(在[解析器](http://en.wikipedia.org/wiki/Parsing)捕获检测是否会有明显[拼写错误](http://en.wikipedia.org/wiki/Typographical_error)之后)是这些对象是否存在; +首先要检查的(在[解析器](http://en.wikipedia.org/wiki/Parsing)捕获检测是否会有明显[拼写错误](http://en.wikipedia.org/wiki/Typographical_error)之后)是这些对象**是否存在**; 失败应该导致类似“这里没有...“或”你看不到任何东西...”等文字出现。在本章中,我们将构建一个通用函数,每个命令都可以使用它来找出玩家是否在可及的范围内。 @@ -38,7 +38,7 @@ | distHereContained | 一个物体(NPC 或“容器”)存在于玩家的位置,正在拿着另一个物体 | object->location != NULL &&
object->location->location == player->location | | distOverthere | 对象是附近的位置 | getPassage(player->location, object) != NULL | -第一种情况(对象是玩家)可能看起来微不足道,但它仍然很重要。例如,命令“examine yourself”不应该返回“这里没有你自己”。 +第一种情况(对象是玩家)可能看起来微不足道,但它仍然很重要。例如,命令“examine yourself”*不应该*返回“这里没有你自己”。 我试图遵循一个逻辑顺序:附近的事物最高优先级,随后优先级会变低。 @@ -48,7 +48,7 @@ 请注意,我们有七种不同的“这里”案例,但只有一种是“不在这里”。这是因为通常,游戏只需要提供有关玩家可以感知的事物的信息。如果它不在这里,那么就没什么可说的了。 -在最左边的列中,我们为每个案例提出了一个符号名称。我们将在名为 DISTANCE 的[枚举](http://en.wikipedia.org/wiki/Enumerated_type)中收集这些名称。 +在最左边的列中,我们为每个案例提出了一个符号名称。我们将在名为 **DISTANCE** 的[枚举](http://en.wikipedia.org/wiki/Enumerated_type)中收集这些名称。 ```c typedef enum { @@ -91,7 +91,7 @@ DISTANCE getDistance(OBJECT *from, OBJECT *to) 注:自行实验即可 ::: -就这样!我们可以调用此函数并对其返回值进行比较。例如,我们在 noun.c中有以下代码: +就这样!我们可以调用此函数并对其返回值进行比较。例如,我们在 noun*.c*中有以下代码: ```c else if (!(obj == player || @@ -125,9 +125,9 @@ else if (getDistance(player, obj) >= distNotHere) ::: warning 🤔 尝试理解一下这样做的意义 ::: -这只是一个例子,让你对这个概念有所了解;您将在下面找到noun.c的实际实现,看起来略有不同。 +这只是一个例子,让你对这个概念有所了解;您将在下面找到*noun.c*的实际实现,看起来略有不同。 -是时候把事情落实到位了。枚举 DISTANCE 和函数 getDistance 的定义被添加到 misc.hmisc.c 中,因为我们将在多个模块中使用它们。 +是时候把事情落实到位了。枚举 *DISTANCE* 和函数 *getDistance* 的定义被添加到 *misc.h* 和 *misc.c* 中,因为我们将在多个模块中使用它们。 ## misc.h @@ -237,7 +237,7 @@ extern void executeLook(const char *noun); extern void executeGo(const char *noun); ``` -在函数 executeGo 中,我们可以用检查距离来替换大多数 if 条件。 +在函数 *executeGo* 中,我们可以用检查距离来替换大多数 *if* 条件。 ## location.c @@ -297,9 +297,9 @@ void executeGo(const char *noun) ::: warning 🤔 思考题:你能否为 switch 函数增加更多 case 来完善判断条件? ::: -函数 executeGet 也是如此。 +函数 *executeGet* 也是如此。 -## inventory.h +## **inventory.h** ```c extern void executeGet(const char *noun); @@ -309,7 +309,7 @@ extern void executeGive(const char *noun); extern void executeInventory(void); ``` -## inventory.c +## **inventory.c** ```c #include @@ -372,7 +372,7 @@ void executeInventory(void) } ``` -最后,我们将调整 noun.c中的约束。我们正在向函数getObject添加两个参数,以便找到特定名词的匹配项,同时忽略任何被认为不存在的对象。这将在下一章中得到真正的回报,我们将在下一章中介绍具有相同标签的不同对象。 +最后,我们将调整 noun*.c*中的约束。我们正在向函数*getObject*添加两个参数,以便找到特定名词的匹配项,同时忽略任何被认为不存在的对象。这将在下一章中得到真正的回报,我们将在下一章中介绍具有相同标签的不同对象。 ## noun.h @@ -463,7 +463,7 @@ OBJECT *getPossession(OBJECT *from, const char *verb, const char *noun) ::: warning 🤔 思考题:你能理解什么时候加 const,什么时候不用吗? ::: -在本章中,距离的概念主要用于在游戏可以给用户的不同响应之间进行选择。但是,距离的好处并不局限于输出端;它可以同样很好地用于在输入端进行改进。在下一章中,我们将使用距离来提高对用户输入的名词的识别。 +在本章中,*距离*的概念主要用于在游戏可以给用户的不同响应之间进行选择。但是,距离的好处并不局限于**输出**端;它可以同样很好地用于在**输入**端进行改进。在下一章中,我们将使用距离来提高对用户输入的名词的识别。 输出样例 diff --git a/3.编程思维体系构建/3.4.6.8.移动方向.md b/3.编程思维体系构建/3.4.6.8.移动方向.md index a7220d9..c29610c 100644 --- a/3.编程思维体系构建/3.4.6.8.移动方向.md +++ b/3.编程思维体系构建/3.4.6.8.移动方向.md @@ -1,8 +1,8 @@ # 8.移动方向 -传统的文本冒险使用[指南针方向](https://en.wikipedia.org/wiki/Cardinal_direction)进行导航。 +*传统的文本冒险使用[指南针方向](https://en.wikipedia.org/wiki/Cardinal_direction)进行导航。* -例如,我们在第 6 章中绘制的地图上,玩家可能想向东移动,从田野移动到洞穴。我们可以通过给连接Cave的通道标上“east”来实现这一点。但是,我们首先需要解决两个问题。 +例如,我们在第 6 章中绘制的地图上,玩家可能想**向东**移动,从田野移动到洞穴。我们可以通过给连接**Cave**的通道标上“east”来实现这一点。但是,我们首先需要解决两个问题。 1. 我们可能仍然想把这段通道称为“entrance”和“east”。但现在,一个对象只能有一个标签。 2. 在更大的地图上,具有更多的位置和道路,标签“east”将被定义多次。到目前为止,标签在我们的游戏中是全球独一无二的,没有重复项。 @@ -80,9 +80,9 @@ OBJECT objs[] = { }; ``` -当然,要让这个改动生效,我们还需要调整noun.c中的objectHasTag函数。 +当然,要让这个改动生效,我们还需要调整*noun.c*中的*objectHasTag*函数。 -同时,我们将让函数 getVisiblegetPossession 告知玩家他必须更具体的选择你到底是银币还是金币,而不是随机选择任何一个对象。 +*同时,我们将让函数 getVisible*和*getPossession* 告知玩家他必须更具体的选择你到底是银币还是金币,而不是随机选择任何一个对象。 ## noun.h @@ -91,7 +91,7 @@ extern OBJECT *getVisible(const char *intention, const char *noun); extern OBJECT *getPossession(OBJECT *from, const char *verb, const char *noun); ``` -## noun.c +## **noun.c** ```c #include @@ -188,7 +188,7 @@ OBJECT *getPossession(OBJECT *from, const char *verb, const char *noun) } ``` -问题 #3 可以通过从函数parseAndExecute中删除一个 [空格](http://en.wikipedia.org/wiki/Space_(punctuation))字符来解决(下面的第 10 行)。这个解决方案远非完美('silver' 和 'coin' 之间的双空格是打咩的),但直到我们在第 13 章中让自己成为一个更好的解析器之前。 +问题 #3 可以通过从函数*parseAndExecute*中删除一个 [空格](http://en.wikipedia.org/wiki/Space_(punctuation))字符来解决(下面的第 10 行)。这个解决方案远非完美('silver' 和 'coin' 之间的双空格是打咩的),但直到我们在第 13 章中让自己成为一个更好的解析器之前。 ## parsexec.c @@ -246,9 +246,9 @@ bool parseAndExecute(char *input) } ``` -模块main.cinventory.clocation.cmove.cmisc.c保持不变 +模块*main.c*、*inventory.c*、*location.c*、*move.c* 和*misc.c*保持不变 -现在对象数组 ( object.c ) 开始在多个维度上增长(特别是在引入多个标签的情况下),我们需要一种使其更易于维护的方法。 +现在对象数组 ( *object.c* ) 开始在多个维度上增长(特别是在引入多个标签的情况下),我们需要一种使其更易于维护的方法。 ::: warning 🤔 猜猜看该怎么办? ::: diff --git a/3.编程思维体系构建/3.4.6阶段二:文字冒险(cool).md b/3.编程思维体系构建/3.4.6阶段二:文字冒险(cool).md index f492b80..d7d44a8 100644 --- a/3.编程思维体系构建/3.4.6阶段二:文字冒险(cool).md +++ b/3.编程思维体系构建/3.4.6阶段二:文字冒险(cool).md @@ -2,9 +2,9 @@ ## 前言 -本来打算让各位做下面的任务来进行进一步的学习的,但是想了想,实在是,太无聊啦! +本来打算让各位做下面的任务来进行进一步的学习的,但是想了想,实在是,**太无聊啦**! -又想让你们来做一个管理系统,但是又想到你们可能会进行无数个管理系统,这也太无聊啦! +又想让你们来做一个管理系统,但是又想到你们可能会进行无数个管理系统,**这也太无聊啦**! 因此呢,我打算带大家玩一个文字冒险游戏![源头取自这里](https://github.com/helderman/htpataic),如果你想自己体验全流程的话可以试试玩哦! @@ -32,7 +32,7 @@ 在这种情况下,系统能跑起来才是王道,跑不起来什么都是浮云,追求面面俱到只会增加代码维护的难度。 -唯一可以把你从 bug 的混沌中拯救出来的就是 KISS 法则,它的宗旨是从易到难,逐步推进, 一次只做一件事,少做无关的事。 +唯一可以把你从 bug 的混沌中拯救出来的就是 KISS 法则,它的宗旨是**从易到难,逐步推进**, 一次只做一件事,少做无关的事。 如果你不知道这是什么意思,我们以可能发生的 `str` 成员缓冲区溢出问题来作为例子。KISS 法则告诉你,你应该使用 `assert(0)`, 就算不"得体"地处理上述问题,仍然不会影响表达式求值的核心功能的正确性。 diff --git a/3.编程思维体系构建/3.4.7.1GDB初探索(编程可阅览).md b/3.编程思维体系构建/3.4.7.1GDB初探索(编程可阅览).md index 855b24b..fc5f39d 100644 --- a/3.编程思维体系构建/3.4.7.1GDB初探索(编程可阅览).md +++ b/3.编程思维体系构建/3.4.7.1GDB初探索(编程可阅览).md @@ -16,7 +16,7 @@ [GDB 快速入门教程](https://www.bilibili.com/video/BV1EK411g7Li/) -### GDB 使用表 +### **GDB 使用表** `run (r)`运行程序 @@ -50,7 +50,7 @@ `ptype`查看详细信息 -#### TUI +#### **TUI** `ctrl + x + a`开启 diff --git a/3.编程思维体系构建/3.4.7.4Inline Assembly与链接加载.md b/3.编程思维体系构建/3.4.7.4Inline Assembly与链接加载.md index 7613471..cc76c13 100644 --- a/3.编程思维体系构建/3.4.7.4Inline Assembly与链接加载.md +++ b/3.编程思维体系构建/3.4.7.4Inline Assembly与链接加载.md @@ -20,7 +20,7 @@ C 艹可能没那么容易了····比如说虚函数调用,那你就不太 你可以写任何一个指令,他完全不会检查 也不会优化 编译器默认你知道你在干什么。 -然后 C 编译器就会将这部分代码 原封不动地 拷贝进你的二进制代码当中 +然后 C 编译器就会将这部分代码 **原封不动地**拷贝进你的二进制代码当中 当然,你可以通过 RTFM 来将 C 语言的变量塞到汇编中处理。 diff --git a/3.编程思维体系构建/3.5git与github.md b/3.编程思维体系构建/3.5git与github.md index 4a151f0..27aef66 100644 --- a/3.编程思维体系构建/3.5git与github.md +++ b/3.编程思维体系构建/3.5git与github.md @@ -2,15 +2,15 @@ 引自 nju-ics-pa -## 光玉 +## 光玉 想象一下你正在玩 Flappy Bird,你今晚的目标是拿到 100 分,不然就不睡觉。经过千辛万苦,你拿到了 99 分,就要看到成功的曙光的时候,你竟然失手了!你悲痛欲绝,滴血的心在呼喊着,“为什么上天要这样折磨我?为什么不让我存档?” -[**Play Happy Bird**](https://flappybird.io/) +[Play Happy Bird](https://flappybird.io/) 想象一下你正在写代码,你今晚的目标是实现某一个新功能,不然就不睡觉。经过千辛万苦,你终于把代码写好了,保存并编译运行,你看到调试信息一行一行地在终端上输出。就要看到成功的曙光的时候,竟然发生了错误!你仔细思考,发现你之前的构思有着致命的错误,但之前正确运行的代码已经永远离你而去了。你悲痛欲绝,滴血的心在呼喊着,“为什么上天要这样折磨我?”你绝望地倒在屏幕前 ... ... 这时,你发现身边渐渐出现无数的光玉,把你包围起来,耀眼的光芒令你无法睁开眼睛 ... ... 等到你回过神来,你发现屏幕上正是那份之前正确运行的代码!但在你的记忆中,你确实经历过那悲痛欲绝的时刻 ... ... 这一切真是不可思议啊 ... ... -## 人生如戏戏如人生 +## 人生如戏,戏如人生 人生就像不能重玩的 Flappy Bird,但软件工程领域却并非如此,而那不可思议的光玉就是“版本控制系统”。版本控制系统给你的开发流程提供了比朋也收集的更强大的光玉,能够让你在过去和未来中随意穿梭,避免上文中的悲剧降临你的身上。 @@ -18,7 +18,7 @@ 在本节,我们使用 `git` 进行版本控制。下面简单介绍如何使用 `git` : -### 游戏设置 +### 游戏设置 首先你得安装 `git` : @@ -52,7 +52,7 @@ git init 进行初始化。初始化后会创建一个隐藏的文件夹名为 `.git` git 会基于这个文件夹来进行版本控制功能。 -### 查看commit信息 +### 查看 commit 信息 使用 @@ -147,7 +147,7 @@ subject为commit概述 你可以使用 `git log` 查看存档记录,你应该能看到刚才编辑的注释。 -### 读档(回溯到某一个 commit) +### 读档(回溯到某一个 commit) 如果你遇到了上文提到的让你悲痛欲绝的情况,现在你可以使用光玉来救你一命了。首先使用 `git log` 来查看已有的存档,并决定你需要回到哪个过去。每一份存档都有一个 `hash code`,例如 `b87c512d10348fd8f1e32ddea8ec95f87215aaa5` , 你需要通过 `hash code` 来告诉 `git` 你希望读哪一个档。使用以下命令进行读档: @@ -194,7 +194,7 @@ git checkout -B 分支名 不同的分支之间不会相互干扰,这也给项目的分布式开发带来了便利。有了分支功能,你就可以像第三视点那样在一个世界的不同时间 ( 一个分支的多个存档 ),或者是多个平行世界(多个分支)之间来回穿梭了。 -### 更多功能 +### 更多功能 以上介绍的是 `git` 的一些基本功能,`git` 还提供很多强大的功能,例如使用 `git diff` 比较同一个文件在不同版本中的区别,使用 `git bisect` 进行二分搜索来寻找一个 bug 在哪次提交中被引入... @@ -246,13 +246,54 @@ git checkout -B 分支名 最后你访问[GitHub 官网](https://github.com)应该会显示你的 dashboard 管理台界面 -#### 第二步:创建 SSH Key 并获取公钥 +#### 第二步:选择你拉取仓库的方式 -先在 C:\Users\用户名\.ssh 下找有没有 `id_rsa` 和 `id_rsa.pub` 文件 +点开 github 某个仓库的绿油油的 `<>Code` 按钮,你会发现有三种 clone 方式。 + +分别为 + +- https(基本无配置,有图形化界面就能用) +- ssh(有公私钥设置,没有图形化界面也能用) +- gh-cli(github 出品的 cli 工具) + +![](https://cdn.xyxsw.site/Snipaste_2023-08-27_14-06-28.png) + +#### 【https 方法配置】账号绑定 github + +在命令行配置好你的 id 和邮箱 + +```bash +git config --global user.name "Zhang San" # your name +git config --global user.email "zhangsan@foo.com" # your email +``` + +在 GitHub 主页,找到 `New` 或者 `Create repository` 一个绿色的按钮,创建一个新的仓库 + +![](https://cdn.xyxsw.site/boxcn5sVnE76FYpVW2RDxtWDiZc.png) + +然后填上这个仓库的大名就可以创建了 + +![](https://cdn.xyxsw.site/boxcnsN133WrLrbxsX8JgvsQmif.png) + +进入你新创建的仓库 + +跟随新创建之后的指引,`…or create a new repository on the command line` 内他描述了如何创建一个文件夹、创建一个 README.md 的文件,然后和 github 仓库绑定。 + +push 的时候 github 会弹窗索要你的 github 账号和密码,填上去就能用了。 + +#### 【ssh 方法配置】创建 SSH Key 并获取公钥 + +先在 `C:\Users\用户名\.ssh` 下找有没有 `id_rsa` 和 `id_rsa.pub` 文件 + +:::tip +这里 `.ssh` 文件夹是一个隐藏文件夹 + +如何显示隐藏文件夹请搜索互联网或看这篇文章 [support microsoft 显示隐藏的文件](https://support.microsoft.com/zh-cn/windows/%E6%98%BE%E7%A4%BA%E9%9A%90%E8%97%8F%E7%9A%84%E6%96%87%E4%BB%B6-0320fe58-0117-fd59-6851-9b7f9840fdb2) +::: 如果有就直接跳过这一步 -如果没有,打开 Shell(Windows 下打开 Git Bash 前提是你已经安装好了 git 在桌面右键应该会有 Git bash here 选项 ),创建 SSH Key: +如果没有,打开 Shell(Windows 下打开 Git Bash *前提是你已经安装好了 git 在桌面右键应该会有 Git bash here 选项*),创建 SSH Key: ```bash ssh-keygen -t rsa -C "youremail@example.com" # youremail为你注册用的电子邮件地址 @@ -260,7 +301,7 @@ ssh-keygen -t rsa -C "youremail@example.com" # youremail为你注册用的电 打开 `id_rsa.pub`,复制里面的内容 -#### 第三步:绑定 Github +#### 【ssh 方法配置】绑定 Github 登陆 `GitHub`,点击右上角自己的头像,打开 `settings` @@ -272,7 +313,7 @@ ssh-keygen -t rsa -C "youremail@example.com" # youremail为你注册用的电 然后,点 `New SSH Key`,填上任意 Title,在 Key 文本框里粘贴 `id_rsa.pub` 文件的内容即可 -#### 第四步:创建仓库并和本地绑定 +#### 【ssh 方法配置】创建仓库并和本地绑定 绑定完 GitHub 然后你可以创建仓库了 @@ -301,8 +342,6 @@ git remote add origin git@github.com:yourname/gitexample.git git clone git@github.com:yourname/gitexample.git ``` -> 以上方法是基于 ssh 方式的,下面方法是基于 HTTPS 方式的 - 或者你可以跟随新创建之后的指引,`…or create a new repository on the command line` 内他描述了如何创建一个文件夹、创建一个 README.md 的文件,然后和 github 仓库绑定。 ![](https://cdn.xyxsw.site/Snipaste_2023-07-16_17-19-18.png) @@ -442,7 +481,7 @@ git commit -m "feat(helloworld): add helloworld file" 这样会在你的名下多出来一份这个同名仓库,而这个仓库你是拥有所有权限的,你可以 clone 你这个同名仓库,更改代码,提交代码之后 - 回到源仓库点击 Pull Request 然后创建 PR `New pull request` + 回到源仓库点击 Pull Request 然后创建 PR `New pull request` 最上面会提示你说 diff --git a/3.编程思维体系构建/3.6.2环境配置.md b/3.编程思维体系构建/3.6.2环境配置.md index db7792d..2843b85 100644 --- a/3.编程思维体系构建/3.6.2环境配置.md +++ b/3.编程思维体系构建/3.6.2环境配置.md @@ -4,7 +4,7 @@ ## 什么是环境? -环境是包的集合,我们一般用 Anaconda 来配置虚拟环境。 +环境是**包的集合**,我们一般用 Anaconda 来配置虚拟环境。 [戳这里安装](https://www.anaconda.com/) diff --git a/3.编程思维体系构建/3.6.3安装python.md b/3.编程思维体系构建/3.6.3安装python.md index 371ff94..2cd12a6 100644 --- a/3.编程思维体系构建/3.6.3安装python.md +++ b/3.编程思维体系构建/3.6.3安装python.md @@ -27,11 +27,11 @@ 打开 [Python 官方网站](https://www.python.org/),找到“Download”里的“Latest: Python 3.x.y”。 -下载完成后,请大家按照下图的示意,务必勾选“Add Python 3.x to PATH”,然后再点击“Install Now”,等待安装完成后关闭安装程序。 +**下载完成后,请大家按照下图的示意,务必勾选“Add Python 3.x to PATH”,然后再点击“Install Now”,等待安装完成后关闭安装程序。** -注意:windows11 安装好后 命令行输入 python 可能会跳到 Microsoft 应用商店 可在 customize installation(自定义安装)next 勾选 install for all users +**注意:windows11 安装好后 命令行输入 python 可能会跳到 Microsoft 应用商店 可在 customize installation(自定义安装)next 勾选 install for all users** -GNU/Linux 系统 +**GNU/Linux 系统** 在终端输入 `sudo apt install python3` 即可完成 Python3 的全部安装流程 diff --git a/3.编程思维体系构建/3.6.4.3阶段三:数据抽象.md b/3.编程思维体系构建/3.6.4.3阶段三:数据抽象.md index 27b8096..9e0fc16 100644 --- a/3.编程思维体系构建/3.6.4.3阶段三:数据抽象.md +++ b/3.编程思维体系构建/3.6.4.3阶段三:数据抽象.md @@ -135,9 +135,9 @@ s 可变对象的示例包括列表和字典。不可变对象的示例包括元组和函数。 -我们假定已经知道了如何使用 `==` 运算符来检查两个表达式的计算结果是否相同。 +我们假定已经知道了如何使用 `==` 运算符来检查两个表达式的计算结果是否**相同**。 -我们现在引入一个新的比较运算符 `is`,它检查两个表达式的计算结果是否相同。 +我们现在引入一个新的比较运算符 `is`,它检查两个表达式的计算结果是否**相同**。 ```python >>> 2 + 2 == 3 + 1 diff --git a/3.编程思维体系构建/3.6.4.5阶段五:迭代生成.md b/3.编程思维体系构建/3.6.4.5阶段五:迭代生成.md index c59468a..09996a0 100644 --- a/3.编程思维体系构建/3.6.4.5阶段五:迭代生成.md +++ b/3.编程思维体系构建/3.6.4.5阶段五:迭代生成.md @@ -37,7 +37,7 @@ iterator = iter(iterable) # do something ``` -- 首先,在可迭代对象上调用内置 `iter` 函数以创建对应的迭代器。 +- 首先,在可迭代对象上调用内置 `iter` 函数以创建对应的*迭代器*。 - 要获取序列中的下一个元素,在此迭代器上调用内置 `next` 函数。 如果没有下一个元素了,怎么办? @@ -76,7 +76,7 @@ StopIteration ## 英语练习,对迭代器的类比 -Analogy: An iterable is like a book (one can flip through the pages) and an iterator for a book would be a bookmark (saves the position and can locate the next page). Calling `iter` on a book gives you a new bookmark independent of other bookmarks, but calling `iter` on a bookmark gives you the bookmark itself, without changing its position at all. Calling `next` on the bookmark moves it to the next page, but does not change the pages in the book. Calling `next` on the book wouldn't make sense semantically. We can also have multiple bookmarks, all independent of each other. +**Analogy**: An iterable is like a book (one can flip through the pages) and an iterator for a book would be a bookmark (saves the position and can locate the next page). Calling `iter` on a book gives you a new bookmark independent of other bookmarks, but calling `iter` on a bookmark gives you the bookmark itself, without changing its position at all. Calling `next` on the bookmark moves it to the next page, but does not change the pages in the book. Calling `next` on the book wouldn't make sense semantically. We can also have multiple bookmarks, all independent of each other. ## 生成器:懒人迭代器! diff --git a/3.编程思维体系构建/3.6.5.1CS61A Sec1.md b/3.编程思维体系构建/3.6.5.1CS61A Sec1.md index c668860..b854495 100644 --- a/3.编程思维体系构建/3.6.5.1CS61A Sec1.md +++ b/3.编程思维体系构建/3.6.5.1CS61A Sec1.md @@ -1,6 +1,6 @@ # CS61A Sec1 -观前须知: +**观前须知:** 本章节内容基于 Berkeley 大学的教材 [Composing Programs](http://www.composingprograms.com/) by [John DeNero](http://www.denero.org/),并在此基础上做了部分修改,是在[知识共享协议](https://creativecommons.org/licenses/by-nc-sa/3.0/deed.zh)下所许可的。 @@ -28,7 +28,7 @@ from urllib.request import urlopen 这个 Python 代码是一个导入语句,加载了在互联网上访问数据的功能。实际上,它提供了一个叫做 urlopen 的函数,它可以在一个[统一资源定位符(URL)](https://developer.mozilla.org/zh-CN/docs/Learn/Common_questions/Web_mechanics/What_is_a_URL)上访问内容,可以通过它来访问互联网上的数据。 -语句和表达式 +**语句和表达式** Python 代码由语句和表达式组成。大体上,计算机程序由以下指令组成 @@ -37,7 +37,7 @@ Python 代码由语句和表达式组成。大体上,计算机程序由以下 语句通常描述行动;当 Python 解释器执行一个语句时,它执行相应的动作。另一方面,表达式通常描述的是计算;当 Python 评估一个表达式时,它计算该表达式的值。在这篇文章下,介绍了几种类型的声明和表达方式。 -赋值语句 +**赋值语句** ```python shakespeare = urlopen('http://www.composingprograms.com/shakespeare.txt') @@ -47,7 +47,7 @@ shakespeare = urlopen('http://www.composingprograms.com/shakespeare.txt') 将变量名 `shakespeare` 用 `=` 和后面的表达式的值联系起来。该表达式将 `urlopen` 函数应用于一个 URL,该 URL 包含威廉 - 莎士比亚 37 部戏剧的完整文本,全部保存在一个文本文件中。 -函数 +**函数** 函数封装了操作数据的逻辑。 @@ -64,7 +64,7 @@ shakespeare = urlopen('http://www.composingprograms.com/shakespeare.txt') 你可能不了解 `urlopen` 这个函数背后的逻辑,但这不影响你去调用这个函数,这就是函数封装的好处之一。 -因此,函数是本章节关注的重点。 +**因此,函数是本章节关注的重点。** 我们来看另一个赋值语句: @@ -74,7 +74,7 @@ words = set(shakespeare.read().decode().split()) 这个语句将名字词与莎士比亚戏剧中出现的所有出现过的词(重复出现的词只统计一次)的集合联系起来,其中有 33,721(?) 个词。上述语句包含一个读取、解码和分割的命令链,每个命令都在一个中间计算实体上操作:我们从打开的 URL 中读取数据,然后将数据解码成文本,最后将文本分割成单词。所有这些词都被放在一个集合(Set,Python 中的一种数据类型)中。 -对象 +**对象** 前文中提到的 Set,不仅仅是数据类型,也是一个对象。对象用一种能同时处理两者复杂性的方式,把数据和操作该数据的逻辑无缝衔接在一起。 @@ -91,7 +91,7 @@ words = set(shakespeare.read().decode().split()) 这是一个复合表达式,其值是所有长度为 6 的、本身和反向拼写都在原集合中的词组成的集合。其中的 `w[::-1]` 是一种隐式表达,它枚举了 `w` 中的所有字母,但因为 `step = -1` 规定了步长是反方向的。 -解释器 +**解释器** 计算复合表达式需要一个精确的程序,以可预测的方式解释代码。一个能实现程序和计算符合表达式的程序被称为解释器;没错,其实解释器是程序(可能再写一篇文章来讲讲解释器和编译器的区别?) @@ -109,9 +109,9 @@ words = set(shakespeare.read().decode().split()) 每种强大的语言都有三种这样的机制: -- 原始的表达式和语句,代表了该语言提供的最简单的构建模块。 -- 组合的方式,由较简单的元素建立成复合元素。 -- 抽象的手段,通过它,复合元素可以作为单位被命名和操作。 +- **原始的表达式和语句**,代表了该语言提供的最简单的构建模块。 +- **组合的方式**,由较简单的元素建立成复合元素。 +- **抽象的手段**,通过它,复合元素可以作为单位被命名和操作。 在编程中,我们处理两种元素:函数和数据。(很快就会发现,它们其实并不那么明显)。不那么正式地说,数据是我们想要操作的东西,而函数描述了操作数据的规则。因此,任何强大的编程语言都应该能够描述原始数据和原始函数,以及有一些方法来组合和抽象函数和数据。 @@ -133,20 +133,20 @@ words = set(shakespeare.read().decode().split()) 0.9921875 ``` -这些数学表达式使用中缀符号,其中运算符(例如,+,-,*,或/)出现在操作数(数字)之间。Python 包括许多形成复合表达式的方法。我们不会试图立即列举它们,而是会随着我们的学习引入新的表达形式,以及它们所支持的语言特性。 +这些数学表达式使用*中缀*符号,其中*运算符*(例如,+,-,*,或/)出现在*操作数*(数字)之间。Python 包括许多形成复合表达式的方法。我们不会试图立即列举它们,而是会随着我们的学习引入新的表达形式,以及它们所支持的语言特性。 -最重要的一种复合表达式是调用表达式,它将一个函数应用于一些参数。回顾一下代数,函数的数学概念是一个从一些自变量到因变量的映射。例如,一个求最大值的函数将其的多个输入映射到当中最大值的一个单一的输出。Python 表达函数应用的方式与传统数学中相同。 +最重要的一种复合表达式是*调用表达式*,它将一个函数应用于一些参数。回顾一下代数,函数的数学概念是一个从一些自变量到因变量的映射。例如,一个求最大值的函数将其的多个输入映射到当中最大值的一个单一的输出。Python 表达函数应用的方式与传统数学中相同。 ```python >>> max(7.5, 9.5) 9.5 ``` -这个调用表达式有子表达式:操作符是括号前的表达式,它包含了一个用逗号分隔的操作数列表。 +这个调用表达式有子表达式:*操作符*是括号前的表达式,它包含了一个用逗号分隔的*操作数*列表。 ![](https://cdn.xyxsw.site/call_expression.png) -运算符指定了一个函数。当这个调用表达式被评估时,我们说对参数`7.5` 和 `9.5`调用函数 `max`,并返回一个 9.5 的返回值。 +运算符指定了一个*函数*。当这个调用表达式被评估时,我们说对*参数*`7.5` 和 `9.5`*调用*函数 `max`,并*返回*一个 9.5 的*返回值*。 调用表达式中参数的顺序很重要。例如,函数 `pow` 计算第一个参数的第二个参数次方。 @@ -166,7 +166,7 @@ words = set(shakespeare.read().decode().split()) 不会产生歧义,因为函数名总是优先于其参数。 -此外,函数符号以一种直接的方式延伸到嵌套表达式,其中的元素本身就是复合表达式。在嵌套的调用表达式中,与复合的中缀表达式不同,嵌套的结构在括号中是完全明确的。 +此外,函数符号以一种直接的方式延伸到*嵌套表达式*,其中的元素本身就是复合表达式。在嵌套的调用表达式中,与复合的中缀表达式不同,嵌套的结构在括号中是完全明确的。 ```python >>> max(min(1, -2), min(pow(3, 5), -4)) @@ -205,7 +205,7 @@ Python 定义了大量的函数,包括上一节中提到的运算符函数, ### 变量名和环境 -编程语言的一个关键方面是它提供了使用变量名来指代计算对象的手段。如果一个值被赋予了一个变量名,我们就说这个变量名与这个值绑定了。 +编程语言的一个关键方面是它提供了使用变量名来指代计算对象的手段。如果一个值被赋予了一个变量名,我们就说这个变量名与这个值*绑定*了。 在 Python 中,我们可以使用赋值语句建立新的绑定,其中包含左边的变量名 `=` 右边的值。 @@ -225,9 +225,9 @@ Python 定义了大量的函数,包括上一节中提到的运算符函数, 1.0002380197528042 ``` -`=` 符号在 Python(以及许多其他语言)中被称为赋值操作符。赋值是我们最简单的抽象手段,因为它允许我们使用简单的名称来指代复合操作的结果。用这种方式,复杂的程序就是通过一步一步地建立复杂度越来越高的计算对象来构建的。 +`=` 符号在 Python(以及许多其他语言)中被称为*赋值*操作符。赋值是我们最简单的抽象手段,因为它允许我们使用简单的名称来指代复合操作的结果。用这种方式,复杂的程序就是通过一步一步地建立复杂度越来越高的计算对象来构建的。 -将变量名与值绑定,然后通过变量名检索这些值意味着解释器必须保持某种内存,以跟踪变量名、值和绑定。这样的内存空间被称为环境。 +将变量名与值绑定,然后通过变量名检索这些值意味着解释器必须保持某种内存,以跟踪变量名、值和绑定。这样的内存空间被称为*环境*。 变量名也可以被绑定到函数上。例如,变量名 `max` 与我们使用的求最大值的函数绑定。与数字不同的是,函数在呈现为文本时很棘手,所以当被要求描述一个函数时,Python 会打印一个识别描述。 @@ -256,7 +256,7 @@ Python 定义了大量的函数,包括上一节中提到的运算符函数, 2 ``` -在 Python 中,名称通常被称为变量名变量,因为它们在执行程序的过程中可能被绑定到不同的值。当一个名称通过赋值被绑定到一个新的值时,它就不再被绑定到任何以前的值。人们甚至可以将内置名称与新值绑定。 +在 Python 中,名称通常被称为*变量名*或*变量*,因为它们在执行程序的过程中可能被绑定到不同的值。当一个名称通过赋值被绑定到一个新的值时,它就不再被绑定到任何以前的值。人们甚至可以将内置名称与新值绑定。 ```python >>> max = 5 @@ -315,7 +315,7 @@ Python 定义了大量的函数,包括上一节中提到的运算符函数, 1. 计算运算符和操作数的子表达式,然后 2. 将作为运算符子表达式的值的函数应用于作为运算符子表达式的值的参数。 -即使这是个简单的程序也说明了关于一般过程的一些重要观点。第一步决定了为了完成一个调用表达式的计算过程,我们必须首先计算其他表达式。因此,计算过程在本质上是递归的;也就是说,作为其步骤之一,它也包括调用规则本身。 +即使这是个简单的程序也说明了关于一般过程的一些重要观点。第一步决定了为了完成一个调用表达式的计算过程,我们必须首先计算其他表达式。因此,计算过程在本质上是*递归的*;也就是说,作为其步骤之一,它也包括调用规则本身。 例如,计算 @@ -328,7 +328,7 @@ Python 定义了大量的函数,包括上一节中提到的运算符函数, ![](https://cdn.xyxsw.site/expression_tree.png) -这张插图被称为表达式树。在计算机科学中,树(Tree,一种数据结构,我们将在后续的章节中进行讨论)通常是自上而下生长的。树中每一点的对象被称为节点;在这张插图的情况下,节点是与值配对的表达式。 +这张插图被称为*表达式树*。在计算机科学中,树(Tree,一种数据结构,我们将在后续的章节中进行讨论)通常是自上而下生长的。树中每一点的对象被称为节点;在这张插图的情况下,节点是与值配对的表达式。 计算它的根,即顶部的完整表达式,需要首先计算作为其子表达式的分支。叶表达式(即没有分支的节点)代表函数或数字。内部节点有两个部分:我们的计算规则所适用的调用表达式,以及该表达式的结果。从这棵树的计算来看,我们可以想象操作数的值是向上渗滤的,从末端节点开始,然后在越来越高的层级上进行组合。 @@ -357,7 +357,7 @@ Python 定义了大量的函数,包括上一节中提到的运算符函数, 这个语句不返回一个值,也不在某些参数上调用一个函数,因为赋值的目的是将一个变量名绑定到一个值上。 -一般来说,赋值语句不是被计算而是被执行;它们不产生一个值,而是做一些改变。每种类型的表达式或语句都有自己的计算或执行过程。 +一般来说,赋值语句不是被计算而是*被执行*;它们不产生一个值,而是做一些改变。每种类型的表达式或语句都有自己的计算或执行过程。 ### 纯函数和非纯函数 diff --git a/3.编程思维体系构建/3.6.5CS61A食用指南.md b/3.编程思维体系构建/3.6.5CS61A食用指南.md index 4c9c372..a54665d 100644 --- a/3.编程思维体系构建/3.6.5CS61A食用指南.md +++ b/3.编程思维体系构建/3.6.5CS61A食用指南.md @@ -85,7 +85,7 @@ cs61a 绝对是一个挑战,但是我们都希望你学习并且成功,所 - 再次强调,这门课对于大多数学生来说都不是一门简单的课程,你可能会感到不知所措。给你的小伙伴们发送一个信息,并与班上的其他同学取得联系; 一起完成作业或一起学习准备考试,只要你不违反课程大纲中规定的诚实学习的[课程政策](https://inst.eecs.berkeley.edu/~cs61a/fa22/articles/about/#academic-misconduct)。 - 当遇到问题时,试着组织语言来解释你遇到困难的地方。 - - 这并不需要一个找到懂得如何解决问题的人 (或者甚至是一个人——这种做法通常被称为**橡皮鸭**,因为你可以把一只橡皮鸭当作你的练习对象) ,因为主要目标是让你弄清楚你自己的想法,弄清楚你的理解和代码到底在哪里卡住了。从那里你可以专注于那一部分,以便更好地理解。 + - 这并不需要一个找到懂得如何解决问题的人 (或者甚至是一个人——这种做法通常被称为**橡皮鸭**,因为你可以把一只橡皮鸭当作你的练习对象) ,因为主要目标是让你弄清楚你自己的想法,弄清楚你的理解和代码到底在哪里卡住了。这样你可以知道应该专注于哪一部分,以便更好地理解。 - 做所有的 hw(或者至少认真地尝试)。我们没有给出很多 hw 问题,但那些我们给你的可能会发现是具有挑战性、耗时且有回报的。 - 做所有的 lab。其中大部分的设计更多的是作为一个课程材料的介绍,并可能需要半个小时左右的时间。这是一个熟悉新的知识点的好时机。 @@ -99,15 +99,21 @@ cs61a 绝对是一个挑战,但是我们都希望你学习并且成功,所 要使用 Ok 来运行指定函数的 doctests,请运行以下命令 -```python3 ok -q #会和你要补充的代码一起给出``` +```bash +python3 ok -q #会和你要补充的代码一起给出 +``` 默认情况下,只有没有通过的测试才会出现。你可以使用-v 选项来显示所有的测试,包括你已经通过的测试 -```python3 ok -v``` +```bash +python3 ok -v +``` 有时我们会看到类似这样的 ok 指令 -```python3 ok -q control -u``` +```bash +python3 ok -q control -u +``` 在终端中输入后,需要按照要求回答问题,有些时候会做为某些函数测试的前置条件 diff --git a/3.编程思维体系构建/3.X 聊聊设计模式和程序设计.md b/3.编程思维体系构建/3.X 聊聊设计模式和程序设计.md index 9abf2f6..c430822 100644 --- a/3.编程思维体系构建/3.X 聊聊设计模式和程序设计.md +++ b/3.编程思维体系构建/3.X 聊聊设计模式和程序设计.md @@ -1,7 +1,7 @@ # 3.X 聊聊设计模式和程序设计 -Author: yyl - Last revised 2022/08/07 +*Author: yyl + Last revised 2022/08/07* ## 前言 diff --git a/3.编程思维体系构建/3.Y.1VMware的安装与安装Ubuntu22.04系统.md b/3.编程思维体系构建/3.Y.1VMware的安装与安装Ubuntu22.04系统.md index e88b0e7..e7edef8 100644 --- a/3.编程思维体系构建/3.Y.1VMware的安装与安装Ubuntu22.04系统.md +++ b/3.编程思维体系构建/3.Y.1VMware的安装与安装Ubuntu22.04系统.md @@ -1,13 +1,16 @@ # VMware 的安装与安装 Ubuntu22.04 系统 -::: warning 💡 与 wsl 安装二选一 安装了 wsl 不用 VMware +::: warning 💡 +一般与 wsl 安装二选一,因为都是虚拟系统,安装了 wsl 不用 VMware + +文章撰写于 2022 年,可能其中的一些内容已过时。 ::: 首先下载 VMware -如果是 pro16 版本(key ZF3R0-FHED2-M80TY-8QYGC-NPKYF) +如果是 pro16 版本(key **ZF3R0-FHED2-M80TY-8QYGC-NPKYF**) -如果是 pro17 版本(key JU090-6039P-08409-8J0QH-2YR7F ) +如果是 pro17 版本(key **JU090-6039P-08409-8J0QH-2YR7F**) 本文写的时候用的版本是 pro16,但目前已经更新到 pro17 所以来更新个 key(如下安装与 16 版本无异) @@ -25,9 +28,14 @@ 安装过后点许可证 输上面的 key 激活 -[https://mirror.nju.edu.cn/ubuntu-releases/22.04/ubuntu-22.04.2-desktop-amd64.iso](https://mirror.nju.edu.cn/ubuntu-releases/22.04/ubuntu-22.04.2-desktop-amd64.iso) +[https://mirror.nju.edu.cn/ubuntu-releases/22.04](https://mirror.nju.edu.cn/ubuntu-releases/22.04) + +去这里下载 Ubuntu22.04 镜像包 iso 选择 `ubuntu--desktop-amd64.iso` + +:::tip +这里推荐使用多线程下载器下载,比如 [IDM](../2.高效学习/2.2优雅的使用工具.md),如果直接用浏览器下载(线程少)可能会出现下载慢、下载失败的情况。 +::: -去这里下载 Ubuntu22.04 镜像包 iso 下好回到 VMware @@ -101,7 +109,7 @@ ![](https://cdn.xyxsw.site/boxcnnLCJzGoFrUbWIMAPGFkxcb.png) -至此 恭喜安装完成! +**至此 恭喜安装完成!** 之后就可以在桌面上右键 @@ -109,4 +117,4 @@ 打开命令行 -开始你的 Linux 学习吧 +**开始你的 Linux 学习吧** diff --git a/3.编程思维体系构建/3.Y.2WSL的安装.md b/3.编程思维体系构建/3.Y.2WSL的安装.md index e70a953..a73d528 100644 --- a/3.编程思维体系构建/3.Y.2WSL的安装.md +++ b/3.编程思维体系构建/3.Y.2WSL的安装.md @@ -3,12 +3,12 @@ ::: warning 💡与 VMware 安装二选一 安装了 VMware 不用 wsl ::: -先说坏处: +先说**坏处**: 1. 开启 hyperv 的后果是 如果你电脑装模拟器玩手游的话 装了 hyperv 你的模拟器是打不开的(目前只有 `蓝叠国际版HyperV版`(性能很差)支持共存 hyperv 和模拟器) 2. WSL 很难装辣 安装过程中会出很多 bug 需要你自行 STFW -## 官方文档 +## **官方文档** ## [史上最全的 WSL 安装教程](https://blog.csdn.net/wojiuguowei/article/details/122100090) @@ -18,7 +18,7 @@ ![](https://cdn.xyxsw.site/boxcnYVkEecWdUs710e8h6G9GTh.png) -如果你的 windows 版本为家庭版 那么 hyperv 选项是没有的 +如果你的 windows 版本为**家庭版** 那么 hyperv 选项是没有的 你需要右键以管理员权限打开以下脚本来强行开启 hyperv diff --git a/3.编程思维体系构建/3.Y.3Linux初探索.md b/3.编程思维体系构建/3.Y.3Linux初探索.md index 94327f8..0868f69 100644 --- a/3.编程思维体系构建/3.Y.3Linux初探索.md +++ b/3.编程思维体系构建/3.Y.3Linux初探索.md @@ -49,7 +49,7 @@ Linux 命令行中的命令使用格式都是相同的: man 3 freopen ``` -### 统计代码行数 +### **统计代码行数** 第一个例子是统计一个目录中 (包含子目录) 中的代码行数。如果想知道当前目录下究竟有多少行的代码,就可以在命令行中键入如下命令: @@ -65,7 +65,7 @@ find . | grep '\.c$\|\.h$' | xargs wc -l 我们最后的任务是统计这些文件所占用的总行数,此时可以用 `man` 查看 `wc` 命令。`wc` 命令的 `-l` 选项能够计算代码的行数。`xargs` 命令十分特殊,它能够将标准输入转换为参数,传送给第一个参数所指定的程序。所以,代码中的 `xargs wc -l` 就等价于执行 `wc -l aaa.c bbb.c include/ccc.h ...`, 最终完成代码行数统计。 -### 统计磁盘使用情况 +### **统计磁盘使用情况** 以下命令统计 `/usr/share` 目录下各个目录所占用的磁盘空间: @@ -83,7 +83,7 @@ du -sc /usr/share/* | sort -nr | more 此时将会看到输出的前几行结果。`more` 工具使用空格翻页,并可以用 `q` 键在中途退出。`less` 工具则更为强大,不仅可以向下翻页,还可以向上翻页,同样使用 `q` 键退出。这里还有一个[关于 less 的小故事](http://en.wikipedia.org/wiki/Less_(Unix)). -### 在 Linux 下编写 Hello World 程序 +### **在 Linux 下编写 Hello World 程序** Linux 中用户的主目录是 `/home/用户名称`, 如果你的用户名是 `user`, 你的主目录就是 `/home/user`. 用户的 `home` 目录可以用波浪符号 `~` 替代,例如临时文件目录 `/home/user/Templates` 可以简写为 `~/Templates`. 现在我们就可以进入主目录并编辑文件了。如果 `Templates` 目录不存在,可以通过 `mkdir` 命令创建它: @@ -100,7 +100,7 @@ cd Templates 可以完成目录的切换。注意在输入目录名时,`tab` 键可以提供联想。 -#### 你感到键入困难吗? +#### ** 你感到键入困难吗?** ::: warning 💡 你可能会经常要在终端里输入类似于 diff --git a/3.编程思维体系构建/3.Y.4Vim初探索.md b/3.编程思维体系构建/3.Y.4Vim初探索.md index 0c67c33..4875bb6 100644 --- a/3.编程思维体系构建/3.Y.4Vim初探索.md +++ b/3.编程思维体系构建/3.Y.4Vim初探索.md @@ -35,7 +35,7 @@ apt-get install vim 如果您能够遵循上述步骤,并且坚持使用新的编辑器完成您所有的文本编辑任务,那么学习一个复杂的代码编辑器的过程一般是这样的:头两个小时,您会学习到编辑器的基本操作,例如打开和编辑文件、保存与退出、浏览缓冲区。当学习时间累计达到 20 个小时之后,您使用新编辑器的效率应该已经和使用老编辑器一样快。在此之后,其益处开始显现:有了足够的知识和肌肉记忆后,使用新编辑器将大大节省你的时间。而现代文本编辑器都是些复杂且强大的工具,永远有新东西可学:学的越多,效率越高。 -## Vim 的哲学 +## **Vim 的哲学** 在编程的时候,你会把大量时间花在阅读/编辑而不是在写代码上。所以,Vim 是一个_多模态_编辑 器:它对于插入文字和操纵文字有不同的模式。Vim 是可编程的(可以使用 Vimscript 或者像 Python 一样的其他程序语言),Vim 的接口本身也是一个程序语言:键入操作(以及其助记名)是命令,这些命令也是可组合的。Vim 避免了使用鼠标,因为那样太慢了;Vim 甚至避免用 上下左右键因为那样需要太多的手指移动。 diff --git a/4.人工智能/4.10科研论文写作.md b/4.人工智能/4.10科研论文写作.md index aebee2e..23c424f 100644 --- a/4.人工智能/4.10科研论文写作.md +++ b/4.人工智能/4.10科研论文写作.md @@ -14,7 +14,7 @@ 大白话 -> 提取后的逻辑链条 -> 科研写作 -> 英文翻译 -干了什么: +**干了什么:** 1. 如果没有想清楚要做的是什么,要写什么,可以先用大白话,在草稿上写,有利于理清思路,抽丝剥茧 @@ -45,7 +45,7 @@ 之所以要用大白话是因为基础的不足,如果有一定功底的人,可能先天写出来文字自带规范性,所以仅供大家参考) -表达规范性: +**表达规范性:** 此处的方法论为一句话,则是从模仿到超越的浑然天成。 diff --git a/4.人工智能/4.11从 AI 到 智能系统 —— 从 LLMs 到 Agents.md b/4.人工智能/4.11从 AI 到 智能系统 —— 从 LLMs 到 Agents.md index 4f5645b..4caf991 100644 --- a/4.人工智能/4.11从 AI 到 智能系统 —— 从 LLMs 到 Agents.md +++ b/4.人工智能/4.11从 AI 到 智能系统 —— 从 LLMs 到 Agents.md @@ -2,11 +2,11 @@ author:廖总 -Last revised 2023/04/18 +*Last revised 2023/04/18* 先声夺人:AI 时代最大的陷阱,就是盲目考察 AI 能为我们做什么,而不去考虑我们能为 AI 提供什么 -## 免责声明 +## *免责声明* 本文纯文本量达 16k(我也不知道字数统计的 28k 是怎么来的),在这 游离散乱的主线 和 支离破碎的文字 中挣扎,可能浪费您生命中宝贵的十数分钟。 @@ -616,7 +616,7 @@ AutoGPT 主要特性如下: 作为正题的回归,我们需要重新考虑什么是一个 AI,一个能帮助我们的 AI 应当处于什么样的现实形态? -我们需要的 AI 仅仅是大语言模型吗?如果是,它能帮我们做什么呢?如果不是,那 AI 的实质是什么呢? +*我们需要的 **AI** 仅仅是大语言模型吗?如果是,它能帮我们做什么呢?如果不是,那 AI 的实质是什么呢?* 我首先武断地认为,我们需要的 AI,并不是一个语言模型实体,而是一个复杂智能系统 @@ -803,7 +803,7 @@ Generative Agents 的知觉设计:关联性难题 仅就这方面而言,作为一个方向性的倡议,对知觉系统的开发可能分为以下步骤 -#### 数据处理/管理 +#### *数据处理/管理* - 对 办公文件/数据 构建通用读取接口 - 以同类信息为单位,设计通用的字段(由人设计和管理,AI 能力尚不至此) @@ -827,7 +827,7 @@ Generative Agents 的知觉设计:关联性难题 - 如储存进 mongoDB - (设计孪生数据的自动更新机制) -#### 知觉系统驱动 +#### *知觉系统驱动* - 基于上述索引数据库,以视图为单位进行访问,并设计 视图 2 Prompt 的转化格式 diff --git a/4.人工智能/4.12LLMAgent之结构化输出.md b/4.人工智能/4.12LLMAgent之结构化输出.md index a6ce5c0..4cf3a32 100644 --- a/4.人工智能/4.12LLMAgent之结构化输出.md +++ b/4.人工智能/4.12LLMAgent之结构化输出.md @@ -2,7 +2,7 @@ author:Marlene -Last revised 2023/07/26 +*Last revised 2023/07/26* ## 引言 diff --git a/4.人工智能/4.1前言.md b/4.人工智能/4.1前言.md index 9b5f9bf..9164be9 100644 --- a/4.人工智能/4.1前言.md +++ b/4.人工智能/4.1前言.md @@ -10,7 +10,7 @@ ### CV(计算机视觉) -计算机视觉旨在用计算机模拟人类处理图片信息的能力,就比如这里有一张图片——手写数字 9 +计算机视觉旨在**用计算机模拟人类处理图片信息的能力**,就比如这里有一张图片——手写数字 9 ![](https://cdn.xyxsw.site/boxcnvQiaAx6WgPx64s8fBklVwh.png) @@ -18,7 +18,7 @@ 相信你通过上面简单的介绍应该能够了解到计算机视觉是在干嘛了,接下来我会举几个相对复杂的例子来让大家了解一下目前的 cv 是在做怎样的研究: -::: warning 🐱 图像分割是在图片中对物体分类,并且把它们所对应的位置标示出来。下图就是把人的五官,面部皮肤和头发分割出来,效 (小) 果 (丑) 图如下: +::: warning 🐱 **图像分割**是在图片中对物体分类,并且把它们所对应的位置标示出来。下图就是把人的五官,面部皮肤和头发分割出来,效 (小) 果 (丑) 图如下: ::: @@ -29,15 +29,15 @@
-::: warning 🐱 图像生成相信大家一定不陌生,NovalAI 在 2022 年火的一塌糊涂,我觉得不需要我过多赘述,对它 (Diffusion model) 的改进工作也是层出不穷,这里就放一张由可控姿势网络 (ControlNet) 生成的图片吧: +::: warning 🐱 **图像生成**相信大家一定不陌生,NovalAI 在 2022 年火的一塌糊涂,我觉得不需要我过多赘述,对它 (Diffusion model) 的改进工作也是层出不穷,这里就放一张由可控姿势网络 (ControlNet) 生成的图片吧: ::: ![](https://cdn.xyxsw.site/boxcnUjnRociXua1yKj6dmU1A3c.png) -::: warning 🐱 三维重建也是很多研究者关注的方向,指的是传入对同一物体不同视角的照片,来生成 3D 建模的任务。这方面比图像处理更加前沿并且难度更大。具体见[4.6.5.4 神经辐射场 (NeRF)](4.6.5.4%E7%A5%9E%E7%BB%8F%E8%BE%90%E5%B0%84%E5%9C%BA(NeRF).md) 章节。 +::: warning 🐱 **三维重建**也是很多研究者关注的方向,指的是传入对同一物体不同视角的照片,来生成 3D 建模的任务。这方面比图像处理更加前沿并且难度更大。具体见[4.6.5.4 神经辐射场 (NeRF)](4.6.5.4%E7%A5%9E%E7%BB%8F%E8%BE%90%E5%B0%84%E5%9C%BA(NeRF).md) 章节。 ::: -如果对计算机视觉有兴趣,可以通过以下路线进行学习:深度学习快速入门—> 经典网络。本块内容的主要撰写者之一SRT 社团多数成员主要从事 CV 方向研究,欢迎与我们交流。 +如果对计算机视觉有兴趣,可以通过以下路线进行学习:深度学习快速入门—> 经典网络。本块内容的主要撰写者之一**SRT 社团**多数成员主要从事 CV 方向研究,欢迎与我们交流。 ### NLP(自然语言处理) @@ -56,9 +56,9 @@ 而多模态就是让计算机能够将不同模态的信息相对应,一种常用的方法就是让计算机把图片的内容和文本的内容理解为相同的语义(在这个领域一般用一个较长的向量来表示语义)。 -也就是说我传入一张狗子的照片经过模型得到的向量DOG 这个单词经过模型得到的向量相近。 +也就是说我**传入一张狗子的照片经过模型得到的向量**与**DOG 这个单词经过模型得到的向量**相近。 -具体的任务比如说图片问答,传入一张图片,问 AI 这张图片里面有几只猫猫,它们是什么颜色,它告诉我有一只猫猫,是橙色的: +具体的任务比如说**图片问答**,传入一张图片,问 AI 这张图片里面有几只猫猫,它们是什么颜色,它告诉我有一只猫猫,是橙色的: ![](https://cdn.xyxsw.site/boxcnrMvM1THshjXXOuh8WXi2zr.jpg) diff --git a/4.人工智能/4.2机器学习(AI)快速入门(quick start).md b/4.人工智能/4.2机器学习(AI)快速入门(quick start).md index 464c06e..02ea69c 100644 --- a/4.人工智能/4.2机器学习(AI)快速入门(quick start).md +++ b/4.人工智能/4.2机器学习(AI)快速入门(quick start).md @@ -175,7 +175,7 @@ def estimate_house_sales_price(num_of_bedrooms, sqft, neighborhood): ![](https://cdn.xyxsw.site/boxcnXbd7bqnqPwF8f1Up8rHq5e.png) -θ 表示当前的权重值。J(θ) 表示「当前权重的代价」。 +*θ 表示当前的权重值。J(θ) 表示「当前权重的代价」。* 这个等式表示,在当前权重值下,我们估价程序的偏离程度。 @@ -203,7 +203,7 @@ def estimate_house_sales_price(num_of_bedrooms, sqft, neighborhood): 不过幸运的是,有很多办法来处理这种情况。有许多机器学习算法可以处理非线性数据。除此之外,灵活使用线性回归也能拟合更复杂的线条。在所有的情况下,寻找最优权重这一基本思路依然适用。 -如果你还是无法理解,你可以将 cost 类比为你出错误的程度,而数学科学家找到各种方法来降低这种程度,当程度降到最低时,我们就可以知道我们要求的数值了 +**如果你还是无法理解,你可以将 cost 类比为你出错误的程度,而数学科学家找到各种方法来降低这种程度,当程度降到最低时,我们就可以知道我们要求的数值了** 另外,我忽略了过拟合(overfitting)的概念。得到一组能完美预测原始数据集中房价的权重组很简单,但用这组权重组来预测原始数据集之外的任何新房屋其实都不怎么准确。这也是有许多解决办法的(如[正则化](https://link.zhihu.com/?target=http%3A//en.wikipedia.org/wiki/Regularization_%2528mathematics%2529%23Regularization_in_statistics_and_machine_learning)以及使用[交叉验证](https://link.zhihu.com/?target=http%3A//en.wikipedia.org/wiki/Cross-validation_%2528statistics%2529)的数据集)。学习如何应对这一问题,是学习如何成功应用机器学习技术的重点之一。 @@ -226,7 +226,7 @@ def estimate_house_sales_price(num_of_bedrooms, sqft, neighborhood): ![](https://cdn.xyxsw.site/boxcnhbR6lGSXd6UAEpRvSIYSHg.png) -箭头头表示了函数中的权重。 +*箭头头表示了函数中的权重。* 然而,这个算法仅仅能用于处理一些简单的问题,就是那些输入和输出有着线性关系的问题。但如果真实价格和决定因素的关系并不是如此简单,那我们该怎么办?比如说,地段对于大户型和小户型的房屋有很大影响,然而对中等户型的房屋并没有太大影响。那我们该怎么在我们的模型中收集这种复杂的信息呢? @@ -392,13 +392,13 @@ model.add(Activation('relu'))# 激活函数,你可以理解为加上这个东 ### 卷积是如何工作的 -之前我们提到过,我们可以把一整张图片当做一串数字输入到神经网络里面。不同的是,这次我们会利用平移不变性的概念来把这件事做得更智能。 +之前我们提到过,我们可以把一整张图片当做一串数字输入到神经网络里面。不同的是,这次我们会利用**平移不变性**的概念来把这件事做得更智能。 当然也有最新研究说卷积不具备平移不变性,但是我这里使用这个概念是为了大伙更好的理解,举个例子:你将 8 无论放在左上角还是左下角都改变不了他是 8 的事实 ![](https://cdn.xyxsw.site/boxcnHo4tt4wmnC7sUykRPPLKmm.png) -我们将一张图像分成这么多个小块,然后输入神经网络中的是一个小块。每次判断一张小图块。 +我们将一张图像分成这么多个小块,然后输入神经网络中的是一个小块。*每次判断一张小图块。* 然而,有一个非常重要的不同:对于每个小图块,我们会使用同样的神经网络权重。换一句话来说,我们平等对待每一个小图块。如果哪个小图块有任何异常出现,我们就认为这个图块是「异常」 diff --git a/4.人工智能/4.3.1搜索.md b/4.人工智能/4.3.1搜索.md index ccfe88e..806d895 100644 --- a/4.人工智能/4.3.1搜索.md +++ b/4.人工智能/4.3.1搜索.md @@ -84,7 +84,7 @@ - 最优解 (Optimal Solution) - 在所有解决方案中路径成本最低的解决方案。 -- 在搜索过程中,数据通常存储在节点 (Node) 中,节点是一种包含以下数据的数据结构: +- 在搜索过程中,数据通常存储在**节点 (Node)** 中,节点是一种包含以下数据的数据结构: - 状态——state - 其父节点,通过该父节点生成当前节点——parent node @@ -314,6 +314,6 @@ def remove(self): - 深度限制的极大极小算法 (Depth-Limited Minimax) - - 总共有$255168$个可能的井字棋游戏,以及有$10^{29000}$个可能的国际象棋中游戏。到目前为止,最小最大算法需要生成从某个点到终端条件的所有假设游戏状态。虽然计算所有的井字棋游戏状态对现代计算机来说并不是一个挑战,但目前用来计算国际象棋是不可能的。 + - 总共有$255168$个可能的井字棋游戏,以及有$10^{29000}$个可能的国际象棋中游戏。到目前为止,最小最大算法需要生成从某个点到**终端条件**的所有假设游戏状态。虽然计算所有的井字棋游戏状态对现代计算机来说并不是一个挑战,但目前用来计算国际象棋是不可能的。 - 深度限制的 Minimax 算法在停止之前只考虑预先定义的移动次数,而从未达到终端状态。然而,这不允许获得每个动作的精确值,因为假设的游戏还没有结束。为了解决这个问题,深度限制 Minimax 依赖于一个评估函数,该函数从给定状态估计游戏的预期效用,或者换句话说,为状态赋值。例如,在国际象棋游戏中,效用函数会将棋盘的当前配置作为输入,尝试评估其预期效用(基于每个玩家拥有的棋子及其在棋盘上的位置),然后返回一个正值或负值,表示棋盘对一个玩家对另一个玩家的有利程度。这些值可以用来决定正确的操作,并且评估函数越好,依赖它的 Minimax 算法就越好。 diff --git a/4.人工智能/4.3.2知识推理.md b/4.人工智能/4.3.2知识推理.md index 2121334..e0ee992 100644 --- a/4.人工智能/4.3.2知识推理.md +++ b/4.人工智能/4.3.2知识推理.md @@ -2,7 +2,7 @@ 人类根据现有的知识进行推理并得出结论。表示知识并从中得出结论的概念也被用于人工智能中,在本章中我们将探讨如何实现这种行为。 -::: warning 说好的 AI 呢?怎么感觉越来越偏了? +::: warning **说好的 AI 呢?怎么感觉越来越偏了?** 如果有这样的疑问的同学,可能存在一定的误区,认为人工智能就是局限在深度学习的算法或者说机器学习的部分算法上,其实这是对这个领域一个巨大的误解。 @@ -42,7 +42,7 @@ - 命题符号通常是用于表示命题的字母$P、Q、R$ - 逻辑连接词 (Logical Connectives) - 逻辑连接词是连接命题符号的逻辑符号,以便以更复杂的方式对世界进行推理。 - - Not ($\lnot$) 逻辑非:命题真值的反转。例如,如果 $P$:“正在下雨”,那么 $¬P$:“没有下雨”。 + - **Not**** ****(**$\lnot$**)** 逻辑非:命题真值的反转。例如,如果 $P$:“正在下雨”,那么 $¬P$:“没有下雨”。 - 真值表用于将所有可能的真值赋值与命题进行比较。该工具将帮助我们更好地理解与不同逻辑连接词相关联的命题的真值。例如,下面是我们的第一个真值表: | $P$ | $\lnot P$ | @@ -50,7 +50,7 @@ | false(0) | true(1) | | true(1) | false(0) | -- And($\land$) 逻辑乘 (合取): 连接两个不同的命题。当这两个命题$P$和$Q$用$∧$连接时,得到的命题$P∧Q$只有在$P$和$Q$都为真的情况下才为真。 +- **And(**$\land$**)** 逻辑乘 (合取): 连接两个不同的命题。当这两个命题$P$和$Q$用$∧$连接时,得到的命题$P∧Q$只有在$P$和$Q$都为真的情况下才为真。 | $P$ | $Q$ | $P\land Q$ | | --- | --- | ---------- | @@ -59,7 +59,7 @@ | 1 | 0 | 0 | | 1 | 1 | 1 | -- Or($\lor$) 逻辑和 (析取): 只要它的任何一个参数为真,它就为真。这意味着要使 $P ∨ Q$为真,$P$ 或 $Q$ 中至少有一个必须为真。 +- **Or(**$\lor$**)** 逻辑和 (析取): 只要它的任何一个参数为真,它就为真。这意味着要使 $P ∨ Q$为真,$P$ 或 $Q$ 中至少有一个必须为真。 | $P$ | $Q$ | $P\lor Q$ | | --- | --- | --------- | @@ -70,7 +70,7 @@ - 值得一提的是,Or 有两种类型:同或 Or 和异或 Or。在异或中,如果$P\lor Q$为真,则$P∧Q$为假。也就是说,一个异或要求它只有一个论点为真,而不要求两者都为真。如果$P、Q$或$P∧Q$中的任何一个为真,则包含或为真。在 Or($\lor$) 的情况下,意图是一个包含的 Or。 -- Implication (→) 逻辑蕴含:表示“如果$P$,则$Q$的结构。例如,如果$P$:“正在下雨”,$Q$:“我在室内”,则$P→ Q$的意思是“如果下雨,那么我在室内。”在$P$的情况下,意味着$Q$,$P$被称为前件,$Q$ 被称为后件。 +- **Implication (→)** 逻辑蕴含:表示“如果$P$,则$Q$的结构。例如,如果$P$:“正在下雨”,$Q$:“我在室内”,则$P→ Q$的意思是“如果下雨,那么我在室内。”在$P$的情况下,意味着$Q$,$P$被称为前件,$Q$ 被称为后件。 - 当前件为真时,在后件为真的情况下,整个蕴含逻辑为真(这是有道理的:如果下雨,我在室内,那么“如果下雨,那么我在室内”这句话是真的)。当前件为真时,如果后件为假,则蕴含逻辑为假(如果下雨时我在外面,那么“如果下雨,那么我在室内”这句话是假的)。然而,当前件为假时,无论后件如何,蕴含逻辑总是真的。这有时可能是一个令人困惑的概念。从逻辑上讲,我们不能从蕴含中学到任何东西$(P→ Q)$如果前件 ($P$) 为假。看一下我们的例子,如果没有下雨,这个蕴含逻辑并没有说我是否在室内的问题。我可能是一个室内型的人,即使不下雨也不在外面走,或者我可能是一个室外型的人,不下雨的时候一直在外面。当前件是假的,我们说蕴含逻辑是真的。 @@ -81,6 +81,7 @@ | 1 | 0 | 0 | | 1 | 1 | 1 | + - Biconditional ($\leftrightarrow$) :是一个双向的蕴含。你可以把它读成“如果且仅当”$P↔ Q$等同$P→ Q$和$Q→ P$合在一起。例如,如果$P$:“正在下雨”,$Q$:“我在室内”,那么$P↔ Q$的意思是“如果下雨,那么我在室内”,“如果我在室内,那么就在下雨。”这意味着我们可以推断出比简单蕴含更多的东西。如果$P$为假,那么$Q$ 也为假;如果不下雨,我们知道我也不在室内。 | $P$ | $Q$ | $P\leftrightarrow Q$ | diff --git a/4.人工智能/4.3.3不确定性问题.md b/4.人工智能/4.3.3不确定性问题.md index 6c049bb..32f2ac2 100644 --- a/4.人工智能/4.3.3不确定性问题.md +++ b/4.人工智能/4.3.3不确定性问题.md @@ -340,11 +340,11 @@ print(Counter(data)) - 到目前为止,我们已经研究了概率问题,给出了我们观察到的一些信息。在这种范式中,时间的维度没有以任何方式表示。然而,许多任务确实依赖于时间维度,例如预测。为了表示时间变量,我们将创建一个新的变量$X$,并根据感兴趣的事件对其进行更改,使$X_t$ 是当前事件,$X_{t+1}$ 是下一个事件,依此类推。为了能够预测未来的事件,我们将使用马尔可夫模型。 -### 马尔科夫假设 (The Markov Assumption) +### 马尔科夫假设 (**The Markov Assumption**) - 马尔科夫假设是一个假设,即当前状态只取决于有限的固定数量的先前状态。想想预测天气的任务。在理论上,我们可以使用过去一年的所有数据来预测明天的天气。然而,这是不可行的,一方面是因为这需要计算能力,另一方面是因为可能没有关于基于 365 天前天气的明天天气的条件概率的信息。使用马尔科夫假设,我们限制了我们以前的状态(例如,在预测明天的天气时,我们要考虑多少个以前的日子),从而使这个任务变得可控。这意味着我们可能会得到感兴趣的概率的一个更粗略的近似值,但这往往足以满足我们的需要。此外,我们可以根据最后一个事件的信息来使用马尔可夫模型(例如,根据今天的天气来预测明天的天气)。 -### 马尔科夫链 (Markov Chain) +### 马尔科夫链 (**Markov Chain**) - 马尔科夫链是一个随机变量的序列,每个变量的分布都遵循马尔科夫假设。也就是说,链中的每个事件的发生都是基于之前事件的概率。 - 为了构建马尔可夫链,我们需要一个过渡模型,该模型将根据当前事件的可能值来指定下一个事件的概率分布。 @@ -399,9 +399,9 @@ print(model.sample(50)) - 基于隐马尔科夫模型,可以实现多种任务: - - 筛选 Filtering: 给定从开始到现在的观察结果,计算出当前状态的概率分布。例如,给从从特定时间开始到今天人们带伞的信息,我们产生一个今天是否下雨的概率分布。 - - 预测 Prediction: 给定从开始到现在的观察,计算未来状态的概率分布。 - - 平滑化 Smoothing: 给定从开始到现在的观察,计算过去状态的概率分布。例如,鉴于今天人们带了雨伞,计算昨天下雨的概率。 + - 筛选 Filtering: 给定从开始到现在的观察结果,计算出**当前**状态的概率分布。例如,给从从特定时间开始到今天人们带伞的信息,我们产生一个今天是否下雨的概率分布。 + - 预测 Prediction: 给定从开始到现在的观察,计算**未来**状态的概率分布。 + - 平滑化 Smoothing: 给定从开始到现在的观察,计算**过去**状态的概率分布。例如,鉴于今天人们带了雨伞,计算昨天下雨的概率。 - 最可能的解释 Most likely explanation: 鉴于从开始到现在的观察,计算最可能的事件顺序。 - 最可能的解释任务可用于语音识别等过程,根据多个波形,人工智能推断出给这些波形带来的最有可能的单词或音节的序列。接下来是一个隐马尔科夫模型的 Python 实现,我们将用于最可能的解释任务: diff --git a/4.人工智能/4.6.2你可能会需要的术语介绍.md b/4.人工智能/4.6.2你可能会需要的术语介绍.md index 56057b5..50fde69 100644 --- a/4.人工智能/4.6.2你可能会需要的术语介绍.md +++ b/4.人工智能/4.6.2你可能会需要的术语介绍.md @@ -1,6 +1,6 @@ # 你可能会需要的术语介绍 -众所周知,一个领域的黑话对新人来说是比较不友好的,为此我从知乎上找了一篇黑话大赏(bushi)做了点改良放在这里。如果遇到看不懂的词了可以来这找找。在系统学习之前可以先无视这篇文章,遇到问题再来找找 +众所周知,一个领域的黑话对新人来说是比较不友好的,为此我从知乎上找了一篇黑话大赏(bushi)做了点改良放在这里。如果遇到看不懂的词了可以来这找找。**在系统学习之前可以先无视这篇文章,遇到问题再来找找** > 作者:Young
链接:[https://www.zhihu.com/question/469612040/answer/2008770105](https://www.zhihu.com/question/469612040/answer/2008770105)
来源:知乎 @@ -38,7 +38,7 @@ - 体素:我把世界变成 MC 了,世界是一堆方块,他们在不同视角下有各自的颜色和透明度 - 点云:我每采样一次得到一个点,由这些点去表示我要的物体,不太直观,来张图 -这是我用照片重建的独角兽稀疏点云,红色的不用管,是照相机视角(图不够多,巨糊) +这是我用照片重建的独角兽**稀疏**点云,红色的不用管,是照相机视角(图不够多,巨糊) ![](https://cdn.xyxsw.site/boxcnWx8hYfT6kFug4A1iA3uftg.png) diff --git a/4.人工智能/4.6.3深度学习快速入门.md b/4.人工智能/4.6.3深度学习快速入门.md index 88dc912..6276771 100644 --- a/4.人工智能/4.6.3深度学习快速入门.md +++ b/4.人工智能/4.6.3深度学习快速入门.md @@ -1,6 +1,6 @@ # 深度学习快速入门 -## 刘二大人(Pytorch) +## **刘二大人(Pytorch)** ## 速成课:人工智能 [【速成课:人工智能】Ai - [21 集全/中英双语] - Artificial Intelligence_哔哩哔哩_bilibili](https://www.bilibili.com/video/BV1P7411r7Dw) @@ -62,7 +62,7 @@ Crash course 的课程,可以基本了解pytorch的内容,但是当然有很 ## torch 我还不会呢! -学会一个庞大并且高度封装的包并不是一蹴而就的,我们建议从实践开始,比如说自己搭建一个神经网络来实现 MNIST 的分类。在使用这些函数和类的过程中你能更快地掌握它们的方法。 +学会一个**庞大并且高度封装**的包并不是一蹴而就的,我们建议从实践开始,比如说自己搭建一个神经网络来实现 MNIST 的分类。在使用这些函数和类的过程中你能更快地掌握它们的方法。 # 关于梯度下降算法: @@ -103,12 +103,12 @@ Crash course 的课程,可以基本了解pytorch的内容,但是当然有很 # 接下来干什么? -- 我想学 CV !!!!!! +- **我想学 CV !!!!!!** -你可以在 CV 模块中找到[4.6.5.3CV中的经典网络](4.6.5.3CV%E4%B8%AD%E7%9A%84%E7%BB%8F%E5%85%B8%E7%BD%91%E7%BB%9C.md) ,这里是一些最最经典的论文,我们推荐你阅读它们的原文并且复现它们的代码,这可以同时锻炼你的coding 能力和论文阅读能力,在阅读前,请参见[如何读论文](../1.%E6%9D%AD%E7%94%B5%E7%94%9F%E5%AD%98%E6%8C%87%E5%8D%97/1.10%E5%A6%82%E4%BD%95%E8%AF%BB%E8%AE%BA%E6%96%87.md) 。本模块的撰写者SRT 社团主要从事 CV 方向的研究,遇到问题欢迎与我们交流。(你都完成这些了不至于找不到我们的联系方式吧~)如果你读完了经典网络模块,你可以在它的最后找到接下来的学习路线~ +你可以在 CV 模块中找到[4.6.5.3CV中的经典网络](4.6.5.3CV%E4%B8%AD%E7%9A%84%E7%BB%8F%E5%85%B8%E7%BD%91%E7%BB%9C.md) ,这里是一些最最经典的论文,我们推荐你阅读它们的原文并且复现它们的代码,这可以同时锻炼你的**coding 能力和论文阅读能力**,在阅读前,请参见[如何读论文](../1.%E6%9D%AD%E7%94%B5%E7%94%9F%E5%AD%98%E6%8C%87%E5%8D%97/1.10%E5%A6%82%E4%BD%95%E8%AF%BB%E8%AE%BA%E6%96%87.md) 。本模块的撰写者**SRT 社团**主要从事 CV 方向的研究,遇到问题欢迎与我们交流。(你都完成这些了不至于找不到我们的联系方式吧~)**如果你读完了经典网络模块,你可以在它的最后找到接下来的学习路线~** -- 我想做NLP !!!!!! +- **我想做****NLP**** !!!!!!** NLP 研究方向庞大且复杂,若直接从 GPT 系列开始不免有些过于困难。我们建议你从了解 NLP 的任务开始,在有足够的基础后开始学习 RNN,LSTM 基准方法后向 [4.6.7Transformer](4.6.7Transformer.md) 进发 ,这个方法广泛运用在几乎所有深度学习领域,尤其是 NLP 的前沿研究已经无法离开 Transformer 了 hhhh。这个模块中我们也加入了一些 Transformer 的改进工作,包括 NLP,CV,和多模态 -- 如果你想做多模态,对比学习等,请同时了解 CV 和 NLP 模块。这将是你后续知识的基础。多模态我们没有完善的讲义推出,对比学习可以参见[4.6.8对比学习](4.6.8%E5%AF%B9%E6%AF%94%E5%AD%A6%E4%B9%A0.md) 。这是撰写者之一的论文阅读笔记,不保证准确性与理解是否准确,可以作为论文阅读路线图来参考~ +- **如果你想做多模态,对比学习等**,请同时了解 CV 和 NLP 模块。这将是你后续知识的基础。多模态我们没有完善的讲义推出,对比学习可以参见[4.6.8对比学习](4.6.8%E5%AF%B9%E6%AF%94%E5%AD%A6%E4%B9%A0.md) 。这是撰写者之一的论文阅读笔记,不保证准确性与理解是否准确,可以作为论文阅读路线图来参考~ diff --git a/4.人工智能/4.6.4Pytorch安装.md b/4.人工智能/4.6.4Pytorch安装.md index 6a5ee3b..afcfb16 100644 --- a/4.人工智能/4.6.4Pytorch安装.md +++ b/4.人工智能/4.6.4Pytorch安装.md @@ -17,7 +17,7 @@ Pip 在通过 python 官网下载 python 并安装时可以选择同时安装 pi 3. 对于 Windows 用户,在 C:\Users\xx\pip 目录下(没有 pip 目录就新建)创建一个 pip.ini 文件,并将下面代码块中内容复制进去: 4. 对于 Linux 用户,同样在~/.pip/pip.conf 进行配置。如果没有.pip 目录就新建,然后将下面代码块中内容复制进去: -``` +```bash [global] index-url = http://pypi.douban.com/simple extra-index-url = https://pypi.mirrors.ustc.edu.cn/simple/ diff --git a/4.人工智能/4.6.5.1CV领域任务(研究目标).md b/4.人工智能/4.6.5.1CV领域任务(研究目标).md index 49be167..7ae18e7 100644 --- a/4.人工智能/4.6.5.1CV领域任务(研究目标).md +++ b/4.人工智能/4.6.5.1CV领域任务(研究目标).md @@ -4,11 +4,11 @@ ![](https://cdn.xyxsw.site/boxcnTUlm8EI0byGJJQ78IqGWGx.png) -#### (a)Image classification 图像分类 +#### (a)Image classification **图像分类** - 识别这个图片整体所属的类别,解决的是"what"问题,给这个图片打上相应的标签,在 a 图内标签是 `bottle,cup,cube`,其他类型的图片也都有它们自己的标签,然后把这些打上标签的图片带进网络结构里作为训练集训练。 -#### (b)Object localization 目标检测(对象定位) +#### (b)Object localization **目标检测**(对象定位) - 识别图片中各个物体所在的位置,解决的是"where"问题,此处还细分两个问题: @@ -20,12 +20,12 @@ ![](https://cdn.xyxsw.site/boxcnoyxKL4bOeYOOjrh6it0BHd.gif) -#### (c)Semantic segmentation 语义分割 +#### (c)Semantic segmentation **语义分割** - 语义分割需要进一步判断图像中哪些像素属于哪个目标(进阶目标检测)。 - 看图右下角两个 `cube` 是连在一块的 并没有分出哪一部分是哪一个的 `cube` -#### (d)Instance segmentation 实例分割 +#### (d)Instance segmentation **实例分割** - 实例分割需要区分出哪些像素属于第一个物体、哪些像素属于第二个物体,即目标检测 + 语义分割。 - 看图右下角两个 `cube` 是分开的 diff --git a/4.人工智能/4.6.5.2.1数据读取.md b/4.人工智能/4.6.5.2.1数据读取.md index 63d10ed..bc8d9bb 100644 --- a/4.人工智能/4.6.5.2.1数据读取.md +++ b/4.人工智能/4.6.5.2.1数据读取.md @@ -20,7 +20,7 @@ PyTorch 中的 Dataset 类是一个抽象类,它可以用来表示数据集。 下面我们来编写一个简单的例子,看下如何使用 Dataset 类定义一个 Tensor 类型的数据集。 -``` +```python import torch from torch.utils.data import Dataset @@ -43,7 +43,7 @@ class MyDataset(Dataset): 然后我们来看一下如何调用刚才定义的数据集。首先随机生成一个 10*3 维的数据 Tensor,然后生成 10 维的标签 Tensor,与数据 Tensor 相对应。利用这两个 Tensor,生成一个 MyDataset 的对象。查看数据集的大小可以直接用 len() 函数,索引调用数据可以直接使用下标。 -``` +```python # 生成数据 data_tensor = torch.randn(10, 3) target_tensor = torch.randint(2, (10,)) # 标签是0或1 @@ -67,7 +67,7 @@ DataLoader 是一个迭代器,最基本的使用方法就是传入一个 Datas DataLoader 类的调用方式如下: -``` +```python from torch.utils.data import DataLoader tensor_dataloader = DataLoader(dataset=my_dataset, # 传入的数据集, 必须参数 batch_size=2, # 输出的batch大小 @@ -107,7 +107,7 @@ One batch tensor data: [tensor([[ 0.9451, -0.4923, -1.8178], - shuffle:bool 类型,在每个 epoch 开始的时候,是否对数据进行重新打乱; - num_workers:int 类型,加载数据的进程数,0 意味着所有的数据都会被加载进主进程,默认为 0。 -思考题 +**思考题** 按照上述代码,One batch tensor data 的输出是否正确,若不正确,为什么? @@ -143,7 +143,7 @@ MNIST 数据集是 ubyte 格式存储,我们先将“训练集图片”解析 以 MNIST 为例,我们可以用如下方式调用: -``` +```python # 以MNIST为例 import torchvision mnist_dataset = torchvision.datasets.MNIST(root='./data', @@ -173,7 +173,7 @@ torchvision.datasets.MNIST 是一个类,对它进行实例化,即可返回 如果想要查看 mnist_dataset 中的具体内容,我们需要把它转化为列表。(如果 IOPub data rate 超限,可以只加载测试集数据,令 train=False) -``` +```python mnist_dataset_list = list(mnist_dataset) print(mnist_dataset_list) ``` @@ -182,7 +182,7 @@ print(mnist_dataset_list) 这里图像数据是 PIL.Image.Image 类型的,这种类型可以直接在 Jupyter 中显示出来。显示一条数据的代码如下。 -``` +```python display(mnist_dataset_list[0][0]) print("Image label is:", mnist_dataset_list[0][1]) ``` diff --git a/4.人工智能/4.6.5.2.2数据增强.md b/4.人工智能/4.6.5.2.2数据增强.md index 01f18f2..c1ade4b 100644 --- a/4.人工智能/4.6.5.2.2数据增强.md +++ b/4.人工智能/4.6.5.2.2数据增强.md @@ -27,7 +27,7 @@ Torchvision 库中的 torchvision.transforms 包中提供了常用的图像操 我们来看一个具体的例子加深理解。将图片进行一下数据类型的相互转换。具体代码如下: -``` +```python from PIL import Image from torchvision import transforms @@ -58,7 +58,7 @@ print(type(img2)) ''' ``` -首先用读取图片,查看一下图片的类型为 PIL.JpegImagePlugin.JpegImageFile,这里需要注意,PIL.JpegImagePlugin.JpegImageFile 类是 PIL.Image.Image 类的子类。然后,用 transforms.ToTensor() 将 PIL.Image 转换为 Tensor。最后,再将 Tensor 转换回 PIL.Image。 +首先用读取图片,查看一下图片的类型为 PIL.JpegImagePlugin.JpegImageFile,这里需要注意,**PIL.JpegImagePlugin.JpegImageFile 类是 PIL.Image.Image 类的子类**。然后,用 transforms.ToTensor() 将 PIL.Image 转换为 Tensor。最后,再将 Tensor 转换回 PIL.Image。 ## 对 PIL.Image 和 Tensor 进行变换 @@ -68,7 +68,7 @@ torchvision.transforms 提供了丰富的图像变换方法,例如:改变尺 将输入的 PIL Image 或 Tensor 尺寸调整为给定的尺寸,具体定义为: -``` +```python torchvision.transforms.Resize(size, interpolation=2) ``` @@ -81,7 +81,7 @@ torchvision.transforms.Resize(size, interpolation=2) 在 resize 之后呢,一般会接一个 crop 操作,crop 到指定的大小。对于高与宽接近的图片来说,这么做问题不大,但是高与宽的差距较大时,就会 crop 掉很多有用的信息。关于这一点,我们在后续的图像分类部分还会遇到,到时我在详细展开。 -``` +```python from PIL import Image from torchvision import transforms @@ -105,7 +105,7 @@ torchvision.transforms 提供了多种剪裁方法,例如中心剪裁、随机 先说中心剪裁,在中心裁剪指定的 PIL Image 或 Tensor,其定义如下: -``` +```python torchvision.transforms.CenterCrop(size) ``` @@ -113,7 +113,7 @@ torchvision.transforms.CenterCrop(size) 然后是随机剪裁,在一个随机位置剪裁指定的 PIL Image 或 Tensor,定义如下: -``` +```python torchvision.transforms.RandomCrop(size, padding=None) ``` @@ -121,13 +121,13 @@ torchvision.transforms.RandomCrop(size, padding=None) 最后要说的是 FiveCrop,我们将给定的 PIL Image 或 Tensor ,分别从四角和中心进行剪裁,共剪裁成五块,定义如下: -``` +```python torchvision.transforms.FiveCrop(size) ``` size 可以是 int 或 tuple,用法同上。掌握了各种剪裁的定义和参数用法以后,我们来看一下这些剪裁操作具体如何调用,代码如下: -``` +```python from PIL import Image from torchvision import transforms @@ -158,13 +158,13 @@ for img in imgs: 以概率 p 随机水平翻转图像,定义如下: -``` +```python torchvision.transforms.RandomHorizontalFlip(p=0.5) ``` 以概率 p 随机垂直翻转图像,定义如下: -``` +```python torchvision.transforms.RandomVerticalFlip(p=0.5) ``` @@ -172,7 +172,7 @@ torchvision.transforms.RandomVerticalFlip(p=0.5) 这里的随机翻转,是为数据增强提供方便。如果想要必须执行翻转操作的话,将 p 设置为 1 即可。图片翻转代码如下: -``` +```python from PIL import Image from torchvision import transforms @@ -202,7 +202,7 @@ display(img2) 标准化是指每一个数据点减去所在通道的平均值,再除以所在通道的标准差,数学的计算公式:output=(input−mean)/std -而对图像进行标准化,就是对图像的每个通道利用均值和标准差进行正则化。这样做的目的,是为了保证数据集中所有的图像分布都相似,这样在训练的时候更容易收敛,既加快了训练速度,也提高了训练效果。 +而对图像进行标准化,就是对图像的每个通道利用均值和标准差进行正则化。这样做的目的,是**为了保证数据集中所有的图像分布都相似,这样在训练的时候更容易收敛,既加快了训练速度,也提高了训练效果**。 让我来解释一下:首先,标准化是一个常规做法,可以理解为无脑进行标准化后再训练的效果,大概率要好于不进行标准化。 @@ -212,7 +212,7 @@ display(img2) torchvision.transforms 提供了对 Tensor 进行标准化的函数,定义如下: -``` +```python torchvision.transforms.Normalize(mean, std, inplace=False) ``` @@ -224,7 +224,7 @@ torchvision.transforms.Normalize(mean, std, inplace=False) 我们来看看以 (R, G, B) 均值和标准差均为 (0.5, 0.5, 0.5) 来标准化图片后,是什么效果: -``` +```python from PIL import Image from torchvision import transforms @@ -254,7 +254,7 @@ display(img_norm) Compose 类是将多个变换组合到一起,它的定义如下: -``` +```python torchvision.transforms.Compose(transforms) ``` @@ -262,7 +262,7 @@ torchvision.transforms.Compose(transforms) 我们还是结合例子动手试试,如果我们想要将图片变为 200*200 像素大小,并且随机裁切成 80 像素的正方形。那么我们可以组合 Resize 和 RandomCrop 变换,具体代码如下所示: -``` +```python from PIL import Image from IPython.display import display from torchvision import transforms @@ -292,7 +292,7 @@ Compose 类是未来我们在实际项目中经常要使用到的类,结合 to 我们还是以读取 MNIST 数据集为例,看下如何在读取数据的同时,完成数据预处理等操作。具体代码如下: -``` +```python from torchvision import transforms from torchvision import datasets @@ -320,7 +320,7 @@ print(type(item[0])) 我们下面先来看看,在图像分类实战中使用的 transform,可以感受一下实际使用的 transforms 是什么样子: -``` +```python transform = transforms.Compose([ transforms.RandomResizedCrop(dest_image_size), transforms.RandomHorizontalFlip(), diff --git a/4.人工智能/4.6.5.3.1AlexNet.md b/4.人工智能/4.6.5.3.1AlexNet.md index 84436b7..410d154 100644 --- a/4.人工智能/4.6.5.3.1AlexNet.md +++ b/4.人工智能/4.6.5.3.1AlexNet.md @@ -10,17 +10,17 @@ AlexNet 有 6 千万个参数和 650,000 个神经元。 [论文](http://www.cs.toronto.edu/~fritz/absps/imagenet.pdf) -### 网络框架图 +### **网络框架图** ![](https://cdn.xyxsw.site/boxcng0jB2dmDD18EwU8nAIFPIc.png) -### 使用 ReLU 激活函数代替 tanh +### **使用 ReLU 激活函数代替 tanh** 在当时,标准的神经元激活函数是 tanh()函数,这种饱和的非线性函数在梯度下降的时候要比非饱和的非线性函数慢得多,因此,在 AlexNet 中使用 ReLU 函数作为激活函数。 ![](https://cdn.xyxsw.site/boxcnFlENdpKXUR7l4MhUXFKzfg.png) -### 采用 Dropout 防止过拟合 +### **采用 Dropout 防止过拟合** dropout 方法会遍历网络的每一层,并设置消除神经网络中节点的概率。假设网络中的每一层,每个节点都以抛硬币的方式设置概率,每个节点得以保留和消除的概率都是 0.5,设置完节点概率,我们会消除一些节点,然后删除掉从该节点进出的连线,最后得到一个节点更少,规模更小的网络(如下图所示),然后再用反向传播方法进行训练。 @@ -32,7 +32,7 @@ dropout 方法会遍历网络的每一层,并设置消除神经网络中节点 ### -### 视频讲解 +### **视频讲解** # 思考 @@ -40,7 +40,7 @@ dropout 方法会遍历网络的每一层,并设置消除神经网络中节点 AlexNet 中有着卷积和 MLP 两种不同的网络结构,那两者之间有着何种区别和联系呢?(可以从两者的权值矩阵去思考) -### 思考 2 +### **思考 2** 卷积中有一个叫感受野的概念,是什么意思呢?不同的感受野对网络有什么影响? diff --git a/4.人工智能/4.6.5.3.2FCN.md b/4.人工智能/4.6.5.3.2FCN.md index de453d7..53a6352 100644 --- a/4.人工智能/4.6.5.3.2FCN.md +++ b/4.人工智能/4.6.5.3.2FCN.md @@ -2,7 +2,7 @@ 图像分割领域的开山之作。 -首次将End-to-End的思想应用在了 CV 领域。 +首次将**End-to-End**的思想应用在了 CV 领域。 [知乎](https://zhuanlan.zhihu.com/p/30195134) @@ -18,7 +18,7 @@ FCN 对图像进行像素级的分类,从而解决了语义级别的图像分割问题。与经典的 CNN 在卷积层之后使用全连接层得到固定长度的特征向量进行分类不同,FCN 可以接受任意尺寸的输入图像,采用反卷积层对最后一个卷积层的 feature map 进行上采样, 使它恢复到输入图像相同的尺寸,从而可以对每个像素都产生了一个预测, 同时保留了原始输入图像中的空间信息, 最后在上采样的特征图上进行逐像素分类。 -简单的来说,FCN 与 CNN 的区域在把于 CNN 最后的全连接层换成卷积层,输出的是一张已经 Label 好的图片。 +**简单的来说,FCN 与 CNN 的区域在把于 CNN 最后的全连接层换成卷积层,输出的是一张已经 Label 好的图片。** ### 反卷积 diff --git a/4.人工智能/4.6.5.4.1NeRF.md b/4.人工智能/4.6.5.4.1NeRF.md index 01418e2..0a2aea0 100644 --- a/4.人工智能/4.6.5.4.1NeRF.md +++ b/4.人工智能/4.6.5.4.1NeRF.md @@ -8,13 +8,13 @@ NeRF 想做这样一件事,不需要中间三维重建的过程,仅根据位 ![](https://cdn.xyxsw.site/boxcn6jg09V944MU1sBsstmdaib.png) -你可以看到,这 100 张图片是对一个乐高推土机的多角度拍摄结果。我们需要的是一个可以获取这个推土机在任意角度下拍摄的图片的模型。如图所示: +你可以看到,这 100 张图片是对一个乐高推土机的多角度拍摄结果。我们需要的是一个可**以获取这个推土机在任意角度下拍摄的图片**的模型。如图所示: ![](https://cdn.xyxsw.site/boxcnLEEyuUWOwiJOePhmmsAakd.gif) 现在来看 NeRF 网络: -在 NeRF 中,我们把空间认为是一个个的小方块叠成的空间(可以理解为 MC)每一个方块有以下属性: +在 NeRF 中,我们把空间**认为是一个个的小方块叠成的空间**(可以理解为 MC)每一个方块有以下属性: - 3 个位置坐标(x,y,z) - 透明度$\sigma$ @@ -24,27 +24,27 @@ NeRF 想做这样一件事,不需要中间三维重建的过程,仅根据位 ## 得到模型 -我们需要的是每个视角下的图片,可以理解为从一个视角发射光线一根光线对应一个像素点。这些光线穿透路径上的所有方块,把这些方块上的属性信息以某种方式累计,就能得到这个像素的颜色。这是 一个已有的公式,只要我们获得每个小方块的颜色信息和不透明度,我们就能知道这个角度下的视图。(这个我们后面介绍) +我们需要的是每个视角下的图片,可以理解为从一个视角发射**光线**,一根光线对应一个像素点。这些光线穿透路径上的所有方块,把这些方块上的属性信息以某种方式累计,就能得到这个像素的颜色。这是 一个已有的公式,只要我们获得每个小方块的颜色信息和不透明度,我们就能知道这个角度下的视图。(这个我们后面介绍) -现在的难点在于:我们不知道每个小方块的颜色信息(因为颜色会随着观察角度变化)。众所周知,算法解决不了的问题就扔给神经网络试试啦~ +现在的难点在于:我们不知道**每个小方块的颜色信息**(因为颜色会随着观察角度变化)。众所周知,算法解决不了的问题就扔给神经网络试试啦~ -为了获取根据角度变化而变化的颜色信息,我们选择了神经网络。 +**为了获取根据角度变化而变化的颜色信息,我们选择了神经网络。** -这个网络的输入是: +**这个网络的输入是:** - 小方块的位置坐标(x,y,z) - 观察角度(以二维坐标表示两个偏转角) -这个网络的输出是: +**这个网络的输出是:** - 对应的小方块的 RGB 信息 - 不透明度 ![](https://cdn.xyxsw.site/boxcni4q9Cp8G7H9HjKMrfImcZe.jpg) -在这里,作者选择了最简单的 MLP,因此,这是一个输入为 5 维,输出为 4 维向量($R,G,B,\sigma$)的简单网络,值得注意的是,不透明度与观察角度无关,这里在网络中进行了特殊处理,让这个值与后两维无关。 +在这里,作者选择了最简单的 MLP,因此,**这是一个输入为 5 维,输出为 4 维向量**($R,G,B,\sigma$)的简单网络,值得注意的是,不透明度与观察角度无关,这里在网络中进行了特殊处理,让这个值与后两维无关。 -现在我们能够输入坐标和视角信息得到小方块的颜色和不透明度,我们就可以对光线穿过的小方块进行计算了。 +**现在我们能够输入坐标和视角信息得到小方块的颜色和不透明度,我们就可以对光线穿过的小方块进行计算了。** ## 进行渲染 @@ -54,9 +54,9 @@ NeRF 想做这样一件事,不需要中间三维重建的过程,仅根据位 这个公式对光线上的所有小方块的颜色进行加权求和,权重是关于不透明度$\sigma$的一个函数$T(\sigma)$,不透明度在[0,1]之间,越不透明这个值越大。也就是越不透明,占的颜色比重越高,比如空气的$\sigma$就接近于 0,乐高本身就接近 1。而求和的结果就是这个光线对应像素的颜色。 -这里展开说一下$T(\sigma)$,我们把不透明度理解为光线在这个小方块被阻止的概率,越不透明,越容易阻挡光线,而光线一旦被阻挡,就不用计算后面的小方块颜色了。因此,我们的$T(\sigma)$就表示光线能够行进到这个小方块的概率,也就是这点之前所有小方块的$(1-\sigma)$的乘积。 +这里展开说一下$T(\sigma)$,我们把不透明度理解为光线在这个小方块被阻止的概率,越不透明,越容易阻挡光线,而光线一旦被阻挡,就不用计算后面的小方块颜色了。因此,我们的$T(\sigma)$就表示**光线能够行进到这个小方块的概率**,也就是这点之前所有小方块的$(1-\sigma)$的乘积。 -这段要仔细看和推导,第一遍不容易直接懂。顺带一提,我们的小方块学名叫体素为了显得我们更专业一点以后就叫它体素罢 +这段要仔细看和推导,第一遍不容易直接懂。顺带一提,我们的**小方块**学名叫**体素**,为了显得我们更专业一点以后就叫它体素罢 ![](https://cdn.xyxsw.site/boxcnnwHy3Hlhbu2bOsi6r2BYJe.png) @@ -84,7 +84,7 @@ NeRF 想做这样一件事,不需要中间三维重建的过程,仅根据位 我们使用了两个网络:粗网络和精细网络。 -粗网络就是上述采样方法用的普通网络,而粗网络输出的不透明度值会被作为一个概率分布函数,精细网络根据这个概率分布在光线上进行采样,不透明度越大的点,它的邻域被采样的概率越大,也就实现了我们要求的在实体上多采样,空气中少采样。最后精细网络输出作为结果,因此粗网络可以只求不透明度,无视颜色信息。 +粗网络就是上述采样方法用的普通网络,而**粗网络输出的不透明度值会被作为一个概率分布函数**,精细网络根据这个概率分布在光线上进行采样,不透明度越大的点,它的邻域被采样的概率越大,也就实现了我们要求的在实体上多采样,空气中少采样。最后精细网络输出作为结果,因此粗网络可以只求不透明度,无视颜色信息。 ![](https://cdn.xyxsw.site/boxcnwl72wntQgYMFvRPTWY5fPf.png) diff --git a/4.人工智能/4.6.5.4.2NeRF的改进方向.md b/4.人工智能/4.6.5.4.2NeRF的改进方向.md index b889f72..22c492e 100644 --- a/4.人工智能/4.6.5.4.2NeRF的改进方向.md +++ b/4.人工智能/4.6.5.4.2NeRF的改进方向.md @@ -10,19 +10,19 @@ ### 1.Pixel-nerf -Pixel-nerf 对输入图像使用卷积进行特征提取再执行 nerf,若有多个输入,对每个视角都执行 CNN,在计算光线时,取每一个已有视角下该坐标的特征,经过 mlp 后算平均。可以在少量视角下重建视图,需要进行预训练才能使用,有一定自动补全能力(有限) +**Pixel-nerf**** **对输入图像使用卷积进行特征提取再执行 nerf,若有多个输入,对每个视角都执行 CNN,在计算光线时,取每一个已有视角下该坐标的特征,经过 mlp 后算平均。可以在少量视角下重建视图,需要进行预训练才能使用,有一定自动补全能力(有限) ![](https://cdn.xyxsw.site/boxcnEiUODOd4FOBxYIZmmihyef.png) ### 2.IBRnet -IBRnet 是 pixel-nerf 的改进版,取消了 CNN,并且在 mlp 后接入了 transformer 结构处理体密度(不透明度),对这条光线上所有的采样点进行一个 transformer。同时,在获取某个体素的颜色和密度时,作者用了本视角相邻的两个视角,获取对应体素在这两张图片中的像素,以图片像素颜色,视角,图片特征作为 mlp 的输入。 +**IBRnet**** **是 pixel-nerf 的改进版,取消了 CNN,并且在 mlp 后接入了 transformer 结构处理体密度(不透明度),对这条光线上所有的采样点进行一个 transformer。同时,在获取某个体素的颜色和密度时,作者用了本视角相邻的两个视角,获取对应体素在这两张图片中的像素,以图片像素颜色,视角,图片特征作为 mlp 的输入。 ![](https://cdn.xyxsw.site/boxcnwH75jIO9NiVwQaBqDrbe8e.png) ### 3.MVSnerf -MVSnerf 它用 MVS 的方法构建代价体然后在后面接了一个 nerf,MVS 是使用多视角立体匹配构建一个代价体,用 3D 卷积网络进行优化,这里对代价体进行 nerf 采样,可以得到可泛化网络。它需要 15min 的微调才能在新数据上使用。多视角立体匹配是一种传统算法,通过光线,几何等信息计算图像中小块的相似度,得出两个相机视角之间的位置关系。这个算法也被广泛使用在得到我们自己采样的数据的相机变换矩阵上(我就是这么干的) +**MVSnerf**** **它用 MVS 的方法构建代价体然后在后面接了一个 nerf,MVS 是使用**多视角立体匹配**构建一个代价体,用 3D 卷积网络进行优化,这里对代价体进行 nerf 采样,可以得到可泛化网络。它需要 15min 的微调才能在新数据上使用。**多视角立体匹配是一种传统算法,通过光线,几何等信息计算图像中小块的相似度,得出两个相机视角之间的位置关系。这个算法也被广泛使用在得到我们自己采样的数据的相机变换矩阵上(我就是这么干的)** ![](https://cdn.xyxsw.site/boxcnbd2YxumunZR9LZG3ANrPrb.png) @@ -45,13 +45,13 @@ ## 2)可以 zero-shot 或者 fine-tune 类 -MVSnerf,上面已经说了。 +**MVSnerf****,上面已经说了。** # 2.速度提升 ### 1.instan-ngp -使用了哈希表结构的instant-ngp,渲染完美只需要几分钟(采样正常的情况下)这块的速度已经到极致了。 +使用了**哈希表**结构的**instant-ngp**,渲染完美只需要几分钟(采样正常的情况下)这块的速度已经到极致了。 展开说说:其实这也是神经网络发展的一个方向,以前的深层网络倾向于把所有东西用网络参数表示,这样推理速度就会慢,这里使用哈希表的快速查找能力存储一些数据信息,instant-ngp 就是把要表达的模型数据特征按照不同的精细度存在哈希表中,使用时通过哈希表调用或插值调用。 @@ -61,15 +61,15 @@ ### 1.Human-nerf -Human-nerf 生成可编辑的人体运动视频建模,输入是一段人随便动动的视频。输出的动作可以编辑修改,并且对衣物折叠等有一定优化。使用的模型并非全隐式的,并且对头发和衣物单独使用变换模型。使用了逆线性蒙皮模型提取人物骨骼(可学习的模型),上面那个蓝色的就是姿态矫正模块,这个模块赋予骨骼之间运动关系的权重(因为使用的是插值处理同一运动时不同骨骼的平移旋转矩阵,一块骨骼动会牵动其他骨骼)图中的 Ω 就是权重的集合,它通过 mlp 学习得到。然后得到显式表达的人物骨骼以及传入视频中得到的对应骨骼的 mesh,skeletal motion 就是做游戏人物动作用的编辑器这种,后面残差链接了一个 non-rigid-motion(非刚性动作),这个是专门处理衣物和毛发的,主要通过学习得到,然后粗暴的加起来就能得到模型,再经过传统的 nerf 渲染出图像。 +**Human-nerf**** **生成可编辑的人体运动视频建模,输入是一段人随便动动的视频。输出的动作可以编辑修改,并且对衣物折叠等有一定优化。使用的模型并非全隐式的,并且对头发和衣物单独使用变换模型。使用了逆线性蒙皮模型提取人物骨骼(可学习的模型),上面那个蓝色的就是姿态矫正模块,这个模块赋予骨骼之间运动关系的权重(因为使用的是插值处理同一运动时不同骨骼的平移旋转矩阵,一块骨骼动会牵动其他骨骼)图中的 Ω 就是权重的集合,它通过 mlp 学习得到。然后得到显式表达的人物骨骼以及传入视频中得到的对应骨骼的 mesh,skeletal motion 就是做游戏人物动作用的编辑器这种,后面残差链接了一个 non-rigid-motion(非刚性动作),这个是专门处理衣物和毛发的,主要通过学习得到,然后粗暴的加起来就能得到模型,再经过传统的 nerf 渲染出图像。 ![](https://cdn.xyxsw.site/boxcnHRnNXHvwVXrRmM8wnl53p9.png) ### 2.Neural Body -Neural Body 通过下面这种单视角视频或稀疏视角照片来生成人体建模。 +**Neural Body** 通过下面这种**单视角视频**或稀**疏视角照片**来生成人体建模。 -因为生成的是人体建模,作者使用了他们以前的工作 EasyMocap 得到SMPL 模型(就是人体的结构)然后在 SMPL 表面生成一些 latent code(包含颜色,不透明度和位置),也就是下左中的那些点。 +因为生成的是人体建模,作者使用了他们以前的工作 EasyMocap 得到**SMPL 模型(就是人体的结构)然后在 SMPL 表面生成一些 latent code(包含颜色,不透明度和位置),也就是下左中的那些点。** [EasyMocap 的代码](https://link.zhihu.com/?target=https%3A//github.com/zju3dv/EasyMocap) @@ -85,25 +85,25 @@ EasyMocap 是通过多视角视频生成骨架以及 SMPL 模型的一个工作 个人感觉这个模型不能很好处理光影效果,还有待改进。 -是个预训练模型,训练的模块就是这个 3D 卷积神经网络。 +是个预训练模型,**训练的模块就是这个 3D 卷积神经网络**。 ![](https://cdn.xyxsw.site/boxcnbclBwg3BsubGOrt8vZf0qb.png) ### 3.wild-nerf -wild-nerf 思路很简单,就是加入了新的输入参数来调整白天黑夜等等一些简单的变化,并且把行人车辆之类的在采样过程中不固定的物品作为随机项,在渲染时按照概率加入。 +**wild-nerf** 思路很简单,就是加入了新的输入参数来调整白天黑夜等等一些简单的变化,并且把行人车辆之类的在采样过程中**不固定的物品**作为**随机项**,在渲染时按照概率加入。 ### 4.D-nerf -D-nerf 是一种动态编辑的 nerf,输入为:x,y,z,相机位置,相机角度,时间 t。 +**D-nerf** 是一种动态编辑的 nerf,输入为:x,y,z,相机位置,相机角度,**时间 t。** -把整个网络分为两块,一块是正常的 nerf 渲染,另一块是下面这个,输入时间与现在的位置坐标,输出这个位置坐标中的物体现在的位置与 t=0 时的位置的差。再用 t=0 时物体的点信息进行渲染。 +把整个网络分为两块,一块是正常的 nerf 渲染,另一块是下面这个,输入时间与现在的位置坐标,输出**这个位置坐标中的物体现在的位置**与 t=0 时的**位置的差**。再用 t=0 时物体的点信息进行渲染。 在此网络的单个输出上貌似是不监督的,因为没办法进行人为标注。这点我不是很确定,以后如果发现了会来修改的。 ![](https://cdn.xyxsw.site/boxcnYeaiioqtFzQlztsTwiEpzg.png) -渲染经过形变的物体时,光线其实是在 t=0 时刻进行渲染的,因为推土机的铲子放下去了,所以光线是弯曲的。 +渲染经过形变的物体时,光线其实是在 t=0 时刻进行渲染的,因为推土机的铲子放下去了,所以**光线是弯曲的**。 ![](https://cdn.xyxsw.site/boxcng7xDooDmmpbCJRyLJBucwe.png) @@ -115,13 +115,13 @@ EasyMocap 是通过多视角视频生成骨架以及 SMPL 模型的一个工作 ### 1.clip-nerf -clip-nerf 太贵了玩不起,没仔细研究,应该是文本跟 3D 建模关联,跟 clip 一样。 +**clip-nerf**** 太贵了玩不起,没仔细研究,应该是文本跟 3D 建模关联,跟 clip 一样。** # 6.生成类(指加入新物体或者额外生成新场景) ### 1.GRAF -GRAF 把 GAN 与 nerf 结合,增加了两个输入,分别是外观/形状编码 z2D 采样编码 v,z 用来改变渲染出来东西的特征,比如把生成的车变色或者变牌子,suv 变老爷车之类的。v(s,u)用来改变下图 2 中训练时选择光线的标准。这里训练时不是拿 G 生成的整张图扔进 D 网络,而是根据 v 的参数选择一些光线组成的 batch 扔进 D 进行辨别 +**GRAF**** **把 GAN 与 nerf 结合,增加了两个输入,分别是**外观/形状编码 z**和**2D 采样编码 v**,z 用来改变渲染出来东西的特征,比如把生成的车变色或者变牌子,suv 变老爷车之类的。v(s,u)用来改变下图 2 中训练时选择光线的标准。这里训练时不是拿 G 生成的整张图扔进 D 网络,而是根据 v 的参数选择一些光线组成的 batch 扔进 D 进行辨别 ![](https://cdn.xyxsw.site/boxcnVyFqHIoA2MGGc4JJo9tObh.png) @@ -129,7 +129,7 @@ EasyMocap 是通过多视角视频生成骨架以及 SMPL 模型的一个工作 ### 2.GIRAFFE -GIRAFFE 是 GRAF 的改进工作,可以把图片中的物品,背景一个个解耦出来单独进行改变或者移动和旋转,也可以增加新的物品或者减少物品,下图中蓝色是不可训练的模块,橙色可训练。以我的理解好像要设置你要解耦多少个(N)物品再训练,网络根据类似 k 近邻法的方法在特征空间上对物品进行分割解耦,然后分为 N 个渲染 mlp 进行训练,训练前加入外观/形状编码 z。最后还是要扔进 D 训练。 +**GIRAFFE** 是 GRAF 的改进工作,可以把图片中的物品,背景一个个解耦出来单独进行改变或者移动和旋转,也可以增加新的物品或者减少物品,下图中蓝色是不可训练的模块,橙色可训练。以我的理解好像要设置你要解耦多少个(N)物品再训练,网络根据类似 k 近邻法的方法在特征空间上对物品进行分割解耦,然后分为 N 个渲染 mlp 进行训练,训练前加入外观/形状编码 z。最后还是要扔进 D 训练。 ![](https://cdn.xyxsw.site/boxcnB04hwHA1o64WBvYSyVTDod.png) @@ -137,7 +137,7 @@ EasyMocap 是通过多视角视频生成骨架以及 SMPL 模型的一个工作 ### 3.OSF -OSFObject-Centric Neural Scene Rendering,可以给移动的物体生成合理的阴影和光照效果。加入了新的坐标信息:光源位置,与相机坐标等一起输入。对每个小物件构建一个单独的小 nerf,计算这个小 nerf 的体素时要先经过光源照射处理(训练出来的)然后在每个小物件之间也要计算反射这样的光线影响,最后进行正常的渲染。这篇文章没人写 review,有点冷门,这些都是我自己读完感觉的,不一定对。 +**OSF**Object-Centric Neural Scene Rendering,可以给移动的物体生成合理的阴影和光照效果。加入了新的坐标信息:光源位置,与相机坐标等一起输入。对每个小物件构建一个单独的小 nerf,计算这个小 nerf 的体素时要先经过光源照射处理(训练出来的)然后在每个小物件之间也要计算反射这样的光线影响,最后进行正常的渲染。这篇文章没人写 review,有点冷门,这些都是我自己读完感觉的,不一定对。 ![](https://cdn.xyxsw.site/boxcnV7YcKIq5y8TkOGEGzrPc5g.png) @@ -147,9 +147,9 @@ EasyMocap 是通过多视角视频生成骨架以及 SMPL 模型的一个工作 作者用了几个我比较陌生的技术,比如超网络 hypernet,还有超网络与 gan 结合的 INR-Gan。 -hypernet:把随机初始化和直接梯度回传更新的网络参数用另一个神经网络来更新,就是我们要同时训练两个网络,一个是本体,一个是调整参数用的超网络。 +**hypernet**:把随机初始化和直接梯度回传更新的网络参数用另一个神经网络来更新,就是我们要同时训练两个网络,一个是本体,一个是调整参数用的超网络。 -INR-Gan:把超网络技术与 Gan 结合,并且用了 INR 技术,这个技术类似 nerf,不过是处理图片用到的,是构建一个坐标(x,y)->RGB 的网络,可以让图片达到更高分辨率,也就是把离散的像素变成连续的。 +**INR-Gan**:把超网络技术与 Gan 结合,并且用了 INR 技术,这个技术类似 nerf,不过是处理图片用到的,是构建一个坐标(x,y)->RGB 的网络,可以让图片达到更高分辨率,也就是把离散的像素变成连续的。 左边是常规卷积网络生成图像,右边是用 INR 生成图像。 @@ -161,12 +161,12 @@ EasyMocap 是通过多视角视频生成骨架以及 SMPL 模型的一个工作 2.因为使用神经网路去表示图片,占用内存更大。 -因此,作者设计了FMM去应对这两个问题,这也是 Hyper-nerf-gan 借鉴的主要部分。 +因此,作者设计了**FMM**去应对这两个问题,这也是 Hyper-nerf-gan 借鉴的主要部分。 FMM 主要是把要学习的矩阵转化为两个低秩矩阵,去先生成他们俩再相乘,减少网络计算量。 ![](https://cdn.xyxsw.site/boxcn0oHY54dgL2bxmryxjqxC6f.png) -现在开始讲 Hyper-nerf-gan 本身,它看上去其实就是 nerf 接在 gan 上。不过有一些变化,比如输入不再包含视角信息,我很怀疑它不能很好表达反光效果。而且抛弃了粗网络细网络的设计,只使用粗网络减少计算量。这里的 generator 完全就是 INR-Gan 的形状,生成权重,然后再经过 nerf 的 mlp 层生成,没啥别的了,就这样吧。 +现在开始讲 Hyper-nerf-gan 本身,它看上去其实就是 nerf 接在 gan 上。不过有一些变化,比如输入不再包含视角信息,我**很怀疑它不能很好表达反光效果**。而且抛弃了粗网络细网络的设计,只使用粗网络减少计算量。这里的 generator 完全就是 INR-Gan 的形状,生成权重,然后再经过 nerf 的 mlp 层生成,没啥别的了,就这样吧。 ![](https://cdn.xyxsw.site/boxcnc9bZ1nqt3Lighlrj9zSrdd.png) diff --git a/4.人工智能/4.6.5.4.3自制数据集的工具COLMAP.md b/4.人工智能/4.6.5.4.3自制数据集的工具COLMAP.md index bfae611..efad9a8 100644 --- a/4.人工智能/4.6.5.4.3自制数据集的工具COLMAP.md +++ b/4.人工智能/4.6.5.4.3自制数据集的工具COLMAP.md @@ -5,7 +5,7 @@ ![](https://cdn.xyxsw.site/boxcnXzgaIhmUQ7HQtEn52ksWIf.png) 这里主要是记录一下它的原理: -首先是一个经典关键点匹配技术:SIFT +首先是一个经典关键点匹配技术:**SIFT** # SIFT 特征点匹配 @@ -17,7 +17,7 @@ 下面是原理方法: -首先是高斯金字塔,它是把原图先放大两倍,然后使用高斯滤波(高斯卷积)对图像进行模糊化数次,取出倒数第三层缩小一半继续进行这个过程,也就是说它是由一组一组的小金字塔组成的。 +首先是**高斯金字塔**,它是把原图先放大两倍,然后使用高斯滤波(高斯卷积)对图像进行模糊化数次,取出倒数第三层缩小一半继续进行这个过程,也就是说它是由一组一组的小金字塔组成的。 ![](https://cdn.xyxsw.site/boxcnKJWrCUc5cPOuZg01HqNCsc.png) diff --git a/4.人工智能/4.6.6.1NLP领域任务(研究目标).md b/4.人工智能/4.6.6.1NLP领域任务(研究目标).md index f0516f9..93af65a 100644 --- a/4.人工智能/4.6.6.1NLP领域任务(研究目标).md +++ b/4.人工智能/4.6.6.1NLP领域任务(研究目标).md @@ -2,25 +2,25 @@ 下面给出了 NLP 的四大常见的应用。由于预训练的模型是在连续的文本序列上训练的,所以需要进行一些修改才能将其应用于不同的这些 NLP 任务。 -分类 (text classification): 给一句话或者一段文本,判断一个标签。 +**分类 (text classification):** 给一句话或者一段文本,判断一个标签。 ![](https://cdn.xyxsw.site/PxE3b05ApofzZ1x8u49cirdUnye.png) 图 2:分类 (text classification) -蕴含 (textual entailment): 给一段话,和一个假设,看看前面这段话有没有蕴含后面的假设。 +**蕴含 (textual entailment):** 给一段话,和一个假设,看看前面这段话有没有蕴含后面的假设。 ![](https://cdn.xyxsw.site/OuhabfzABoqxQxxS1n1cPLTinKb.png) 图 3:蕴含 (textual entailment) -相似 (Similarity): 判断两段文字是否相似。 +**相似 (Similarity):** 判断两段文字是否相似。 ![](https://cdn.xyxsw.site/ByeFbxTfToxFlgxh6xmcIKeRnzd.png) 图 4:相似 (Similarity) -多选题 (Multiple Choice): 给个问题,从 N 个答案中选出正确答案。 +**多选题 (Multiple Choice):** 给个问题,从 N 个答案中选出正确答案。 ![](https://cdn.xyxsw.site/ZYgybsj5dol1Ifx96Koc6SRpnmc.jpeg) diff --git a/4.人工智能/4.6.6.2.2.2推荐系统概念解释 and 一个好的推荐系统.md b/4.人工智能/4.6.6.2.2.2推荐系统概念解释 and 一个好的推荐系统.md index d9ce1f9..578951d 100644 --- a/4.人工智能/4.6.6.2.2.2推荐系统概念解释 and 一个好的推荐系统.md +++ b/4.人工智能/4.6.6.2.2.2推荐系统概念解释 and 一个好的推荐系统.md @@ -1,13 +1,13 @@ # 推荐系统概念解释 and 一个好的推荐系统 -- 用户满意度 +- **用户满意度** - 用户满意度是推荐系统测评的重要指标,但是实际上,用户满意度数据获得的方式十分有限,因为这是一种用户的主观情感。 - 设计合适的方式对于用户的满意度进行回收分析,是改进推荐系统的一个很好的方式。这样的的方式包括但不限于,设计合适的调查问卷,在物品的购买结束后附上一份满意度调查。 - 满意度在一些程度上可以细分为更加具体的信息。例如点击率,用户停留时间,转化率,完播率,或者是哔站视频点赞,三连的比例。 -- 预测准确度 +- **预测准确度** - - 召回率(Recall) + - **召回率(Recall)** $$ Recall =\frac{\sum_{u\in U}{\vert R(u)\cap T(u) \vert}}{\sum_{u\in U \vert T(u)\vert}} @@ -19,7 +19,7 @@ - 召回率的意义?可以参考机器学习中留下的定义进行理解 -- 精确率 +- **精确率** $$ Precision =\frac{\sum_{u\in U}{\vert R(u)\cap T(u)\vert}}{\sum_{u\in U}{\vert R(u) \vert}} @@ -31,7 +31,7 @@ - 精确率的意义? -- 覆盖率 +- **覆盖率** - 描述了一个系统对于物品长尾的发掘能力。 - 覆盖率的一个定义可以是: @@ -42,7 +42,7 @@ - 覆盖率的意义:覆盖率越高,以为这系统中被推荐给用户的物品,占所有物品的比例越大,对于一个好的推荐系统,不仅需要有较高的用户满意度,还需要有较高的覆盖率。 - 当然对于覆盖率的定义,不止以上的这一种,甚至说,在实际使用上,上述简单的覆盖率不足以支撑大规模复杂系统的覆盖率计算,所以如何对于覆盖率进行修正和更新?信息熵与基尼系数! - 推荐了解,马太效应,一个强者更强,弱者更弱的效应,在推荐系统中也同样存在。 -- 多样性 +- **多样性** - 假设,$s(i,j)$ 定义了物品 i 和 j 之间的相似度,给用户 $u$ 的推荐列表 $R(u)$的多样性定义: $$ @@ -52,12 +52,12 @@ $$ Diversity = \frac{1}{\vert U\vert}\sum_{u\in U}{Diversity(R(u))} $$ -- 信任度 +- **信任度** - 用户对于该系统的信任程度 -- 实时性 +- **实时性** - 系统对于数据更新的时效性 -- 健壮性 +- **健壮性** - 系统对于外来攻击的防护性 diff --git a/4.人工智能/4.6.6.2.2.7利用上下文信息.md b/4.人工智能/4.6.6.2.2.7利用上下文信息.md index 02f769d..1201571 100644 --- a/4.人工智能/4.6.6.2.2.7利用上下文信息.md +++ b/4.人工智能/4.6.6.2.2.7利用上下文信息.md @@ -12,12 +12,12 @@ - 时间信息对于用户的的影响可以主要分为以下几项: - - 用户的兴趣是变化的 + - **用户的兴趣是变化的** 对于一个用户,其幼年时期和青年时期喜欢的动画片是不一样的;晴天和雨天想要的物品是不一样的;一个人开始工作前和开始工作后的需求也是不同的。 所以应该关注用户的近期行为,确定他的兴趣,最后给予用户推荐。 - - 物品具有生命周期 + - **物品具有生命周期** 流行物品会随着热度持续火爆一段时间,但最终会无人问津;生活必需品无论在什么时候都有稳定的需求量。 - - 季节效应 + - **季节效应** 正如概述中列出的冬衣与夏衣的区别,应该在合适的季节给用户推荐合适的物品。 ### 系统时间特性分析 @@ -25,10 +25,10 @@ - 当系统由之前的静态系统变成随时间变化的时变系统后,需要关注特性也会发生变化,则需要重新观测一些数据,以推断系统的关于时间变化的特性。 下面是一些可以用来观测的数据: - - 确定系统的用户增长数,以判断系统的增长情况或是衰退情况。 - - 物品的平均在线天数,即将满足用户物品互动次数的物品标记为在线,测算物品的平均在线天数以标量物品的生命周期。 - - 系统的时效性,判断相隔一段时间的物品流行度向量的相似度,若是相隔一段时间的相似度仍然较大,说明经过一段时间后,该物品还是被大众喜欢,则说明这件物品具有持久流行性。而对于系统来说,若是系统中大量物品的相似度变化都不大,则说明这个系统是一个推荐热度较持久物品的系统,说明系统的时效性较弱。 - - 系统对于用户的黏着性,统计用户的平均活跃天数,或者计算相隔一段时间的用户活跃度,以此判断系统对于用户的留存力或者说黏着性。 + - **确定系统的用户增长数**,以判断系统的增长情况或是衰退情况。 + - **物品的平均在线天数**,即将满足用户物品互动次数的物品标记为在线,测算物品的平均在线天数以标量物品的生命周期。 + - 系统的时效性,判断**相隔一段时间的物品流行度向量的相似度**,若是相隔一段时间的相似度仍然较大,说明经过一段时间后,该物品还是被大众喜欢,则说明这件物品具有持久流行性。而对于系统来说,若是系统中大量物品的相似度变化都不大,则说明这个系统是一个推荐热度较持久物品的系统,说明系统的时效性较弱。 + - 系统对于用户的黏着性,统计**用户的平均活跃天数**,或者计算**相隔一段时间的用户活跃度**,以此判断系统对于用户的留存力或者说黏着性。 ### 推荐系统的实时性 @@ -45,9 +45,9 @@ 综上,时间多样性会提高用户的满意度,所以如何在确保精度的条件下提高系统的时间多样性呢? - - 需要用户在有新行为时,更新推荐列表 + - **需要用户在有新行为时,更新推荐列表** 传统的离线更新的推荐系统无法满足需求,所以需要使用实时推荐系统。 - - 需要用户在没有新行为的时候,经常变化推荐列表 + - **需要用户在没有新行为的时候,经常变化推荐列表** 通常采取以下三种方法: - 生成推荐列表时加入一定的随机性。 @@ -58,7 +58,7 @@ ### 时间上下文推荐算法 -- 最近最热门 +- **最近最热门** 一种最朴素的思想, 在系统引入了时间信息之后,最简单的非个性化推荐算法就是给用户推荐最近最热门的物品。 给定时间 T,物品 i 在最近的流行度可定义为: @@ -67,10 +67,10 @@ n_i(T)= \sum_{(u,i,t) \in Train ,t时间上下文相关的 itemCF 算法 +- **时间上下文相关的 itemCF 算法** itemCF 算法所依赖的核心部分,在引入时间信息后可以进行进一步更新 - - 物品相似度 利用用户行为,计算物品间的相似度,用户在相隔很短的时间内喜欢的物品通常具有更高的相似度,所以可以在相似度计算公式中引入时间信息,使得相似度计算更加准确。 + - **物品相似度** 利用用户行为,计算物品间的相似度,用户在相隔很短的时间内喜欢的物品通常具有更高的相似度,所以可以在相似度计算公式中引入时间信息,使得相似度计算更加准确。 原本的相似度公式为: $$ @@ -91,7 +91,7 @@ 其中$\alpha$ 是时间衰减参数,它的取值与系统的对于自身定义有关系。收到用户兴趣变化的额外影响。 - - 在线推荐 用户近期行为相比用户很久之前的行为,更能体现用户目前的兴趣,所以在进行预测时,应当加重用户近期行为的权重,但不应该偏离用户长期行为的行为基调。 + - **在线推荐** 用户近期行为相比用户很久之前的行为,更能体现用户目前的兴趣,所以在进行预测时,应当加重用户近期行为的权重,但不应该偏离用户长期行为的行为基调。 原本的用户u对于物品i的兴趣$p(u,i)$ 可通过如下公式计算: $$p(u,i)=\sum_{j\in N(u)}{sim(i,j)}$$ @@ -106,11 +106,11 @@ 在上面的更新后公式中,$t_0$ 表示当前时间,该公式表明,当 $t_{uj}$ 与 $t_0$ 越靠近,和物品j相似的物品就会在用户u的推荐列表中获得更高的排名。其中的$\beta$和上文的 $\alpha$ 是一样的,需要根据系统的情况选择合适的值。 -- 时间上下文相关的userCF算法 +- **时间上下文相关的userCF算法** 与itemCF算法类似,userCF在引入时间信息后也可以进行更新 - - 用户兴趣相似度 用户相似度在引入时间信息后,会将用户相同的逆时序选择相似度降低。简单来说,就是A一月BF1长时间在线,二月BF5长时间在线,而B一月BF5长时间在线,二月BF1长时间在线;C行为信息与A相同。如果不引入时间信息,那么AB的相似度与AC的相似度是一样的,而实际上,AC的相似度会大于AB的相似度。 + - **用户兴趣相似度** 用户相似度在引入时间信息后,会将用户相同的逆时序选择相似度降低。简单来说,就是A一月BF1长时间在线,二月BF5长时间在线,而B一月BF5长时间在线,二月BF1长时间在线;C行为信息与A相同。如果不引入时间信息,那么AB的相似度与AC的相似度是一样的,而实际上,AC的相似度会大于AB的相似度。 userCF的用户uv间相似度的基本公式为: @@ -130,7 +130,7 @@ 同样增加了一个时间衰减因子,用户uv对于i的作用时间差距越大,那么两人的相似度会相应降低。 - - 相似兴趣用户的最近行为 对于用户u来说,存在最近行为与用户u相似的用户v,那么用户v的最近行为,将会比用户u很久之前的行为更具有参考价值。 + - **相似兴趣用户的最近行为** 对于用户u来说,存在最近行为与用户u相似的用户v,那么用户v的最近行为,将会比用户u很久之前的行为更具有参考价值。 userCF中用户u对于物品i兴趣的基础公式为: @@ -146,7 +146,7 @@ p(u,i)=\sum_{v\in S(u,k)}{w_{ui}r_{vi}} \frac{1}{1+\alpha(\vert t_0-t_{vi}\vert)} $$ -- 时间段图模型 +- **时间段图模型** 同样是一个基于图的推荐系统模型,引入时间信息,建立一个二分图时间段图模型: $$ @@ -169,11 +169,11 @@ 在构建了引入时间信息的图结构后,最简单的思想就是利用PersonalRank算法给用进行个性化推荐。但由于其复杂度较高,所以引入路径融合算法。 一般来说,图上两个点的相关度强有以下的特征: - - 两个顶点间有很多路径 + - **两个顶点间有很多路径** - - 两个顶点间路径比较短 + - **两个顶点间路径比较短** - - 两点间不经过出度大的点 ,即不经过与很多其他点相连的节点,在推荐系统思维中等效于不与过热门物品关系紧密。 + - **两点间不经过出度大的点** ,即不经过与很多其他点相连的节点,在推荐系统思维中等效于不与过热门物品关系紧密。 #### 路径融合算法 @@ -199,15 +199,15 @@ ### 地点信息效应 -- 基于用户当前位置的推荐:对于用户当前位置,为其推荐距离更近的餐馆,娱乐场所或消费场所。 +- **基于用户当前位置的推荐**:对于用户当前位置,为其推荐距离更近的餐馆,娱乐场所或消费场所。 -- 基于用户活跃位置的推荐:对于用户长期活跃的区域,降低该区域内物品的权重,提高范围外物品的权重,以提高系统的新鲜度。 +- **基于用户活跃位置的推荐**:对于用户长期活跃的区域,降低该区域内物品的权重,提高范围外物品的权重,以提高系统的新鲜度。 ### 基于位置的推荐算法 - 明尼苏达大学的LARS推荐系统(Location Aware Recommender System,位置感知推荐系统)。 - - 对于数据的预处理 + - **对于数据的预处理** 将物品分为两类:(1)有空间属性的物品,餐馆,商店,旅游景点。(2)没有空间属性的物品,图书电影等。 @@ -223,9 +223,9 @@ (用户,用户位置,物品,物品位置,评分):记录了某个位置的用户,对于某个地点的物品的评分。 - - 研究前两组数据:发现两种特征:(1)兴趣本地化,不同位置的用户存在较大的兴趣差异,不同国家和不同地区的差异。(2)活动本地化,一个用户往往在附近的地区活动。 + - **研究前两组数据**:发现两种特征:(1)兴趣本地化,不同位置的用户存在较大的兴趣差异,不同国家和不同地区的差异。(2)活动本地化,一个用户往往在附近的地区活动。 - - 对于不同数据的处理 + - **对于不同数据的处理** - 第一种数据:LARS的基本思想是,采用树状结构来进行数据集划分。 @@ -236,7 +236,7 @@ (3)LARS通过该节点的行为数据,利用基本推荐算法进行为用户进行推荐。 但是,对于上述过程,若是树的深度较大,则划分到每个节点的用户数据将较少,难以训练出一个令人满意的模型。所以有改进方法如下: - 从根节点出发,利用每个中间节点的数据训练出一个模型,而最终的推荐结果,是这一些列推荐模型所产出的推荐结果的加权结果。这个模型也被称为“金字塔模型”,其中深度是影响这个模型性能的重要参数,选取合适的深度对于该算法十分重要。 + 从根节点出发,利用每个中间节点的数据训练出一个模型,而最终的推荐结果,是这一些列推荐模型所产出的推荐结果的加权结果。这个模型也被称为“**金字塔模型**”,其中**深度**是影响这个模型性能的重要参数,选取合适的深度对于该算法十分重要。 - 第二种数据:对于物品i在用户u推荐列表中的权重公式进行修正 (1)首先忽略物品的位置信息,利用itemCF算法计算用户u对物品i的兴趣。 diff --git a/4.人工智能/4.6.7.1VIT.md b/4.人工智能/4.6.7.1VIT.md index 1203809..24462ff 100644 --- a/4.人工智能/4.6.7.1VIT.md +++ b/4.人工智能/4.6.7.1VIT.md @@ -4,7 +4,7 @@ VIT前Transformer模型被大量应用在NLP自然语言处理当中,而在CV领域,Transformer的注意力机制attention也被广泛应用,比如Se模块,CBAM模块等等注意力模块,这些注意力模块能够帮助提升网络性能。 - 而VIT的工作展示了不需要依赖CNN的结构,也可以在图像分类任务上达到很好的效果。 + 而**VIT的工作展示了不需要依赖CNN的结构,也可以在图像分类任务上达到很好的效果**。 同时VIT也影响了近2年的CV领域,改变了自2012年AlexNet提出以来卷积神经网络在CV领域的绝对统治地位。 @@ -24,7 +24,7 @@ 结构上,VIT 采取的是原始 Transformer 模型,方便开箱即用,即在 encoder-decoder 结构上与 NLP 的 Transform 模型并无差别。 -主要做出的贡献在于数据处理和分类头 +主要做出的贡献在于**数据处理和分类头** ### Patch embedding @@ -38,7 +38,7 @@ > 今天天气不错,我要去看电影 -其中则编码为[0.5,0.6,0.6] +其中**我**则编码为[0.5,0.6,0.6] 而具体来说 Word embedding 分为以下两步 diff --git a/4.人工智能/4.6.7.2BERT.md b/4.人工智能/4.6.7.2BERT.md index 5d3b8e1..836a7dc 100644 --- a/4.人工智能/4.6.7.2BERT.md +++ b/4.人工智能/4.6.7.2BERT.md @@ -6,9 +6,9 @@ # 前言 -BERT 是一种基于 transformer 架构的自然语言处理模型,它把在 cv 领域广为应用的预训练(pre-trainning)微调(fine-tune)的结构成功引入了 NLP 领域。 +BERT 是一种基于 transformer 架构的自然语言处理模型,它把在 cv 领域广为应用的**预训练(pre-trainning)**和**微调(fine-tune)**的结构成功引入了 NLP 领域。 -简单来说,BERT 就是一种认识几乎所有词的训练好的网络,当你要做一些下游任务时,可以在 BERT 预训练模型的基础上进行一些微调,以进行你的任务。也就是 backbone 模型,输出的是文本特征。 +简单来说,BERT 就是一种**认识几乎所有词的**,**训练好**的网络,当你要做一些下游任务时,可以在 BERT 预训练模型的基础上进行一些微调,以进行你的任务。也就是 backbone 模型,输出的是文本特征。 举个例子,我要做一个文本情感分析任务,也就是把文本对情感进行分类,那我只需要在 BERT 的基础上加一个 mlp 作为分类头,在我的小规模数据上进行继续训练即可(也就是微调)。 @@ -24,9 +24,9 @@ mlp 的重点和创新并非它的模型结构,而是它的训练方式,前 在文本被输入模型之前,我们要对它进行一些处理: -1. 词向量(wordpiece embedding):单词本身的向量表示。每个词(或者进行时过去时后缀之类的)会被记录为一个向量。它们被储存在一个字典里,这一步其实就是在字典中查找这个词对应的向量。 -2. 位置向量(position embedding):将单词的位置信息编码成特征向量。构建 position embedding 有两种方法:BERT 是初始化一个 position embedding,然后通过训练将其学出来;而 Transformer 是通过制定规则来构建一个 position embedding。 -3. 句子向量(segment embedding):用于区分两个句子的向量表示。这个在问答等非对称句子中是用于区别的。(这个主要是因为可能会用到对句子的分析中) +1. **词向量**(wordpiece embedding):单词本身的向量表示。每个词(或者进行时过去时后缀之类的)会被记录为一个向量。它们被储存在一个字典里,这一步其实就是在字典中查找这个词对应的向量。 +2. **位置向量**(position embedding):将单词的位置信息编码成特征向量。构建 position embedding 有两种方法:BERT 是初始化一个 position embedding,**然后通过训练将其学出来**;而 Transformer 是通过**制定规则**来构建一个 position embedding。 +3. **句子向量**(segment embedding):用于区分两个句子的向量表示。这个在问答等非对称句子中是用于区别的。(这个主要是因为可能会用到对句子的分析中) BERT 模型的输入就是上面三者的和,如图所示: @@ -34,7 +34,7 @@ BERT 模型的输入就是上面三者的和,如图所示: ## 模型结构 -简单来说,BERT 是 transformer编码器的叠加,也就是下图左边部分。这算一个 block。 +简单来说,BERT 是 transformer**编码器**的叠加,**也就是下图左边部分**。这算一个 block。 ![](https://cdn.xyxsw.site/boxcnPg8594YzCdnX6KZxpEYYod.png) @@ -50,7 +50,7 @@ BERT 训练方式跟 cv 里的很多 backbone 模型一样,是先用几个具 跟以往的 nlp 模型不同,BERT 的掩码并非 transformer 那样,给前面不给后面,而是在句子中随机把单词替换为 mask,让模型去猜,也就是完形填空。下面给个例子: -划掉的单词是被 mask 的 +**划掉的单词是被 mask 的** 正常的掩码:I am a little cat diff --git a/4.人工智能/4.6.7.3MAE.md b/4.人工智能/4.6.7.3MAE.md index 3533bf9..58ee7d3 100644 --- a/4.人工智能/4.6.7.3MAE.md +++ b/4.人工智能/4.6.7.3MAE.md @@ -14,7 +14,7 @@ cv 领域,其实预训练模型早已推广,一般是在 imagenet 上进行 那么问题来了,既然我们要学习 BERT 的随机掩码,那么我们应该对什么做 mask 呢? -因为图片不像文本,有单词这一基础单位。图片的基础单位像素在被单独拿出来的时候包含的语义信息是完全不如单词的。因为像素的语义信息与上下左右的连续关系很密切。于是作者采用了像 VIT 那样把图片分成好几个 patch,对 patch 做随机掩码。 +因为图片不像文本,有单词这一基础单位。图片的基础单位像素在被单独拿出来的时候包含的语义信息是完全不如单词的。因为像素的语义信息与**上下左右的连续关系**很密切。于是作者采用了像 VIT 那样把图片分成好几个 patch,对 patch 做随机掩码。 # 模型结构与训练方式 diff --git a/4.人工智能/4.6.8.1前言.md b/4.人工智能/4.6.8.1前言.md index 20ddac7..790ab9a 100644 --- a/4.人工智能/4.6.8.1前言.md +++ b/4.人工智能/4.6.8.1前言.md @@ -16,7 +16,7 @@ 对比学习,故名思意,是对比着来学习。而我们拿来对比的东西就是在模型眼里的语义,也就是我们叫做特征的向量。 -在具体讲对比之前,我们先看看传统的监督学习是怎么学特征的: +在具体讲对比之前,我们先看看传统的**监督学习**是怎么学特征的: 数据 + 模型=> 特征,特征对人工标注进行学习,也就是说我们要把模型抽取的特征尽可能的靠近人工标注 @@ -26,15 +26,15 @@ ![](https://cdn.xyxsw.site/boxcnJ6HpIJqxJuxiz7Cw5GopSh.png) -我们通过正样本(跟拿到的特征应当相近的另一个特征)与负样本(反之)的对比,使得 +我们通过**正样本**(跟拿到的特征**应当相近**的另一个特征)与**负样本**(反之)的对比,使得 越相近的物体,它们的特征就在超球面上越靠近,越不像的物体离的越远,去学习图片更本质的特征 那么具体的对比学习方法我在后面结合一些论文一起讲吧~ -这部分内容更像一个综述,讲述对比学习这几年的发展路程,所以我会尽可能的描述作者在论文里讲的故事,来方便大家弄清为什么要这么做。 +这部分内容更像一个综述,讲述对比学习这几年的发展路程,所以我会尽可能的描述作者在论文里讲的**故事**,来方便大家弄清为什么要这么做。 -可能会有很多我的主观理解在此,并且不会深入细节。可以算是一个总结和分享,我会在这里带着读者过一遍近期对比学习的工作来给大家一个对比学习方向的直观感性理解。 +**可能会有很多我的主观理解在此**,并且**不会**深入细节。可以算是一个总结和分享,我会在这里带着读者过一遍近期对比学习的工作来给大家一个对比学习方向的直观感性理解。 同时因为笔者水平,视野,精力有限,不可能包含所有的算法,也不可能保证完全正确。因此仅作为笔记分享使用。若有错误,请多多指正。 diff --git a/4.人工智能/4.6.8.2Inst Disc.md b/4.人工智能/4.6.8.2Inst Disc.md index 88ad2c4..5aef0c1 100644 --- a/4.人工智能/4.6.8.2Inst Disc.md +++ b/4.人工智能/4.6.8.2Inst Disc.md @@ -14,7 +14,7 @@ 既然有了上面这个发现,那么作者想我能不能把分类任务推到极致呢? -于是他们把每一个图片当作一个类别,去跟其他的图片做对比,具体模型如下 +于是他们**把每一个图片当作一个类别**,去跟其他的图片做对比,具体模型如下 ![](https://cdn.xyxsw.site/boxcnPNukes2FlNwUFSKiqIJEbd.png) @@ -24,9 +24,9 @@ 2.后面接了一个 Non-param Softmax(非参数 softmax),其实就是一个不被训练的,把所有特征投射到超球面上的一个分类头(把所有特征模长变为 1)。 -3.后面的Memory Bank是这篇文章的重点,它是一个动态字典。我们把每一个图片抽取出来的特征存入 memory bank,每次计算时抽取其中部分作为一个 batch 进行对比学习,把更新后的模型得到的特征替换 memory bank 里原先的特征。 +3.后面的**Memory Bank**是这篇文章的**重点**,它是一个**动态字典**。我们把每一个图片抽取出来的特征存入 memory bank,每次计算时抽取其中部分作为一个 batch 进行对比学习,把更新后的模型得到的特征替换 memory bank 里原先的特征。 -4.具体损失函数用的是一个叫 NCEloss 的损失,它把多分类问题分为若干个二分类问题不是,每个 batch 中只有一个的 ground truth 是’yes‘,其余都是’no‘ +4.具体损失函数用的是一个叫 NCEloss 的损失,它把多分类问题分为**若干个二分类问题**,**是**与**不是**,每个 batch 中只有一个的 ground truth 是’yes‘,其余都是’no‘ 在训练的时候,相当于是有一组以前的编码器抽取的特征 A,B,C,D...,一组当前编码器抽取的特征 a,b,c,d...,对它们进行对比学习。对 a 来说,A 是正样本,其他都是负样本,同理类推。 @@ -38,9 +38,9 @@ 用动量更新的方法去更新 memory bank 中的特征 -也就是让特征的变化不那么剧烈 +也就是让特征的变化**不那么剧烈** -原因:如果一直保持更新,特征总体的变化就会比较大,而我们在大数据集上训练的时候,等第二次调用一个特征时,它跟现在的特征分布已经大相径庭,那就不好训练了,也就是特征缺乏一致性。因此我们引入动量更新来确保特征进行平稳的改变,而非突变。 +原因:如果一直保持更新,**特征总体的变化就会比较大**,而我们在大数据集上训练的时候,等第二次调用一个特征时,它跟现在的特征分布已经大相径庭,那就不好训练了,也就是**特征缺乏一致性**。因此我们引入动量更新来确保特征进行平稳的改变,而非突变。 #### 关于动量的小拓展 @@ -60,4 +60,4 @@ m 表示动量,k 是新的特征,q 是上一个特征,只要设置小的 总体来说,Inst Disc 把对比学习成功引入了 CV 领域,核心思想是构建动态字典进行对比学习 -PS:若无特殊说明,最后保留下来去做下游任务的模型只有编码器,其他都删除了。 +**PS:若无特殊说明,最后保留下来去做下游任务的模型只有编码器,其他都删除了。** diff --git a/4.人工智能/4.6.8.3定义正负样本的方式.md b/4.人工智能/4.6.8.3定义正负样本的方式.md index 04af727..982a2cb 100644 --- a/4.人工智能/4.6.8.3定义正负样本的方式.md +++ b/4.人工智能/4.6.8.3定义正负样本的方式.md @@ -6,9 +6,9 @@ ![](https://cdn.xyxsw.site/boxcnC10uzdj0G0BJPlUZKFIi7C.png) -这是处理音频的一个例子,给模型 t 时刻以前的信息,让它抽取特征并对后文进行预测,真正的后文作为正样本,负样本当然是随便选取就好啦。 +这是处理音频的一个例子,**给模型 t 时刻以前的信息,让它抽取特征并对后文进行预测,真正的后文作为正样本,负样本当然是随便选取就好啦。** -不同于之前说的个体判别,这个是生成式模型,这个模型不止可以处理音频,还可以处理图片(每一个块换成一个词)或者处理图片(以 patch 为单位)。 +不同于之前说的个体判别,这个是**生成式模型**,这个模型不止可以处理音频,还可以处理图片(每一个块换成一个词)或者处理图片(以 patch 为单位)。 是不是有点眼熟?这跟我前面写的 BERT 和 MAE 其实异曲同工,不过这两位是随机 mask,而非时序性的 mask。 diff --git a/4.人工智能/4.6.8.4MoCo.md b/4.人工智能/4.6.8.4MoCo.md index e048089..7dd55ad 100644 --- a/4.人工智能/4.6.8.4MoCo.md +++ b/4.人工智能/4.6.8.4MoCo.md @@ -14,9 +14,9 @@ MoCo 是 Inst Disc 的改进工作,那我们自然要先看一下 Inst Disc ## 3.NCEloss 负样本分类不合理的问题 -NCE 把所有负样本都视作一样的,但实际上负样本并不能被完全归为一类 +NCE 把**所有负样本都视作一样的**,但实际上负样本**并不能被完全归为一类** -举个例子:我现在的正样本是猫猫,然后有两个负样本是狗勾汽车,那猫猫肯定跟狗勾更相近,跟汽车更不相似,也就是说的得分虽然低于,但是一定要高于汽车而不是像 NCE 那样把狗和车打成一类,这样不利于模型学习。 +举个例子:我现在的正样本是**猫猫**,然后有两个负样本是**狗勾**和**汽车**,那**猫猫**肯定跟**狗勾**更相近,跟**汽车**更不相似,也就是说**狗**的得分虽然低于**猫**,但是一定要高于**汽车**,**而不是像 NCE 那样把狗和车打成一类**,这样不利于模型学习。 并且它也不是很灵活,下文细讲 @@ -34,7 +34,7 @@ NCE 把所有负样本都视作一样的,但实际上负样 ## 2.针对动量更新不能完全解决特征一致性差的问题 -作者提出了一个新的动量编码器来替代动量更新。 +作者提出了一个新的**动量编码器**来替代动量更新。 动量编码器是独立于原编码器的一个编码器,它的参数是根据原编码器动量更新的,k 和 q 就是指代全部参数了 @@ -52,9 +52,9 @@ NCE 把所有负样本都视作一样的,但实际上负样 q·k 其实就是各个特征(因为那时候用的都是 transformer 了,这里就是 trnasformer 里的 k 和 q) -这里分母级数上的k 是代表负样本的个数,也就是 k=batchsize-1(总样本-正样本)。其实就是对一个 batch 做 k+1 分类,并且引入了一个超参数 T。它的名字叫做温度参数,控制的是 softmax 后得分分布的平滑程度(直观理解,不是很严谨) +这里分母级数上的**k 是代表负样本的个数,也就是 k=batchsize-1(总样本-正样本)**。其实就是**对一个 batch 做 k+1 分类**,并且引入了一个**超参数 T**。它的名字叫做**温度参数**,控制的是 softmax 后得分分布的平滑程度(直观理解,不是很严谨) -T 越大,损失函数就越对所有负样本一视同仁,退化为二分类的 NCEloss;T 越小,损失函数就越关注一些难分类的特征,但有时候会出现两张其实都是猫猫的图片,你硬要让模型说猫猫跟猫猫不一样,这也不太好,这个参数要根据数据集情况适中调整。 +T 越大,损失函数就越对所有负样本**一视同仁**,退化为二分类的 NCEloss;T 越小,损失函数就**越关注一些难分类的特征**,但有时候会出现两张其实都是猫猫的图片,你硬要让模型说猫猫跟猫猫不一样,这也不太好,这个参数要根据数据集情况适中调整。 ![](https://cdn.xyxsw.site/boxcnhuabU9XzXmVQfu0ruENs83.png) diff --git a/4.人工智能/4.6.8.5SimCLR.md b/4.人工智能/4.6.8.5SimCLR.md index 7721627..b02e225 100644 --- a/4.人工智能/4.6.8.5SimCLR.md +++ b/4.人工智能/4.6.8.5SimCLR.md @@ -8,9 +8,9 @@ x 是输入的图片,它经过两种不同的数据增强得到 xi 和 xj 两 ![](https://cdn.xyxsw.site/boxcnq5TYzSltn6CsPM3Bn3xxAb.png) -左右的f 都是编码器,并且是完全一致共享权重的,可以说是同一个。 +左右的**f 都是编码器**,并且是**完全一致共享权重**的,可以说是同一个。 -而 g 是一层 mlp 结构,只在训练中使用,应用到下游任务时用的仅仅是 f(与前面几篇一样都是 RES50),很神奇的是,就仅仅多了这么一层 mlp,它在 imagenet 上的正确率直接加了十个点。 +而 g 是一层 mlp 结构,只在训练中使用,**应用到下游任务时用的仅仅是 f**(与前面几篇一样都是 RES50),很神奇的是,就仅仅多了这么一层 mlp,它在 imagenet 上的正确率直接加了十个点。 关于这点也很奇怪,作者做了很多实验但是也没有很合理的解释。 diff --git a/4.人工智能/4.6.8.6SwAV.md b/4.人工智能/4.6.8.6SwAV.md index 9d270fe..80fcd8e 100644 --- a/4.人工智能/4.6.8.6SwAV.md +++ b/4.人工智能/4.6.8.6SwAV.md @@ -2,7 +2,7 @@ # 前言 -与前面的一些工作不同,SwAV不再进行个体判别任务,而是提出了新的任务————聚类 +与前面的一些工作不同,SwAV**不再进行个体判别任务**,而是提出了新的任务————**聚类** 并在训练的模型结构上也做了相应改动,而非只调整训练方法。 @@ -26,17 +26,17 @@ ## 聚类中心? -首先我们有个新的东西prototypes,它是聚类中心的集合,也就是许多作为聚类中心的向量构成的矩阵。 +首先我们有个新的东西**prototypes**,它是**聚类中心的集合**,也就是许多作为聚类中心的向量构成的矩阵。 这些聚类中心是我设定在超球面上的,离散的一些点,我希望让不同的特征向它们靠拢以进行区分(也就是所谓聚类)。 -更直白地讲,我在地上撒了一把面包屑,地上本来散乱的蚂蚁会向面包屑聚集,形成一个个小团体。蚂蚁就是不同图像的特征,面包屑就是我设定的聚类中心 +更直白地讲,我在地上撒了一把面包屑,地上本来散乱的蚂蚁会向面包屑聚集,形成一个个**小团体**。蚂蚁就是**不同图像的特征**,面包屑就是**我设定的聚类中心** ## 聚类中心我知道了,然后呢? 先说我拿他干了什么,再一步步讲为什么要这么做吧。 -首先我们手里有抽取出来的特征z1z2,以及一个我随机初始化的聚类中心矩阵 c。我分别求这个矩阵z1z2的内积,并进行一些变换得到 Q1,Q2。当 z1,z2 都是正样本时,我希望Q1 与 z2 相近Q2 与 z1 相近。如果有一个是负样本则尽可能远离。也就是拿 Q 当 ground-truth 做训练。最后这步前面已经讲过 NCEloss 等损失函数了,用它们就可以达成这个任务。 +首先我们手里有抽取出来的特征**z1**,**z2**,以及一个我随机初始化的**聚类中心矩阵 c**。我分别求这个**矩阵**和**z1**,**z2**的内积,并**进行一些变换**得到 Q1,Q2。当 z1,z2 都是正样本时,我希望**Q1 与 z2 相近**,**Q2 与 z1 相近**。如果有一个是负样本则尽可能远离。也就是拿 Q 当 ground-truth 做训练。最后这步前面已经讲过 NCEloss 等损失函数了,用它们就可以达成这个任务。 而我们的优化要采用 [K-means](https://zhuanlan.zhihu.com/p/78798251)(不懂可以看这里)的类似做法,先对聚类中心进行优化,再对特征进行优化。 @@ -46,13 +46,13 @@ so,why?相信你现在肯定是一脸懵,不过别急,希望我能为你 ## 首先是第一步,为什么要求内积? -如果你有好好了解线性代数的几何性质,应当了解两个向量的内积就是一个向量在另一个向量上的投影,而一个向量与一个矩阵的内积,就是把这个向量投影到这个矩阵代表的基空间中。 +如果你有好好了解线性代数的几何性质,应当了解**两个向量的内积就是一个向量在另一个向量上的投影**,而一个向量与一个矩阵的内积,**就是把这个向量投影到这个矩阵代表的基空间中**。 -我做的第一步就是把抽出来的特征 z 用聚类中心的向量表示,这样更加方便对比聚类成功与否。 +我做的第一步就是把**抽出来的特征 z 用聚类中心的向量表示,这样更加方便对比聚类成功与否**。 ## 然后是第二步,我说的变换是什么呢? -我们现在求内积是为了把特征投影到聚类中心空间,为了避免模型训练坍塌(就是网络把特征全部聚到同一个点,开摆~)我要保证每个聚类中心被"使用"的次数,所以我们请出了Sinkhorn-Knopp 算法。这个算法比较硬核,我在这里不展开了,大家知道它是干啥的就行,具体的推导可以看我后面贴的视频,那里面有讲。 +我们现在求内积是为了把特征投影到聚类中心空间,为了避免模型训练坍塌(就是网络把特征全部聚到同一个点,开摆~)我要保证每个聚类中心被**"使用"**的次数,所以我们请出了**Sinkhorn-Knopp 算法。**这个算法比较硬核,我在这里不展开了,大家知道它是干啥的就行,具体的推导可以看我后面贴的视频,那里面有讲。 ## 第三步应该不用怎么讲了吧? @@ -64,7 +64,7 @@ so,why?相信你现在肯定是一脸懵,不过别急,希望我能为你 # 总结 -主要贡献是上面我说的三步聚类算法以及后面的小 trick,Sinkhorn-Knopp 算法难度较高,大家有兴趣的话自行观看后面这个视频理解哈~ +主要贡献是上面我说的三步聚类算法以及后面的小 trick,**Sinkhorn-Knopp 算法难度较高,大家有兴趣的话自行观看后面这个视频理解哈~** # 相关资料 diff --git a/4.人工智能/4.6.8.7BYOL.md b/4.人工智能/4.6.8.7BYOL.md index fbfd220..d8beb84 100644 --- a/4.人工智能/4.6.8.7BYOL.md +++ b/4.人工智能/4.6.8.7BYOL.md @@ -2,25 +2,25 @@ # 前言 -这篇论文的主要特点是它的训练不需要负样本,并且能保证模型不坍塌。 +这篇论文的主要特点是**它的训练不需要负样本**,并且能保证**模型不坍塌**。 -当一个普通的对比学习模型没有负样本时,它的损失函数就只有正样本之间的差距,这样模型只会学到一个捷径解————你给我什么输入我都输出同一个值,这样 loss 就永远=0 了(开摆) +当一个普通的对比学习模型没有负样本时,它的损失函数就**只有正样本之间的差距**,这样模型只会学到一个**捷径解**————你给我什么输入我都输出同一个值,这样 loss 就永远=0 了(~~开摆~~) -而BYOL就解决了这一问题,使得训练不再需要负样本。 +而**BYOL**就解决了这一问题,使得训练不再需要负样本。 # 模型结构 前半部分很普通,跟 SimCLR 是基本一致的,一个图片经过两种不同的数据增强,进入两个编码器,得到两个不同的特征。 -值得一提的是,这里下面的这个粉色的编码器用的是动量编码器的更新方式。也就是说它是紫色那个编码器的动量编码器。 +值得一提的是,这里下面的这个粉色的编码器用的是**动量编码器**的更新方式。也就是说它是紫色那个编码器的动量编码器。 -而提取特征之后,经过两个 `SimCLR` 中提出的额外的 mlp 层 z,在此之后,它们给紫色的那支加了一个新的模块,predictor。 +而提取特征之后,经过两个 `SimCLR` 中提出的额外的 mlp 层 z,在此之后,它们给紫色的那支加了一个新的模块,**predictor**。 -predictor的模型结构就是跟 z 一样的mlp 层。它的任务是通过紫色的特征去预测粉色的特征。也就是说它的代理任务换成了生成式。 +**predictor**的模型结构就是跟 z 一样的**mlp 层**。它的任务是**通过紫色的特征去预测粉色的特征**。也就是说它的代理任务换成了**生成式**。 ![](https://cdn.xyxsw.site/boxcne7eizRhw5GKRSpF40KcMEh.png) -而具体的损失只有预测特征和真实特征的损失,用的是MSEloss。 +而具体的损失只有预测特征和真实特征的损失,用的是**MSEloss**。 下面的粉色分支最后一步是不进行梯度回传的。它的更新完全依赖紫色的那个编码器。 @@ -42,29 +42,29 @@ BN 根据批次的均值和方差进行归一化 推理时,均值、方差是基于所有批次的期望计算所得。 -因此,博客作者认为,虽然我们只用了正样本进行训练,但是这个正样本包含了本批次所有样本的信息(均值,方差),所以实际上并不是真正的无负样本。 +因此,博客作者认为,虽然我们只用了正样本进行训练,但是这个正样本包含了**本批次所有样本的信息**(均值,方差),所以**实际上并不是真正的无负样本。** 而这个 batch 的均值,即平均图片,可以看作 `SawAV` 里的聚类中心,是所有历史样本的聚类中心。(很玄学) ### 作者看到这个博客就急了 -如果真是这样的话,BYOL 就还是没有逃脱出对比学习的范畴,它还是找了一个东西去做对比,其创新性就大大降低了。所以作者赶紧做实验,看看能不能找到 BYOL 模型不坍塌的另外一种解释。最终又写了一篇论文进行回应。 +如果真是这样的话,**BYOL 就还是没有逃脱出对比学习的范畴**,它还是找了一个东西去做对比,其创新性就大大降低了。所以作者赶紧做实验,看看能不能找到 BYOL 模型不坍塌的另外一种解释。最终又写了一篇论文进行回应。   这篇论文叫 BYOL works even without batch statistics,即在没有 BN 的时候 BYOL 照样能工作,详细的消融实验结果如下表所示 : ![](https://cdn.xyxsw.site/boxcncmJWb99mlUUIFTPjGoCqYb.png) -BN 非常关键:只要是 `projector`(SimCLR 提出的 mlp)中没有 BN 的地方,SimCLR 性稍微下降;但是 BYOL 全都模型坍塌了。 +**BN 非常关键**:只要是 `projector`(SimCLR 提出的 mlp)中没有 BN 的地方,SimCLR 性稍微下降;但是 BYOL 全都模型坍塌了。 -有 BN 也会坍塌:作者找到了特例(红色框),即使当 `projector` 有 BN 的时候,BYOL 还是训练失败了 。如果 BN 真的很关键,它真的提供了隐式负样本的对比学习的话,训练就不应该失败 +**有 BN 也会坍塌**:作者找到了特例(红色框),即使当 `projector` 有 BN 的时候,BYOL 还是训练失败了 。如果 BN 真的很关键,它真的提供了隐式负样本的对比学习的话,训练就不应该失败 -完全没有 BN,SimCLR 也坍塌(最后三列的结果。要注意 SimCLR 只有一层 projector)。这表明完全不用归一化,SimCLR 这种使用负样本进行对比学习的方式也无法训练。 +**完全没有 BN,SimCLR 也坍塌**(最后三列的结果。要注意 SimCLR 只有一层 projector)。这表明完全不用归一化,SimCLR 这种使用负样本进行对比学习的方式也无法训练。   最终结论:BN 跟它原来的设计初衷一样,主要作用就是提高模型训练时的稳定性,从而不会导致模型坍塌 。作者进一步延伸,如果一开始就能让模型初始化的比较好,后面的训练即使离开了 BN 也没有问题。 作者为此又设计了一个实验,使用 `group norm`+`weight standardization` (前者也是一种归一化方式,后者是一种卷积权重标准化方式,但都没有对 batch 中的数据进行融合),BYOL 的 top-准确率可以达到 74.1%,和原来精度可以认为是一样了(74.3%)。 -至今其实这个问题也没有一个很合理能服众的解释。 +**至今其实这个问题也没有一个很合理能服众的解释。** # 总结 diff --git a/4.人工智能/4.6.8.8SimSiam.md b/4.人工智能/4.6.8.8SimSiam.md index f9480a1..86b4861 100644 --- a/4.人工智能/4.6.8.8SimSiam.md +++ b/4.人工智能/4.6.8.8SimSiam.md @@ -30,13 +30,13 @@ BYOL 之后,大家都发现对比学习是靠许许多多的小 trick 和技 原论文中提出的解释并不是最完美的。而且这个问题的解释涉及了动力学等知识,我也没有足够的知识储备去讲解这个问题,这里只能讲一些与解答相关的信息,如果有兴趣可以看下面链接中的解释: -这里要涉及到一个机器学习的经典算法,EM 算法,它也是k-means的核心思想之一。 +这里要涉及到一个机器学习的经典算法,**EM 算法**,它也是**k-means**的核心思想之一。 因为本文的主旨原因,我不会在这里细讲这个算法,但是大家了解这是个什么东西即可。 -EM 算法用于优化带有未知参数的模型,`k-means` 的聚类中心就可以看作一个未知参数,我们要同时优化模型本体和聚类中心。所以我们先对其中一个目标 A 做随机初始化,然后先优化另一个目标 B,再反过来用另一个目标 B 优化后的结果优化被随机初始化的目标 A,这就是一次迭代,只要不断循环这个迭代,EM 算法往往能找到最优解。 +**EM 算法**用于优化带有未知参数的模型,`k-means` 的聚类中心就可以看作一个未知参数,我们要同时优化模型本体和聚类中心。所以我们先对其中一个目标 A 做**随机初始化**,然后**先优化**另一个目标 B,再反过来用另一个目标 B 优化后**的结果优化被随机初始化的目标 A**,这就是一次迭代,只要不断循环这个迭代,EM 算法往往能找到最优解。 -这里可以把经过 predictor 预测头的特征作为 `k-means` 里的特征,而另一个作为目标的特征作为聚类中心,经过预测头的特征直接反向传播进行优化,作为目标的特征则是通过上面说的对称的操作经过预测头进行优化。 +这里可以把**经过 predictor 预测头的特征**作为 `k-means` 里的特征,而另一个作为**目标的特征**作为**聚类中心**,经过预测头的特征直接反向传播进行优化,作为目标的特征则是通过上面说的对称的操作经过预测头进行优化。 最最直白地解读结论的话,可以说是,这种先后优化的 EM 算法,使得模型“来不及“去把权重全部更新为 0。(模型坍塌)具体的推导需要动力学的知识,这里不做展开。 @@ -48,9 +48,8 @@ BYOL 之后,大家都发现对比学习是靠许许多多的小 trick 和技 下面是这些网络训练结果的对比,也列出了它们分别有哪些 trick(用的是分类任务) -``` - 负样本 动量编码器 训练轮数 -``` + 负样本 动量编码器 训练轮数 + ![](https://cdn.xyxsw.site/boxcn3uizAKNhAxQryOwvHxFSDb.png) diff --git a/4.人工智能/4.6.8.9MoCo v3.md b/4.人工智能/4.6.8.9MoCo v3.md index e3e0ecc..67ff70b 100644 --- a/4.人工智能/4.6.8.9MoCo v3.md +++ b/4.人工智能/4.6.8.9MoCo v3.md @@ -20,7 +20,7 @@ MoCo v3,它缝合了 MoCo 和 SimSiam,以及新的骨干网络 VIT。 ![](https://cdn.xyxsw.site/boxcnMMhbVk6wc81H8BSoack7Mg.png) -在使用 VIT 训练的时候,batchsize 不算太大时训练很平滑,但是一旦 batchsize 变大,训练的图像就会出现如上图这样的波动。于是作者去查看了每一层的梯度,发现问题出在VIT 的第一层线性变换上。也就是下图中的粉色那个层,把图片打成 patch 后展平做的线性变换。 +在使用 VIT 训练的时候,batchsize 不算太大时训练很平滑,但是一旦 batchsize 变大,训练的图像就会出现如上图这样的**波动**。于是作者去查看了每一层的梯度,发现问题出在**VIT 的第一层线性变换**上。也就是下图中的粉色那个层,**把图片打成 patch 后展平做的线性变换**。 ![](https://cdn.xyxsw.site/boxcniBkiypcv6IQbxr9D6JukOb.png) diff --git a/4.人工智能/4.7图网络略述(intro&GCN).md b/4.人工智能/4.7图网络略述(intro&GCN).md index 795df26..d9c441e 100644 --- a/4.人工智能/4.7图网络略述(intro&GCN).md +++ b/4.人工智能/4.7图网络略述(intro&GCN).md @@ -8,7 +8,7 @@ 在周志华的机器学习一书半监督学习章节中,有对基本的图学习策略进行基本的描述,详见我为了应付课程考试整理的[图半监督学习](http://blog.cyasylum.top/index.php/2020/07/05/%E5%9B%BE%E5%8D%8A%E7%9B%91%E7%9D%A3%E5%AD%A6%E4%B9%A0/)。其基本思路是这样的,通过”样本距离度量“刻画获取样本之间的联系,将样本嵌入到“图”,即样本即其关系的集合中。后通过图将半监督学习中有标记样本的标签对未标记样本进行传递,从而获取未标记样本的属性,进行学习。 -如此,便定下来图网络的基本思路,即通过信息在图上的传递,迭代学习知识。有了这样的基础,我们便可以开始对图网络进行讨论了。 +如此,便定下来图网络的基本思路,即通过*信息在图上的传递*,迭代学习知识。有了这样的基础,我们便可以开始对图网络进行讨论了。 接下来,我们从最基础的部分来讲讲,信息是如何在图上进行传播的。 @@ -55,7 +55,7 @@ $$ 现在,我们可以尝试用$\mathbf{L}$对图进行表示了。 -另外还有个随机游走归一化拉普拉斯矩阵 +另外还有个*随机游走归一化拉普拉斯矩阵* $$ \mathbf{L}^{sym}=\mathbf{D}^{-1}\mathbf{L}=\mathbf{I}-\mathbf{D}^{-1}\mathbf{A} $$ diff --git a/4.人工智能/4.8数据分析.md b/4.人工智能/4.8数据分析.md index 772072c..051972c 100644 --- a/4.人工智能/4.8数据分析.md +++ b/4.人工智能/4.8数据分析.md @@ -54,7 +54,7 @@ author:zzm day 1 End!🤣 -## Day 2 +### Day 2 昨天真是美滋滋的一天,玩了一晚上的你有点头昏脑涨,今天就开始干活好了,反正一周时间呢,比期末复习周可长太多了,就做这么个玩意我还能做不出来吗? @@ -79,7 +79,7 @@ day 1 End!🤣 什么?!刚开始学 python?!woc! 完蛋,你逐渐来到了绝望之谷,唉!明天继续做吧!看来休息不了了。 day 2 End 😔! -## Day 3 +### Day 3 God!No! 昨天已经够累的了,今天老师还要讲课,还要早起!你期待着老师可以降低要求,可是当老师托起长音,讲起了他知道了学生的累,所以今天决定开始讲课了!(现在讲有毛用啊,你明天就要验收我们的进度了!) @@ -117,7 +117,7 @@ God!No! 昨天已经够累的了,今天老师还要讲课,还要早起!你 day 3 end!👿 👹 👺 🤡 -## Day 4 +### Day 4 老师在验收的时候认为你什么工作也没做,他认为一份数据实在是太单薄了,特别是被你疯狂结构优化后的数据已经没几个特征了,让你去做点看得到的东西,不然就要让你不及格了,你的心里很难过,你想到也许你需要一些更好看的东西。数据可视化你在昨天的 pandas 看到过,可是你并没有详细了解,你觉得 pandas 已经在昨天把你狠狠的暴捶一顿了,并且老师想要更好看的图。 @@ -141,7 +141,7 @@ day 3 end!👿 👹 👺 🤡 day 4 end!~🤤 -## Day 5 +### Day 5 你睡得很死,因为你已经你做完了所有的东西,第二天只要美美的验收结束,买了机票就可以回家了,可是老师仍然制止了你,跟你说如果你今晚走了就给你挂科,因为你没有用机器学习来分析他! @@ -169,7 +169,7 @@ day 4 end!~🤤 day 5 end!😍 🥰 😘 -## Day 6 +### Day 6 验收日,老师端坐在底下,宛如一尊大佛,提出了一系列无关紧要的问题,比如问“我们能不能拿这个程序给老年人查资料???” @@ -212,7 +212,7 @@ The End~~~~~~~~~~ ## 补充内容:下个定义 -数据分析是独立于开发和算法岗的另一个方向,它主要是通过应用机器学习和深度学习的已有算法来分析现实问题的一个方向 +数据分析是独立于开发和算法岗的另一个方向,它主要是通过**应用**机器学习和深度学习的**已有算法**来分析现实问题的一个方向 我们常说:数据是客观的,但是解读数据的人是主观的。 diff --git a/4.人工智能/4.9如何做研究.md b/4.人工智能/4.9如何做研究.md index a34f168..fd10e0a 100644 --- a/4.人工智能/4.9如何做研究.md +++ b/4.人工智能/4.9如何做研究.md @@ -11,17 +11,17 @@ Email: yqykrhf@163.com ## 术语的介绍 -Benchmark:评测的基准。通常会是一些公开的数据集。 +**Benchmark:**评测的基准。通常会是一些公开的数据集。 -Baseline: 基准,一般指的是一个现有的工作。 +**Baseline:** 基准,一般指的是一个现有的工作。 -SOTA (state-of-art): 截止目前,指标最好。 +**SOTA **(state-of-art): 截止目前,指标最好。 举个例子: 我们选取 XXX-Net 作为我们的 Baseline,在加入我们设计的注意力机制的模块,在 KITTI 这个 Benchmark 上性能达到了 SOTA。 -Backbone: +**Backbone:** 这个单词原意指的是人的脊梁骨,后来引申为支柱,核心的意思。 @@ -29,13 +29,13 @@ Email: yqykrhf@163.com 所以将这一部分网络结构称为 backbone 十分形象,仿佛是一个人站起来的支柱。 -Solid +**Solid** 一般是描述这个工作非常扎实。 这个工作很 solid。每一步都 make sense(合理)。没有特意为了刷 benchmark 上的指标,用一些 fancy trick(奇技淫巧)。 -Robust +**Robust** 鲁棒性,是描述一个系统受到外界的干扰情况下,仍然能保持较好的性能。 @@ -76,7 +76,7 @@ Step 3. 验证解决方案的有效性。 从上一小节的几个例子当中,其实不同的人做研究所需要完成的工作是完全不一样的。很多时候只需要做 step 3 即可,从功利的角度来讲这是性价比最高的。 -如果我们是一个合格的博士或者我们致力于如此,那么首先的第一步要找到一个好的问题,这是一个非常重要的开始,一个好的问题往往意味着研究已经成功了一半。 什么是一个好的问题?它可能会有以下几个特点: +如果我们是一个合格的博士或者我们致力于如此,那么首先的第一步要找到一个好的问题,这是一个非常重要的开始,**一个好的问题往往意味着研究已经成功了一半。 **什么是一个好的问题?它可能会有以下几个特点: 1. 理论上能实现某种意义上的统一,从而使得问题的描述变得非常优雅。比如 [DepthAwareCNN](https://arxiv.org/abs/1803.06791) 2. 对于之后的工作非常具有启发的作用,甚至达到某种意义的纠偏作用。比如 [OccuSeg](https://arxiv.org/abs/2003.06537) @@ -91,7 +91,7 @@ Step 3. 验证解决方案的有效性。 2. 做加法。举个例子:图片可以做语义分割。那么图片 + 深度图如何更好的做语义分割。图片 + 文字描述的做语义分割。现在的语义分割的标注都是 0,1,2,3 这些数字,然后每一个数字对应一个实际的类别,这个对应表是认为规定的。如果我把 0,1 的对应关系换掉。重新训练以后就,网络的性能是否会影响? 3. 做减法。对于点云的语义分割的标注,通过是非常费时费力的。那么对于点云来说,少量的标注是否是可行的?比如只标注百分之 10 的点。 -以上是一些技巧,把输入调整一下,约束去掉一些,就会有很多新的问题。这个过程通常被叫做“调研” +以上是一些技巧,把输入调整一下,约束去掉一些,就会有很多新的问题。这个过程通常被叫做**“调研”** 这个过程在是一个相对比较痛苦的过程,因为调研的过程中你会发现很多问题,想到很多所谓创新的解决方法,但是实际上你会发现你的解决方法已经有很多人做过了。这一阶段调整心态很重要,切忌急于求成。 @@ -114,9 +114,9 @@ Step 3. 验证解决方案的有效性。 ## 快速出成果的捷径与方法 -如何快速的出成果,不管别人如何帮你,前提是你自己要足够的强。不能存在 “靠别人” 的想法。 +如何快速的出成果,不管别人如何帮你,前提是你自己要足够的强。不能存在 **“靠别人” **的想法。 -对于一个博士生来讲,出成果保毕业,那么可能要对学术的进展要敏感,比如 Nerf 八月份刚出来的时候,如果你非常敏锐的意识到这个工作的基础性和重要性。那么你稍微思考一两个月,总是能有一些创新的 ieda 产生的。所以这个timing 和 senstive就非常重要,当然导师是不是审稿人可能更重要。 +对于一个博士生来讲,出成果保毕业,那么可能要对学术的进展要敏感,比如 Nerf 八月份刚出来的时候,如果你非常敏锐的意识到这个工作的基础性和重要性。那么你稍微思考一两个月,总是能有一些创新的 ieda 产生的。所以这个**timing 和 senstive**就非常重要,当然导师是不是审稿人可能更重要。 对于一个本科生来讲,当然是跟着指导老师的脚步去做。但是如果指导老师只是把你当成一个工具人,一直打杂货的话。你想发论文,一种所谓的捷径是 A+B。就是把一个方法直接拿过来用在另一个地方,大概率这样会有一些问题,那么你就可以针对性的改进,如何针对性的改进?不好的方式是 A+B 套娃,好一些的方式是分析这个不好的原因在哪里,现有的方法多大程度可以帮助解决这个问题,或者现有的方法解决不了这个问题,但是其中的一个模块是否是可以参考的。 diff --git a/4.人工智能/4.人工智能.md b/4.人工智能/4.人工智能.md index 2ebe6d3..0126cb6 100644 --- a/4.人工智能/4.人工智能.md +++ b/4.人工智能/4.人工智能.md @@ -148,7 +148,7 @@ AI 是一个复杂且多样化的研究领域,他能取得如此长远的发 而这些都不会使他停滞 -这是本讲义想做的第三件事,拥有学习新技术,跟上时代的能力** +**这是本讲义想做的第三件事,拥有学习新技术,跟上时代的能力**** 而愿不愿意在这激荡翻腾的年份,贡献出你的力量,让世界变得更好/更坏,就取决于你的选择了! diff --git a/4.人工智能/ch02/ch2.1/ch2.1.1/itemcf.md b/4.人工智能/ch02/ch2.1/ch2.1.1/itemcf.md index 5cda620..f79a8b5 100644 --- a/4.人工智能/ch02/ch2.1/ch2.1.1/itemcf.md +++ b/4.人工智能/ch02/ch2.1/ch2.1.1/itemcf.md @@ -97,7 +97,7 @@ $$ print(similarity_matrix) ``` - ``` + ```python A B C D E A 1.000000 -0.476731 -0.123091 0.532181 0.969458 B -0.476731 1.000000 0.645497 -0.310087 -0.478091 @@ -124,7 +124,7 @@ $$ print(f'与物品{target_item}最相似的{num}个物品为:{sim_items}') ``` - ``` + ```python 与物品E最相似的2个物品为:['A', 'D'] ``` @@ -147,7 +147,7 @@ $$ print(f'用户{target_user}对物品{target_item}的预测评分为:{target_item_pred}') ``` - ``` + ```python 用户 Alice 对物品E的预测评分为:4.6 ``` diff --git a/4.人工智能/ch02/ch2.1/ch2.1.1/usercf.md b/4.人工智能/ch02/ch2.1/ch2.1.1/usercf.md index 68fd0f0..1dad7cc 100644 --- a/4.人工智能/ch02/ch2.1/ch2.1.1/usercf.md +++ b/4.人工智能/ch02/ch2.1/ch2.1.1/usercf.md @@ -234,7 +234,7 @@ UserCF算法的两个步骤: print(similarity_matrix) ``` - ``` + ```python 1 2 3 4 5 1 1.000000 0.852803 0.707107 0.000000 -0.792118 2 0.852803 1.000000 0.467707 0.489956 -0.900149 @@ -253,7 +253,7 @@ UserCF算法的两个步骤: print(f'与用户{target_user}最相似的{num}个用户为:{sim_users}') ``` - ``` + ```python 与用户 Alice 最相似的2个用户为:['user1', 'user2'] ``` @@ -277,7 +277,7 @@ UserCF算法的两个步骤: print(f'用户{target_user}对物品{target_item}的预测评分为:{target_item_pred}') ``` - ``` + ```python 用户 Alice 对物品E的预测评分为:4.871979899370592 ``` diff --git a/5.富有生命的嵌入式/5.1嵌入式是什么?可以吃吗?.md b/5.富有生命的嵌入式/5.1嵌入式是什么?可以吃吗?.md index 7879620..7b64644 100644 --- a/5.富有生命的嵌入式/5.1嵌入式是什么?可以吃吗?.md +++ b/5.富有生命的嵌入式/5.1嵌入式是什么?可以吃吗?.md @@ -1,8 +1,8 @@ # 嵌入式是什么?可以吃吗? -> Author:肖扬 +> Author:肖扬 -# 概念引入与讲解 +## 概念引入与讲解 刚开始接触嵌入式的人,往往会有这样的疑惑:嵌入式到底是什么? @@ -14,7 +14,7 @@ 而我也常常遇到学弟学妹们去向我提问:什么是嵌入式? -我觉得以我通俗的话来讲就是:在硬件设备上写软件代码。虽然这种说法并不是完全准确,但是对于初学者而言暂时性的保持这样的认知,在探索嵌入式的过程中不断完善自己的学习体系,已是极好。 +**我觉得以我通俗的话来讲就是:在硬件设备上写软件代码。**虽然这种说法并不是完全准确,但是对于初学者而言暂时性的保持这样的认知,在探索嵌入式的过程中不断完善自己的学习体系,已是极好。 不如举一个大学里玩嵌入式的常见概念吧:机器人。 @@ -36,17 +36,17 @@ 还有一个我最近关注的一个博主,我喜欢其富有想法的创造力与强大的执行力。 -# 想说的话 +## 想说的话 相信到这里,你对嵌入式或者嵌入式产品已经有了初步的认识。 说相对实在点的东西的话:在大学中,或者在杭州电子科技大学,学了嵌入式的一些基础知识后你可以去参与一些相关的竞赛(全国大学生电子设计竞赛、全国大学生智能车竞赛、全国大学生工程实践与创新能力大赛、Robot Master 机甲大师竞赛等等),也许你已经了解到杭电的环境会让你不断地接触许许多多的竞赛,在竞赛的学习过程中你可以获得一定的能力、获得一定的感悟,也许能获得到一定的荣誉,如果你足够优秀的话可以最后保研上岸,成为别人眼里的佼佼者。 -但是,笔者想说的是: +**但是,笔者想说的是:** 大学不再是像从前那般循规蹈矩,你可以在大学的生活中尝试各种各样的事情,这四年时光本就是一个不断试错的过程。如果你本身对竞赛十分感兴趣,或者说想要通过竞赛让自己之后的路走的更加顺畅,那么我会祝愿你能学有所成,并且最终能获得到自己满意的成绩; -但我更希望你是真正地对嵌入式感兴趣,热爱创造它的时光,热爱披荆斩棘后成功的欣喜,热爱它的生命,热爱它赋予你的意义...在这段学习历程中,竞赛会是你成长的一部分,但不是全部,也不能是全部。作为一个伪理想主义者(我认为完全的理想主义者不会痛苦,只有现实的理想主义者才会痛不欲生),生命中总会有更重要的东西,比如爱,无论是喜爱还是热爱,比如人,无论是亲朋还是蒹葭。 +**但我更希望你是真正地对嵌入式感兴趣,热爱创造它的时光,热爱披荆斩棘后成功的欣喜,热爱它的生命,热爱它赋予你的意义...在这段学习历程中,竞赛会是你成长的一部分,但不是全部,也不能是全部。作为一个伪理想主义者(我认为完全的理想主义者不会痛苦,只有现实的理想主义者才会痛不欲生),生命中总会有更重要的东西,比如爱,无论是喜爱还是热爱,比如人,无论是亲朋还是蒹葭。** 科技的最终意义是提高生产力,但科技带来的意义也远不止于此,我希望你们在接下来学习嵌入式的过程中,能不忘本心,钦佩自己的永远独立,钦佩自己的永远自由,不被世界的功利化所迷惑,感受嵌入式那独特而又真实的生命力! diff --git a/5.富有生命的嵌入式/5.2New meaning of C.md b/5.富有生命的嵌入式/5.2New meaning of C.md index 42117e4..87af6b3 100644 --- a/5.富有生命的嵌入式/5.2New meaning of C.md +++ b/5.富有生命的嵌入式/5.2New meaning of C.md @@ -16,15 +16,15 @@ Intel 的 STC89C51\C52 系列早在上世纪 80 年代就已经广泛运用, 以下是比较推荐的学习路线: -1、购买 51 单片机:[https://m.tb.cn/h.UuGJR5G?tk=kN94dm040JX](https://m.tb.cn/h.UuGJR5G?tk=kN94dm040JX) CZ0001 「普中 51 单片机学习板开发板 stc89c52 单片机实验板 C51 单片机 diy 套件」 +1、购买 51 单片机:[CZ0001「普中 51 单片机学习板开发板 stc89c52 单片机实验板 C51 单片机 diy 套件」](https://m.tb.cn/h.UuGJR5G?tk=kN94dm040JX) -2、推荐学习视频:【51 单片机入门教程-2020 版 程序全程纯手打 从零开始入门】[https://b23.tv/KmaWgUK](https://b23.tv/KmaWgUK) +2、推荐学习视频:[【51 单片机入门教程 -2020 版 程序全程纯手打 从零开始入门】](https://b23.tv/KmaWgUK) 3、相关学习资料: 软件安装包、开发板资料、课件及程序源码百度网盘链接: -[https://pan.baidu.com/s/1vDTN2o8ffvczzNQGfyjHng](https://pan.baidu.com/s/1vDTN2o8ffvczzNQGfyjHng) 提取码:gdzf,链接里压缩包的解压密码:51 ,如果打不开请复制链接到浏览器再打开 +[https://pan.baidu.com/s/1vDTN2o8ffvczzNQGfyjHng](https://pan.baidu.com/s/1vDTN2o8ffvczzNQGfyjHng) 提取码:gdzf,链接里压缩包的解压密码:51,如果打不开请复制链接到浏览器再打开 ### 一些简单的任务 @@ -46,9 +46,9 @@ Intel 的 STC89C51\C52 系列早在上世纪 80 年代就已经广泛运用, 如果我们在图书馆上准备看书,去获取知识,此时我们是 CPU、书则是数据。 -如果我们去图书馆里的书架上拿书并观看,则需要:走到对应书架-拿书(获取数据)-回到书桌,这需要花费相当一部分的时间,此时硬盘相当于书架;如果我们直接拿书桌上的书,则相对速度会快很多,此时书桌相当于主存;如果我们手上就有一本书,那么我们低头就可以看到,手就相当于寄存器。所以,寄存器是 CPU 内部用来存放数据的一些小型的存储区域,用来暂时存放参与运算的数据和运算结果以及一些 CPU 运行所需要的信息。 +如果我们去图书馆里的书架上拿书并观看,则需要:走到对应书架 - 拿书(获取数据)- 回到书桌,这需要花费相当一部分的时间,此时硬盘相当于书架;如果我们直接拿书桌上的书,则相对速度会快很多,此时书桌相当于主存;如果我们手上就有一本书,那么我们低头就可以看到,手就相当于寄存器。所以,寄存器是 CPU 内部用来存放数据的一些小型的存储区域,用来暂时存放参与运算的数据和运算结果以及一些 CPU 运行所需要的信息。 -以我举例而言,可见寄存器获得数据的速度会快于主存与硬盘,而存储数据的大小将会小于主存与硬盘,如果这块不清楚的话也可以去看 也许你会用上的基础知识 中的存储器知识部分。 +以我举例而言,**可见寄存器获得数据的速度会快于主存与硬盘,而存储数据的大小将会小于主存与硬盘**,如果这块不清楚的话也可以去看 也许你会用上的基础知识 中的存储器知识部分。 而从汇编语言的角度来讲(此为 Intel 的汇编语法): @@ -79,7 +79,7 @@ ORG 0BH 以上简单例举了寄存器的一般作用,以汇编语言出发去讲的原因是:它能有效地展现底层代码的工作原理,既不会像机器语言那样只用 0、1 表示的晦涩难懂,又不会像高级语言那般难以直观地看到底层的工作方式。但是,我们做嵌入式入门开发的过程中并不会让你直接去写汇编语言,而是以最基础的 C 语言(相比汇编而言,C 在功能上、结构性、可读性、可维护性上有明显的优势),通过 Keil、IAR 等拥有交叉编译器的 C 语言软件开发系统来完成高级语言、汇编语言、机器语言的转码工作,从而通过 C 语言的编写来控制单片机等嵌入式系统的开发。 -而抽象层面的 C 代码需要通过访问寄存器来直接控制硬件。所以在嵌入式开发的过程中,C 有了特殊的含义:C 里的数字代表的可能只是一个地址或者一个数据,但是在嵌入式开发里,这样一个数字也可以代表着一种寄存器状态。 +而抽象层面的 C 代码需要通过访问寄存器来直接控制硬件。所以在嵌入式开发的过程中,C 有了特殊的含义:**C 里的数字代表的可能只是一个地址或者一个数据,但是在嵌入式开发里,这样一个数字也可以代表着一种寄存器状态。** 下面引入一个 STM32F1 系列的 GPIO 部分寄存器图(来源正点原子提供的 F1 参考手册): @@ -87,7 +87,7 @@ ORG 0BH ![](https://cdn.xyxsw.site/LJ1SbFfv6oUIgtx8CstcbWTNnRg.png) -如果我们想做一个简单的实验-驱动一个 LED 灯(假设此 LED 灯以 PB5 为输出驱动口),在对相应的 RCC 时钟等配置之外,最重要的是对相应的 GPIO 口的配置,首先我们查阅其寄存器的物理起始地址: +如果我们想做一个简单的实验 - 驱动一个 LED 灯(假设此 LED 灯以 PB5 为输出驱动口),在对相应的 RCC 时钟等配置之外,最重要的是对相应的 GPIO 口的配置,首先我们查阅其寄存器的物理起始地址: ![](https://cdn.xyxsw.site/CZ3cbiEhsoWDgJxhwXIcpUkAnMg.png) @@ -99,19 +99,19 @@ ORG 0BH #define PERIPH_BASE ((uint32_t)0x40000000) //外设基址 #define APB1PERIPH_BASE PERIPH_BASE -#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000) //APB2基址 +#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000) //APB2 基址 #define AHBPERIPH_BASE (PERIPH_BASE + 0x20000) #define AFIO_BASE (APB2PERIPH_BASE + 0x0000) #define EXTI_BASE (APB2PERIPH_BASE + 0x0400) #define GPIOA_BASE (APB2PERIPH_BASE + 0x0800) -#define GPIOB_BASE (APB2PERIPH_BASE + 0x0C00)//GPIOB基址,计算可得0x40010C00 +#define GPIOB_BASE (APB2PERIPH_BASE + 0x0C00)//GPIOB 基址,计算可得 0x40010C00 #define GPIOC_BASE (APB2PERIPH_BASE + 0x1000) #define GPIOD_BASE (APB2PERIPH_BASE + 0x1400) #define GPIOE_BASE (APB2PERIPH_BASE + 0x1800) #define GPIOF_BASE (APB2PERIPH_BASE + 0x1C00) #define GPIOG_BASE (APB2PERIPH_BASE + 0x2000) -//APB2还有相关定时器的基址,这里就不再展示 +//APB2 还有相关定时器的基址,这里就不再展示 #define GPIOB ((GPIO_TypeDef *) GPIOB_BASE) ``` @@ -121,11 +121,11 @@ ORG 0BH ```c void LED_Init(void) { - RCC->APB2ENR|=1<<3; //GPIOB的时钟使能,只有使能对应的时钟后GPIO才能正常工作 + RCC->APB2ENR|=1<<3; //GPIOB 的时钟使能,只有使能对应的时钟后 GPIO 才能正常工作 - GPIOB->CRL&=0XFF0FFFFF; //由图可知,CRL的第20-23位控制5口,此举是对第20-23位清零 - GPIOB->CRL|=0X00300000; //此举是对第20-23位赋值0011,根据寄存器功能可知此代表50Mhz推挽输出 - GPIOB->ODR|=1<<5; //设置ODR第5位为1,输出高电平 + GPIOB->CRL&=0XFF0FFFFF; //由图可知,CRL 的第 20-23 位控制 5 口,此举是对第 20-23 位清零 + GPIOB->CRL|=0X00300000; //此举是对第 20-23 位赋值 0011,根据寄存器功能可知此代表 50Mhz 推挽输出 + GPIOB->ODR|=1<<5; //设置 ODR 第 5 位为 1,输出高电平 } ``` @@ -146,9 +146,9 @@ typedef struct 所以由以上提到的例子而言,C 语言可以从如下三方面进行与寄存器之间的控制: -1. 寄存器的地址可以使用指针变量来访问。 -2. C 语言中的结构体可以用于表示寄存器映射。 -3. C 语言中的位域可以用于表示寄存器中的位。 +1. 寄存器的地址可以使用**指针变量**来访问。 +2. C 语言中的**结构体可以用于表示寄存器映射**。 +3. C 语言中的**位域可以用于表示寄存器中的位**。 而且 C 语言中的内联汇编可以用于直接访问寄存器。在某些情况下,如果我们需要直接访问寄存器来完成复杂的硬件控制操作,则可以使用汇编语言指令来直接访问寄存器,从而实现复杂的硬件控制操作。常见的如,堆栈大小的设置等。 diff --git a/5.富有生命的嵌入式/5.3还玩裸机?上操作系统!.md b/5.富有生命的嵌入式/5.3还玩裸机?上操作系统!.md index 3e8d5cf..14e9eff 100644 --- a/5.富有生命的嵌入式/5.3还玩裸机?上操作系统!.md +++ b/5.富有生命的嵌入式/5.3还玩裸机?上操作系统!.md @@ -6,11 +6,11 @@ 而在此栏目中,我们将讲述相关操作系统在嵌入式上的应用,让你的嵌入式产品更加的智慧!(当然裸机并不一定就比带操作系统的嵌入式产品差,只是应用方向不同或者说有时候需要考虑产品的成本问题) -Ps:本栏目只例举几个目前开发工程中常见的操作系统的学习与开发,具体的移植过程可 web 或者自行探索-相信我,出色的移植能力是嵌入式开发者必不可少的。 +Ps:本栏目只例举几个目前开发工程中常见的操作系统的学习与开发,**具体的移植过程可 web 或者自行探索 - 相信我,出色的移植能力是嵌入式开发者必不可少的。** ## RTOS -MCU 本身就能做到一定的实时性,那为什么还是需要 RTOS(实时操作系统)呢,其实评判实时系统的关键并不是系统对外部事件的处理速度,而是处理事件的时间的可预见性和确定性。举个例子,Windows 操作系统在 CPU 没有其他任务时可以在很短的时间内对外部事件作出一定的响应,但是当某些后台任务在运行时,有时候响应速度会变得很慢甚至出现假死现象,这并不是因为 Windows 速度不够快或者效率不够高导致的,而是因为 Windows 对事件的响应不能提供准确性,所以其不能算作一个实时操作系统。并且在笔者看来,实时操作系统除了可以达到完成每次任务所需时间的一致性外,其相应的操作系统产品(例如我们本栏目将重点介绍的 FreeRTOS,这里可以简单提一下为啥要选 FreeRTOS,显而易见因为-Free)还具有可以简化整体架构、开发等工作的作用。 +MCU 本身就能做到一定的实时性,那为什么还是需要 RTOS(实时操作系统)呢,**其实评判实时系统的关键并不是系统对外部事件的处理速度,而是处理事件的时间的可预见性和确定性。**举个例子,Windows 操作系统在 CPU 没有其他任务时可以在很短的时间内对外部事件作出一定的响应,但是当某些后台任务在运行时,有时候响应速度会变得很慢甚至出现假死现象,这并不是因为 Windows 速度不够快或者效率不够高导致的,而是因为 Windows 对事件的响应不能提供准确性,所以其不能算作一个实时操作系统。**并且在笔者看来,实时操作系统除了可以达到完成每次任务所需时间的一致性外,其相应的操作系统产品(例如我们本栏目将重点介绍的 FreeRTOS,这里可以简单提一下为啥要选 FreeRTOS,显而易见因为-Free)还具有可以简化整体架构、开发等工作的作用。** RTOS 中最重要的概念则是“任务”。 @@ -24,7 +24,7 @@ RTOS 中最重要的概念则是“任务”。 ![](https://cdn.xyxsw.site/boxcntQgR61yRboDpyb1bpI10Xp.png) -所以,其实可以这么说:RTOS 将整个流程变成了很多个 while(1)【每个任务都是个 while(1)】。 +所以,**其实可以这么说:RTOS 将整个流程变成了很多个 while(1)【每个任务都是个 while(1)】。** 并且根据我上述所描述的内容,一个任务需要的属性大致如下(以启动函数为例进行介绍): @@ -51,7 +51,6 @@ int main(){ 1、b 站正点原子官方 FreeRTOS 教学(在今年有做全面的更新,比之前讲的更为清晰,难得的优秀入门视频) - 2、FreeRTOS 官网(官网往往是最适合学习的地方)[www.freertos.org](http://www.freertos.org) @@ -64,7 +63,7 @@ int main(){ 如果你已经对以上所涉及到的方面有了一定的了解,那么欢迎来到机器人开发者的殿堂-Robot Operating System! -由于硬件技术的飞速发展,针对于机器人软件设计的框架也面临着极大的挑战,而 ROS 的出现无异是所有机器人开发者的福音,因为如果按照以前的制作一个机器人流程来讲,也许你要经历以下步骤:硬件结构搭建、控制处理、相关算法构建等等,但是 ROS 的开源共享模式令其可以在其平台上巧妙利用别人的开源模型完成自己的机器人搭建,也就是说 Ros 的出现打破了原本各个开发者(或团队)闭门造车的开发现象,使得其可以共享优秀的机器人应用软件,换句话说就是提高了机器人研发的软件复用率。(毕竟哪个团队都不可能同时在建图、导航、视觉等机器人应用方面处于顶尖位置) +由于硬件技术的飞速发展,针对于机器人软件设计的框架也面临着极大的挑战,而 ROS 的出现无异是所有机器人开发者的福音,因为如果按照以前的制作一个机器人流程来讲,也许你要经历以下步骤:硬件结构搭建、控制处理、相关算法构建等等,但是 ROS 的开源共享模式令其可以在其平台上巧妙利用别人的开源模型完成自己的机器人搭建,**也就是说 Ros 的出现打破了原本各个开发者(或团队)闭门造车的开发现象,使得其可以共享优秀的机器人应用软件,换句话说就是提高了机器人研发的软件复用率。(毕竟哪个团队都不可能同时在建图、导航、视觉等机器人应用方面处于顶尖位置)** ![](https://cdn.xyxsw.site/boxcnRy7E27xggqNshXX3cu4J5Q.png) @@ -72,15 +71,15 @@ int main(){ 但是 Linux 只是一个通用系统,并没有在机器人开发上提供相应的中间件,所以 ROS 提供了基于 TCP/UDP 的通信接口(机器人的工作当然需要通讯),在再此之上提供了相应的基础开发库供给至应用层。 -此时应用层则有个很重要的概念-Master(管理者),其负责管理整个系统的正常运行。如果我们需要获得比较成熟的相关领域开源机器人包,按以往的操作必将是进行一次比较复杂的移植(你需要考虑各种因素:比如硬件支持、与其他移植包是否冲突等等)。但是在 ROS 系统中引入了功能包的概念,你可以在 ROS 社区中下载相关版本(与你的 ROS 版本相匹配)的机器人应用功能包,完成一次非常简单的移植过程(CV),你不需要关注其内部的具体运行机制,只需关注接口的定义与使用规则便可进行相应的二次开发(在 ROS 中你需要关注的是相关节点之间的关系,可以通过 rqt_graph 获取清晰的节点图),相当于给你做好了一个跟机器人开发有关的高集成度SDK平台。(当然如果你感兴趣的话可以做一定的了解,但这将牵扯到相关内容的庞大体系,比如如果你想了解自主导航是如何运行的,你首先需要了解 SLAM 算法的运行机制以及激光雷达或者相关深度摄像机的运用,然后你需要了解什么是深度信息什么是里程计信息,为什么可以表示机器人的位置信息,要如何进行一些相关的位置信息修正,然后 bulabula。以笔者自身的学习经历而言,学习相关的理论基础体系,将对你的二次开发有极大的帮助,而不会造成盲目使用接口的情况) +此时应用层则有个很重要的概念-Master(管理者),其负责管理整个系统的正常运行。如果我们需要获得比较成熟的相关领域开源机器人包,按以往的操作必将是进行一次比较复杂的移植(你需要考虑各种因素:比如硬件支持、与其他移植包是否冲突等等)。**但是在 ROS 系统中引入了功能包的概念,你可以在 ROS 社区中下载相关版本(与你的 ROS 版本相匹配)的机器人应用功能包,完成一次非常简单的移植过程(CV),你不需要关注其内部的具体运行机制,只需关注接口的定义与使用规则便可进行相应的二次开发(在 ROS 中你需要关注的是相关节点之间的关系,可以通过 rqt_graph 获取清晰的节点图),相当于给你做好了一个跟机器人开发有关的高集成度****SDK****平台。**(当然如果你感兴趣的话可以做一定的了解,但这将牵扯到相关内容的庞大体系,比如如果你想了解自主导航是如何运行的,你首先需要了解 SLAM 算法的运行机制以及激光雷达或者相关深度摄像机的运用,然后你需要了解什么是深度信息什么是里程计信息,为什么可以表示机器人的位置信息,要如何进行一些相关的位置信息修正,然后 bulabula。**以笔者自身的学习经历而言,学习相关的理论基础体系,将对你的二次开发有极大的帮助,而不会造成盲目使用接口的情况**) -根据以上我讲述的相关内容可知:ROS 系统的优点在于,你能将社区里的有关机器人的开发模块集大成于一身,并且通过 ROS 与控制板通讯(此时类似于 STM32 的裸机主控便变成了控制板-用于接收 ROS 的调控完成相应电机、舵机的控制,或者完成一定的例如 oled 显示的简单任务),从而完成 ROS 系统内部开源算法对整个机器人的控制。 +根据以上我讲述的相关内容可知:**ROS 系统的优点在于,你能将社区里的有关机器人的开发模块集大成于一身,并且通过 ROS 与控制板通讯(此时类似于 STM32 的裸机主控便变成了控制板 - 用于接收 ROS 的调控完成相应电机、舵机的控制,或者完成一定的例如 oled 显示的简单任务),从而完成 ROS 系统内部开源算法对整个机器人的控制。** 以下我简单介绍一下 ROS 的基础通讯方式: 在裸机开发中,我们的通讯(不论是蓝牙、WiFi 还是最基础的串口通讯)本质上都来自于串口中断,也就是说裸机开发引入了 ISR 来处理相应的数据接收。ROS 通讯中同样需要这样的函数来完成对目标数据的处理,而在 ROS 中我们称之为回调函数。 -我们以话题通讯机制来做简要介绍,在此通讯中需要有两个节点,一个 Publisher(发布者)以及一个 Listener(订阅者),他们将发布和订阅同一个来完成相应的通讯-将发布和订阅的内容交给 ROS Master(整体流程类似于 WiFi 中的 mqtt 协议通信,将发布和订阅的内容交给公共服务器,形成一个转接的效果)。 +我们以话题通讯机制来做简要介绍,在此通讯中需要有两个节点,一个 Publisher(发布者)以及一个 Listener(订阅者),他们将发布和订阅同一个来完成相应的通讯 - 将发布和订阅的内容交给 ROS Master(整体流程类似于 WiFi 中的 mqtt 协议通信,将发布和订阅的内容交给公共服务器,形成一个转接的效果)。 所以通过这样的一个流程,具体的代码如下(以 C++ 为例): @@ -92,14 +91,14 @@ int main(int argc, char **argv) ros::init(argc, argv, "talker"); //其次,为了对这个类更好地进行处理,我们需要创建节点句柄 ros::NodeHandle n; - //创建一个Publisher=> pub,发布名为chat的topic,消息类型为std_msgs::String + //创建一个 Publisher=> pub,发布名为 chat 的 topic,消息类型为 std_msgs::String ros::Publisher pub = n.advertise("chat", 1000); - //设置循环的频率,对应着sleep延时 + //设置循环的频率,对应着 sleep 延时 ros::Rate loop_rate(10); while (ros::ok()) { - // 初始化std_msgs::String类型的消息 + // 初始化 std_msgs::String 类型的消息 std_msgs::String msg; /* @@ -125,7 +124,7 @@ int main(int argc, char **argv) //节点与节点句柄是必不可缺的 ros::init(argc, argv, "listener"); ros::NodeHandle n; - // 创建一个Subscriber,订阅名为chatter的topic,注册回调函数chatCallback + // 创建一个 Subscriber,订阅名为 chatter 的 topic,注册回调函数 chatCallback ros::Subscriber sub = n.subscribe("chat", 1000, chatCallback); // 循环等待回调函数 ros::spin(); @@ -133,7 +132,7 @@ int main(int argc, char **argv) } ``` -而其中,在 Listener 中出现了回调函数,其功能类似于裸机中的中断控制-当接收到对应的订阅消息后,进行对应的数据、逻辑处理,例如如果我只是想把接收到的数据打印出来的话,我可以这么写回调函数 chatCallback: +而其中,在 Listener 中出现了回调函数,其功能类似于裸机中的中断控制 - 当接收到对应的订阅消息后,进行对应的数据、逻辑处理,例如如果我只是想把接收到的数据打印出来的话,我可以这么写回调函数 chatCallback: ```cpp void chatterCallback(const std_msgs::String::ConstPtr& msg) @@ -148,7 +147,7 @@ void chatterCallback(const std_msgs::String::ConstPtr& msg) -提一嘴:很多人学 ROS 就学一个开头-比如就学了古月居的 21 讲,就认为自己已经了解到了 ROS 的大部分内容了(不会有人现在还是纯看视频学习吧),实际上这是非常错误的想法。当你学完了视频的内容后,你甚至可能不会移植 wiki 上的功能包(x_x),甚至不知道如何去开发一个真实的机器人(因为此 21 讲只是理论上的讲解,去做一个虚拟机器人在 gazebo 上运行)。ROS 的学习上需要我们花大量的心思去学会接触新的东西,你们并不能只局限于我提供的推荐学习资料,因为相应的功能包不是一成不变的,而且也不是只有那么几个功能包,当你感受了 ROS 的自主建图、自主导航、机械臂控制、机器学习开发等等等等等等后,你才会发现 ROS 的世界是如此美妙! +**提一嘴:很多人学 ROS 就学一个开头 - 比如就学了古月居的 21 讲,就认为自己已经了解到了 ROS 的大部分内容了****(不会有人现在还是纯看视频学习吧)****,实际上这是非常错误的想法。当你学完了视频的内容后,你甚至可能不会移植 wiki 上的功能包(x_x),甚至不知道如何去开发一个真实的机器人(因为此 21 讲只是理论上的讲解,去做一个虚拟机器人在 gazebo 上运行)。ROS 的学习上需要我们花大量的心思去学会接触新的东西,你们并不能只局限于我提供的推荐学习资料,因为相应的功能包不是一成不变的,而且也不是只有那么几个功能包,当你感受了 ROS 的自主建图、自主导航、机械臂控制、机器学习开发等等等等等等后,你才会发现 ROS 的世界是如此美妙!** 2、b 站赵虚左 ROS 课程(讲得细致多了,需要耐心看下去,要是我入门 ROS 的时候有这个视频就好了) diff --git a/5.富有生命的嵌入式/5.富有生命的嵌入式.md b/5.富有生命的嵌入式/5.富有生命的嵌入式.md index 0fd5f17..8607f45 100644 --- a/5.富有生命的嵌入式/5.富有生命的嵌入式.md +++ b/5.富有生命的嵌入式/5.富有生命的嵌入式.md @@ -1,10 +1,10 @@ # 5.富有生命的嵌入式 -Author:肖扬 +> Author:肖扬 -孵化器实验室 2023 招新群(QQ): 879805955 +孵化器实验室 2023 招新群 (QQ): 879805955 -预热 OJ 平台:[OJ 平台(C 语言为主)](http://hdufhq.cn/) +预热 OJ 平台:[OJ 平台 (C 语言为主)](http://hdufhq.cn/) > 实验室不仅有嵌入式方向,还有硬件、网络 web 开发方向! @@ -18,4 +18,4 @@ Author:肖扬 ![](https://cdn.xyxsw.site/boxcn3t2GyLQqe4RpGdRtakcwBc.png) -ps:若对此部分讲义有相关疑问或者建议,欢迎 QQ 联系-1213047454 +ps:若对此部分讲义有相关疑问或者建议,欢迎 QQ 联系 -1213047454 diff --git a/6.计算机安全/6.1.1SQL 注入.md b/6.计算机安全/6.1.1SQL 注入.md index 9a8242d..ef00655 100644 --- a/6.计算机安全/6.1.1SQL 注入.md +++ b/6.计算机安全/6.1.1SQL 注入.md @@ -2,11 +2,11 @@ Author: `Liki4` from Vidar-Team -Vidar-Team 2023 招新 QQ 群: 861507440(仅向校内开放) +Vidar-Team 2023 招新 QQ 群:861507440(仅向校内开放) -Vidar-Team 官网: [https://vidar.club/](https://vidar.club/) +Vidar-Team 官网:[https://vidar.club/](https://vidar.club/) -Vidar-Team 招新报名表: [https://reg.vidar.club/](https://reg.vidar.club/) +Vidar-Team 招新报名表:[https://reg.vidar.club/](https://reg.vidar.club/) 本文中所有涉及的代码全部都托管在 [https://github.com/Liki4/SQLi](https://github.com/Liki4/SQLi) @@ -168,7 +168,7 @@ mysql> select group_concat(id,username separator '_') from users; ![](https://cdn.xyxsw.site/boxcniDohuM3F8FbMqz7YSC0Y5g.png) -真是惊人的壮举!我完全不认识这个叫 Liki5 的家伙,但我居然知道了他的密码对应的哈希值! +**真是惊人的壮举!我完全不认识这个叫 Liki5 的家伙,但我居然知道了他的密码对应的哈希值!** 那么到这里 SQL 注入你就已经完全学会了,接下来做一些小练习吧。 @@ -482,8 +482,6 @@ if __name__ == "__main__": ![](https://cdn.xyxsw.site/boxcnXyMaLh26lkNuAPiQVHuaNg.png) -#### - #### 时间盲注 时间盲注的场景和原理与布尔盲注类似,都是在没有回显查询结果的时候使用的 @@ -782,22 +780,20 @@ INSERT 语句也被成功执行了,向数据库中插入了 Liki3 的数据 在 SQL 注入中,`infromation_schema` 库的作用无非就是可以获取到 `table_schema, table_name, column_name` 这些数据库内的信息。 -#### - -##### MySQL 5.6 的新特性 +#### MySQL 5.6 的新特性 在 MySQL 5.5.x 之后的版本,MySQL 开始将 innoDB 引擎作为 MySQL 的默认引擎,因此从 MySQL 5.6.x 版本开始,MySQL 在数据库中添加了两张表,`innodb_index_stats` 和 `innodb_table_stats`,两张表都会存储数据库和对应的数据表。 因此,从 MySQL 5.6.x 开始,有了取代 `information_schema` 的表名查询方式,如下所示 ```python -select table_name from mysql.innodb_index_stats where database_name=database(); -select table_name from mysql.innodb_table_stats where database_name=database(); +select table_name from mysql.innodb_index_stats where database_name=*database*(); +select table_name from mysql.innodb_table_stats where database_name=*database*(); ``` ![](https://cdn.xyxsw.site/boxcnbMtjAq8osStjcSbFuIdDSc.png) -##### MySQL 5.7 的新特性 +#### MySQL 5.7 的新特性 由于 `performance_schema` 过于发杂,所以 MySQL 在 5.7 版本中新增了 `Sys schema` 视图,基础数据来自于 `performance_chema` 和 `information_schema` 两个库。 @@ -808,8 +804,8 @@ select table_name from mysql.innodb_table_stats where database_name=database 其中就包含了存储数据库和对应的数据表,于是就有了如下的表名查询方式 ```sql -select table_name from sys.schema_table_statistics_with_buffer where table_schema=database(); -select table_name from sys.x$schema_table_statistics_with_buffer where table_schema=database(); +select table_name from sys.schema_table_statistics_with_buffer where table_schema=*database*(); +select table_name from sys.x$schema_table_statistics_with_buffer where table_schema=*database*(); ``` ![](https://cdn.xyxsw.site/boxcnV68mdIQmovJwczDsOc53gc.png) @@ -848,13 +844,13 @@ select table_name from sys.x$schema_table_statistics_with_buffer where table_sch ### Gorm SQL 注入 -# 数据库注入工具 SQLMAP 及其高级使用指南 +## 数据库注入工具 SQLMAP 及其高级使用指南 > 这里不讨论诸如 -u 这种简单参数 -## 一些特殊参数 +### 一些特殊参数 -### -r [文件名] +#### -r [文件名] 当你从 Burp 之类的工具中发现了 数据库注入的痕迹 @@ -866,7 +862,7 @@ select table_name from sys.x$schema_table_statistics_with_buffer where table_sch 对你传入的报文的目标进行自动化的 sql 注入 -### --sql-shell +#### --sql-shell 在摸索到 数据库注入的时候 生成一个交互式的数据库注入 @@ -878,7 +874,7 @@ Sqlmap 会自动探寻目标的注入返回结果 减少手动编写 payload 的 > 尤其是写了半天发现引号对不上等等 -### --os-shell +#### --os-shell 一个新手以为很牛逼但是其实很鸡肋的功能 可以获取 shell 一般是通过数据库注入获取到写文件的权限,写入 webshell 文件 的原理拿到对方机器的 shell @@ -886,13 +882,13 @@ Sqlmap 会自动探寻目标的注入返回结果 减少手动编写 payload 的 因为 默认数据库配置不具有这种问题需要另外配置 此外环境需要支持类似动态执行的功能 例如 go 起的 web -### --random-agent +#### --random-agent 一般不用 但是 sqlmap 在进行 web 的注入时会使用 sqlmap 的 User-Agent 痕迹非常明显 可以用这个消磨一下自己的痕迹 -### --second-url +#### --second-url 对于一些非常复杂的数据库二次注入 sqlmap 其实是没有办法的 例如需要鉴权(?) @@ -900,7 +896,7 @@ Sqlmap 会自动探寻目标的注入返回结果 减少手动编写 payload 的 但是对于简单的一些二次注入,可以通过这个参数获取到存在数据库注入界面的结果界面。让 sqlmap 获取到 数据库注入的结果。 -### --technique +#### --technique 技巧 指定 sqlmap 使用的注入技术 @@ -925,13 +921,13 @@ Sqlmap 很可能在接下来的 数据库注入后利用中使用耗时更为巨 那么通过这个参数去指定对应的注入技巧 可以大大减少数据库注入获取结果的时间 优化你的进攻效率 -### --dbms +#### --dbms 指定对应的数据库类型 Mysql mssql 之类的 sqlmap 就不会去搜索爆破其他类型的数据库 -### --hex +#### --hex 以十六进制来进行注入的技巧 diff --git a/6.计算机安全/6.1Web安全.md b/6.计算机安全/6.1Web安全.md index ab4323b..b4647f4 100644 --- a/6.计算机安全/6.1Web安全.md +++ b/6.计算机安全/6.1Web安全.md @@ -1,87 +1,88 @@ -# Web入门指北 +# Web 入门指北 -> 本文来自HGAME Mini 2022 Web 入门材料,目的是为了帮助新生更好的入门Web安全。 +> 本文来自 HGAME Mini 2022 Web 入门材料,目的是为了帮助新生更好的入门 Web 安全。 ## 0x00 前言 -本文希望为对Web感兴趣的同学提供在入门方向上的指导,以便与更加平滑的入门Web方向的学习。 +本文希望为对 Web 感兴趣的同学提供在入门方向上的指导,以便与更加平滑的入门 Web 方向的学习。 -## 0x01 Web安全基础 +## 0x01 Web 安全基础 -### Web安全是什么 +### Web 安全是什么 -首先Web安全是CTF比赛一直以来都很重要的一部分,CTF比赛目前主体还是Jeopardy解题模式,主要分为Web安全,Re逆向工程,Pwn,Crypto密码学,Misc安全杂项五个方向。相比于Re和Pwn两个二进制方向,Web安全在初期入门时门槛较低,并不需要太多对底层知识的了解,对小白也较为友好,能够比较快速的上手做题。 +首先 Web 安全是 CTF 比赛一直以来都很重要的一部分,CTF 比赛目前主体还是 Jeopardy 解题模式,主要分为 Web 安全,Re 逆向工程,Pwn,Crypto 密码学,Misc 安全杂项五个方向。相比于 Re 和 Pwn 两个二进制方向,Web 安全在初期入门时门槛较低,并不需要太多对底层知识的了解,对小白也较为友好,能够比较快速的上手做题。 -虽然Web安全入门门槛比较低,但是不得不承认需要学习的技术栈很多,在说起你经常听闻的Java、Php、Go、Javascript等种种语言之前,我们先来看看Web应用的发展史,理解一下Web应用是什么。 +虽然 Web 安全入门门槛比较低,但是不得不承认需要学习的技术栈很多,在说起你经常听闻的 Java、Php、Go、Javascript 等种种语言之前,我们先来看看 Web 应用的发展史,理解一下 Web 应用是什么。 -### Web发展史 +### Web 发展史 -> 这段发展史可能有很多名字不太好懂,但是提到这一段发展史是希望你能够对Web技术的发展过程有个框架性的理解,如果有很多困惑的地方可以多多使用搜索引擎,这篇[文章]()写的很详细也可以阅读一下~ +> 这段发展史可能有很多名字不太好懂,但是提到这一段发展史是希望你能够对 Web 技术的发展过程有个框架性的理解,如果有很多困惑的地方可以多多使用搜索引擎,这篇[文章]()写的很详细也可以阅读一下~ -最初的Web应用是静态页面,托管在ISP(Internet Service Provider)上,主要就是比较简单的文字,图片,当时能做的也就是简单浏览网页。而后有了Flash等多媒体技术,网页的功能开始逐渐丰富,音视频和网页的动态交互也让网页开始能够完成更多的事,给用户更好的体验。再随着CGI(Common Gateway Interface)的产生,CGI是Web服务器和外部应用程序的通信接口标准,Web服务器就可以通过CGI执行外部程序,再通过外部程序根据请求内容生成动态内容。再之后随着PHP/JSP等编程语言的加入,MVC思想、REST(Representation State Transformation)架构风格的产生,Web应用开发技术也逐步变化,直到如今,Web应用的开发技术主要分为前端和后端。**简单来说,前端就是用户直接可以看见的部分,比如说我们访问百度,百度页面上面的搜索框、按钮、logo,搜索后展示的网页文字和内容,这些都是属于前端的范畴;而后端主要是用户看不见的部分,比如在百度上搜索Vidar-Team,会能根据搜索内容返回相关的文章,这就是后端所做的部分**。 +最初的 Web 应用是静态页面,托管在 ISP(Internet Service Provider) 上,主要就是比较简单的文字,图片,当时能做的也就是简单浏览网页。而后有了 Flash 等多媒体技术,网页的功能开始逐渐丰富,音视频和网页的动态交互也让网页开始能够完成更多的事,给用户更好的体验。再随着 CGI(Common Gateway Interface) 的产生,CGI 是 Web 服务器和外部应用程序的通信接口标准,Web 服务器就可以通过 CGI 执行外部程序,再通过外部程序根据请求内容生成动态内容。再之后随着 PHP/JSP 等编程语言的加入,MVC 思想、REST(Representation State Transformation) 架构风格的产生,Web 应用开发技术也逐步变化,直到如今,Web 应用的开发技术主要分为前端和后端。**简单来说,前端就是用户直接可以看见的部分,比如说我们访问百度,百度页面上面的搜索框、按钮、logo,搜索后展示的网页文字和内容,这些都是属于前端的范畴;而后端主要是用户看不见的部分,比如在百度上搜索 Vidar-Team,会能根据搜索内容返回相关的文章,这就是后端所做的部分**。 -### Web应用的数据是如何交互的 +### Web 应用的数据是如何交互的 -> 非常推荐查看MDN文章[万维网是如何工作的](https://developer.mozilla.org/zh-CN/docs/Learn/Getting_started_with_the_web/How_the_Web_works)和[浏览器的工作原理](https://developer.mozilla.org/zh-CN/docs/Web/Performance/How_browsers_work)详细了解一下~ +> 非常推荐查看 MDN 文章[万维网是如何工作的](https://developer.mozilla.org/zh-CN/docs/Learn/Getting_started_with_the_web/How_the_Web_works)和[浏览器的工作原理](https://developer.mozilla.org/zh-CN/docs/Web/Performance/How_browsers_work)详细了解一下~ -而Web应用的数据是如何交互的呢?为什么用户输入`https://vidar.club`访问协会官网后浏览器上就会呈现页面呢? +而 Web 应用的数据是如何交互的呢?为什么用户输入`https://vidar.club`访问协会官网后浏览器上就会呈现页面呢? ![What happens when you visit a URL](https://ek1ng.oss-cn-hangzhou.aliyuncs.com/1.png) -当我们在浏览器的地址栏中输入`https://vidar.club`后,首先会做的事情是DNS查询,浏览器会去寻找页面资源的位置,也就是寻找这个域名对应的ip地址是多少。因为ip地址的格式为xxx.xxx.xxx.xxx,这对于一个用户并不容易记住,因此我们用形象的域名来让用户记住网址,你看,`vidar.club`就比`1.117.117.147`这个ip好记太多了吧。浏览器根据域名`vidar.club`向DNS服务器查询对应ip地址,得到响应对应ip地址为`1.117.117.147`。 +当我们在浏览器的地址栏中输入`https://vidar.club`后,首先会做的事情是 DNS 查询,浏览器会去寻找页面资源的位置,也就是寻找这个域名对应的 ip 地址是多少。因为 ip 地址的格式为 xxx.xxx.xxx.xxx,这对于一个用户并不容易记住,因此我们用形象的域名来让用户记住网址,你看,`vidar.club`就比`1.117.117.147`这个 ip 好记太多了吧。浏览器根据域名`vidar.club`向 DNS 服务器查询对应 ip 地址,得到响应对应 ip 地址为`1.117.117.147`。 -而当浏览器知道了服务器的IP地址后,就会与服务器进行TCP三次握手,三次握手机制是用来让两端尝试进行通信,之后为了让链接更加安全,就会进行TLS协商。你看我们输入的是`https://`,这表明我们使用了https协议进行访问,http协议的数据传输是明文的,这并不安全,而https使用ssl/tls协议进行加密处理,这会让访问变得安全。顺带一提如果使用http访问协会官网也会强制使用https哦,可以试一试`http://vidar.club`。当三次握手和TLS协商完成后,我们就已经和服务器建立了安全连接啦。 +而当浏览器知道了服务器的 IP 地址后,就会与服务器进行 TCP 三次握手,三次握手机制是用来让两端尝试进行通信,之后为了让链接更加安全,就会进行 TLS 协商。你看我们输入的是`https://`,这表明我们使用了 https 协议进行访问,http 协议的数据传输是明文的,这并不安全,而 https 使用 ssl/tls 协议进行加密处理,这会让访问变得安全。顺带一提如果使用 http 访问协会官网也会强制使用 https 哦,可以试一试`http://vidar.club`。当三次握手和 TLS 协商完成后,我们就已经和服务器建立了安全连接啦。 -建立安全连接后,浏览器会向服务器发送HTTP Get请求,请求服务器返回我们事先放在服务器上面的对应网页的内容,这个请求的内容通常是一个HTML文件,而当服务器受到请求后,就会使用相关的响应头和HTML的内容进行回复。 +建立安全连接后,浏览器会向服务器发送 HTTP Get 请求,请求服务器返回我们事先放在服务器上面的对应网页的内容,这个请求的内容通常是一个 HTML 文件,而当服务器受到请求后,就会使用相关的响应头和 HTML 的内容进行回复。 -浏览器收到服务端的200 OK的HTTP响应,收到服务端发过来的HTML文件后,会处理HTML标记并且构建DOM树,最终就形成了你看到的页面啦。 +浏览器收到服务端的 200 OK 的 HTTP 响应,收到服务端发过来的 HTML 文件后,会处理 HTML 标记并且构建 DOM 树,最终就形成了你看到的页面啦。 -HTTP请求和响应的具体内容可以使用浏览器(推荐使用Chrome、Firefox或Edge)的F12开发者工具进行查看,打开f12后选择网络并且刷新页面捕获请求,点击这个vidar.club就可以看到啦。 +HTTP 请求和响应的具体内容可以使用浏览器(推荐使用 Chrome、Firefox 或 Edge)的 F12 开发者工具进行查看,打开 f12 后选择网络并且刷新页面捕获请求,点击这个 vidar.club 就可以看到啦。 -![Chrome的开发者工具图1](https://ek1ng.oss-cn-hangzhou.aliyuncs.com/2.png) -![Chrome的开发者工具图1](https://ek1ng.oss-cn-hangzhou.aliyuncs.com/3.png) +![Chrome 的开发者工具图 1](https://ek1ng.oss-cn-hangzhou.aliyuncs.com/2.png) +![Chrome 的开发者工具图 1](https://ek1ng.oss-cn-hangzhou.aliyuncs.com/3.png) -## 0x02 Web安全入门 +## 0x02 Web 安全入门 ### 我是零基础小白,从什么开始好呢? > 万丈高楼平地起 -虽然在Web安全的技术栈中,会比较少的提及C/C++安全的问题,更多的都是一些你经常听说的Java、Php等语言的安全问题,不过如果你目前是没有任何编程基础,协会也同样推荐打好基础,先好好学习C语言。对于没有编程基础的你,从C语言这样一门接近底层的高级语言开始学习可以更好学习计算机内部原理,并且学会C语言后有一定的编程基础,入门其他语言也绝非难事。 +虽然在 Web 安全的技术栈中,会比较少的提及 C/C++安全的问题,更多的都是一些你经常听说的 Java、Php 等语言的安全问题,不过如果你目前是没有任何编程基础,协会也同样推荐打好基础,先好好学习 C 语言。对于没有编程基础的你,从 C 语言这样一门接近底层的高级语言开始学习可以更好学习计算机内部原理,并且学会 C 语言后有一定的编程基础,入门其他语言也绝非难事。 -### Web技术栈 +### Web 技术栈 -首先需要明确的是,Web安全和Web开发是分不开的,并不是说对安全感兴趣就不需要懂开发,恰恰相反,开发是安全的基础,如果没有开发能力,在之后学习中面对一些代码审计也会感觉到非常茫然,所以学习Web安全之前首要的就是先学习Web开发。而Web开发的学习路线在学长们身上大多不是很固定,有的人接触到的Web开发的第一门语言是PHP,PHP虽然在现在看来已经不是一门优秀的语言了,后端开发的主流技术栈已经是Java和Go了,但是PHP仍然是一门在安全学习上非常推荐的语言,有很多历史漏洞可以让大家更好的入门。也有的学长最先开始接触的是Go/Java/Js,那如果你已经有一定Web开发基础,可以直接参考下面的学习路线与学习资料,如果你还没有Web开发基础并且认为C语言已经学的不错了,就可以尝试选择一门自己感兴趣的语言进行学习,并且尝试自己写一些感兴趣的Web应用,比如搭建一个博客,写一个Todolist用来记事等等,兴趣是最好的导师,一边写自己感兴趣的Web应用一边学习是非常不错的。 +首先需要明确的是,Web 安全和 Web 开发是分不开的,并不是说对安全感兴趣就不需要懂开发,恰恰相反,开发是安全的基础,如果没有开发能力,在之后学习中面对一些代码审计也会感觉到非常茫然,所以学习 Web 安全之前首要的就是先学习 Web 开发。而 Web 开发的学习路线在学长们身上大多不是很固定,有的人接触到的 Web 开发的第一门语言是 PHP,PHP 虽然在现在看来已经不是一门优秀的语言了,后端开发的主流技术栈已经是 Java 和 Go 了,但是 PHP 仍然是一门在安全学习上非常推荐的语言,有很多历史漏洞可以让大家更好的入门。也有的学长最先开始接触的是 Go/Java/Js,那如果你已经有一定 Web 开发基础,可以直接参考下面的学习路线与学习资料,如果你还没有 Web 开发基础并且认为 C 语言已经学的不错了,就可以尝试选择一门自己感兴趣的语言进行学习,并且尝试自己写一些感兴趣的 Web 应用,比如搭建一个博客,写一个 Todolist 用来记事等等,兴趣是最好的导师,一边写自己感兴趣的 Web 应用一边学习是非常不错的。 ## 0x03 学习资料与学习路线推荐 -- 兔兔的sql注入小游戏 - 招新群中的迎新机器人具有一个blog功能,这个blog功能存在一个sql注入的漏洞,通过漏洞查询出数据库中的flag可以找管理员兑换一杯奶茶哦~(支线任务x) +- 兔兔的 sql 注入小游戏 + 招新群中的迎新机器人具有一个 blog 功能,这个 blog 功能存在一个 sql 注入的漏洞,通过漏洞查询出数据库中的 flag 可以找管理员兑换一杯奶茶哦~(支线任务 x) - 搭建博客 - 博客可以记录自己的学习过程与经历,也可以当作一个Web应用开发的小练习 + 博客可以记录自己的学习过程与经历,也可以当作一个 Web 应用开发的小练习 - 刷题 - 如果你想一边学习Web开发一边做做题目,感受一下Web安全,可以在协会的招新训练平台上面做做题目,要是毫无头绪也可以问问学长学姐们哦~训练平台上的题目可以帮助你更好的入门CTF! + 如果你想一边学习 Web 开发一边做做题目,感受一下 Web 安全,可以在协会的招新训练平台上面做做题目,要是毫无头绪也可以问问学长学姐们哦~训练平台上的题目可以帮助你更好的入门 CTF! - 学习资料 面对网络各式各样的学习资料,这些网站和书籍会对你入门有所帮助 - - [MDN 网络文档](https://developer.mozilla.org) - - [Web 安全学习笔记](https://websec.readthedocs.io) - - [CTF wiki](https://github.com/ctf-wiki/ctf-wiki) - - [HTML CSS 基础](https://www.w3cschool.cn/) - - JS:《JavaScript DOM编程基础》 - - C:《C Primer Plus》 - - PHP:《PHP和MySQL Web开发》 - - Python: 《Python从入门到实践》的入门部分 - - HTTP:《图解HTTP》 - - 《从0到1:CTFer成长之路》 - - 《白帽子讲Web安全》 - 上面提到的书协会都有哦,欢迎有空的时候来协会看书自习! + - [MDN 网络文档](https://developer.mozilla.org) + - [Web 安全学习笔记](https://websec.readthedocs.io) + - [CTF wiki](https://github.com/ctf-wiki/ctf-wiki) + - [HTML CSS 基础](https://www.w3cschool.cn/) + - JS:《JavaScript DOM 编程基础》 + - C:《C Primer Plus》 + - PHP:《PHP 和 MySQL Web 开发》 + - Python: 《Python 从入门到实践》的入门部分 + - HTTP:《图解 HTTP》 + - 《从 0 到 1:CTFer 成长之路》 + - 《白帽子讲 Web 安全》 + + 上面提到的书协会都有哦,欢迎有空的时候来协会看书自习! - 学习路线 - 可以根据上面提到的学习资料和协会的2022提前批招新标准进行个人学习路线的规划,这份Github上很火的[Web Roadmap](https://github.com/hideraldus13/roadmap-do-desenvolvedor-web)也可以参考一下。 + 可以根据上面提到的学习资料和协会的 2022 提前批招新标准进行个人学习路线的规划,这份 Github 上很火的[Web Roadmap](https://github.com/hideraldus13/roadmap-do-desenvolvedor-web)也可以参考一下。 ## 0x04 最后 > 勿以浮沙筑高台 -欢迎对Web安全感兴趣的你,如果在学习过程中遇到困难可以随时在 Vidar-Team 招新群中提问哦,祝你在Web安全的学习道路上越走越远~ +欢迎对 Web 安全感兴趣的你,如果在学习过程中遇到困难可以随时在 Vidar-Team 招新群中提问哦,祝你在 Web 安全的学习道路上越走越远~ `VIDAR{Web_1s_3asy_t0_st4rt!!}` diff --git a/6.计算机安全/6.2.1基础工具的使用.md b/6.计算机安全/6.2.1基础工具的使用.md index 3b794ea..c43d386 100644 --- a/6.计算机安全/6.2.1基础工具的使用.md +++ b/6.计算机安全/6.2.1基础工具的使用.md @@ -1,55 +1,59 @@ # 基础工具的使用 -IDA pro (交互式反编译器专业版)是二进制安全研究人员必备的反汇编、反编译工具,功能繁多而强大,反编译结果清晰明了。 +IDA pro(交互式反编译器专业版)是二进制安全研究人员必备的反汇编、反编译工具,功能繁多而强大,反编译结果清晰明了。 IDA pro 是收费软件,价格极其昂贵,一套完全版人民币 10W 左右,因此可以到各大网站下载破解版,注意到一些知名网站下载,比如吾爱破解等,防止下载的软件包含病毒。在编写此文时,IDA pro 更新到了 8.3,网上能找到的最新的版本为 7.7。本文由于版权原因,不提供下载链接。 -# 简易使用方法 +## 简易使用方法 > 本文档仅作快速入门,更加细节的内容还请读者查阅其他资料以及多加实践。 > > 另外在任何使用上操作的问题,都可以在群里提问! -## 0x00 IDA 简单介绍 +### 0x00 IDA 简单介绍 ![](https://cdn.xyxsw.site/image-20220809113855166.png) -IDA是一款交互式反汇编和反编译工具,其支持文件类型和文件平台丰富。 +IDA 是一款交互式反汇编和反编译工具,其支持文件类型和文件平台丰富。 可静态分析也可动态调试,可以说是二进制手的吃饭工具了 -## 0x01 启动界面 +### 0x01 启动界面 ![](https://cdn.xyxsw.site/image-20220809114834244.png) -``` -NEW:打开IDA同时弹出对话框选择要打开的文件 -Go:单独打开ida,打开界面将文件拖入 +```txt +NEW:打开 IDA 同时弹出对话框选择要打开的文件 +Go:单独打开 ida,打开界面将文件拖入 Previous,或者下面的列表项:快速打开之前的的文件 ``` -这里选择Go键,打开以后,将文件拖入 +这里选择 Go 键,打开以后,将文件拖入 ![](https://cdn.xyxsw.site/image-20220809124156697.png) ![](https://cdn.xyxsw.site/image-20220809124408179.png) -这里按我们的默认选项点击OK即可 +这里按我们的默认选项点击 OK 即可 -## 0x02 关闭界面 +### 0x02 关闭界面 ![](https://cdn.xyxsw.site/image-20220809125554853.png) -``` +:::tip 第一个选项:就是不打包数据包文件,那么这些数据库文件就会分开这放。 -第二个选项及图中选项:就是把这几个数据库文件打包为1个(如.i64文件),下次打开我们分析的文件的时候,打开这个文件即可。 + +第二个选项及图中选项:就是把这几个数据库文件打包为 1 个 (如.i64 文件),下次打开我们分析的文件的时候,打开这个文件即可。 + 第三个选项:不会删掉数据库文件,而是打包压缩到存储的文件里面去了。 + 下面两个选项 第一个选项:回收垃圾,如果打包文件太大了,可以选用这个选项,清理不必要的内存 -最后一个选项:当分析时候写错了,选中最后一个,最后一次打开的操作不保留了。(解决错误操作) -``` -## 0x03 主界面- IDA View&Pseudocode +最后一个选项:当分析时候写错了,选中最后一个,最后一次打开的操作不保留了。(解决错误操作) +::: + +### 0x03 主界面 - IDA View&Pseudocode 反汇编代码的图表窗口 @@ -59,7 +63,7 @@ Previous,或者下面的列表项:快速打开之前的的文件 ![](https://cdn.xyxsw.site/image-20220809130940294.png) - 按**F5**进行反编译跳转至`Pseudocode`(伪代码)界面 + 按**F5**进行反编译跳转至`Pseudocode`(伪代码) 界面 ![](https://cdn.xyxsw.site/image-20220809131038284.png) @@ -67,25 +71,25 @@ Previous,或者下面的列表项:快速打开之前的的文件 直接点击函数名可以进入到对应函数内部查看函数逻辑 -## 0x04 主界面- Hex View +### 0x04 主界面 - Hex View -十六进制窗口(不太常用) +十六进制窗口 (不太常用) ![](https://cdn.xyxsw.site/image-20220809132027773.png) -## 0x05 主界面-Structures +### 0x05 主界面-Structures 结构体窗口 ![](https://cdn.xyxsw.site/image-20220809132130778.png) -## 0x06 主界面-Enums +### 0x06 主界面-Enums 枚举类型界面 ![](https://cdn.xyxsw.site/image-20220809132242739.png) -## 0x07 主界面-Imports +### 0x07 主界面-Imports 导入表 @@ -93,13 +97,13 @@ Previous,或者下面的列表项:快速打开之前的的文件 ![](https://cdn.xyxsw.site/image-20220809132327043.png) -## 0x08 主界面-Exports +### 0x08 主界面-Exports 导出表 ![](https://cdn.xyxsw.site/image-20220809151050575.png) -## 0x09 主界面-Strings +### 0x09 主界面-Strings 按`Shift+F12`转到`String`界面,该操作会搜索程序中的字符串数据并展示 @@ -109,7 +113,7 @@ Previous,或者下面的列表项:快速打开之前的的文件 ![](https://cdn.xyxsw.site/image-20220809153408536.png) -## 0x0a 其他界面-Functions +### 0x0a 其他界面-Functions 罗列了程序中用到的所有函数,包括底层调用的库的函数 @@ -117,25 +121,23 @@ Previous,或者下面的列表项:快速打开之前的的文件 ![](https://cdn.xyxsw.site/image-20220809151328885.png) -## 0x0b 其他界面-Output +### 0x0b 其他界面-Output 程序的输出信息都会展示在这里 其中包括插件的加载信息、插件/脚本运行时的输出等 -另外还可以直接在下面输入python语句,方便在ida使用过程中简单的数据处理 +另外还可以直接在下面输入 python 语句,方便在 ida 使用过程中简单的数据处理 ![](https://cdn.xyxsw.site/image-20220809151536894.png) -## 0x0c 其他界面-导航栏 +### 0x0c 其他界面 - 导航栏 一个二进制文件包括不同的区块,这里显示程序的不同类型数据,不同的颜色代表二进制文件中不同的块 ![](https://cdn.xyxsw.site/image-20220809151815243.png) - - -## 0x0d 常用快捷键 +### 0x0d 常用快捷键 > 边用边记,多打打就会记住了! > @@ -146,9 +148,9 @@ Previous,或者下面的列表项:快速打开之前的的文件 - `g` 跳转到任意地址 - `Esc` 返回到跳转前的位置 - `n` 定义或修改名称,常用来修改函数和变量的名字 -- `A` 按照ASCII显示数据 +- `A` 按照 ASCII 显示数据 - `D` 分别按字节、字、双字来显示数据 -- `F5`反编译汇编代码,得到C伪代码 +- `F5`反编译汇编代码,得到 C 伪代码 - `Shift+F12` 搜索程序中的字符串 - `Alt+t` 搜索程序中的指令 @@ -156,19 +158,19 @@ Previous,或者下面的列表项:快速打开之前的的文件 - `Y` 修改变量/函数类型 - `F2`快速下断点 -## 0x0e 常用插件 +### 0x0e 常用插件 > 具体安装和使用不在此展开了 - [Find Crypt](https://github.com/polymorf/findcrypt-yara) -- 寻找常用加密算法中的常数(需要安装 [yara-python](https://github.com/VirusTotal/yara-python)) - [Keypatch](https://github.com/keystone-engine/keypatch) -- 基于 Keystone 的 Patch 二进制文件插件 -- [LazyIDA: Make your IDA Lazy! ](https://github.com/P4nda0s/LazyIDA) -- 快速Dump内存数据 +- [LazyIDA: Make your IDA Lazy!](https://github.com/P4nda0s/LazyIDA) -- 快速 Dump 内存数据 - [Finger](https://github.com/aliyunav/Finger) -- 函数签名识别插件 - [D810](https://gitlab.com/eshard/d810) -- 去混淆插件 ## 0x10 IDA Python -IDA 提供可与其交互的IDA Python接口,可以使用Python做很多的辅助操作 +IDA 提供可与其交互的 IDA Python 接口,可以使用 Python 做很多的辅助操作 ![](https://cdn.xyxsw.site/image-20220809154742462.png) @@ -178,36 +180,36 @@ IDA 提供可与其交互的IDA Python接口,可以使用Python做很多的辅 ## 0x11 IDA 动态调试 -> 暂时只对Windows和Linux下的文件调试做介绍,Mac和Android下的文件调试有待读者后续探索 +> 暂时只对 Windows 和 Linux 下的文件调试做介绍,Mac 和 Android 下的文件调试有待读者后续探索 -### 调试Windows下的文件 +### 调试 Windows 下的文件 可以先在汇编代码或伪代码界面下断点,然后`F9`选择调试器,这里直接选`Local Windows Debugger` ![](https://cdn.xyxsw.site/image-20220809160044665.png) -之后就可以用F7(单步不跳过执行)/F8(单步跳过执行)/F9(继续执行,遇到断点停止)进行调试 +之后就可以用 F7(单步不跳过执行)/F8(单步跳过执行)/F9(继续执行,遇到断点停止) 进行调试 ![](https://cdn.xyxsw.site/image-20220809163138453.png) -### 调试Linux下的文件 +### 调试 Linux 下的文件 可以先在汇编代码或伪代码界面下断点 ![](https://cdn.xyxsw.site/image-20220809155352920.png) -由于Linux下文件调试比较特殊,需要远程起一个服务器运行服务端,这里可以使用**Vmware**或者**WSL2(Windows subsystem Linux)**进行调试 +由于 Linux 下文件调试比较特殊,需要远程起一个服务器运行服务端,这里可以使用**Vmware**或者**WSL2(Windows subsystem Linux)**进行调试 -因篇幅有限,在这里直接贴篇链接供大家学习并选择调试方式 +因篇幅有限,在这里直接贴篇链接供大家学习并选择调试方式 -- Vmware 调试 [IDA动态调试ELF](https://bbs.pediy.com/thread-247830.htm) -- WSL 调试 (安装好WSL直接运行ida dbgsrv目录下linux_server文件即可以) +- Vmware 调试 [IDA 动态调试 ELF](https://bbs.kanxue.com/thread-247830.htm) +- WSL 调试(安装好 WSL 直接运行 ida dbgsrv 目录下 linux_server 文件即可以) 后面是一样的调试步骤 ## 0x12 一个简单程序的分析 -#### 源代码 +### 源代码 ```c #include @@ -238,13 +240,13 @@ int main() { #### 分析历程 -##### 将程序拖入IDA +##### 将程序拖入 IDA ![](https://cdn.xyxsw.site/image-20220809173439491.png) ![](https://cdn.xyxsw.site/image-20220809173548998.png) -##### F5分析查看伪代码 +##### F5 分析查看伪代码 ![](https://cdn.xyxsw.site/image-20220809173627488.png) @@ -260,23 +262,23 @@ int main() { ##### 查看函数逻辑 -change函数 +change 函数 ![](https://cdn.xyxsw.site/image-20220809174035800.png) -check函数 +check 函数 ![](https://cdn.xyxsw.site/image-20220809174058831.png) ###### 静态分析逻辑 -change函数是对输入字符串的每一个字节进行修改 +change 函数是对输入字符串的每一个字节进行修改 -然后在check函数进行比较 +然后在 check 函数进行比较 ###### 动态分析逻辑 -在change函数进入前下好断点 +在 change 函数进入前下好断点 随意的进行一些输入 @@ -286,17 +288,16 @@ change函数是对输入字符串的每一个字节进行修改 ![](https://cdn.xyxsw.site/image-20220809174957987.png) -F7进入函数进行单步不跳过调试 +F7 进入函数进行单步不跳过调试 ![](https://cdn.xyxsw.site/image-20220809175413448.png) -遇到类似`strlen`等库函数可以F8单步调试跳过 +遇到类似`strlen`等库函数可以 F8 单步调试跳过 ![](https://cdn.xyxsw.site/image-20220809175459668.png) -可以发现输入字符串的每一个字节的Ascii值都减小了1 +可以发现输入字符串的每一个字节的 Ascii 值都减小了 1 ##### 脚本编写 试试写一个脚本解出这道题吧! - diff --git a/6.计算机安全/6.2.2软件破解、软件加固.md b/6.计算机安全/6.2.2软件破解、软件加固.md index 7ec8ecb..95c3fb7 100644 --- a/6.计算机安全/6.2.2软件破解、软件加固.md +++ b/6.计算机安全/6.2.2软件破解、软件加固.md @@ -24,30 +24,30 @@ upx -1 文件名 upx -d 文件名 ``` -### ESP 定律脱壳法(本节来源于 ctf-wiki:[https://ctf-wiki.org/reverse/windows/unpack/esp/](https://ctf-wiki.org/reverse/windows/unpack/esp/)) +### ESP 定律脱壳法(本节来源于 ctf-wiki:[https://ctf-wiki.org/reverse/platform/windows/unpack/esp/](https://ctf-wiki.org/reverse/platform/windows/unpack/esp/)) -ESP 定律法是脱壳的利器, 是应用频率最高的脱壳方法之一. +ESP 定律法是脱壳的利器,是应用频率最高的脱壳方法之一。 #### 要点 ESP 定律的原理在于利用程序中堆栈平衡来快速找到 OEP. -由于在程序自解密或者自解压过程中, 不少壳会先将当前寄存器状态压栈, 如使用 `pushad`, 在解压结束后, 会将之前的寄存器值出栈, 如使用 `popad`. 因此在寄存器出栈时, 往往程序代码被恢复, 此时硬件断点触发. 然后在程序当前位置, 只需要少许单步操作, 就很容易到达正确的 OEP 位置. +由于在程序自解密或者自解压过程中,不少壳会先将当前寄存器状态压栈,如使用 `pushad`, 在解压结束后,会将之前的寄存器值出栈,如使用 `popad`. 因此在寄存器出栈时,往往程序代码被恢复,此时硬件断点触发。然后在程序当前位置,只需要少许单步操作,就很容易到达正确的 OEP 位置。 1. 程序刚载入开始 pushad/pushfd 2. 将全部寄存器压栈后就设对 ESP 寄存器设硬件断点 -3. 运行程序, 触发断点 +3. 运行程序,触发断点 4. 删除硬件断点开始分析 #### 示例 -示例程序可以点击此处下载: [2_esp.zip](https://github.com/ctf-wiki/ctf-challenges/blob/master/reverse/unpack/2_esp.zip) +示例程序可以点击此处下载:[2_esp.zip](https://github.com/ctf-wiki/ctf-challenges/blob/master/reverse/unpack/2_esp.zip) -还是上一篇的示例, 入口一句 `pushad`, 我们按下 F8 执行 `pushad` 保存寄存器状态, 我们可以在右边的寄存器窗口里发现 `ESP` 寄存器的值变为了红色, 也即值发生了改变. +还是上一篇的示例,入口一句 `pushad`, 我们按下 F8 执行 `pushad` 保存寄存器状态,我们可以在右边的寄存器窗口里发现 `ESP` 寄存器的值变为了红色,也即值发生了改变。 ![](https://cdn.xyxsw.site/boxcnJdWqlHmhlvB471dIGT4GEh.png) -我们鼠标右击 `ESP` 寄存器的值, 也就是图中的 `0019FF64`, 选择 `HW break[ESP]` 后, 按下 `F9` 运行程序, 程序会在触发断点时断下. 如图来到了 `0040D3B0` 的位置. 这里就是上一篇我们单步跟踪时到达的位置, 剩余的就不再赘述. +我们鼠标右击 `ESP` 寄存器的值,也就是图中的 `0019FF64`, 选择 `HW break[ESP]` 后,按下 `F9` 运行程序,程序会在触发断点时断下。如图来到了 `0040D3B0` 的位置。这里就是上一篇我们单步跟踪时到达的位置,剩余的就不再赘述。 ## 软件加密常用算法 diff --git a/6.计算机安全/6.2.3漏洞挖掘、漏洞利用.md b/6.计算机安全/6.2.3漏洞挖掘、漏洞利用.md index 2be07c7..1c1b834 100644 --- a/6.计算机安全/6.2.3漏洞挖掘、漏洞利用.md +++ b/6.计算机安全/6.2.3漏洞挖掘、漏洞利用.md @@ -1,15 +1,22 @@ # 漏洞挖掘、漏洞利用 + ## 常见二进制安全漏洞 + ### 栈溢出 + #### 栈介绍 + 栈是一种典型的后进先出 (Last in First Out) 的数据结构,其操作主要有压栈 (push) 与出栈 (pop) 两种操作,如下图所示(维基百科)。两种操作都操作栈顶,当然,它也有栈底。 ![](https://cdn.xyxsw.site/stack.png) 高级语言在运行时都会被转换为汇编程序,在汇编程序运行过程中,充分利用了栈这一数据结构。每个程序在运行时都有虚拟地址空间,其中某一部分就是该程序对应的栈,用于保存函数调用信息和局部变量。此外,常见的操作也是压栈与出栈。需要注意的是,**程序的栈是从进程地址空间的高地址向低地址增长的**。 + #### 栈溢出基本原理 -以最基本的C语言为例,C语言的函数局部变量就保存在栈中。 -```C + +以最基本的 C 语言为例,C 语言的函数局部变量就保存在栈中。 + +```c #include int main() { @@ -19,14 +26,14 @@ int main() } ``` -对于如上程序,运行后可以发现`ch`和`a`的地址相差不大(`a`和`ch`的顺序不一定固定为`a`在前`ch`在后): +对于如上程序,运行后可以发现`ch`和`a`的地址相差不大 (`a`和`ch`的顺序不一定固定为`a`在前`ch`在后): ![](https://cdn.xyxsw.site/out1.PNG) 可以发现`ch`和`ch2`刚好差`8`个字节,也就是`ch`的长度。 `ch`只有`8`个字节,那么如果我们向`ch`中写入超过`8`个字节的数据呢?很显然,会从`ch`处发生溢出,写入到`ch2`的空间中,覆盖`ch2`的内容。 -```C +```c #include int main() { @@ -42,10 +49,12 @@ int main() 这就是栈溢出的基本原理。 #### 栈溢出的基本利用 + ##### 0x0 + 对于以上程序,“栈溢出”带来的后果仅仅是修改了局部变量的值,会造成一些程序的逻辑错误: -```C +```c #include int main() { @@ -64,15 +73,15 @@ int main() } ``` -如上代码所示,如果我们想办法通过向input中输入过长的字符串覆盖掉password的内容,我们就可以实现任意password“登录”。 +如上代码所示,如果我们想办法通过向 input 中输入过长的字符串覆盖掉 password 的内容,我们就可以实现任意 password“登录”。 那么能不能有一些更劲爆的手段呢? -> 以下内容涉及x86汇编语言知识 +> 以下内容涉及 x86 汇编语言知识 -在C语言编译之后,通常会产生汇编语言,汇编语言的字节码可以直接在物理CPU上运行。而C语言函数调用会被编译为如下形式: +在 C 语言编译之后,通常会产生汇编语言,汇编语言的字节码可以直接在物理 CPU 上运行。而 C 语言函数调用会被编译为如下形式: -```C +```c #include int add(int a,int b) { @@ -86,6 +95,7 @@ int main() return 0; } ``` + ```asm add: endbr64 @@ -133,11 +143,11 @@ retn ![](https://cdn.xyxsw.site/stack2.png) -> 注意该图中,使用32位的寄存器(EBP、ESP、EIP),实际原理一样的,并且上方为高地址,下方为低地址 +> 注意该图中,使用 32 位的寄存器(EBP、ESP、EIP),实际原理一样的,并且上方为高地址,下方为低地址 -在此给出一道题作为例子:https://github.com/ctf-wiki/ctf-challenges/raw/master/pwn/stackoverflow/ret2text/bamboofox-ret2text/ret2text +在此给出一道题作为例子:[ret2tetx](https://github.com/ctf-wiki/ctf-challenges/raw/master/pwn/stackoverflow/ret2text/bamboofox-ret2text/ret2text) -32位的程序,我们使用IDA来打开该题目,查看反编译代码,可以发现有非常明显的栈溢出: +32 位的程序,我们使用 IDA 来打开该题目,查看反编译代码,可以发现有非常明显的栈溢出: ![](https://cdn.xyxsw.site/main.png) @@ -148,7 +158,7 @@ retn ![](https://cdn.xyxsw.site/backdoor.png) -接着计算溢出长度,这里我们使用gdb来调试程序,图中的gdb安装了pwndbg插件,该插件在pwn调试时比较好用: +接着计算溢出长度,这里我们使用 gdb 来调试程序,图中的 gdb 安装了 pwndbg 插件,该插件在 pwn 调试时比较好用: ![](https://cdn.xyxsw.site/gdb.png) @@ -160,7 +170,7 @@ retn from pwn import * sh=process("./pwn") exp=b'a'*(0x6c+4) -exp+=p32(0x0804863A) # 4字节的返回地址 +exp+=p32(0x0804863A) # 4 字节的返回地址 sh.sendline(exp) sh.interactive() # 切换为手动交互模式 ``` @@ -168,37 +178,42 @@ sh.interactive() # 切换为手动交互模式 ![](https://cdn.xyxsw.site/shell.png) ##### 0x1 -通过上面的学习,我们已经可以知道执行任意函数的办法,但很多情况下,对于攻击者来说,程序中并没有可用的后门函数来达到攻击的目的,因此我们需要一种手段,来让程序执行任意代码(任意汇编代码),这样就可以最高效地进行攻击。ROP(Return Oriented Programming)面向返回编程就是这样的一种技术,在栈溢出的基础上,通过在程序中寻找以retn结尾的小片段(gadgets),来改变某些寄存器、栈变量等的值,再结合Linux下的系统调用,我们就可以执行需要的任意代码。 -ROP网上已有非常系统的资料,在这里不做过多的叙述,可参考ctf-wiki: https://ctf-wiki.org/pwn/linux/user-mode/stackoverflow/x86/basic-rop/#ret2shellcode +通过上面的学习,我们已经可以知道执行任意函数的办法,但很多情况下,对于攻击者来说,程序中并没有可用的后门函数来达到攻击的目的,因此我们需要一种手段,来让程序执行任意代码(任意汇编代码),这样就可以最高效地进行攻击。ROP(Return Oriented Programming)面向返回编程就是这样的一种技术,在栈溢出的基础上,通过在程序中寻找以 retn 结尾的小片段(gadgets),来改变某些寄存器、栈变量等的值,再结合 Linux 下的系统调用,我们就可以执行需要的任意代码。 + +ROP 网上已有非常系统的资料,在这里不做过多的叙述,可参考 ctf-wiki: [ret2shellcode](https://ctf-wiki.org/pwn/linux/user-mode/stackoverflow/x86/basic-rop/#ret2shellcode) ### 格式化字符串 -格式化字符串的利用思路来源于`printf`函数中的`%n`format标签,该标签的作用和`%s`、`%d`等不同,是将已打印的字符串的长度返回到该标签对应的变量中。在正常情况下的使用不会出现什么问题: -```C +格式化字符串的利用思路来源于`printf`函数中的`%n`format 标签,该标签的作用和`%s`、`%d`等不同,是将已打印的字符串的长度返回到该标签对应的变量中。在正常情况下的使用不会出现什么问题: + +```c printf("abcd%n",&num); //输出abcd,并且num的值为4 ``` -但如果在编写代码时忘记format字符串: +但如果在编写代码时忘记 format 字符串: -```C +```c printf(something_want_print); ``` 此时若攻击者可以自定义该字符串,就可以使用`%d`、`%p`、`%s`等打印栈上数据,或者`%n`来覆写栈上的数据,如果覆写了返回地址,就可以实现任意代码执行。 -```C +```c char ch[20]; scanf("%s",ch);// 输入 %d%n%n%n%n%n printf(ch); ``` ## 漏洞挖掘技术 -### 代码审计 -代码审计分人工代码审计和自动化代码审计,人工审计由安全研究人员查看代码来发现漏洞,需要安全研究人员很高的研究经验,投入大量的人力。自动化代码审计目前的发展进度迅速,如由 Vidar-Team 毕业学长 LoRexxar 主导的开源项目Kunlun-M:https://github.com/LoRexxar/Kunlun-M -以及字节跳动公司开源的appshark:https://github.com/bytedance/appshark +### 代码审计 + +代码审计分人工代码审计和自动化代码审计,人工审计由安全研究人员查看代码来发现漏洞,需要安全研究人员很高的研究经验,投入大量的人力。自动化代码审计目前的发展进度迅速,如由 Vidar-Team 毕业学长 LoRexxar 主导的开源项目 [Kunlun-M](https://github.com/LoRexxar/Kunlun-M) + +以及字节跳动公司开源的 [appshark](https://github.com/bytedance/appshark) ### fuzz -fuzz是一种自动化测试手段,通过一定的算法生成一定规律的随机的数据输入到程序中,如果程序发生崩溃等异常,即可知道此处可能有漏洞。比较著名的有[AFL](https://github.com/google/AFL)、[AFLplusplus](https://github.com/AFLplusplus/AFLplusplus)、[libfuzzer](https://llvm.org/docs/LibFuzzer.html)、[honggfuzz](https://github.com/google/honggfuzz)等。 + +fuzz 是一种自动化测试手段,通过一定的算法生成一定规律的随机的数据输入到程序中,如果程序发生崩溃等异常,即可知道此处可能有漏洞。比较著名的有[AFL](https://github.com/google/AFL)、[AFLplusplus](https://github.com/AFLplusplus/AFLplusplus)、[libfuzzer](https://llvm.org/docs/LibFuzzer.html)、[honggfuzz](https://github.com/google/honggfuzz)等。 diff --git a/6.计算机安全/6.2二进制安全.md b/6.计算机安全/6.2二进制安全.md index ccc2f81..2a38468 100644 --- a/6.计算机安全/6.2二进制安全.md +++ b/6.计算机安全/6.2二进制安全.md @@ -11,9 +11,12 @@ reverse 主要研究软件破解,软件加固,计算机病毒等。 现实场景下,这两种方向通常界限比较模糊,统称的二进制安全主要研究漏洞挖掘,漏洞利用,软件加固,计算机病毒,游戏安全等。 ## 入门材料 + > HGAME Mini 2022 Reverse Pwn 入门材料 -> Reverse:https://www.notion.so/b92ca2bfaacf4e7c873882dff9dbf649 -> Pwn:[PWN入门指北](https://ek1ng.oss-cn-hangzhou.aliyuncs.com/HGAME%20Mini%202022%20Pwn%E5%85%A5%E9%97%A8%E6%8C%87%E5%8C%97.pdf) +> +> Reverse:[逆向入门指南](https://www.notion.so/b92ca2bfaacf4e7c873882dff9dbf649) +> +> Pwn:[PWN 入门指北](https://ek1ng.oss-cn-hangzhou.aliyuncs.com/HGAME%20Mini%202022%20Pwn%E5%85%A5%E9%97%A8%E6%8C%87%E5%8C%97.pdf) ## 学习二进制安全需要具备哪些基础? diff --git a/6.计算机安全/6.3密码学.md b/6.计算机安全/6.3密码学.md index 92cd764..886f6c8 100644 --- a/6.计算机安全/6.3密码学.md +++ b/6.计算机安全/6.3密码学.md @@ -1,8 +1,8 @@ -## 什么是密码学 +# 什么是密码学 -> 本文来自HGAME Mini 2022 Crypto 入门材料。 +> 本文来自 HGAME Mini 2022 Crypto 入门材料。 -密码学分为密码编码学和密码分析学,前者寻求**提供信息机密性、完整性和非否认性等的方法**,后者研究**加密信息的破译和伪造等破坏密码技术所能提供安全性**的方法。CTF比赛中的密码学题目偏向于密码分析。 +密码学分为密码编码学和密码分析学,前者寻求**提供信息机密性、完整性和非否认性等的方法**,后者研究**加密信息的破译和伪造等破坏密码技术所能提供安全性**的方法。CTF 比赛中的密码学题目偏向于密码分析。 ## 如何学习密码学 @@ -16,7 +16,7 @@ ### 编程基础 -你可能需要了解一些python的基础语法。还有一些简单的算法。 +你可能需要了解一些 python 的基础语法。还有一些简单的算法。 ### 一些基础的密码系统 @@ -40,15 +40,15 @@ 还有近几年多起来的格密码 -主要看一些书籍,或者在ctf-wiki.org学习。学习的过程中尽可能的多写一些demo,既锻炼了编程能力也可以更好的了解一些密码系统。 +主要看一些书籍,或者在 ctf-wiki.org 学习。学习的过程中尽可能的多写一些 demo,既锻炼了编程能力也可以更好的了解一些密码系统。 有能力的同学可以先看一下这位教授的关于密码学的课程 [https://m.youtube.com/channel/UC1usFRN4LCMcfIV7UjHNuQg](https://m.youtube.com/channel/UC1usFRN4LCMcfIV7UjHNuQg) ## 工具 -一些python的库: +一些 python 的库: -- pycryptodome(就是Crypto库) +- pycryptodome(就是 Crypto 库) [https://pycryptodome.readthedocs.io/en/latest/](https://pycryptodome.readthedocs.io/en/latest/) diff --git a/6.计算机安全/6.4安全杂项.md b/6.计算机安全/6.4安全杂项.md index 311c511..70cc394 100644 --- a/6.计算机安全/6.4安全杂项.md +++ b/6.计算机安全/6.4安全杂项.md @@ -1,12 +1,12 @@ -# MISC入门指南 +# MISC 入门指南 -> 本文来自HGAME Mini 2022 Misc 入门材料 +> 本文来自 HGAME Mini 2022 Misc 入门材料 -## MISC简单介绍 +## MISC 简单介绍 -Misc 是 Miscellaneous 的缩写,杂项、混合体、大杂烩的意思,它是一个庞大而又有趣的分支,几乎会涉及所有分类的基础,包括内容安全、安全运维、网络编程、AI安全等不属于传统分类的知识,作为发散思维、拓展自己的一个知识面而言也是挺不错的方向。 +Misc 是 Miscellaneous 的缩写,杂项、混合体、大杂烩的意思,它是一个庞大而又有趣的分支,几乎会涉及所有分类的基础,包括内容安全、安全运维、网络编程、AI 安全等不属于传统分类的知识,作为发散思维、拓展自己的一个知识面而言也是挺不错的方向。 -**MISC大概有这些方面内容**: +**MISC 大概有这些方面内容**: - 信息收集 - 编码转换 @@ -25,7 +25,7 @@ Misc 是 Miscellaneous 的缩写,杂项、混合体、大杂烩的意思,它 简单一句话:多问搜索引擎,搜就完事了! - 目标 Web 网页、地理位置、相关组织 -- Google 基本搜索与挖掘技巧 (Google hacking) +- Google 基本搜索与挖掘技巧(Google hacking) - 网站、域名、IP:whois 等 - 通过搜索引擎查找特定安全漏洞或私密信息 - 组织结构和人员、个人资料、电话、电子邮件 @@ -44,15 +44,15 @@ Misc 是 Miscellaneous 的缩写,杂项、混合体、大杂烩的意思,它 - 计算机常用编码 - Ascii - Unicode - - HTML实体编码 + - HTML 实体编码 - 其他编码 - 二维码 - 条形码 - Js加密/Jother/JSFuck - - URL编码 - - Hex编码 - - Base大家族 - - MD5、SHA1等类似加密型 + - URL 编码 + - Hex 编码 + - Base 大家族 + - MD5、SHA1 等类似加密型 - 与佛论禅 - 兽音译者 - ... @@ -60,18 +60,18 @@ Misc 是 Miscellaneous 的缩写,杂项、混合体、大杂烩的意思,它 ### 隐写 - 图片隐写 - - jpg隐写 + - jpg 隐写 - Steghide - Stegdetect - Slienteye - Jhps - - png隐写 + - png 隐写 - Stepsolve - Stepic - - gif隐写 + - gif 隐写 - 时间 - 空间 - - bmp隐写 + - bmp 隐写 - LSB - 音频隐写 - 频谱 @@ -102,7 +102,6 @@ Misc 是 Miscellaneous 的缩写,杂项、混合体、大杂烩的意思,它 - Vmdk - dsfok-tools - ### 取证 - 图片取证 @@ -119,7 +118,7 @@ Misc 是 Miscellaneous 的缩写,杂项、混合体、大杂烩的意思,它 - Wireshark - Tshark - Pacpfix -- 内存取证 +- 内存取证 - Vol - 磁盘文件取证 - Ftx @@ -139,8 +138,4 @@ Misc 是 Miscellaneous 的缩写,杂项、混合体、大杂烩的意思,它 - binwalk - sleuthkit - - - - `VIDAR{Misc_1s_e4sy_t0_st4rt!!}` diff --git a/6.计算机安全/6.5学习资料推荐.md b/6.计算机安全/6.5学习资料推荐.md index ea875e6..b6f6290 100644 --- a/6.计算机安全/6.5学习资料推荐.md +++ b/6.计算机安全/6.5学习资料推荐.md @@ -1,7 +1,8 @@ +# 学习资料推荐 > 计算机基础是非常重要的,协会一直推荐打好基础,勿在浮沙筑高台。 -> -> 以下是一些CTF领域写的不错的入门文章和平台,也可以根据文章内容进行学习~ +> +> 以下是一些 CTF 领域写的不错的入门文章和平台,也可以根据文章内容进行学习~ ## 学习网站: @@ -14,7 +15,7 @@ ## 靶场推荐: - [主页 | NSSCTF](https://www.nssctf.cn/index) -- [BUUCTF在线评测 (buuoj.cn)](https://buuoj.cn/) +- [BUUCTF 在线评测 (buuoj.cn)](https://buuoj.cn/) - [攻防世界 (xctf.org.cn)](https://adworld.xctf.org.cn) - [Hack The Box: Hacking Training For The Best | Individuals & Companies](https://www.hackthebox.com/) - [CryptoHack – A fun, free platform for learning cryptography](https://cryptohack.org/) @@ -27,20 +28,20 @@ > 主题比较宽泛,大多是计算机技术相关 -- https://www.leavesongs.com/ -- https://github.red/ -- https://lorexxar.cn/ -- https://su18.org/ +- +- +- +- 安全类博客: -> 主要是一些安全研究成果或者CTF竞赛题解,主要都是安全相关内容 +> 主要是一些安全研究成果或者 CTF 竞赛题解,主要都是安全相关内容 -- https://4ra1n.github.io/ -- https://y4tacker.github.io/ -- https://y4er.com/ -- https://cjovi.icu/ -- https://crazymanarmy.github.io/ -- https://www.gem-love.com -- https://blog.huli.tw/ -- https://blog.orange.tw/ \ No newline at end of file +- +- +- +- +- +- +- +- diff --git a/6.计算机安全/6.计算机安全.md b/6.计算机安全/6.计算机安全.md index 02b6c47..24d3e0a 100644 --- a/6.计算机安全/6.计算机安全.md +++ b/6.计算机安全/6.计算机安全.md @@ -1,12 +1,12 @@ # 6.计算机安全 > 本模块由 [Vidar-Team](https://vidar.club) 信息安全协会成员倾情奉献。 -> -> Vidar-Team 成立于2008年9月,其名 Vidar 来源于北欧神话"诸神黄昏"中幸存于难、带领人类重建了家园的神 Víðarr,是由杭州电子科技大学一群热爱信息安全的小伙伴自发成立的技术型团体 ,作为高校战队活跃于各大ctf赛事。 -> -> 2023 招新 QQ 群: 861507440(仅向校内开放),欢迎对技术感兴趣的小伙伴加入我们! +> +> Vidar-Team 成立于 2008 年 9 月,其名 Vidar 来源于北欧神话"诸神黄昏"中幸存于难、带领人类重建了家园的神 Víðarr,是由杭州电子科技大学一群热爱信息安全的小伙伴自发成立的技术型团体,作为高校战队活跃于各大 ctf 赛事。 +> +> 2023 招新 QQ 群:861507440(仅向校内开放),欢迎对技术感兴趣的小伙伴加入我们! -**招新方向汇总:** +**招新方向汇总:** - Web(网络安全) - 渗透(模拟黑客攻击,找寻漏洞,修补、加固系统) @@ -19,7 +19,7 @@ - Misc 杂项(流量分析,电子取证,大数据统计等,覆盖面比较广) - Crypto 密码学(与加密系统相关,从已加密的信息中破译明文) - 无线安全(RFID,无线遥控,ADS-B,BLE,ZigBee,移动通信,卫星通信) - - Iot安全 (从软件和硬件出发,多方向探索物联网设备) + - Iot 安全 (从软件和硬件出发,多方向探索物联网设备) - 人工智能安全 (使用人工智能技术赋能安全,模型本身安全问题) - 美工(负责协会相关的设计,如比赛海报与 LOGO,会服、钥匙扣等等各类周边的制作) - 计算机图形学(游戏开发,游戏引擎开发) @@ -28,9 +28,9 @@ ## 什么是安全 -计算机安全,通俗的讲就是黑客,主要研究计算机领域的攻防技术,主要包括网络安全(Web)和二进制安全(Bin,包含Pwn和Reverse)两大类。现有的 CTF 信息安全竞赛里面还会看到密码学(Crypto)和安全杂项(Misc),以及最近几年新兴的 IoT 安全,人工智能安全等方向。本系列文章会按照CTF的5个方向,Web、Pwn、Reverse、Crypto、Misc来进行介绍。目前引入了HGAME Mini2022我们编写给新生的入门材料,在今年的10月份和寒假,我们也会分别举办HGAME Mini和HGAME这两场CTF,来帮助新生更好的入门安全。 +计算机安全,通俗的讲就是黑客,主要研究计算机领域的攻防技术,主要包括网络安全(Web)和二进制安全(Bin,包含 Pwn 和 Reverse)两大类。现有的 CTF 信息安全竞赛里面还会看到密码学(Crypto)和安全杂项(Misc),以及最近几年新兴的 IoT 安全,人工智能安全等方向。本系列文章会按照 CTF 的 5 个方向,Web、Pwn、Reverse、Crypto、Misc 来进行介绍。目前引入了 HGAME Mini2022 我们编写给新生的入门材料,在今年的 10 月份和寒假,我们也会分别举办 HGAME Mini 和 HGAME 这两场 CTF,来帮助新生更好的入门安全。 -## CTF竞赛形式 +## CTF 竞赛形式 ### 解题赛 diff --git a/7.网络应用开发/7.1.1.1基础部分.md b/7.网络应用开发/7.1.1.1基础部分.md index ca6cc8b..c51a2af 100644 --- a/7.网络应用开发/7.1.1.1基础部分.md +++ b/7.网络应用开发/7.1.1.1基础部分.md @@ -21,15 +21,15 @@ [现代 JavaScript 教程](https://zh.javascript.info/) ::: warning 🎈 -快速上手的参考建议 +**快速上手的参考建议** -HTML 可以先认知常用标签( body / div / span / a / img 等)及其常用属性 +**HTML**** **可以先认知常用标签( body / div / span / a / img 等)及其常用属性 -CSS 了解常见的颜色属性(字体颜色 / 背景颜色 / 边框颜色 等)、字体相关属性(字号 / 字重 / 行高 等)、盒子模型(padding / border / margin)、用于布局的属性(float / flex / grid)、单位(px / rem / em / vh / vw 等)、选择器(id 选择器 / 类选择器 等) +**CSS**了解常见的颜色属性(字体颜色 / 背景颜色 / 边框颜色 等)、字体相关属性(字号 / 字重 / 行高 等)、盒子模型(padding / border / margin)、用于布局的属性(float / flex / grid)、单位(px / rem / em / vh / vw 等)、选择器(id 选择器 / 类选择器 等) -JS 了解基本语法(变量定义 / 判断 / 循环 / 函数定义 / etc)与 DOM 操作 +**JS**** **了解基本语法(变量定义 / 判断 / 循环 / 函数定义 / etc)与 DOM 操作 -涉及前后端交互的部分可以了解 fetch 的使用 +涉及**前后端交互**的部分可以了解 fetch 的使用 其他诸如 HTML5 / CSS3 / ES6+ 的知识可以暂时跳过,任务要用到再查 @@ -102,7 +102,7 @@ #### 基本要求 - 可以对 todo 进行增删改查 -- 至少存在 待完成/已完成 两种不同的状态,Todo 应该能够在不同状态间切换。更进一步,你也可以设计一个 进行中 状态。 +- 至少存在 **待完成**/**已完成** 两种不同的状态,Todo 应该能够在不同状态间切换。更进一步,你也可以设计一个 **进行中** 状态。 #### 额外发挥 diff --git a/7.网络应用开发/7.1.1.2进阶部分.md b/7.网络应用开发/7.1.1.2进阶部分.md index 0f59f52..19688c5 100644 --- a/7.网络应用开发/7.1.1.2进阶部分.md +++ b/7.网络应用开发/7.1.1.2进阶部分.md @@ -2,7 +2,7 @@ ::: warning 📌 -如果是有一定基础的同学,可以考虑采用一些辅助工具(React / Vue / jQuery 等),样式方面也可以采用你喜欢的组件库(Antd / ElementUI / Bootstrap 等)实现。 +如果是有一定基础的同学,可以考虑采用一些辅助工具(React / Vue / jQuery 等),样式方面也可以采用你喜欢的组件库(Antd / ElementUI / Bootstrap 等)实现。 ::: diff --git a/7.网络应用开发/7.1.2.1基础部分.md b/7.网络应用开发/7.1.2.1基础部分.md index 637eecc..f5acf50 100644 --- a/7.网络应用开发/7.1.2.1基础部分.md +++ b/7.网络应用开发/7.1.2.1基础部分.md @@ -24,9 +24,9 @@ Hello~这里是杭电助手技术部后端,无论基础如何,您都可以 官网虽然是英文,但是非常非常的友好,近年还刚翻新过一次好看了许多,还有各种可爱的吉祥物插图。 -这只吉祥物囊袋鼠的英文学名为 Gopher,每位热爱 Golang 的开发者都会自称 Gopher (就像 jvaver 一样(x),而它的造型出于创始人之一 Rob Pike 的妻子之手。 +这只吉祥物囊袋鼠的英文学名为 **Gopher**,每位热爱 Golang 的开发者都会自称 **Gopher** (就像 jvaver 一样(x),而它的造型出于创始人之一 Rob Pike 的妻子之手。 -#### 视频资料(P2-P3): +#### 视频资料(**P2-P3**): @@ -74,7 +74,7 @@ https://www.jetbrains.com/go/ GoLand 可以使用教育邮箱学生认证白嫖噢~👀 ::: -#### 视频资料(P4-P6): +#### 视频资料(**P4-P6**): @@ -99,7 +99,7 @@ https://polarisxu.studygolang.com/posts/go/2022-dev-env/ Golang 的语法是 C/C++ 系的,在许多地方你都可以看到他们的影子,这对未来 C 的学习更有自顶向下的帮助。当然,如果你曾经用过 Java、Python,Golang 的语法你可能会不太习惯,这不会是问题~在熟悉语法后,你会发现 “Golang 一把梭” 是真实存在的 🤓。 -对于基础语法的学习,无需一时学习过深,也不必花费过多时间在此即使半懵半懂,在多次实践后也会渐渐领悟 +**对于基础语法的学习,无需一时学习过深,也不必花费过多时间在此**。**即使半懵半懂,在多次实践后也会渐渐领悟** 本次任务并不需要用到反射、并发等高级特性(学到时可选择性暂时避开),最深只需要用到结构体与方法的相关知识。 @@ -110,7 +110,7 @@ Golang 的语法是 C/C++ 系的,在许多地方你都可以看到他们的影 #### 文字资料: -- 非常推荐的 Go Tour 中文版。Go Tour 是 Go 官方为初学者打造的渐进式教程,你可以跟随着它的步伐一点点探索 Go 语言 。Go Tour 的代码都充满着它的设计哲学与最佳实践,是每位 Gopher 的必经之路。同时它也是交互式的,左侧是教程,右侧能直接敲代码,在网页上运行。 +- 非常推荐的 Go Tour 中文版。Go Tour 是 **Go 官方为初学者打造的渐进式教程**,你可以跟随着它的步伐一点点探索 Go 语言 。Go Tour 的代码都充满着它的**设计哲学与最佳实践**,是每位 Gopher 的必经之路。同时它也是**交互式的**,左侧是教程,右侧能直接敲代码,在网页上运行。 https://tour.go-zh.org/welcome/1 @@ -133,7 +133,7 @@ HTTP 协议起草与演进之路十分坎坷,但每一步都举足轻重,在 #### 文字资料: -- 非常著名的阮一峰博客 (他的博客可以从最早开始都过一遍,很多计算机科普可以说永不过时) +- 非常著名的阮一峰博客 **(他的博客可以从最早开始都过一遍,很多计算机科普可以说永不过时)** https://www.ruanyifeng.com/blog/2016/08/http.html @@ -183,7 +183,7 @@ https://www.runoob.com/http/http-intro.html 请运用你在第三小节中学习的 `Golang 包(依赖)管理` 正确地安装 Gin 并学习使用它。 -相关资料: +**相关资料**: - [GitHub - gin-gonic/gin: Gin is a HTTP web framework written in Go (Golang)](https://github.com/gin-gonic/gin) - Gin 的官方仓库及权威文档。 - [Go Gin Example](https://github.com/eddycjy/go-gin-example) - 使用 Gin 的一个小项目,难度较高。 diff --git a/7.网络应用开发/7.1WEB开发入门.md b/7.网络应用开发/7.1WEB开发入门.md index fef5b00..fc6096e 100644 --- a/7.网络应用开发/7.1WEB开发入门.md +++ b/7.网络应用开发/7.1WEB开发入门.md @@ -6,13 +6,13 @@ ## 章节题目解释 -- 何为 Web:可以狭义地理解为前端」+「后端」 +- 何为 Web:可以狭义地理解为「前端」+「后端」 - 何为开发:明确产品需求,写代码,调试代码,部署项目,写项目文档,维护项目 - 何为入门:不知道要马上学会,而是知道 Web 开发是什么,以及如何去学 ## 前端?后端? -### 行业背景 +### **行业背景** 前端开发和后端开发可以说是 2023 年以前,计算机学生就业最广泛的方向(当然工资也不低) @@ -20,7 +20,7 @@ 我们接触互联网,直接使用最多的是什么?——软件 -同样,我们可以狭义地把大部分软件开发理解为:「软件」(程序员需要做的部分)=「前端」+「后端」 +同样,我们可以狭义地把大部分软件开发理解为:**「软件」(程序员需要做的部分)=「****前端****」+「后端」** 所以大部分计算机学生毕业,都是为公司的具体的业务,开发对应的手机 APP、网站、电脑软件。 @@ -28,13 +28,13 @@ 本文写于 2023 年 4 月,2023 年以来,AI(ChatGPT、Copilot、MidJourney)正在颠覆每个领域。可能在不远的将来,大部分的前后端开发,都能通过 AI 自动生成 99% 的代码,然后人工审核、校对、修改剩下的 1%。 -### 步入正题 - 何为前后端 - 通俗认识 +### **步入正题 - 何为前后端 - 通俗认识** -前端 +**前端** 前端可以狭义地理解为,一个软件中看得到的部分。比如网页上的文字图片、各种花里胡哨的样式、以及交互操作。广义上来说,大家用的各种 APP、电脑上的应用程序,用户界面的部分都是前端干的活。 -后端 +**后端** 相对于前端,后端当然是「看不见的部分」。 @@ -44,13 +44,13 @@ 所以一个软件的关键数据,肯定不是在用户侧(即前端)的。需要有这么一个东西,来存储数据(存储数据的地方叫数据库),来解析用户的请求,这就是后端。 -例子 +**例子** 举个详细的例子,购物软件上点了下单并支付,这时候前端就会发送一个网络请求,告诉后端:用户某某某,买了什么东西,价格和数量是多少,收货地址是多少。。。 后端收到了信息,先解析,然后修改数据库中存储的关键信息,比如新建一个订单信息,把商品的数量 -1 等等,再把下单的结果告诉给前端。前端收到信息后,就会渲染页面,提示「下单成功」! -### 深入 - 何为前后端 - 技术剖析 +### **深入 - 何为前后端 - 技术剖析** 在了解了前后端的宏观概念后,我们继续来感受一下背后的技术细节吧! @@ -79,7 +79,7 @@ 想知道前端需要用到什么技术,就来看看前端到底需要解决什么问题吧! -1. 页面渲染 +1. **页面渲染** 无论是做网页,还是做 APP 界面,都得「画」出界面。 @@ -89,7 +89,7 @@ (拓展:还有一些技术能够做到跨平台,比如通过某种技术把浏览器包装成一个 APP,就能只出同时支持浏览器和 APP 的前端;比如创建新的第三方前端框架,能把程序员写的代码转换成原生的 IOS、安卓 APP) -1. 用户交互 +1. **用户交互** 如何实现“点击「留言」按钮,系统自动提交留言”?或者当用户点击按钮的时候,检测一下用户输入的内容是不是空。 diff --git a/8.基础学科/8.1经济学科普Part1.md b/8.基础学科/8.1经济学科普Part1.md index 39ef421..dd1b5b4 100644 --- a/8.基础学科/8.1经济学科普Part1.md +++ b/8.基础学科/8.1经济学科普Part1.md @@ -40,7 +40,7 @@ ### 信用、货币的引入 -引入一个概念,信用。 +引入一个概念,**信用**。 做面粉和做面包的都彼此信任,相信对面总有一天会兑现承诺,允许赊账 @@ -61,9 +61,9 @@ | 交易面包 | 信用-1(0),获得 25 个面包 | 信用 +1(1) | | 期末信用 | 0 | 1 | -稍微看一下就会发现,这个所谓的信用,和现在的货币没有任何区别,如果用现在的话说,一个信用就相当于 25 个面包 +稍微看一下就会发现,这个所谓的信用,和现在的**货币**没有任何区别,如果用现在的话说,一个信用就相当于 25 个面包 -因此,可以得到一个结论,货币就是信用, 只是现在我们在使用货币时,信任的不是对面的人,而是国家,货币事实上就是国家信用。 +因此,可以得到一个结论,**货币就是信用**, 只是现在我们在使用货币时,信任的不是对面的人,而是国家,**货币事实上就是国家信用**。 > 这个加入第三方解决问题的思想在计算机科学里也非常常见(没有什么问题是加一个中间层不能解决的),在经济学里亦是如此。但额外补充,引入第三方信用的方案看似是分散了风险,但当考虑金融资产之间的关联性时,可能已经分散的风险又会集中,这是系统性风险的最大来源。(比如,国家如果破产了怎么办?)对应到对第三方的信用丧失,最常见的应对策略是买入避险资产,目前唯一的公认避险资产是黄金。(黄金从性质上来说具有天然的信用(不可人工制造,也就是不会突然增加减少,自然保有量即是信用),而且没有货币作用之外的属性(不能吃,不能穿,没有用,不是工业原料),是天然的货币) @@ -73,7 +73,7 @@ ### 价格对分配结果的影响 -上面的情况中,我们始终在讨论一种可以周而复始,永远循环的情况。财富也不会增长或者减少。出现这种情况的根本原因是每次期初各方的货币总是等于期末各方的货币。换言之,如果每期中,有一方的货币总是减少一点,那么我们就无法建立一个可以永远循环下去的经济系统了。下面用表来举个例子。 +上面的情况中,我们始终在讨论一种可以周而复始,永远循环的情况。**财富也不会增长或者减少**。出现这种情况的根本原因是每次期初各方的货币总是等于期末各方的货币。换言之,如果每期中,有一方的货币总是减少一点,那么我们就无法建立一个可以永远循环下去的经济系统了。下面用表来举个例子。 面包价格:4 元/个,其他条件不变 @@ -86,7 +86,7 @@ 可以看到,由于价格比例的变动,为了维持原先的消费状况,面粉厂不得不增加相应的开支,再 1 轮交易之后,面粉厂就会因为没有货币而无法参与交易。 -因此,在不均衡的价格体系中,假设没有外部货币补充,处于弱势的部门只能通过削减消费来维持经济系统的运转。而且,不难想到,即使有外部的货币补充,货币补充通常也难以直接送到弱势方,这反而会造成弱势方在分配面包时处于更加弱势的地位,不得不消费更少的面包。这可能是今天经常说的“剥削”。 +因此,在不均衡的价格体系中,**假设没有外部货币补充,处于弱势的部门只能通过削减消费来维持经济系统的运转**。而且,不难想到,**即使有外部的货币补充,货币补充通常也难以直接送到弱势方**,这反而会造成弱势方在分配面包时处于更加弱势的地位,不得不消费更少的面包。这可能是今天经常说的“剥削”。 这里还可以深入讨论一下,我们可以讨论一下价格比例的变动进而产生的分配变动。 @@ -98,7 +98,7 @@ 更一般地,可以说,面粉厂消费的面包比例为 k,而面包厂消费的面包比例为 1-k。 -也就是说,价格的绝对值并不怎么重要,重要的是价格之间的比值,这种价格比值的差异形成了分配的阶级性。 +**也就是说,价格的绝对值并不怎么重要,重要的是价格之间的比值,这种价格比值的差异形成了分配的阶级性。** > 我们可以尝试着换一个角度来思考这个问题,从上述讨论中可以思考怎么样的价格调控是合理的,怎么样的是不合理的,通常来说,一些从直觉上感觉非常公平的定价方式,例如在成本基础上统一加一定量的利润,实际上是最不合理的,会带来非常严重的分配问题。 @@ -122,17 +122,17 @@ 几轮循环下来,面粉厂和面包厂都会拥有非常多的货币。 -但显然,单纯有货币没有用,如果我们的系统里生产力不会提升,再多的货币也不能购买到超过 50 个面包。 +但显然,单纯有货币没有用,**如果我们的系统里生产力不会提升,再多的货币也不能购买到超过 50 个面包**。 -我们来讨论一下,由于这里大家都有了很多储蓄,面粉厂和面包厂都会有一种自己可以消费更多面包、或者不用工作也不会饿死的错觉。 +我们来讨论一下,由于这里大家都有了很多储蓄**,面粉厂和面包厂都会有一种自己可以消费更多面包、或者不用工作也不会饿死的错觉**。 -这种错觉是错误的,而它是如此的真实,一定会有人付诸实践,因此,这种错觉一定会被打破。 +**这种错觉是错误的,而它是如此的真实,一定会有人付诸实践,因此,这种错觉一定会被打破。** 假设现在发生了第一种情况,面粉厂觉得自己有了很多储蓄,愿意多消费更多面包,而面包厂也不甘示弱,觉得自己如果要减少面包消费,卖出的额外的面包需要涨价。 假设面粉厂现在愿意以原价购买 25 个面包,额外还想购买 5 个面包,并与面包厂达成了协议,额外的部分每个付费 4 元,那么面包的价格就来到了 2.333 元,同样的,这种价格上涨也会导致双方认为自己的储蓄缩水,进而又回到工作的状态。 -从上述的讨论中可以发现,货币增加后,面包的价格并不一定立即增长,价格的涨幅通常也与货币的增幅没有直接关系,而是买卖双方针对价格博弈的后果。但可以肯定的是,脉冲式的价格上涨一定会出现。 +从上述的讨论中可以发现,**货币增加后,面包的价格并不一定立即增长,价格的涨幅通常也与货币的增幅没有直接关系,而是买卖双方针对价格博弈的后果。但可以肯定的是,脉冲式的价格上涨一定会出现**。 ### 印钞部门 @@ -148,7 +148,7 @@ | 交易面包 | 货币-48(102),获得 24 个面包 | 货币 +52(102) | 购买 2 个面包(-4) | | 期末 | 102(24 个面包) | 102(24 个面包) | 0(2 个面包) | -上述现象的神奇之处在于,铸币部门不做任何工作就获得了面包分配,而面粉厂与面包厂在不了解经济运行全貌的情况下,总是认为自己是由于节俭而增加了储蓄。 +上述现象的神奇之处在于,**铸币部门不做任何工作就获得了面包分配,而面粉厂与面包厂在不了解经济运行全貌的情况下,总是认为自己是由于节俭而增加了储蓄**。 剩下的问题同情况 2 所讨论的,储蓄的积累会带来脉冲式的价格体系变化。 @@ -203,9 +203,9 @@ | 还清债务 | -10(0) | +10(100) | | 期末 | 0 | 100 | -可以看到,这里看起来货币的结余情况一样,但实际上面粉厂减少了面包消费用于偿还债务,也就是说,通过上述描述货币和消费情况表格的表达方式,我们无法完整描述这一过程。在接下来,会引入简单的资产负债表,用于刻画这一过程。 +可以看到,这里看起来货币的结余情况一样,但实际上面粉厂减少了面包消费用于偿还债务,也就是说,**通过上述描述货币和消费情况表格的表达方式,我们无法完整描述这一过程**。在接下来,会引入简单的资产负债表,用于刻画这一过程。 -可惜的是,从另一角度说,面粉厂接下来若要重新获得储蓄,需要在接下来的 4 期内都只消费 10 个面包,否则面粉厂就无法恢复储蓄。更何况,面包厂未必有意愿自己消费 60 个面包,因此,在这种古早的经济系统下,超前的借贷实际上会降低经济活力,形成经济不景气的现象。 +可惜的是,从另一角度说,面粉厂接下来若要重新获得储蓄,需要在接下来的 4 期内都只消费 10 个面包,否则面粉厂就无法恢复储蓄。更何况,面包厂未必有意愿自己消费 60 个面包,因此,**在这种古早的经济系统下,超前的借贷实际上会降低经济活力,形成经济不景气的现象**。 从另一个角度来探讨,可以发现面粉厂还债的时候实际上是通过还面包的方式来进行还债的,由此,可以推出另一个结论:当经济系统中一方货币不足时,可以通过降低消费或者提供服务的方式来偿还债务,也就是说经济系统中的债务量可以大于经济系统中的货币数量。关于这部分内容,下文还会有一些讨论。 @@ -217,7 +217,7 @@ 要回答这个问题,我们就需要讨论一下货币的本质是什么了。 -考虑你想要买一只鸡来吃,在人类社会中,鸡是一种商品,而你拥有货币。看起来你拥有对鸡(商品)的支配权,但实际并非如此。因为你不能走进大山里用货币向大自然换一只鸡来,实际上,在你购买这个商品时付出的货币,是购买了打猎或者养殖鸡的人的劳动力,而非是购买了鸡这种商品本身。同样,价值 1000 元在上文的意思就是,如何建造一个需要 1000 元才能够买得到的劳动力才能建造的博物馆,而不是说博物馆本身价值 1000 元。 +考虑你想要买一只鸡来吃,在人类社会中,鸡是一种商品,而你拥有货币。看起来你拥有对鸡(商品)的支配权,但实际并非如此。因为你不能走进大山里用货币向大自然换一只鸡来,**实际上,在你购买这个商品时付出的货币,是购买了打猎或者养殖鸡的人的劳动力,而非是购买了鸡这种商品本身**。同样,价值 1000 元在上文的意思就是,如何建造一个需要 1000 元才能够买得到的劳动力才能建造的博物馆,而不是说博物馆本身价值 1000 元。 明白了这一点,就很好解释如何建造这个博物馆了,我们引入一个新的经济部门,叫建筑商,建筑商雇佣工人来完成博物馆的建设,每个工人的工资是 4 元,工人会把工资的全部都用来购买面包。所以,建造博物馆需要 1000/4=250 个人/期单位的劳动力。只要经济可以正常循环下去,每期都有工人来参与建设、获得面包,价值 1000 元的博物馆就可以建成。 @@ -259,7 +259,7 @@ 因此,只要政府部门能够敏锐地发现生产余力的存在,并且向经济系统中添加适量货币,就能够促进经济的发展,形成繁荣的经济现象。 -可惜的是,要增加多少储蓄才能让人们有足够多的消费意愿这一问题根本无法准确回答,政府部门在这一过程中总是倾向于多发行货币,因此,这种情况下通常也会带来商品价格的上涨。 +**可惜的是,要增加多少储蓄才能让人们有足够多的消费意愿这一问题根本无法准确回答,政府部门在这一过程中总是倾向于多发行货币,因此,这种情况下通常也会带来商品价格的上涨。** ## 产出结构、资源分配 @@ -275,9 +275,9 @@ 定价 4 元这一动作,其实就是说经济系统内的其他部门花 2 个面包供养农机厂,农机厂消费 2 个面包,产出一台农机。 -在这里,暂时不考虑 4 元这个定价是否合理,可以发现虽然农机厂生产的农机本身可以提高面包产量,但最终农机厂得到的供养却与贡献的面包产量不成正比。而且,可以预见的是,在出售 10 台农机后,农机就不会被需要,这意味着农机厂若没有依靠这 10 期的供养产出更高效的农机就会被放弃供养而倒闭。 +在这里,暂时不考虑 4 元这个定价是否合理,**可以发现虽然农机厂生产的农机本身可以提高面包产量,但最终农机厂得到的供养却与****起****贡献的面包产量不成正比**。而且,可以预见的是,在出售 10 台农机后,农机就不会被需要,这意味着农机厂若没有依靠这 10 期的供养产出更高效的农机就会被放弃供养而倒闭。 -这一事实说明经济系统的运行规则存在其固有缺陷,并不一定可以把资源倾斜给实际提供产出的部门,相反,随着面包产量增加、政府增发货币,农机厂可能是收入提升最少的,意味着农机厂获得的资源分配会越来越少。 +**这一事实说明经济系统的运行规则存在其固有缺陷,并不一定可以把资源倾斜给实际提供产出的部门,相反,随着面包产量增加、政府增发货币,农机厂可能是收入提升最少的,意味着农机厂获得的资源分配会越来越少。** ## 不可能的指数增长 @@ -301,7 +301,7 @@ 可以发现,一开始,不论大家如何努力生产,缺口都保持在 9 以上,甚至还有扩大的趋势,但随着时间推移,很快在第 9 期就迎来了经济衰退,经济系统不再需要这么多农机,在现行的经济评价指标下可以认为是经济陷入了衰退。 -仅从上表就不难看出,追求指数增长是不可能的,经济体通常会在极短的时间以出乎所有人预料的速度内陷入衰退。 +**仅从上表就不难看出,追求指数增长是不可能的,经济体通常会在极短的时间以出乎所有人预料的速度内陷入衰退。** 除此之外,我们可以从实际增长方式的角度论证指数增长是不可能的。 diff --git a/9.计算机网络/9.1计网速通.md b/9.计算机网络/9.1计网速通.md index ae02efa..8b4099f 100644 --- a/9.计算机网络/9.1计网速通.md +++ b/9.计算机网络/9.1计网速通.md @@ -283,7 +283,7 @@ TLS 建立在 TCP 的基础上,他会通过加密来确保传输过程中数 相信在看这篇文章的大家都正在使用互联网,如果你正在使用windows设备,你可以先按 `win`+`R` ,输入 `cmd`,在弹出的窗口输入 `ipconfig` 你可以看到里面有一串类似于下文的内容: -``` +```powershell 无线局域网适配器 WLAN: 连接特定的 DNS 后缀 . . . . . . . : diff --git a/9.计算机网络/9.2.3.2子网与无类域间路由.md b/9.计算机网络/9.2.3.2子网与无类域间路由.md new file mode 100644 index 0000000..4dcb575 --- /dev/null +++ b/9.计算机网络/9.2.3.2子网与无类域间路由.md @@ -0,0 +1,147 @@ +# 子网与无类域间路由 + +在上一篇文章中,我们详细讲解了 IP 数据包的结构。一个 IP 数据包确实非常复杂,但现在请你忘掉他,仅在需要的时候翻看相关文章做参考。 + +你只需要知道一件事 —— IP 头里有一对 IP 地址,分别分别代表这个数据包从哪里来,到哪里去。 + +在组成一个比较大的网络前,我们需要给一个个孤立的IP地址分类。给 IP 分类可以让维护路由表变得更简单,CIDR(无类域间路由)是一种非常良好的分类方法。 + +## CIDR + +我们先看看什么地方会出现 CIDR 这个东西。如果你正在使用 Linux 操作系统,你可以输入命令`ip addr`,他会打印出一串大概这样的内容 + +> windows 的 CIDR 采用点分十进制掩码,后续介绍 + +``` bash +baimeow@server:~$ ip addr +1: lo: mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 + link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 + inet 127.0.0.1/8 scope host lo + valid_lft forever preferred_lft forever + inet6 ::1/128 scope host + valid_lft forever preferred_lft forever +2: eth0: mtu 1500 qdisc fq_codel state UP group default qlen 1000 + link/ether bf:17:21:ab:44:ba brd ff:ff:ff:ff:ff:ff + inet 192.168.1.12/24 metric 100 brd 192.168.1.255 scope global dynamic ens18 + valid_lft 2458sec preferred_lft 2458sec + inet6 fe80::bc57:71ff:febb:24b0/64 scope link + valid_lft forever preferred_lft forever +``` + +其中有 4 个 CIDR,分别是 `127.0.0.1/8` `::1/128` `192.168.1.12/24` `fe80::bc57:71ff:febb:24b0/64`我们以 `192.168.1.12/24`为例。 + +他由一个 IP 地址和一个数字组成,中间用正斜杠分割,IP 地址就是你的设备的 IP,这没有什么特别特殊的。而后面的这个 24 是掩码。这其实表达了很多层意思: + +- 设备 IP 是 `192.168.1.12` + +- 网络号是 `192.168.1.0` + +- 掩码是 24 + +- 广播地址是 `192.168.1.255` + +- 这个 IP 所在的子网拥有的范围的是 `192.168.1.0` - `192.168.1.255` + +- 这个 IP 所在的子网可以分配的 IP 范围的是 `192.168.1.1` - `192.168.1.254` + +为了理解上面这些东西都是怎么来的,我们需要理解这个掩码是如何作用在 IP 上的,我们先把 IP 地址写成二进制的格式(点分二进制) + +`192.168.1.12` -> `11000000.10101000.00000001.00001100` + +目前,我们的这个掩码值为 24,他的意思是把 IP 地址分成,前 24 位,剩下的 8 位,这两部分,被切除的部分用 0 来填充,于是我们得到了 + +- 网络号`11000000.10101000.00000001.00000000` -> `192.168.1.0` + +- 主机号`00000000.00000000.00000000.00001100` -> `0.0.0.12` + +这里由于 /24 刚刚好切到了点上,所以就被非常直观地分成了这样两部分。 + +在 CIDR 的规则中,将拥有同样的网络号和同样的掩码的 IP 的集合作为一个子网。比如网络号为`192.168.1.0`,掩码为 24 的所有 IP 就是 `192.168.1.0` - `192.168.1.255`这些个 IP,他们都在`192.168.1.0/24`这个子网里。 + +注意,“子网”并不是一个非常抽象或者特殊的概念,他只是从互联网这张大网里取了一段 IP 地址构成子网,就像集合的子集一样。只是我们现在正在使用 CIDR 的规则去划分子网,遵循着 CIDR 的规则用一个网络号和掩码去划分出这样一段 IP。 + +在这样的一个子网里,我们定义: + +- 第一个地址是网络地址 +- 最后一个地址是广播地址 +- 剩下的地址可以分配给网络内的设备 + +以上定义是默认行为,其实是可以修改的,比如广播地址就可以不是最后一个地址。 + +严格意义上说,上面提到的子网一部分应该改称呼为网段,简单起见不细究了。 + +## 常见保留IP + +了解一下常见的保留IP吧,这些保留 IP 不会出现在公网,而是被用于其他特殊用途。 + +让我抄一下Wiki的表格。 + +| 地址块 ([CIDR](https://zh.wikipedia.org/wiki/无类别域间路由)) | 范围 | 地址数 | 效用域 | 用途 | +| :----------------------------------------------------------: | :---------------------------: | :---------: | :------: | :----------------------------------------------------------: | +| 0.0.0.0/8 | 0.0.0.0 – 0.255.255.255 | 16,777,216 | 软件 | 用于广播信息到当前主机。[[1\]](https://zh.wikipedia.org/wiki/保留IP地址#cite_note-1) | +| 10.0.0.0/8 | 10.0.0.0 – 10.255.255.255 | 16,777,216 | 专用网络 | 用于[专用网络](https://zh.wikipedia.org/wiki/专用网络)中的本地通信。[[2\]](https://zh.wikipedia.org/wiki/保留IP地址#cite_note-rfc1918-2) | +| 100.64.0.0/10 | 100.64.0.0 – 100.127.255.255 | 4,194,304 | 专用网络 | 用于在[电信级NAT](https://zh.wikipedia.org/wiki/电信级NAT)环境中服务提供商与其用户通信。[[3\]](https://zh.wikipedia.org/wiki/保留IP地址#cite_note-3) | +| 127.0.0.0/8 | 127.0.0.0 – 127.255.255.255 | 16,777,216 | 主机 | 用于到本地主机的[环回地址](https://zh.wikipedia.org/wiki/IPv4#环回地址(Loopback_Address))。[[4\]](https://zh.wikipedia.org/wiki/保留IP地址#cite_note-4) | +| 169.254.0.0/16 | 169.254.0.0 – 169.254.255.255 | 65,536 | 链路 | 用于单链路的两个主机之间的[链路本地地址](https://zh.wikipedia.org/wiki/链路本地地址),而没有另外指定IP地址,例如通常从[DHCP](https://zh.wikipedia.org/wiki/动态主机设置协议)服务器所检索到的IP地址。[[5\]](https://zh.wikipedia.org/wiki/保留IP地址#cite_note-5) | +| 172.16.0.0/12 | 172.16.0.0 – 172.31.255.255 | 1,048,576 | 专用网络 | 用于[专用网络](https://zh.wikipedia.org/wiki/专用网络)中的本地通信。[[2\]](https://zh.wikipedia.org/wiki/保留IP地址#cite_note-rfc1918-2) | +| 192.0.0.0/24 | 192.0.0.0 – 192.0.0.255 | 256 | 专用网络 | 用于IANA的IPv4特殊用途地址表。[[6\]](https://zh.wikipedia.org/wiki/保留IP地址#cite_note-rfc5736-6) | +| 192.0.2.0/24 | 192.0.2.0 – 192.0.2.255 | 256 | 文档 | 分配为用于文档和示例中的“TEST-NET”(测试网),它不应该被公开使用。[[7\]](https://zh.wikipedia.org/wiki/保留IP地址#cite_note-rfc5737-7) | +| 192.88.99.0/24 | 192.88.99.0 – 192.88.99.255 | 256 | 互联网 | 用于[6to4](https://zh.wikipedia.org/wiki/6to4)[任播](https://zh.wikipedia.org/wiki/任播)中继。[[8\]](https://zh.wikipedia.org/wiki/保留IP地址#cite_note-8)(已废弃[[9\]](https://zh.wikipedia.org/wiki/保留IP地址#cite_note-rfc7526-9)) | +| 192.168.0.0/16 | 192.168.0.0 – 192.168.255.255 | 65,536 | 专用网络 | 用于[专用网络](https://zh.wikipedia.org/wiki/专用网络)中的本地通信。[[2\]](https://zh.wikipedia.org/wiki/保留IP地址#cite_note-rfc1918-2) | +| 198.18.0.0/15 | 198.18.0.0 – 198.19.255.255 | 131,072 | 专用网络 | 用于测试两个不同的子网的网间通信。[[10\]](https://zh.wikipedia.org/wiki/保留IP地址#cite_note-10) | +| 198.51.100.0/24 | 198.51.100.0 – 198.51.100.255 | 256 | 文档 | 分配为用于文档和示例中的“TEST-NET-2”(测试-网-2),它不应该被公开使用。[[7\]](https://zh.wikipedia.org/wiki/保留IP地址#cite_note-rfc5737-7) | +| 203.0.113.0/24 | 203.0.113.0 – 203.0.113.255 | 256 | 文档 | 分配为用于文档和示例中的“TEST-NET-3”(测试-网-3),它不应该被公开使用。[[7\]](https://zh.wikipedia.org/wiki/保留IP地址#cite_note-rfc5737-7) | +| 224.0.0.0/4 | 224.0.0.0 – 239.255.255.255 | 268,435,456 | 互联网 | 用于多播。[[11\]](https://zh.wikipedia.org/wiki/保留IP地址#cite_note-rfc1112-11) | +| 233.252.0.0/24 | 233.252.0.0 - 233.252.0.255 | 256 | 文档 | 分配为用于文档和示例中的“MCAST-TEST-NET”,它不应该被公开使用 | +| 240.0.0.0/4 | 240.0.0.0 – 255.255.255.254 | 268,435,455 | 互联网 | 用于将来使用。[[12\]](https://zh.wikipedia.org/wiki/保留IP地址#cite_note-rfc6890-12) | +| 255.255.255.255/32 | 255.255.255.255 | 1 | 子网 | 用于受限广播地址。[[12\]](https://zh.wikipedia.org/wiki/保留IP地址#cite_note-rfc6890-12) | + +如果需要搭建自己的比如说家庭网络,寝室网络,一般会选择 + +- `10.0.0.0/8` +- `192.168.0.0/16` +- `172.16.0.0/12` + +此外另外了解一下其他的特殊地址,避免冲突吧 + +- `169.254.0.0/16` DHCP获取到 IP 前的临时 IP 地址 +- `192.18.0.0/16` 一些代理软件的透明代理模式会解析域名到这里 +- `172.17.0.0/16` Docker 默认网段 + +## 旧闻一则 —— ABCDE 类 IP + +很久很久以前,一群自大的人给 IP 随意地划分了 ABCDE 类。很遗憾,我们仍需要了解一下这个历史包袱。 + +- A类 0.0.0.0~126.255.255.255 大型网络 + +- B类 128.0.0.0~191.255.255.255中型网络 + +- C类 192.0.0.0~223.255.255.255 小型网络 + +- D类 224.0.0.1-239.255.255.254 多播 + +- E类 240.0.0.0---255.255.255.255 保留段与广播地址 + +仅作了解,现今已经不具有实际意义了 + +## 正在消失的 —— 点分10进制掩码 + +当你在 windows 的 cmd 里执行 `ipconfig /all` 时,你可以看到一个点分十进制的掩码。 + +```cmd +无线局域网适配器 WLAN: + + 连接特定的 DNS 后缀 . . . . . . . : + 描述. . . . . . . . . . . . . . . : Intel(R) Wi-Fi 6 AX200 160MHz + IPv4 地址 . . . . . . . . . . . . : 192.168.0.102(首选) + 子网掩码 . . . . . . . . . . . . : 255.255.255.0 + 获得租约的时间 . . . . . . . . . : 2023年8月20日 19:49:53 + 租约过期的时间 . . . . . . . . . : 2023年8月21日 00:49:56 + 默认网关. . . . . . . . . . . . . : 192.168.0.1 +``` + +上面的子网掩码是 `255.255.255.0`,其实就是`/24` + +这种格式其实表达的信息更灵活,你可以在掩码的时候掩住前面一段后面一段,中间留一段做主机号,这是没有问题的。 + +问题在于有点过度设计的了,随意地掩盖住几位只会让网络运维人员心烦,久而久之用的越来越少,就算是用,也只会顺序掩盖前面几位,其实目前碰到的大多数这种格式的掩码他传达的信息 CIDR 也是可以表述的。了解一下,至少目前还是有很多人用这个写法的掩码的。 diff --git a/9.计算机网络/9.计算机网络.md b/9.计算机网络/9.计算机网络.md index a0586c9..3a50b1f 100644 --- a/9.计算机网络/9.计算机网络.md +++ b/9.计算机网络/9.计算机网络.md @@ -92,11 +92,11 @@ 路由佬入门指南 ---> 多节点高可用网络概论 路由佬入门指南 ---> 大规模实验性网络概论 路由佬入门指南 ---> 走得更深入... - 链路层 ---> 数据帧/MAC/CRC - 链路层 ---> PPP + 链路层 ---> 以太网 链路层 ---> ARP - 网络层 ---> IP 协议 - 网络层 ---> 子网/掩码/CIDR + 网络层 ---> IP协议 + 网络层 ---> 子网与无类域间路由 + 网络层 ---> 路由 网络层 ---> IPv6概述 传输层 ---> 端口 传输层 ---> UDP @@ -107,5 +107,5 @@ 路由协议 ---> RIP 路由协议 ---> OSPF 路由协议 ---> 自治域与BGP概述 - + ``` diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 27fcef1..ed57df8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,15 +1,20 @@ # 贡献指南 -感谢您的贡献,并感谢您在执行此操作之前阅读此文档! + +感谢您的贡献,并感谢您在执行贡献操作之前阅读此文档! ## 致新贡献者 + 欢迎你的到来,非常感谢你愿意一起建设 HDU-CS-WIKI 💖。 初次参与,你遇到任何问题都可以直接反馈到本仓库,包括但不限于: - - 开发环境搭建时遇到任何问题。 - - 文档遇到任何问题(笔误,格式,错误等)。 + +- 开发环境搭建时遇到任何问题。 +- 文档遇到任何问题(笔误,格式,错误等)。 + 如果你在运行项目的时候发现任何不符合预期或不合理的地方,请直接提交 Issue 反馈和 Bug 报告! ## 如何贡献 + 我们欢迎各种贡献,包括但不限于: - 新功能(Feature) @@ -21,32 +26,214 @@ - 在各种媒体、博客文章、群内宣传 HDU-CS-WIKI ## 文档风格 + 1. 使用 Markdown 编写文档,文档格式参考 Markdown 语法。 2. 一个页面只有一个1级标题(H1,一个#),其他标题从2级开始(H2,##)。 3. 本项目自动在英文与中文、数字与中文之间添加空格。 + ```markdown AI 与人工智能,AGI 的发展方向。 ``` + 4. 标题内的英文单词首字母大写。 -5. 代码块使用 ` ``` ` 包裹,并标注常见的语言标识符,如 ` ```python `。 +5. 代码块使用 ` ``` ` 包裹,并标注常见的语言标识符,如 ` ```python ` ,其作用是使代码正常高亮。 +::: details 代码高亮支持的语言 + +```ts +export type Lang = + | 'abap' + | 'actionscript-3' + | 'ada' + | 'apache' + | 'apex' + | 'apl' + | 'applescript' + | 'ara' + | 'asm' + | 'astro' + | 'awk' + | 'ballerina' + | 'bat' | 'batch' + | 'beancount' + | 'berry' | 'be' + | 'bibtex' + | 'bicep' + | 'blade' + | 'c' + | 'cadence' | 'cdc' + | 'clarity' + | 'clojure' | 'clj' + | 'cmake' + | 'cobol' + | 'codeql' | 'ql' + | 'coffee' + | 'cpp' + | 'crystal' + | 'csharp' | 'c#' | 'cs' + | 'css' + | 'cue' + | 'cypher' | 'cql' + | 'd' + | 'dart' + | 'dax' + | 'diff' + | 'docker' | 'dockerfile' + | 'dream-maker' + | 'elixir' + | 'elm' + | 'erb' + | 'erlang' | 'erl' + | 'fish' + | 'fsharp' | 'f#' | 'fs' + | 'gdresource' + | 'gdscript' + | 'gdshader' + | 'gherkin' + | 'git-commit' + | 'git-rebase' + | 'glimmer-js' | 'gjs' + | 'glimmer-ts' | 'gts' + | 'glsl' + | 'gnuplot' + | 'go' + | 'graphql' + | 'groovy' + | 'hack' + | 'haml' + | 'handlebars' | 'hbs' + | 'haskell' | 'hs' + | 'hcl' + | 'hjson' + | 'hlsl' + | 'html' + | 'http' + | 'imba' + | 'ini' | 'properties' + | 'java' + | 'javascript' | 'js' + | 'jinja-html' + | 'jison' + | 'json' + | 'json5' + | 'jsonc' + | 'jsonl' + | 'jsonnet' + | 'jssm' | 'fsl' + | 'jsx' + | 'julia' + | 'kotlin' + | 'kusto' | 'kql' + | 'latex' + | 'less' + | 'liquid' + | 'lisp' + | 'logo' + | 'lua' + | 'make' | 'makefile' + | 'markdown' | 'md' + | 'marko' + | 'matlab' + | 'mdx' + | 'mermaid' + | 'mojo' + | 'narrat' | 'nar' + | 'nextflow' | 'nf' + | 'nginx' + | 'nim' + | 'nix' + | 'objective-c' | 'objc' + | 'objective-cpp' + | 'ocaml' + | 'pascal' + | 'perl' + | 'php' + | 'plsql' + | 'postcss' + | 'powerquery' + | 'powershell' | 'ps' | 'ps1' + | 'prisma' + | 'prolog' + | 'proto' + | 'pug' | 'jade' + | 'puppet' + | 'purescript' + | 'python' | 'py' + | 'r' + | 'raku' | 'perl6' + | 'razor' + | 'reg' + | 'rel' + | 'riscv' + | 'rst' + | 'ruby' | 'rb' + | 'rust' | 'rs' + | 'sas' + | 'sass' + | 'scala' + | 'scheme' + | 'scss' + | 'shaderlab' | 'shader' + | 'shellscript' | 'bash' | 'sh' | 'shell' | 'zsh' + | 'shellsession' | 'console' + | 'smalltalk' + | 'solidity' + | 'sparql' + | 'splunk' | 'spl' + | 'sql' + | 'ssh-config' + | 'stata' + | 'stylus' | 'styl' + | 'svelte' + | 'swift' + | 'system-verilog' + | 'tasl' + | 'tcl' + | 'tex' + | 'toml' + | 'tsx' + | 'turtle' + | 'twig' + | 'typescript' | 'ts' + | 'v' + | 'vb' | 'cmd' + | 'verilog' + | 'vhdl' + | 'viml' | 'vim' | 'vimscript' + | 'vue-html' + | 'vue' + | 'vyper' | 'vy' + | 'wasm' + | 'wenyan' | '文言' + | 'wgsl' + | 'wolfram' + | 'xml' + | 'xsl' + | 'yaml' | 'yml' + | 'zenscript' + | 'zig' +``` + +::: ::: tip 🤓 注意 尽量不要使用 `typora` 因为它的渲染效果和本项目前端框架 `vitepress` 不一致。 -在 `typora` 中编辑完成后,确认一下 .md 文件源代码是否为正常 Markdown 。 -编辑完成后尽量启动本项目在前端查看效果。 -::: +在 `typora` 中编辑完成后,确认一下 .md 文件源代码是否为正常 Markdown 。 + +编辑完成后需要启动本项目在前端查看效果。 +::: ## 项目构建指南 -需要 nodejs v16.14.0 及以上版本 +vitepress 框架要求,强制需要 nodejs v18.0 及以上版本。 -使用包管理器 npm +本项目使用包管理器 npm。 ```bash npm install -npm run docs:dev #运行预览环境 +npm run docs:dev #运行预览环境 ``` + ```bash npm run docs:build #编译线上环境 npm run docs:preview #预览线上环境 @@ -62,11 +249,13 @@ npm run docs:preview #预览线上环境 注意尽量不要使用 `img` 标签,因为经前端构建解析后路径会不正确。 -后续会统一放置到 oss 存储桶中。 +后续会统一放置到 cos 存储桶中。 ## 项目配置指南 -修改新添加或移动位置的 md 文件需要在 `.vitepress/config.js` 中的 `sidebar` 中添加或修改对应的配置。 +修改新添加或移动位置的 md 文件需要在 `.vitepress/config.js`、`.vitepress/sidebar.js` 中添加或修改对应的配置。 + +> sidebar.js 文件会管理显示在左侧导航栏的所有路由 详见 [VitePress 官方文档](https://vitepress.dev/reference/default-theme-sidebar) @@ -117,9 +306,10 @@ subject为commit概述 其中详细内容可以参照 [约定式提交](https://www.conventionalcommits.org/zh-hans/v1.0.0/) -[![Conventional Commits](https://img.shields.io/badge/Conventional%20Commits-1.0.0-%23FE5196?logo=conventionalcommits&logoColor=white)](https://conventionalcommits.org) +![Conventional Commits](https://img.shields.io/badge/Conventional%20Commits-1.0.0-%23FE5196?logo=conventionalcommits&logoColor=white) ## Pull Request 流程与指南 + Fork 本仓库,然后在你的仓库中进行修改,修改完成后在本仓库创建 NEW Pull Request ,选择 compare across forks 提交 pr 并评论上你修改的具体信息即可,我们会第一时间审阅并合并。 ## Feature @@ -128,18 +318,19 @@ Fork 本仓库,然后在你的仓库中进行修改,修改完成后在本仓 ```latex $行内公式\arccos{a}$ ``` - 会渲染成 $\arccos{a}$ + > 会渲染成 $\arccos{a}$ ```latex $$单行公式\arcsin{b}$$ ``` - 会渲染成 - $$\arcsin{b}$$ + > 会渲染成 + > + > $$\arcsin{b}$$ ::: tip Latex语法在线编辑器 https://www.latexlive.com ::: 2. 支持Mermaid流程图,格式如下 - ```txt + ```markdown ```mermaid graph TD; A-->B; diff --git a/components/Bilibili.vue b/components/Bilibili.vue index e9fa068..a19860a 100644 --- a/components/Bilibili.vue +++ b/components/Bilibili.vue @@ -1,25 +1,32 @@